Created
April 10, 2025 17:18
-
-
Save gszauer/1beee535a44768d061942490e6bd3141 to your computer and use it in GitHub Desktop.
Object Rotator Prompt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Write a c++ class that rotates an object in 3d space. The camera is orthographic and a fixed distance away, you can only rotate the object. | |
Rotation should have smooth interpolation, giving it a mobile friendly feel. | |
smooth interpolation (even while draggin) is a must! The y axis should not be inverted. | |
This is NOT an arcball it needs to work anywhere the screen is touched. Go with a physics approach like a spring model rather than an arcball. | |
Take things like large or fast inputs, as well as suddent stops in input into account, and keep rotation smooth always. DAMPEN | |
This is the class you are implementing: | |
class ObjectRotator { | |
public: | |
inline void beginDrag(const glm::vec2& mouseScreenPos, const glm::vec2& viewportSize) { | |
// implement this | |
} | |
inline glm::quat drag(const glm::vec2& mouseScreenPos, const glm::vec2& viewportSize) { | |
// implement this. If you need delta time, its ImGui::GetIO().DeltaTime | |
// Return delta rotation to apply to object when dragging | |
} | |
inline glm::quat update(float deltaTime) { | |
// implement this | |
// Return delta rotation to apply to object when not dragging | |
} | |
inline bool endDrag() { | |
// implement this | |
} | |
float getSensitivity(); | |
void setSensitivity(float value); | |
float getDampening(); | |
void setDampening(float value); | |
// Max angular velocity, radians / second | |
float getMaxVelocity(); | |
void setMaxVelocity(float value); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ObjectRotator { | |
private: | |
glm::vec2 previousMousePos; | |
glm::vec3 angularVelocity = glm::vec3(0.0f); | |
bool isDragging = false; | |
float sensitivity = 8.0f; | |
float dampening = 6.0f; // Higher means faster slowdown | |
float maxVelocity = 14.0f; | |
public: | |
inline void beginDrag(const glm::vec2& mouseScreenPos, const glm::vec2& viewportSize) { | |
isDragging = true; | |
previousMousePos = mouseScreenPos; | |
angularVelocity = glm::vec3(0.0f); // Reset velocity when new drag starts | |
} | |
inline glm::quat drag(const glm::vec2& mouseScreenPos, const glm::vec2& viewportSize) { | |
const glm::vec2 currentPos = mouseScreenPos; | |
const glm::vec2 delta = currentPos - previousMousePos; | |
previousMousePos = currentPos; | |
// Convert pixel movement to normalized screen coordinates | |
const glm::vec2 deltaNormalized = delta / viewportSize; | |
// Calculate instantaneous velocity from this frame's movement | |
const float deltaTime = ImGui::GetIO().DeltaTime; | |
glm::vec3 frameVelocity(0.0f); | |
if (deltaTime > 0.0f) { | |
frameVelocity = glm::vec3( | |
deltaNormalized.y * sensitivity, // Pitch (X-axis) | |
deltaNormalized.x * sensitivity, // Yaw (Y-axis) | |
0.0f | |
) / deltaTime; | |
} | |
// During drag: set velocity directly based on current movement | |
angularVelocity = frameVelocity; | |
// Clamp velocity to maximum | |
const float currentSpeed = glm::length(angularVelocity); | |
if (currentSpeed > maxVelocity) { | |
angularVelocity = (angularVelocity / currentSpeed) * maxVelocity; | |
} | |
// Immediate rotation based on current drag | |
return quatFromAngularVelocity(deltaTime); | |
} | |
inline glm::quat update(float deltaTime) { | |
if (!isDragging) { | |
// Apply dampening when not dragging | |
angularVelocity *= glm::max(0.0f, 1.0f - dampening * deltaTime); | |
// Clamp to prevent tiny oscillations | |
if (glm::length(angularVelocity) < 0.01f) { | |
angularVelocity = glm::vec3(0.0f); | |
} | |
} | |
return quatFromAngularVelocity(deltaTime); | |
} | |
inline bool endDrag() { | |
isDragging = false; | |
return glm::length(angularVelocity) > 0.01f; | |
} | |
private: | |
inline glm::quat quatFromAngularVelocity(float deltaTime) const { | |
if (deltaTime <= 0.0f || glm::length(angularVelocity) < 1e-6f) { | |
return glm::quat(1.0f, 0.0f, 0.0f, 0.0f); | |
} | |
const float angle = glm::length(angularVelocity) * deltaTime; | |
const glm::vec3 axis = glm::normalize(angularVelocity); | |
return glm::angleAxis(angle, axis); | |
} | |
public: | |
// Getters/setters remain the same | |
float getSensitivity() { return sensitivity; } | |
void setSensitivity(float value) { sensitivity = value; } | |
float getDampening() { return dampening; } | |
void setDampening(float value) { dampening = value; } | |
float getMaxVelocity() { return maxVelocity; } | |
void setMaxVelocity(float value) { maxVelocity = value; } | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment