CArcballCameraAnimator.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | /* 일리히트 아크볼 회전 카메라 애니메이터 최종 수정일 : 10.04.06 만든이 : 정 광 일 */ #pragma once #pragma warning (disable : 4244) // 형변환 경고 : u32 --> float #include <cassert> #include <irrlicht.h> using namespace irr; using namespace scene; using namespace core; class CArcballCameraAnimator : public ISceneNodeAnimator { public : CArcballCameraAnimator(u32 nWidth, u32 nHeight, f32 ZSpeed = 5.f, float ZoomMin = 50, float ZoomMax = 80); ~CArcballCameraAnimator( void ); // arc ball camera functions void setZoom( float ZoomMin, float ZoomMax, float ZoomSpeed); void setBounds( float newWidth, float newHeight); void reset(); // scene node animator virtual functions virtual void animateNode(ISceneNode* node, u32 timeMs); virtual bool OnEvent( const SEvent& event); virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0); virtual bool isEventReceiverEnabled() const { return true ; } virtual bool hasFinished( void ) const { return false ; } protected : // arc ball inner function void _mapToSphere( const position2df&, vector3df* newVec) const ; private : bool m_bFirstInit; core::vector3df m_vFirstPos; core::vector3df m_vFirstTarget; core::vector3df m_vFirstUp; core::position2df m_MousePt; bool m_bClicked; bool m_bDragging; core::matrix4 m_Transform; core::matrix4 m_LastRot; core::matrix4 m_ThisRot; core::vector3df m_vStart; float m_fAdjustWidth; float m_fAdjustHeight; float m_fZoom; float m_fZoomSpeed; float m_fZoomMin; float m_fZoomMax; }; |
CArcballCameraAnimator.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | #include "CArcballCameraAnimator.h" CArcballCameraAnimator::CArcballCameraAnimator(u32 nWidth, u32 nHeight, f32 ZSpeed, float ZoomMin, float ZoomMax) :m_bFirstInit( true ), m_bDragging( false ), m_bClicked( false ) { setBounds(nWidth, nHeight); setZoom(ZoomMin, ZoomMin, ZSpeed); reset(); } CArcballCameraAnimator::~CArcballCameraAnimator( void ) { } void CArcballCameraAnimator::reset() { m_LastRot.makeIdentity(); m_ThisRot.makeIdentity(); m_Transform.makeIdentity(); } void CArcballCameraAnimator::setBounds( float newWidth, float newHeight) { // normalize -1.0f ~ 1.0f assert ( (newWidth > 1.0f) && (newHeight > 1.0f)); m_fAdjustWidth = 2.0f / (newWidth - 1.0f); m_fAdjustHeight= 2.0f / (newHeight- 1.0f); } void CArcballCameraAnimator::setZoom( float ZoomMin, float ZoomMax, float ZoomSpeed) { m_fZoomMin = ZoomMin; m_fZoomMax = ZoomMax; m_fZoomSpeed = ZoomSpeed; } void CArcballCameraAnimator::_mapToSphere( const position2df& newPt, vector3df* newVec) const { ////////////////////////////////////////////////////////////////////////// // 2차원 평면좌표계에서 3차원 구면좌표계로 변환 position2df TmpPt; f32 length; TmpPt = newPt; TmpPt.X = (TmpPt.X * m_fAdjustWidth) - 1.f; TmpPt.Y = 1.f - (TmpPt.Y * m_fAdjustHeight); // l = x*x + y*y length = (TmpPt.X * TmpPt.X) + (TmpPt.Y * TmpPt.Y); if (length > 1.0f) { f32 norm = 1.0f / squareroot(length); newVec->X = TmpPt.X * norm; newVec->Y = TmpPt.Y * norm; newVec->Z = 0.0f; } else { newVec->X = TmpPt.X; newVec->Y = TmpPt.Y; newVec->Z = squareroot(1.f - length); } } void CArcballCameraAnimator::animateNode(ISceneNode* node, u32 timeMs) { ////////////////////////////////////////////////////////////////////////// // 적합한 노드인가? if (!node || node->getType() != scene::ESNT_CAMERA) return ; ICameraSceneNode* camera = static_cast <ICameraSceneNode*>(node); scene::ISceneManager* smgr = camera->getSceneManager(); if (smgr && smgr->getActiveCamera() != camera) return ; ////////////////////////////////////////////////////////////////////////// // 현재 드래깅 중이 아니라면 카메라의 이동도 없다. if (!m_bDragging) return ; ////////////////////////////////////////////////////////////////////////// // 초기화 과정을 아래와 같은 랜더링 루프 안에 두는 것은 바람직하지 않지만, // 그렇지 않을경우 생성자에서 카메라 노드에 대한 포인터 사용이 필요해지게 된다. if (m_bFirstInit) { m_bFirstInit = false ; m_vFirstPos = camera->getPosition(); m_vFirstTarget = camera->getTarget(); m_vFirstUp = camera->getUpVector(); m_fZoom = (m_vFirstPos - m_vFirstTarget).getLength(); m_vFirstPos.normalize(); } ////////////////////////////////////////////////////////////////////////// // 임시 복사본 생성 및 회전 적용 core::vector3df newPos = m_vFirstPos; core::vector3df newTarget = m_vFirstTarget; core::vector3df newUp = m_vFirstUp; m_Transform.inverseRotateVect(newPos); m_Transform.inverseRotateVect(newTarget); m_Transform.inverseRotateVect(newUp); camera->setPosition( newPos * m_fZoom ); camera->setTarget( newTarget ); camera->setUpVector( newUp ); ////////////////////////////////////////////////////////////////////////// // ICameraSceneNode::setViewMatrixAffector() 함수에 관해 // // 일리히트 엔진에서는 ICameraSceneNode 인터페이스의 맴버 함수로 // setViewMatrixAffector(matrix4) 란 함수를 제공한다. 이름에서와 같이 // ViewMatrix 에 적용되는 함수로서 우리가 구한 회전 매트릭스(m_Transform)를 // 적용하면 아크볼 회전 효과를 얻을수 있으며 다음과 같이 간결히 표현된다. // // camera->setViewMatrixAffector(m_Transform); // // 이 경우 소스코드는 매우 간결해 지지만, 엔진에서 제공하는 기능의 일부분에 // 제약이 생긴다. ViewMatrixAffector 의 사용은 최종 View Matrix 에 단순히 // 매트릭스를 곱하는 것으로서 노드의 Position, Target, UpVector 등은 변하지 않으며, // 이는 엔진의 AutoCulling, Picking, RayTracing 에서 화면에 보이는 것과는 다른 // 결과를 만들어낸다. } bool CArcballCameraAnimator::OnEvent( const SEvent& event) { if (event.EventType != EET_MOUSE_INPUT_EVENT) return false ; switch (event.MouseInput.Event) { case EMIE_MOUSE_MOVED: m_MousePt.X = event.MouseInput.X; m_MousePt.Y = event.MouseInput.Y; m_bClicked = event.MouseInput.isRightPressed(); if (!m_bDragging && m_bClicked) // click { m_bDragging = true ; _mapToSphere(m_MousePt, &m_vStart); } else { if (m_bClicked) //dragging { core::vector3df m_vEnd; core::quaternion thisQuat; this ->_mapToSphere(m_MousePt, &m_vEnd); vector3df perp = m_vStart.crossProduct(m_vEnd); if ( !iszero(perp.getLength()) ) { thisQuat.X = perp.X; thisQuat.Y = perp.Y; thisQuat.Z = perp.Z; thisQuat.W = m_vStart.dotProduct(m_vEnd); } else { thisQuat.makeIdentity(); } thisQuat.getMatrix_transposed(m_ThisRot); m_ThisRot = m_ThisRot * m_LastRot; m_Transform = m_ThisRot; } else { m_bDragging = false ; m_LastRot = m_ThisRot; } } break ; case EMIE_MOUSE_WHEEL: m_fZoom += event.MouseInput.Wheel * m_fZoomSpeed; if (m_fZoom > m_fZoomMax) m_fZoom = m_fZoomMax; else if (m_fZoom < m_fZoomMin) m_fZoom = m_fZoomMin; break ; } return false ; } ISceneNodeAnimator* CArcballCameraAnimator::createClone(ISceneNode* node, ISceneManager* newManager) { ////////////////////////////////////////////////////////////////////////// // 클래스 특성상 복사본이 생성되면 안되며, 복사본 생성시 카메라 움직임에 오류가 발생할 여지가 있다. return NULL; ////////////////////////////////////////////////////////////////////////// // 그래도 만약 복사본이 필요한 경우 아래 소스를 사용하자. //const f32 width = 2 / m_fAdjustWidth + 1.0f; //const f32 height = 2 / m_fAdjustHeight + 1.0f; //CArcballCameraAnimator* newAnimator = new CArcballCameraAnimator(width, height, m_fZoomSpeed); //return newAnimator; ////////////////////////////////////////////////////////////////////////// } |
'Dev.Write' 카테고리의 다른 글
TorusKNotSceneNode (0) | 2011.05.11 |
---|---|
모서리가 둥근 박스 만들기 (0) | 2011.04.18 |
Ambient Occlusion (0) | 2011.04.18 |
(GLSL) cook-torrence sample (0) | 2011.04.18 |
Tutorial 10 - Shader (0) | 2011.04.16 |