 Dakattack64

Member

5

Everything posted by Dakattack64

1.  Hello all!   I'm attempting to write a smooth third-person camera for a DirectX game I am making. My implementation uses a camera target that floats above the player's head, lerping to the player's X and Z location when the player moves. The camera itself is always a set distance away from the target, and calls "LookAt" on the target.   The camera currently follows the player smoothly upon translations, but rotations were jittery so I wanted to use quaternions and SLERP to make a smoother rotation around the player. However, with my current implementation below I seem to get strange rotations the more I rotate the camera. This leads me to believe that I am using the wrong axes or am encountering gimbal lock. Is there anything obviously wrong with my math? Or could it be a separate issue? Thanks in advance for your input.   Side Problem: How would I slerp between the two quaternions smoothly? What would I pass in for the ratio other than a fixed float? It seems impossible to slerp between two things in a single frame. I could do it over multiple frames, but the rotations would be reset after the first frame. So how would I accomplish this? // Decompose the matrix to get the original rotation XMVECTOR trans; XMVECTOR scale; XMVECTOR rotation; XMMatrixDecompose(&scale, &rotation, &trans, XMLoadFloat4x4(&m_camTarg.GetLocalMatrix())); XMVECTOR newRotation = rotation;   // Using the local X axis and the global Y for rotation; pitch and yaw are based on mouse rotation (delta) XMVECTOR rotLocalX = XMQuaternionRotationAxis(XMLoadFloat3(m_camTarg.GetLocalXAxis()), m_fPitch); XMVECTOR rotGlobalY = XMQuaternionRotationAxis(XMLoadFloat3(&XMFLOAT3(0.0f, 1.0f, 0.0f)), m_fYaw);   // Multiply the quaternions into the original rotation newRotation = XMQuaternionMultiply(newRotation, rotLocalX); newRotation = XMQuaternionMultiply(newRotation, rotGlobalY);   // Sluuurrrrpp! newRotation = XMQuaternionSlerp(rotation, newRotation, 0.5f);   // Generate a new matrix with the new rotation XMMATRIX newMat = XMMatrixAffineTransformation(scale, XMLoadFloat3(&XMFLOAT3(0.0f, 0.0f, 0.0f)), newRotation, trans);   // Set local matrix to new matrix with new rotation? m_camTarg.SetLocalMatrix(newMat);   // Move the camera based on the local axes of the camera target Vector3 camOffsetDirection = Vector3::Zero;   camOffsetDirection += *m_camTarg.GetLocalXAxis() * m_camOffset.x; // m_camOffset = (0.0f, 0.0f, -7.0f) camOffsetDirection += *m_camTarg.GetLocalYAxis() * m_camOffset.y; camOffsetDirection += *m_camTarg.GetLocalZAxis() * m_camOffset.z;   SetPosition(*m_camTarg.GetPosition() + camOffsetDirection);   LookAt(*GetPosition(), *m_camTarg.GetPosition(), Vector3::UnitY);
2. DirectX Smooth Third-Person Camera

I have peeked inside the newRotation and they look like valid values. In a previous implementation I was using XMQuaternionRotationRollPitchYaw() but because it uses world axes it wasn't rotating about the local X. This would cause problems where I wouldn't be able to rotate around the X axis when facing the player's left or right side (because I would be looking straight down the world X).   Hence, the reason why I am using the two separate axes for rotation; you want to rotate around the global Y axis, but the local X axis. Using global X won't allow us to change our pitch in all orientations, and using local Y will cause us to orbit in a strange manner. I could probably explain it better on paper.   I think that my problem might be caused by large delta mouse movements when the cursor goes outside of the screen, as the camera looks fine until I move it outside of the window. I'm going to see if setting the cursor to the center of the window every frame fixes the issue.
3. Source Code   I'm making a small DirectX Demo Scene but my camera seems to "snap" to odd positions when I attempt to rotate it. It only happens when rotating and I can't seem to find out what is causing it. // Get the cursor pos and calculate change in movement POINT cursorPos; GetCursorPos(&cursorPos); LONG deltaX = oldCursorPos.x - cursorPos.x; LONG deltaY = oldCursorPos.y - cursorPos.y;   // Hold right click to rotate if (GetAsyncKeyState(VK_RBUTTON)) { XMMATRIX xRotation = XMMatrixRotationY(((float)-deltaX  * (float)timer.Delta())); XMMATRIX yRotation = XMMatrixRotationX(((float)-deltaY * (float)timer.Delta()));   XMMATRIX view = XMLoadFloat4x4(&cameraMatrix);   XMFLOAT4 viewVector = XMFLOAT4(cameraMatrix.m, cameraMatrix.m, cameraMatrix.m, 1.0f); for (size_t i = 0; i < 3; i++) { cameraMatrix.m[i] = 0.0f; }   view = view * xRotation; view = yRotation * view;   XMStoreFloat4x4(&cameraMatrix, view);   cameraMatrix.m = viewVector.x; cameraMatrix.m = viewVector.y; cameraMatrix.m = viewVector.z; }   oldCursorPos = cursorPos; Above is the code that performs the rotations to the camera matrix, below is the code I use to set the view matrix equal to the inverse of the camera matrix. Both of these operations are done every frame. XMMATRIX camera = XMLoadFloat4x4(&cameraMatrix); XMMATRIX view = XMMatrixInverse(NULL, camera); XMStoreFloat4x4(&sceneMatrix.viewMatrix, view); Both of these snippets don't seem to be the problem though, as I have triple checked my notes and this is exactly how my instructor expects it to be done. This bug happens in debug and release mode.   I put the source code in the link above if an attractive person such as yourself dare look at the rest of the code. Beware: It is a small demo application so try not to cringe at the hard-coded objects and such.   Posted this on stackoverflow as well if you feel like getting some +rep over there. Thanks all!
4.   No, time shouldn't be involved because regardless of what frame you are on or how fast your FPS is, the change in mouse movement (deltaX/deltaY) remains constant.   Say I move my mouse 2 inches to the right at a constant speed; to make it simple lets say it takes us 1 second to do this.  At 30fps, each frame will calculate deltaX as 2/30 or 0.0667 inches. At 60fps, each frame will calculate deltaX as 2/60 or 0.0333 inches.   Using 60fps we simply calculate distance at a faster rate than we do at 30fps, but that doesn't change the overall distance I moved or the time it took to get there.    If you imagine a line representing the distance my hand moved, and ticks on the line representing where the program calculated deltaX, the 60fps program will simply have more ticks and they will be spaced closer together. But the distance I traveled and the time it took to get there remain constant.   As a matter of fact I'm not even sure if this would be used in joystick movements either, as you would simply multiply a movement speed times the value of the X axis of the stick ranging from -1.0f to 1.0f. Unless I'm misunderstanding how the hardware is used.
5. Thanks guys! I removed time.Delta() and replaced it with a simple modifiable float value for rotationSpeed. Everything is working now :)