드디어 오늘 플레이어 이동 & 카메라 구현을 완료했다. 


처음 만드는 3D게임이여서 어려웠던거 같다. 

그래도 만들면서 카메라 회전이나 회전행렬등을 이해할 수 있었다



구현 영상

조작은 마우스로도 할 수 있고 키보드 방향키로도 할 수 있다


구현 코드 


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
void PlayerAirplane::InputMouse()
{
    // vGap : 전프레임과 현재 프레임의 마우스 위치의 차이.
    Vector2 vGap(INPUT.GetMouseGap());
 
    //fForwardAngle : Forward축으로 돌릴 회전값
    float fForwardAngle = -(D3DXToRadian(vGap.x) * 0.05f);
    //fRightAngle : Right축으로 돌릴 회전값
    float fRightAngle = -(D3DXToRadian(vGap.y) * 0.05f);
 
    //키보드 사용시 
    if (KEYPRESS(VK_UP))
        fRightAngle += D3DXToRadian(3.f);
    if (KEYPRESS(VK_DOWN))
        fRightAngle -= D3DXToRadian(3.f);
 
    if (KEYPRESS(VK_RIGHT))
        fForwardAngle -= D3DXToRadian(3.f);
    if (KEYPRESS(VK_LEFT))
        fForwardAngle += D3DXToRadian(3.f);
 
    // 각 축의 회전행렬과 초기화
    D3DXMATRIX matForwardRot;
    D3DXMatrixIdentity(&matForwardRot);
 
    D3DXMATRIX matRightRot;
    D3DXMatrixIdentity(&matRightRot);
 
 
#pragma region AIRPLANE ROTATION
    // 플레이어를 회전 코드
 
    if (fForwardAngle)
    {
        // Forward 축으로 회전한 Matrix를 다른축에다 적용시켜준다 
        D3DXMatrixRotationAxis(&matForwardRot, &vAxis[E_AXIS_FORWARD], fForwardAngle);
        
        D3DXVec3TransformNormal(&vAxis[E_AXIS_RIGHT], &vAxis[E_AXIS_RIGHT], &matForwardRot);
        D3DXVec3TransformNormal(&vAxis[E_AXIS_UP], &vAxis[E_AXIS_UP], &matForwardRot);
    }
 
    if (fRightAngle)
    {
        // Right 축으로 회전한 Matrix를 다른축에다 적용시켜준다 
        D3DXMatrixRotationAxis(&matRightRot, &vAxis[E_AXIS_RIGHT], fRightAngle);
        
        D3DXVec3TransformNormal(&vAxis[E_AXIS_FORWARD], &vAxis[E_AXIS_FORWARD], &matRightRot);
        D3DXVec3TransformNormal(&vAxis[E_AXIS_UP], &vAxis[E_AXIS_UP], &matRightRot);
    }
 
    if (fRightAngle != 0 || fForwardAngle != 0)
        transform->matRot = transform->matRot * matForwardRot * matRightRot;    
 
#pragma endregion AIRPLANE ROTATION
 
#pragma region CAMERA_SETTING    
    // 카메라를 회전 코드
    // 구한 회전 행렬을 플레이어와 카메라위치, 카메라LookAt위치에 대한 방향에 적용시켜준다. 
    if (fForwardAngle)
    {
        D3DXVec3TransformNormal(&vCameraLookAtDir, &vCameraLookAtDir, &matForwardRot);
        D3DXVec3TransformNormal(&vCameraDir, &vCameraDir, &matForwardRot);
    }
 
    if (fRightAngle)
    { 
        D3DXVec3TransformNormal(&vCameraLookAtDir, &vCameraLookAtDir, &matRightRot);
        D3DXVec3TransformNormal(&vCameraDir, &vCameraDir, &matRightRot);
    }
    
    //카메라 위치 셋팅
    vCameraPos = transform->pos + (vCameraDir * fCameraDistance);
    vCameraLookAt = transform->pos + (vCameraLookAtDir * fCameraLookAtDistance);
 
    CAMERA.SetCameraInfo(vCameraPos, vCameraLookAt, vAxis[E_AXIS_UP]);
#pragma endregion CAMERA_SETTING
 
}
 
void PlayerAirplane::InputKeyboard()
{
    if (KEYPRESS('W'))
        transform->pos += vAxis[E_AXIS_FORWARD] * (200 * Et);
    if (KEYPRESS('S'))
        transform->pos -= vAxis[E_AXIS_FORWARD] * (200 * Et);
 
}
 
 
 
cs

각 코드의 설명은 주석으로 작성해놨다.


알아두고 가야할 요소들.


* 값의 변화를 잘 알아두고 작업하자 


144줄과 150줄 사이에서 Forward벡터를 축으로한 회전이 이루어진다

그리고 153줄과 160줄 사이에서 Right축으로한 회전이 이루어지면서

Forward벡터가 변경되는데

여기서 입력이 동시에 이루어진다면 Forward벡터는 변경되기 전 값으로 

계속 먼저 회전되고나서 값의 변경이 이루어진다. 

이 값이 계속 누적되면 카메라가 플레이어를 똑바로 바라보지않고 오차가 생기게된다


--------------------------------------------------------------------------

만들때는 어려웠지만 만들고 보닌까 이해가 됐다. 



DirectX 에서는 벡터를 변환하는 함수인


1
2
3
4
5
D3DXVECTOR3* WINAPI D3DXVec3TransformCoord
    ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV, CONST D3DXMATRIX *pM );
 
D3DXVECTOR3* WINAPI D3DXVec3TransformNormal
    ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV, CONST D3DXMATRIX *pM );
cs

함수가 있다.


일단 이 두함수의 공통점은 2번째 인자인 벡터와 3번째 인자인 행렬을 곱하는 함수라는 것이다.


우선 3차원 벡터와 4x4 행렬은 곱해질 수 없다 왜냐하면 행렬을 곱할때는 앞 행렬의 열과 뒤 행렬의

행이 같아야지만 곱할 수 있다


그래서 이 함수는 3차원 벡터를 4차원 벡터로 변환하여 행렬과 곱해주는데 여기서 차이점이 발생한다


3차원 벡터 가 있다면


이 3차원 벡터를


D3DXVec3TransformCoord 함수는 

로 바꿔주고


D3DXVec3TranformNormal 함수는

로 바꿔준다.


둘의 차이는 4차원 벡터의 4번째 요소  가 다르다는 점인데 


 이라면 포인터(좌표) 개념이 되어 이동이 적용되고

 이라면 벡터의(방향) 개념이 되어 이동이 적용되지 않는다


이유는 


DirectX 의 4x4 행렬의 마지막 열은 이동을 담당하는것을 알고 있다면 이해하기 쉽다


------------------------------------------------------------ 

이 식에서 


이라면

  이므로 이동이 적용되는걸 알 수 있다.


 이라면 

      이므로 이동이 적용 안되는 걸 알 수 있다.


-------------------------------------------------------------

그러므로


 벡터와 행렬을 곱하여 


 이동, 회전, 스케일, 을 변환하고 싶다면 D3DXVec3TransformCoord를 쓰고

 이동은 변환하고싶지 않고 회전,스케일만 변환하고 싶다면 D3DXVec3TransformNormal을 쓰면된다








'programing > directX' 카테고리의 다른 글

LPD3DXMESH 쓰는법  (0) 2018.10.13
LPD3DXFONT  (0) 2018.02.13

전체소스코드는 맨 아래있습니다.


DirectX 3D를 공부하던 중 Obj 모델링을 로드하고 그 정보를 저장하기 위해 LPD3DXMESH를 사용했다


LPD3DXMESH를 사용하기 위해 해야할 것들은...


1. LPD3DXMESH 초기화 해주기


D3DXCreateMeshFVF(

삼각형의 갯수,

정점의 갯수,

D3DXMESH_MANAGED,

FVF 포멧,

device,

LPD3DXMESH의 포인터);     위 함수를 이용하여 메쉬를 초기화 한다.


2. VertexBuffer 초기화 하기

일단 정점들을 저장한 배열이나 STL::Vector에 저장한다.

vector<CustomVertex> vVertexs;


버퍼 포인터를 받을 void 포인터 변수를 선언한다.

void * Vertices = nullptr;


락을 걸어준다.

lpD3DXMesh->LockVertexBuffer(0, Vertices);


그리고 배열이나 STL::Vector의 저장된 정점들을 복사해준다.

memcpy(Vertices, &vVertexs[0], sizeof(CustomVertex) * vVertexs.size());


락을 풀어준다.

lpD3DXMesh->UnlockVertexBuffer();


2. IndexBuffer 초기화 하기.

초기화할 인덱스 정보를 배열이나 STL:Vector에 저장한다.

vector<WORD> vIndexs;


버퍼 포인터를 받을 void 포인터 변수를 선언한다

void * Indices = nullptr;


락을 걸어준다.

lpD3DXMesh->LockIndexBuffer(0, &Indices))


그리고 배열이나 STL::Vector의 저장된 정점들을 복사해준다

memcpy(Indices, &vIndexs[0], sizeof(WORD) * vIndexs.size());


락을 풀어준다.

lpD3DXMesh->UnlockIndexBuffer();


2. AttributeBuffer 초기화 하기.

초기화할 속성 정보를 배열이나 STL:Vector에 저장한다.

vector<DWORD> vAttribute;


버퍼 포인터를 받을 DWRD 포인터 변수를 선언한다

DWRD * Attribute= nullptr;


락을 걸어준다.

lpD3DXMesh->LockAttributeBuffer(0, &dwAttribute))


그리고 배열이나 STL::Vector의 저장된 정점들을 복사해준다

memcpy(dwAttribute, &vAttribute[0], sizeof(DWORD) * vAttribute.size());


락을 풀어준다.

    lpD3DXMesh->UnlockAttributeBuffer();



이렇게 설정해주고 그릴때 lpD3DXMesh->DrawSubset(SubsetNum); 이렇게 그려주면 메쉬가 그려진다.


전체 소스코드

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
bool cMeshRenderer::CreateMesh()
{
    if (FAILED(D3DXCreateMeshFVF(
        vVertexs.size() / 3
        vVertexs.size(), 
        D3DXMESH_MANAGED, 
        CustomFVF, 
        g_device, 
        &lpD3DXMesh)))
    {
        MessageBox(nullptr, L"Failed CreateMesh ", L"Error", MB_OK);
        return false;
    }
 
    void * Vertices = nullptr;
 
    if (FAILED(lpD3DXMesh->LockVertexBuffer(0&Vertices)))
    {
        MessageBox(nullptr, L"Failed Mesh->LockVertexBuffer", L"Error", MB_OK);
        return false;
    }
    
    memcpy(Vertices, &vVertexs[0], sizeof(CustomVertex) * vVertexs.size());
 
    lpD3DXMesh->UnlockVertexBuffer();
 
    void * Indices = nullptr;
 
    if (FAILED(lpD3DXMesh->LockIndexBuffer(0&Indices)))
    {
        MessageBox(nullptr, L"Failed Mesh->LockIndexBuffer", L"Error", MB_OK);
        return false;
    }
    
    memcpy(Indices, &vIndexs[0], sizeof(WORD) * vIndexs.size());
 
    lpD3DXMesh->UnlockIndexBuffer();
 
    DWORD * dwAttribute = nullptr;
 
    if (FAILED(lpD3DXMesh->LockAttributeBuffer(0&dwAttribute)))
    {
        MessageBox(nullptr, L"FAiled Mesh->LockAttributeBuffer", L"Error", MB_OK);
        return false;
    }
 
    memcpy(dwAttribute, &vAttribute[0], sizeof(DWORD) * vAttribute.size());
 
    lpD3DXMesh->UnlockAttributeBuffer();
 
    return true;
}
 
cs



틀린 것이나 조언할것이 있다면 댓글로 해주세요 감사합니다

'programing > directX' 카테고리의 다른 글

DirectX D3DXVec3TransformCoord와 D3DXVec3TransformNormal 함수  (0) 2018.10.15
LPD3DXFONT  (0) 2018.02.13

+ Recent posts