으음. 참고로 저는 DirectXMath.h(Windows 8 or higher)를 사용합니다..'만'
옛날에 책 따라서 만든 Box 예제가 있길래 그 위에다가 대충 테스트 할려고 구현한거라 XNAMath를 사용하게 됐습니다 ㅇㅂㅇ;
XNAMath(혹은 DirectXMath.h를 include 한 후 using namespace DirectX를 타이핑 했다면)와 Bullet Physics를 동시에 사용하게 되면 C2084에러를 보게 되는데 이 때는 당황하지 마시고
#define BT_NO_SIMD_OPERATOR_OVERLOADS #include <btBulletDynamicsCommon.h>
이렇게 처리해 주시면됩니다.
자 시작해볼까요?
먼저 엔진을 사용할 준비를 해야겠죠? Bullet Physics Hello World예제는 한번 보고 오셨을거라 생각합니다.
아직 안보신 분은 Hello World! <- 클릭.
btBroadphaseInterface* broadphase = new btDbvtBroadphase; btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration; btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration); btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver; btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration); // 제가 테스트 해볼 박스 위치가 (-1,-1,-1), (1,1,1)입니다. 그러니 아래처럼 해줘야죠. btCollisionShape* boxCollisionShape = new btBoxShape(btVector3(1, 1, 1)); // 변환따위 하지 않습니다. 카메라는 돌아가지만 변환은 하지 않습니다. btDefaultMotionState* motionStatenew btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, btVector3(0, 0, 0))); btRigidBody::btRigidBodyConstructionInfo rigidBodyCI(0, bulletUtil.motionState, bulletUtil.boxCollisionShape, btVector3(0, 0, 0)) btRigidBody* rigidBody = new btRigidBody(rigidBodyCI); dynamicsWord->addRigidBody(rigidBody);
이제 여러분의 DirectX 프레임워크에 있는 마우스 이벤트 처리 함수에 다음과 같이 코딩해봅니다.
void PickingTest::OnMouseDown(WPARAM btnState, int x, int y) { XMMATRIX proj = XMLoadFloat4x4(&m_Proj); // Projection 행렬입니다. XMMATRIX view = XMLoadFloat4x4(&m_View); // View 행렬입니다. XMVECTOR rayOrigin = XMLoadFloat4(&XMFLOAT4(0, 0, 0, 1.0f)); // 혹시 Origin 점 위치가 왜 원점인지 이해가 안가시나요? // / | | // / | | // / | | //뷰----광선---NEAR--------->물체 FAR // \ | | // \ | | // \ | | // // 즉, 광선의 시작점은 카메라 공간(View)에서 카메라 위치인 0,0,0 에서 시작됩니다. // XMVECTOR rayDirection = XMLoadFloat4(&XMFLOAT4( ((float)(2.0f * x) / (float)mScreenViewport.Width - 1.0f) / m_Proj._11, ((float)(-2.0f * y) / (float)mScreenViewport.Height + 1.0f) / m_Proj._22, 1.0f, 0.0f)); // 광선의 시작지점이 원점이므로, 이 원점에서 어떤 "방향"으로 광선이 발사될지 정해줘야합니다. // 광선의 방향은 Point(x, y, z) - O(0, 0, 0) = Point(x, y, z)이므로 // 저희는 스크린 포인트의 마우스 위치를 뷰 행렬까지 옮겨주면 될 듯 합니다. // 원래 Loacl * World * View * Proj * ViewPort 순서대로 곱한 결과가 최종 스크린 좌표이므로(마우스는 이미 최종 스크린 좌표입니다.) // Local * World * View = ScreenPos * ViewPort^-1 * Proj^-1 이겠네요. XMVECTOR det2 = XMMatrixDeterminant(view); // 만약 DirectXMath 가 아니라 XNAMath 를 사용하신다면 반드시 필요합니다. XMMATRIX invView = XMMatrixInverse(&det2, view); // XNAMath XMMatrixInverse는 첫번째 인자가 nullptr 일 수 없습니다. DirectXMath는 nullptr 가능. rayOrigin = XMVector4Transform(rayOrigin, invView); rayDirection = XMVector4Transform(rayDirection, invView); rayDirection = XMVector4Normalize(rayDirection) * 1000.0f; // 방향을 구한다음에 길이를 재설정해줍니다. 으음. 길이를 설정해줘야 하더군요. 노말라이즈 안하고 그냥 값 넣어도 작동은 됩니다. XMFLOAT3 rayOriginF; XMFLOAT3 rayDirectionF; XMStoreFloat3(&rayOriginF, rayOrigin); XMStoreFloat3(&rayDirectionF, rayDirection); // 아래 코드는 이제 보시면 이해 할 것입니다. // 자세한 함수 사용 방법은 Bullet Physics Document를 참고해주세요. btCollisionWorld::ClosestRayResultCallback rayCallback( btVector3(rayOriginF.x, rayOriginF.y, rayOriginF.z), btVector3(rayDirectionF.x, rayDirectionF.y, rayDirectionF.z)); bulletUtil.dynamicsWorld->rayTest( btVector3(rayOriginF.x, rayOriginF.y, rayOriginF.z), btVector3(rayDirectionF.x, rayDirectionF.y, rayDirectionF.z), rayCallback); if (rayCallback.hasHit()) { SetWindowText(mhMainWnd, L"성공"); } else { SetWindowText(mhMainWnd, L"실패"); } }
아래는 결과. 마우스를 캡쳐 할 수 있는 캡쳐 프로그램이 없어서 그냥 그림판으로 대충 동그라미 그렸습니다. 동그라미 가운데 부분이 클릭지점 입니다.
고딩 수학을 말아먹은 관계로 뭔가 틀린 부분이 있다면 알려주시면 감사하겠습니다.
'Programming||Study > DirectX' 카테고리의 다른 글
MikuMikuDance PMX 모델 파서를 이용해 렌더링해보았다. (0) | 2014.09.06 |
---|---|
DirectX11에 EditBox를 만들어보자 4 - DirectX11에 EditBox를 만들자! - 마지막. (2) | 2014.07.27 |
DirectX11에 EditBox를 만들어보자 4 - DirectX11에 EditBox를 만들자! - 진행상황 (0) | 2014.07.26 |
DirectX11에 EditBox를 만들어보자 3 - 커서를 구현해보자 - (0) | 2014.07.20 |
DirectX11에 EditBox를 만들어보자 2 - 평범한 윈도우에 글자를 입력받아 보자. - (0) | 2014.07.20 |