Implementing an ArcbAll MovementController

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Implementing an ArcbAll MovementController

      Hello,

      After messing with the latest version of the GCC Source Code i am trying to program a custom Model Viewer using the framework.

      I checked in the DXUT10 an implementation of a ModelViewer Camera class based on Quaternions and i wanted to adapt this implementation to an ArcBall MovementController inside the framework, but im unable to get the camera to rotate around the target object as it should...

      Some time ago i managed to implement a camera system based on UVN vectors (I dont know if this is the correct name) which worked flawlessly, so im not sure if it would be better to try the DXUT system or adapt what i already had...

      Any suggestion?

      Regards,

      C Source Code

      1. #pragma once
      2. #include "Geometry.h"
      3. // Forward declarations
      4. class SceneNode;
      5. class MovementController;
      6. class ArcBallCamMovementController : public MovementController
      7. {
      8. public:
      9. ArcBallCamMovementController (shared_ptr<SceneNode> object, float initialYaw, float initialPitch, bool rotateWhenLButtonDown);
      10. void Reset();
      11. virtual void OnUpdate(DWORD const elapsedMs);
      12. virtual bool VOnLButtonDown(const CPoint &mousePos);
      13. bool VOnMouseMove(const CPoint &mousePos);
      14. Vec3 ScreenToVector( float fScreenPtX, float fScreenPtY );
      15. Quaternion QuatFromBallPoints( Vec3 &vFrom, Vec3 &vTo );
      16. virtual void SetObject(shared_ptr<SceneNode> newObject);
      17. private:
      18. bool m_bUpdateObject;
      19. shared_ptr<CameraNode> m_pSceneCam;
      20. shared_ptr<SceneNode> m_pCamTarget;
      21. //from MovController
      22. //CRect m_WindowClientRect;
      23. Quaternion m_qDown; // Quaternion before button down
      24. Quaternion m_qNow; // Composite quaternion for current drag
      25. float m_fRadius; // arc ball's radius in screen coords
      26. float m_fRadiusTranslation; // arc ball's radius for translating the target
      27. Vec3 m_vDownPt; // starting point of rotation arc
      28. Vec3 m_vCurrentPt; // current point of rotation arc
      29. Vec3 m_vEye; // Camera eye position
      30. Vec3 m_vLookAt; // LookAt position
      31. Mat4x4 m_CameraRotLast;
      32. };
      33. -----------
      34. #include "u3dVisorStd.h"
      35. #include "..\GameCode.h"
      36. #include "..\Actors.h"
      37. #include "SceneNodes.h"
      38. #include "u3dSceneNodes.h"
      39. /*
      40. MovementController::MovementController(shared_ptr<SceneNode> object, float initialYaw, float initialPitch, bool rotateWhenLButtonDown)
      41. : m_object(object)
      42. {
      43. m_object->VGet()->Transform(&m_matToWorld, &m_matFromWorld);
      44. }
      45. */
      46. ArcBallCamMovementController ::ArcBallCamMovementController (shared_ptr<SceneNode> object, float initialYaw, float initialPitch, bool rotateWhenLButtonDown)
      47. :MovementController(object, initialYaw, initialPitch,rotateWhenLButtonDown),
      48. m_pSceneCam((CameraNode*)(&*m_object))
      49. {
      50. Reset();
      51. assert(m_object);
      52. m_pCamTarget = m_pSceneCam->GetTarget();
      53. //eye and lookat from the camera
      54. m_vEye = m_pSceneCam->GetPosition();
      55. m_vLookAt = Vec3(m_matToWorld._31, m_matToWorld._32, m_matToWorld._33);
      56. //Build quat from the camera object
      57. m_qNow.Build(m_matToWorld);
      58. // Set the radius according to the distance
      59. if(m_pCamTarget)
      60. {
      61. Vec3 v(m_pCamTarget->GetPosition() - m_vEye);
      62. m_fRadius = v.Length();
      63. }
      64. m_bUpdateObject = false;
      65. }
      66. void ArcBallCamMovementController::SetObject(shared_ptr<SceneNode> newObject)
      67. {
      68. // Set the radius according to the distance
      69. m_pCamTarget = m_pSceneCam->GetTarget();
      70. m_vLookAt = m_pCamTarget->GetPosition();
      71. Vec3 v(m_vLookAt - m_vEye);
      72. m_fRadius = v.Length();
      73. }
      74. //--------------------------------------------------------------------------------------
      75. void ArcBallCamMovementController::Reset()
      76. {
      77. m_qDown.Build(Mat4x4::g_Identity);
      78. m_qNow.Build(Mat4x4::g_Identity);
      79. m_fRadiusTranslation = 1.0f;
      80. m_fRadius = 1.0f;
      81. }
      82. //--------------------------------------------------------------------------------------
      83. Vec3 ArcBallCamMovementController::ScreenToVector( float fScreenPtX, float fScreenPtY )
      84. {
      85. // Scale to screen
      86. float x = -(fScreenPtX - m_WinOffset.x - m_nWidth/2) / (m_fRadius*m_nWidth/2);
      87. float y = (fScreenPtY - m_WinOffset.y - m_nHeight/2) / (m_fRadius*m_nHeight/2);
      88. float z = 0.0f;
      89. float mag = x*x + y*y;
      90. if( mag > 1.0f )
      91. {
      92. FLOAT scale = 1.0f/sqrtf(mag);
      93. x *= scale;
      94. y *= scale;
      95. }
      96. else
      97. z = sqrtf( 1.0f - mag );
      98. // Return vector
      99. return Vec3( x, y, z );
      100. }
      101. //--------------------------------------------------------------------------------------
      102. Quaternion ArcBallCamMovementController::QuatFromBallPoints( Vec3 &vFrom, Vec3 &vTo )
      103. {
      104. Vec3 vPart;
      105. float fDot = vFrom.Dot(vTo);
      106. vPart = vFrom.Cross(vTo);
      107. return Quaternion(D3DXQUATERNION(vPart.x, vPart.y, vPart.z, fDot));
      108. }
      109. //--------------------------------------------------------------------------------------
      110. #define MAX(a, b) ((a) >= (b) ? (a) : (b))
      111. #define MIN(a, b) ((a) < (b) ? (a) : (b))
      112. #define RADIANS_TO_DEGREES(x) ((x) * 180.0f / D3DX_PI)
      113. #define DEGREES_TO_RADIANS(x) ((x) * D3DX_PI / 180.0f)
      114. //--------------------------------------------------------------------------------------
      115. bool ArcBallCamMovementController::VOnLButtonDown(const CPoint &mousePos)
      116. {
      117. m_mouseLButtonDown = true;
      118. // We want mouise movement to be relative to the position
      119. // the cursor was at when the user first presses down on
      120. // the left button
      121. if( mousePos.x >= m_WinOffset.x &&
      122. mousePos.x < m_WinOffset.x + m_nWidth &&
      123. mousePos.y >= m_WinOffset.y &&
      124. mousePos.y < m_WinOffset.y + m_nHeight )
      125. {
      126. m_qDown = m_qNow;
      127. m_vDownPt = ScreenToVector( mousePos.x, mousePos.y );
      128. m_lastMousePos = mousePos;
      129. }
      130. return true;
      131. }
      132. bool ArcBallCamMovementController::VOnMouseMove(const CPoint &mousePos)
      133. {
      134. if (m_bRotateWhenLButtonDown)
      135. {
      136. // Mode 1 - rotate the view only when the left mouse button is down
      137. // Only look around if the left button is down
      138. if(m_lastMousePos!=mousePos && m_mouseLButtonDown)
      139. {
      140. m_vCurrentPt = ScreenToVector( mousePos.x, mousePos.y );
      141. m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt );
      142. //m_qNow.Normalize();
      143. m_bUpdateObject = true;
      144. //m_fTargetYaw = m_fTargetYaw + (m_lastMousePos.x - mousePos.x);
      145. //m_fTargetPitch = m_fTargetPitch + (mousePos.y - m_lastMousePos.y);
      146. m_fTargetYaw = (m_lastMousePos.x - mousePos.x);
      147. m_fTargetPitch = (mousePos.y - m_lastMousePos.y);
      148. m_lastMousePos = mousePos;
      149. }
      150. }
      151. else if(m_lastMousePos!=mousePos)
      152. {
      153. m_vCurrentPt = ScreenToVector( mousePos.x, mousePos.y );
      154. m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt );
      155. //m_qNow.Normalize();
      156. m_bUpdateObject = true;
      157. // Mode 2 - rotate the controller when the mouse buttons are up
      158. //m_fTargetYaw = m_fTargetYaw + (m_lastMousePos.x - mousePos.x);
      159. //m_fTargetPitch = m_fTargetPitch + (mousePos.y - m_lastMousePos.y);
      160. m_fTargetYaw = (m_lastMousePos.x - mousePos.x);
      161. m_fTargetPitch = (mousePos.y - m_lastMousePos.y);
      162. m_lastMousePos = mousePos;
      163. }
      164. return true;
      165. }
      166. void ArcBallCamMovementController::OnUpdate(DWORD const deltaMilliseconds)
      167. {
      168. if(!m_bUpdateObject)
      169. return;
      170. float elapsedTime = (float)deltaMilliseconds / 1000.0f;
      171. // Ramp the acceleration by the elapsed time.
      172. float numberOfSeconds = 5.f;
      173. m_currentSpeed += m_maxSpeed * ( (elapsedTime*elapsedTime) / numberOfSeconds);
      174. if (m_currentSpeed > m_maxSpeed)
      175. m_currentSpeed = m_maxSpeed;
      176. //Vec3 direction(m_fTargetYaw, m_fTargetPitch, 0.f),
      177. Vec3 direction(m_fTargetYaw, m_fTargetPitch, 0.f),
      178. posDelta;
      179. //Calculate delta position
      180. posDelta = direction * m_currentSpeed;
      181. // Get the inverse of the arcball's rotation matrix = camera rotation matrix
      182. Mat4x4 CameraRot;
      183. CameraRot.BuildRotationQuat(m_qNow);
      184. CameraRot.Inverse();
      185. Vec3 atToWorld(CameraRot.Xform(g_Forward4)),
      186. upToWorld(CameraRot.Xform(g_Up4)),
      187. vposDeltaWorld( CameraRot.Xform(posDelta));//,
      188. //vLookAt;
      189. //??
      190. //D3DXVec3TransformCoord(&temp, &v, this);
      191. // Move the lookAt position
      192. m_vLookAt += vposDeltaWorld;
      193. // Update the eye point based on a radius away from the lookAt position
      194. m_vEye = m_vLookAt - atToWorld * m_fRadius;
      195. // Update the view matrix
      196. D3DXMATRIX mView;
      197. D3DXMatrixLookAtLH( &mView, &m_vEye, &m_vLookAt, &upToWorld );
      198. Mat4x4 mMView(mView), InvmMView(mMView.Inverse());
      199. InvmMView._41 = InvmMView._42 = InvmMView._43 = 0.f;
      200. //-------------
      201. Mat4x4 matToWorld, matLastToWorldInv(m_matLastToWorld.Inverse()), CameraRotLastInv(m_CameraRotLast.Inverse());
      202. //equals to the camera??????????
      203. matToWorld.BuildRotationQuat(m_qNow);
      204. matToWorld = matToWorld * mMView * matLastToWorldInv * matToWorld * InvmMView;
      205. //??????
      206. //Update world??? according to target-model movement?
      207. matToWorld = matToWorld * CameraRotLastInv * CameraRot;
      208. m_CameraRotLast = CameraRot;
      209. m_matLastToWorld = matToWorld;
      210. Vec3 XBasis(matToWorld._11, matToWorld._12, matToWorld._13),
      211. YBasis(matToWorld._21, matToWorld._22, matToWorld._23),
      212. ZBasis(matToWorld._31, matToWorld._32, matToWorld._33);
      213. XBasis.Normalize();
      214. YBasis.Normalize();
      215. ZBasis.Normalize();
      216. matToWorld._11 = XBasis.x; matToWorld._12 = XBasis.y; matToWorld._13 = XBasis.z;
      217. matToWorld._21 = YBasis.x; matToWorld._22 = YBasis.y; matToWorld._23 = YBasis.z;
      218. matToWorld._31 = ZBasis.x; matToWorld._32 = ZBasis.y; matToWorld._33 = ZBasis.z;
      219. matToWorld.SetPosition(m_vLookAt);
      220. //matToWorld.SetPosition(m_vEye);
      221. //m_matPosition.BuildTranslation(m_vEye * -1.0f);
      222. m_matPosition.BuildTranslation(m_vEye);
      223. m_matToWorld = m_matPosition * matToWorld;
      224. m_matFromWorld = m_matToWorld.Inverse();
      225. m_object->VSetTransform(&m_matToWorld, &m_matFromWorld);
      226. //m_object->VSetTransform(&mMView, NULL);
      227. m_bUpdateObject = false;
      Display All
    • I've only quickly glanced at the code, so I don't know how much help I can be now, but do you see any sort of rotation when you run the app? And are you sure the target of the camera and the other external data is valid?
      "There are of course many problems connected with life, of which some of the most popular are: Why are people born? Why do they die? Why do they want to spend so much of the intervening time wearing digital watches?"
      -Douglas Adams
    • Yeah, sorry if it wasnt well explained... I was running a bit mad, :(...

      - I am sure that the camera target is correctly setup, i made some modifications on the SetViewTransform and viewlistener handling functions to attach the target... Right now, the camera makes like a strafing movement when applying yaw and it pitches a bit but very slowly...

      - Basically, based on the dxut code, i am using a quaternion generated from the movement of the mouse to generate the rotation matrix and applying it to the same mouse movement vector to obtain the camera view direction movement, after that i create a new camera view matrix using Lookatlh. After that i am losing a bit, because it seems to generate a new world matrix using basis change... This is all implemented in the OnUpdate function.

      - Anyway ill try to relax a bit and try to validate all the data, maths isnt my strengh and i overreact when dealing with all these...

      Regards,

      @B^)>
    • talking to myself

      Well finally it worked somehow. I didnt use the dxut version but adopted another from the a arcball opengl version i found....

      I presume this is enough for a simple model viewer, now ill try to load and display some models using a custom model exporter...

      @B^)>

      Brainfuck Source Code

      1. class ArcBallCamMovementController : public MovementController
      2. {
      3. public:
      4. ArcBallCamMovementController (shared_ptr<SceneNode> object, float initialYaw, float initialPitch, bool rotateWhenLButtonDown);
      5. void Reset();
      6. virtual void OnUpdate(DWORD const elapsedMs);
      7. virtual bool VOnLButtonDown(const CPoint &mousePos);
      8. bool VOnMouseMove(const CPoint &mousePos);
      9. Vec3 ScreenToVector( float fScreenPtX, float fScreenPtY );
      10. virtual void SetObject(shared_ptr<SceneNode> newObject);
      11. Vec3 PlanarCoord(float posX, float posY);
      12. private:
      13. bool m_bUpdateObject, m_bViewRotation;
      14. shared_ptr<CameraNode> m_pSceneCam;
      15. shared_ptr<SceneNode> m_pCamTarget;
      16. Quaternion m_qLast, m_qDown, m_qNow;
      17. float m_fZoom, m_fZoom2; // current radius
      18. float m_fRadius, m_fRadius2; // arc ball's radius
      19. float m_fEdge; // the distance from the origin of the plane that intersects
      20. // the edge of the visible sphere (tangent to a ray from the eye)
      21. // whether we are using a sphere or plane
      22. bool m_bPlanar;
      23. Vec3 m_vEye; // Camera eye position
      24. Vec3 m_vLookAt; // LookAt position
      25. Vec3 m_vUptoWorld; // LookAt position
      26. Vec3 m_vRighttoWorld; // LookAt position
      27. Mat4x4 m_CameraRotLast;
      28. //
      29. //CHECK!!!!!!!!!! Windows bounds and projection from MovController!!!!!
      30. //CRect m_WindowClientRect;
      31. //int m_nWidth; // arc ball's window width
      32. //int m_nHeight; // arc ball's window height
      33. Mat4x4 m_matProjection;
      34. Vec3 m_vDownPt; // starting point of rotation arc
      35. Vec3 m_vCurrentPt; // current point of rotation arc
      36. };
      37. ArcBallCamMovementController ::ArcBallCamMovementController (shared_ptr<SceneNode> object, float initialYaw, float initialPitch, bool rotateWhenLButtonDown)
      38. :MovementController(object, initialYaw, initialPitch,rotateWhenLButtonDown),
      39. m_pSceneCam((CameraNode*)(&*m_object))
      40. {
      41. Reset();
      42. assert(m_object);
      43. m_matLastToWorld = m_matToWorld;
      44. m_pCamTarget = m_pSceneCam->GetTarget();
      45. //eye and lookat from the camera
      46. m_vEye = m_pSceneCam->GetPosition();
      47. //NOT VALID, SetObject should be called!!
      48. m_vLookAt = Vec3(m_matToWorld._31, m_matToWorld._32, m_matToWorld._33);
      49. m_vRighttoWorld = Vec3(m_matToWorld._11, m_matToWorld._12, m_matToWorld._13);
      50. m_vUptoWorld = Vec3(m_matToWorld._21, m_matToWorld._22, m_matToWorld._23);
      51. //Build quat from the camera object
      52. m_qNow.Build(m_matToWorld);
      53. // Set the radius according to the distance
      54. if(m_pCamTarget)
      55. {
      56. Vec3 v(m_pCamTarget->GetPosition() - m_vEye);
      57. m_fRadius = v.Length();
      58. }
      59. m_matProjection = m_pSceneCam->GetProjection();
      60. m_bUpdateObject = false;
      61. //TODO: this case is planar rotation
      62. m_bViewRotation = true;
      63. }
      64. //--------------------------------------------------------------------------------------
      65. void ArcBallCamMovementController::SetObject(shared_ptr<SceneNode> newObject)
      66. {
      67. //Case m_bViewRotation = true!!
      68. // Set the radius according to the distance eye-object
      69. m_pCamTarget = m_pSceneCam->GetTarget();
      70. m_vLookAt = m_pCamTarget->GetPosition() - m_vEye;
      71. m_fRadius = m_vLookAt.Length();
      72. //should be equal to toworld._3x??
      73. m_vLookAt.Normalize();
      74. // m_vLookAt = Vec3(m_matToWorld._31, m_matToWorld._32, m_matToWorld._33);
      75. m_vRighttoWorld = Vec3(m_matToWorld._11, m_matToWorld._12, m_matToWorld._13);
      76. m_vUptoWorld = Vec3(m_matToWorld._21, m_matToWorld._22, m_matToWorld._23);
      77. m_qNow.Build(m_matToWorld);
      78. m_qLast = m_qNow;
      79. //TODO:ARG!!!
      80. m_matProjection = m_pSceneCam->GetProjection();
      81. //TODO:Case m_bViewRotation = false!!
      82. }
      83. //--------------------------------------------------------------------------------------
      84. void ArcBallCamMovementController::Reset()
      85. {
      86. m_qLast.Build(Mat4x4::g_Identity);
      87. m_qDown.Build(Mat4x4::g_Identity);
      88. m_qNow.Build(Mat4x4::g_Identity);
      89. m_fZoom = 1.0f;
      90. m_fRadius = 1.0f;
      91. m_fEdge = 1.0f;
      92. m_bPlanar = false;
      93. }
      94. //--------------------------------------------------------------------------------------
      95. Vec3 ArcBallCamMovementController::ScreenToVector( float fScreenPtX, float fScreenPtY )
      96. {
      97. float projx = m_matProjection._11,
      98. projy = m_matProjection._22;
      99. Vec3 vInvProj( (((2.0f * fScreenPtX)/m_nWidth)-1) / projx,
      100. -(((2.0f * fScreenPtY)/m_nHeight)-1) / projy,
      101. 1.0f);
      102. vInvProj = m_matToWorld.Xform(vInvProj);
      103. return vInvProj;
      104. }
      105. //--------------------------------------------------------------------------------------
      106. Vec3 ArcBallCamMovementController::PlanarCoord(float posX, float posY)
      107. {
      108. Vec3 DownPt(ScreenToVector( posX, posY )),
      109. vecEyeDownPt(DownPt - m_vEye),
      110. d;
      111. // intersect the point with the trackball plane
      112. float intersect = (0.0f - m_fRadius) / (m_vLookAt.Dot(vecEyeDownPt));
      113. d = m_vEye + vecEyeDownPt*intersect;
      114. return Vec3(m_vUptoWorld.Dot(d), m_vRighttoWorld.Dot(d), 0.0);
      115. }
      116. //--------------------------------------------------------------------------------------
      117. bool ArcBallCamMovementController::VOnLButtonDown(const CPoint &mousePos)
      118. {
      119. m_mouseLButtonDown = true;
      120. m_vDownPt = PlanarCoord( mousePos.x, mousePos.y );
      121. m_lastMousePos = mousePos;
      122. return true;
      123. }
      124. //--------------------------------------------------------------------------------------
      125. bool ArcBallCamMovementController::VOnMouseMove(const CPoint &mousePos)
      126. {
      127. if (m_bRotateWhenLButtonDown)
      128. {
      129. // Mode 1 - rotate the view only when the left mouse button is down
      130. // Only look around if the left button is down
      131. if(m_lastMousePos!=mousePos && m_mouseLButtonDown)
      132. {
      133. m_vCurrentPt = PlanarCoord( mousePos.x, mousePos.y );
      134. m_lastMousePos = mousePos;
      135. m_bUpdateObject = true;
      136. }
      137. }
      138. else if(m_lastMousePos!=mousePos)
      139. {
      140. m_vCurrentPt = PlanarCoord( mousePos.x, mousePos.y );
      141. //m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt );
      142. //m_qNow.Normalize();
      143. m_bUpdateObject = true;
      144. // Mode 2 - rotate the controller when the mouse buttons are up
      145. //m_fTargetYaw = m_fTargetYaw + (m_lastMousePos.x - mousePos.x);
      146. //m_fTargetPitch = m_fTargetPitch + (mousePos.y - m_lastMousePos.y);
      147. //m_fTargetYaw = (m_lastMousePos.x - mousePos.x);
      148. //m_fTargetPitch = (mousePos.y - m_lastMousePos.y);
      149. m_lastMousePos = mousePos;
      150. }
      151. return true;
      152. }
      153. //--------------------------------------------------------------------------------------
      154. void ArcBallCamMovementController::OnUpdate(DWORD const deltaMilliseconds)
      155. {
      156. if(!m_bUpdateObject)
      157. return;
      158. if(m_vDownPt == m_vCurrentPt)
      159. return;
      160. // d is motion since the last position, note z=0!
      161. Vec3 d = m_vCurrentPt - m_vDownPt;
      162. //float angle = d.Length() * 0.5;
      163. float angle = d.Length() * 0.5;
      164. float cosa = cos( angle );
      165. float sina = sin( angle );
      166. Vec3 p = ((m_vRighttoWorld*d.x)-(m_vUptoWorld*d.y));
      167. p.Normalize();
      168. p *= sina;
      169. m_qDown.BuildAxisAngle(p, cosa*(float)deltaMilliseconds / 1000.0f);
      170. m_qNow = m_qNow * m_qDown;
      171. Mat4x4 mq;
      172. mq.BuildRotationQuat(m_qNow);
      173. //CORRECTO???
      174. m_matToWorld= mq;
      175. m_vRighttoWorld = Vec3(m_matToWorld._11, m_matToWorld._12, m_matToWorld._13);
      176. m_vUptoWorld = Vec3(m_matToWorld._21, m_matToWorld._22, m_matToWorld._23);
      177. m_vLookAt = Vec3(m_matToWorld._31, m_matToWorld._32, m_matToWorld._33);
      178. m_vEye = m_pCamTarget->GetPosition() - (m_vLookAt * m_fRadius);
      179. m_matLastToWorld = mq;
      180. m_matLastToWorld.SetPosition(m_vEye);
      181. m_matFromWorld = m_matLastToWorld.Inverse();
      182. m_object->VSetTransform(&m_matLastToWorld, &m_matFromWorld);
      183. m_vDownPt = m_vCurrentPt;
      184. m_bUpdateObject = false;
      185. }
      Display All