0
\$\begingroup\$

Okay, this is the code that works for a FPS camera, except it allows the player to flip it over by going under/over -/+90° rotation on Y-axis:

transformation->rotateObjectFromRight(glm::radians(angleX), glm::tvec3<GLfloat>(0.0f, 1.0f, 0.0f));
transformation->rotateObjectFromLeft(glm::radians(angleY), glm::tvec3<GLfloat>(1.0f, 0.0f, 0.0f)); 

transformation object holds the data required to construct the view matrix, among others, a quaternion representing the rotation.

The functions called will construct the quaternion with the given data and then multiply it with the rotation quaternion either from the left (relative to global axes) or the right (relative to local axes) side.

angleX and angleY are mouse X and Y offsets representing the angles to rotate around.

The first line yaws the camera around local Y-axis, while the second then pitches it around global X-axis, creating the characteristic FPS camera movement.

Okay. So far so good. This is the code that should limit the pitch to never exceed the +/-90 boundaries:

transformation->rotateObjectFromRight(glm::radians(angleX), glm::tvec3<GLfloat>(0.0f, 1.0f, 0.0f));  

glm::tvec3<GLfloat> forwardVector = glm::rotate(glm::inverse(transformation->getRotation()), glm::tvec3<GLfloat>(0.0f, 0.0f, 1.0f));
GLfloat pitchAngle = forwardVector.y * 90.0f;
angleY = glm::clamp(angleY, -(pitchAngle + 90.0f), -(pitchAngle - 90.0f));

transformation->rotateObjectFromLeft(glm::radians(angleY), glm::tvec3<GLfloat>(1.0f, 0.0f, 0.0f)); 

First and the last line are the same. What happens here?

First I get the unit vector that lies on the Z-axis and rotate it so that it represents the forward vector of the camera. I then take the Y component of that vector (ranging from -1 to 1) and multiply it with 90 to get the degrees. Then I clamp the angleY so that current rotation combined with the new one never exceeds the +/-90° boundary.

If the rotation was about to flip the camera overhead, it would change the new rotation angle so the camera looks straight up. Similar thing for underfoot flipping.

However, the camera acts weird. It's fastest at pitch angles close to 0°, but gets progressively slower as the pitch nears +/-90°. If I move my mouse slower, the camera is faster, if I move it faster, it's slower.

It's as though it's discarding the too large/small angleY values instead of clamping them to the appropriate values (but it's not, and I can confirm via the debugger - all the calculated values look alright and are correct).

What could be amiss here to cause such weird movement?

\$\endgroup\$
1
\$\begingroup\$

I was, interestingly enough, using radians instead of degrees. Usually it's the other way around.

\$\endgroup\$
  • \$\begingroup\$ Do you fix your camera movement speed based on the delta time? Is not the same move 5 pixels in 1 second than moving 5 pixels in 10ms. Another thing, use quaternions for the rotations, they are faster and also they dont have some artifacts which angles have. \$\endgroup\$ – Haruko Nov 3 '16 at 19:29
  • \$\begingroup\$ I only have sensitivity currently, but the engine is still to undeveloped to predict some things. I'll refactor it when I get to it. I'm learning it all stll. I am using quaternions, but I don't know how to translate two angles (X and Y mouse offsets) to a quaternion(s) I can multiply with my rotation quaternion that is stored in the transformation class any other way than I currently am (angle and vector are transformed into a quaternion further down in the code using glm::angleAxis and then multiplied with the stored quaternion from the appropriate side). Is there a better way? \$\endgroup\$ – Karlovsky120 Nov 3 '16 at 19:39
  • 1
    \$\begingroup\$ It is the way to do it. Are you conjugating the quaternion for the calculate of the projection view? It should be like this: ProjectionMatrix * Matrix.ToRotationMatrix(GetRotation().Conjugate()) * Matrix.GetTranslation(Position*-1) \$\endgroup\$ – Haruko Nov 3 '16 at 19:46
  • \$\begingroup\$ iewMatrix = glm::tmat4x4<GLfloat>(); viewMatrix *= glm::mat4_cast(glm::tquat<GLfloat>(transformation->getRotation())); viewMatrix = glm::translate(viewMatrix, (transformation->getPosition())); <---- this is the code I use to create a viewMatrix from transformation. Getters get the quaternion and the position vector. I ignore the scale for the camera. I'll research what you said. \$\endgroup\$ – Karlovsky120 Nov 3 '16 at 20:29
  • \$\begingroup\$ Oh, I see what you mean. I'm doing it kind of loopsided. The transformation holds the data that gets inverted on input. Should I change it so it's converted upon matrix creation? What is faster? \$\endgroup\$ – Karlovsky120 Nov 3 '16 at 20:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.