본문 바로가기
DirectX11/코드정리

[DirectX11] Box 예제

by 마두식 2022. 11. 17.
반응형

※  아래의 내용들은 DirectX 11을 이용한 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
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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
//***************************************************************************************
// BoxDemo.cpp by Frank Luna (C) 2011 All Rights Reserved.
//
// Demonstrates rendering a colored box.
// 색깔 있는 상자의 렌더링을 보여 준다.
// 
//
// Controls:
//        Hold the left mouse button down and move the mouse to rotate.
//      Hold the right mouse button down to zoom in and out.
// 조작 방법:
//        왼쪽 버튼을 누른 채로 마우스를 움직이면 상자가 회전한다.
//        오른쪽 버튼을 누른 채로 마우스를 움직이면 상자가 확대ㆍ축소된다.
//
//***************************************************************************************
 
#include <iostream>
 
#include "d3dApp.h"
#include "d3dx11Effect.h"
#include "MathHelper.h"
 
struct Vertex
{
    XMFLOAT3 Pos;
    XMFLOAT4 Color;
};
 
class BoxApp : public D3DApp
{
public:
    BoxApp(HINSTANCE hInstance);
    ~BoxApp();
 
    bool Init();
    void OnResize();
    void UpdateScene(float dt);
    void DrawScene();
 
    void OnMouseDown(WPARAM btnState, int x, int y);
    void OnMouseUp(WPARAM btnState, int x, int y);
    void OnMouseMove(WPARAM btnState, int x, int y);
 
private:
    void BuildGeometryBuffers();
    void BuildFX();
    void BuildVertexLayout();
 
private:
    ID3D11Buffer* mBoxVB;
    ID3D11Buffer* mBoxIB;
 
    ID3DX11Effect* mFX;                                    // 하나 이상의 렌더링 패스들을 캡슐화하며, 각 패스마다 정점 셰이더가 연관된다.
    ID3DX11EffectTechnique* mTech;
    ID3DX11EffectMatrixVariable* mfxWorldViewProj;
 
    ID3D11InputLayout* mInputLayout;
 
    XMFLOAT4X4 mWorld;
    XMFLOAT4X4 mView;
    XMFLOAT4X4 mProj;
 
    float mTheta;
    float mPhi;
    float mRadius;
 
    POINT mLastMousePos;
};
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
    PSTR cmdLine, int showCmd)
{
    // Enable run-time memory check for debug builds.
    // 디버그 빌드의 경우 실행시점 메모리 점검 기능을 활성화한다.
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
 
    // 아래 코드들을 작성해주면 디버그용 콘솔이 프로그램 실행시 함께 나오게 된다.
    // 사용 스트림을 stdout(표준출력) 스트림으로 설정했으므로
    // std::cout 등과 같은 출력 함수들로 log를 남길 수가 있다.
    AllocConsole();
    freopen("CONOUT$""wb", stdout);
 
#endif
 
    BoxApp theApp(hInstance);
 
    if (!theApp.Init())
        return 0;
 
    return theApp.Run();
}
 
 
BoxApp::BoxApp(HINSTANCE hInstance)
    : D3DApp(hInstance), mBoxVB(0), mBoxIB(0), mFX(0), mTech(0),
    mfxWorldViewProj(0), mInputLayout(0),
    mTheta(1.5f * MathHelper::Pi), mPhi(0.25f * MathHelper::Pi), mRadius(5.0f)
{
    mMainWndCaption = L"Box Demo";
 
    mLastMousePos.x = 0;
    mLastMousePos.y = 0;
 
    XMMATRIX I = XMMatrixIdentity();
    XMStoreFloat4x4(&mWorld, I);
    XMStoreFloat4x4(&mView, I);
    XMStoreFloat4x4(&mProj, I);
}
 
BoxApp::~BoxApp()
{
    ReleaseCOM(mBoxVB);
    ReleaseCOM(mBoxIB);
    ReleaseCOM(mFX);
    ReleaseCOM(mInputLayout);
    FreeConsole();
}
 
bool BoxApp::Init()
{
    if (!D3DApp::Init())
        return false;
 
    BuildGeometryBuffers();        // 정점 버퍼, 색인 버퍼 생성
    BuildFX();                    // 효과 파일 생성(셰이더 코드 컴파일)
    BuildVertexLayout();        // 입력 배치 생성
 
    return true;
}
 
// 투영 행렬 다시 계산
void BoxApp::OnResize()
{
    D3DApp::OnResize();
 
    // The window resized, so update the aspect ratio and recompute the projection matrix.
    // 창의 크기가 변했으므로 종횡비를 갱신하고 투영 행렬을 다시 계산한다.
    // XMMatrixPerspectiveFovLH : 원근투영 행렬을 구축해주는 함수
    // 첫번째 매개변수 : 수직 시야각(라디안 단위)
    // 두번째 매개변수 : 종횡비 = 너비 / 높이
    // 세번째 매개변수 : 가까운 평면까지의 거리
    // 네번째 매개변수 :  먼 평면까지의 거리
    XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f * MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
    XMStoreFloat4x4(&mProj, P);
}
 
// 카메라가 바라보는 방향 설정(시야 행렬 구축)
void BoxApp::UpdateScene(float dt)
{
    // Convert Spherical to Cartesian coordinates.
    // 구면 좌표를 데카르트 좌표로 변환한다.
    // 구면 좌표계 : 3차원 공간 상의 점들을 나타내는 좌표계. 보통 (r, Theta, Phi)로 나타낸다.
    // 데카르트 좌표계 : 임의의 차원의 유클리드 공간을 나타내는 좌표계. 보통 x, y, z로 나타낸다. 
    // 참고 : https://iskim3068.tistory.com/23
    // x, y, z값을 변경하면 카메라 위치가 바뀜(mPhi, mTheta 변수 값을 변경해보면서 확인함)
    // 여기서 mPhi는 z축 양의 방향과 선분 OP가 이루는 각, mTheta는 x축 양의 방향과 선분 OP가 이루는 각
    // mTheta 값이 작아질수록 카메라가 왼쪽으로 이동, 커질수록 오른쪽으로 이동
    // mPhi 값이 작아질수록 카메라가 위로 이동, 커질수록 카메라가 아래로 이동
    float x = mRadius * sinf(mPhi) * cosf(mTheta);
    float z = mRadius * sinf(mPhi) * sinf(mTheta);
    float y = mRadius * cosf(mPhi);
 
    //std::cout << "(" << x << ", " << y << ", " << z << ")" << std::endl;
 
    // Build the view matrix.
    // 시야 행렬을 구축한다.
    // 카메라 위치, 바라볼 대상 위치, 상향 벡터를 알면 시야 행렬을 구축할 수 있다.
    XMVECTOR pos = XMVectorSet(x, y, z, 1.0f);
    XMVECTOR target = XMVectorZero();
    
    // mPhi값 범위 제한을 변경했을 경우 카메라 상하 이동 중에 튀는 문제에 대한 원인을 찾기 위해 테스트 한 코드
    // 해당 주석 코드를 적용하면 튀는 문제를 해결할 수 있다.(완벽하진 않음)
    /*XMVECTOR up;
    if(mPhi >= MathHelper::Pi || mPhi <= 0)
        up = XMVectorSet(0.0f, -1.0f, 0.0f, 0.0f);
    else
        up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);*/
 
    XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
 
    XMMATRIX V = XMMatrixLookAtLH(pos, target, up);
    XMStoreFloat4x4(&mView, V);
}
 
// 화면에 그림 그리기
void BoxApp::DrawScene()
{
    // 렌더 대상(화면)을 깨끗이 지우라고 명령한다.(지운다는 의미는 대상의 모든 원소를 특정한 하나의 값으로 설정하는 것을 뜻한다) (4.4.7절 151p)
    // => 후면 버퍼를 LightSteelBlue 색으로 지운다.(Colors::LightSteelBlue는 d3dUtil.h에 정의되어 있다.)
    md3dImmediateContext->ClearRenderTargetView(mRenderTargetView, reinterpret_cast<const float*>(&Colors::LightSteelBlue));
    // 깊이 버퍼를 1.0f, 스텐실 버퍼를 0으로 지운다.
    md3dImmediateContext->ClearDepthStencilView(mDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
 
    // BuildVertexLayout 함수에서 생성한 입력 배치는 아직 장치에 묶이지 않은 상태이다.
    // 따라서 해당 입력 배치를 사용하고자 하는 장치에 묶어야 한다.
    md3dImmediateContext->IASetInputLayout(mInputLayout);
 
    // 기본도형 위상구조(5.5.2절 172p)
    // 기본도형을 형성하는 방식을 Direct3D에게 알려 주는 코드
    // 삼각형 목록을 적용해서 물체들을 그리라는 명령임.
    md3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
 
 
    // BuildGeometryBuffers 함수에서 생성한 정점 버퍼와 색인 버퍼를 실제 파이프라인에 공급하려면
    // 버퍼를 장치의 한 입력 슬롯에 붙여야(묶어야)한다.
    // 아래는 이를 위한 명령이다.(정점버퍼 6.2절 221p, 색인버퍼 6.3절 223p)
    UINT stride = sizeof(Vertex);
    UINT offset = 0;
    md3dImmediateContext->IASetVertexBuffers(01&mBoxVB, &stride, &offset);
    md3dImmediateContext->IASetIndexBuffer(mBoxIB, DXGI_FORMAT_R32_UINT, 0);
 
    // Set constants
    // 상수 설정(6.8.4절 245p)
    // 세계ㆍ뷰ㆍ투영 결합 행렬을 설정한다.
    XMMATRIX world = XMLoadFloat4x4(&mWorld);
    XMMATRIX view = XMLoadFloat4x4(&mView);
    XMMATRIX proj = XMLoadFloat4x4(&mProj);
    XMMATRIX worldViewProj = world * view * proj;
 
    mfxWorldViewProj->SetMatrix(reinterpret_cast<float*>(&worldViewProj));
 
    D3DX11_TECHNIQUE_DESC techDesc;
    mTech->GetDesc(&techDesc);
    for (UINT p = 0; p < techDesc.Passes; ++p)
    {
        // Apply의 첫번째 매개변수 : 이후 용도를 위해 예약된 것으로, 현재로서는 항상 0을 지정
        // Apply의 두번째 매개변수 : 패스를 적용할 장치 문맥
        // 효과 기법의 각 패스를 훑으면서 각 패스를 장치문맥에 적용함
        mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext);
 
        // 36 indices for the box.
        // 색인 36개로 상자를 그린다.(6.3절 224p)
        // 첫번째 매개변수 : 현재 그리기 호출에서 사용할 색인들의 개수
        // 두번째 매개변수 : 사용할 첫 색인의 위치(버퍼 안에서의 색인)
        // 세번째 매개변수 : 정점 버퍼에서 정점들을 가져오기 전에, 각 정점들의 인덱스에 추가되는 값
        md3dImmediateContext->DrawIndexed(3600);
    }
 
    // 렌더링 처리를 최적화 하기 위한 힌트 전달
    // 스왑체인에서 렌더링 하고있는 윈도우가 최소화 되는 등
    // 표시되는 부분이 존재하지 않는 상태가 되면 DXGI_STATUS_OCCLUDED를 반환한다
    //--------------------------------------------------------------------------------- 
    // 위는 Present를 최적화 하는 방법에 대한 설명인 것 같음(https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=sorkelf&logNo=40161605210)
    // 여기서 Present는 후면 버퍼를 화면에 제시하는 기능이다.
    HR(mSwapChain->Present(00));
}
 
// 마우스 클릭 좌표 지정 및 SetCapture 호출
void BoxApp::OnMouseDown(WPARAM btnState, int x, int y)
{
    // 마우스 클릭 하는 순간의 클릭 좌표를 저장해둠
    mLastMousePos.x = x;
    mLastMousePos.y = y;
 
    // 마우스가 윈도우창 바깥으로 나갔을 때도, WM_MOUSEMOVE를 받기 위한 함수
    // 이전에 SetCapture 했던 HWND가 있다면 이전 HWND를 반환한다. 없다면 NULL 반환
    // SetCapture를 했다면 후에 ReleaseCapture를 호출해야 한다.
    SetCapture(mhMainWnd);
}
 
// ReleaseCapture 호출
void BoxApp::OnMouseUp(WPARAM btnState, int x, int y)
{
    // ReleaseCapture를 하면 영역 밖에서 더이상 WM_MOUSEMOVE가 받아지지 않는다.
    // 함수가 실패하면 return 0
    // 실패한 경우 GetLastError를 호출하여 실패 이유를 확인할 수 있다.
    ReleaseCapture();
}
 
// 마우스 버튼 클릭 상태와 이동에 따라 카메라 이동
void BoxApp::OnMouseMove(WPARAM btnState, int x, int y)
{
    // 마우스 왼쪽 버튼을 누르고 있는 상태라면
    if ((btnState & MK_LBUTTON) != 0)
    {
        // Make each pixel correspond to 0.005 unit in the scene.
        // 1픽셀이 장면의 0.005단위가 되게 한다.
        float dx = 0.005f * static_cast<float>(x - mLastMousePos.x);
        float dy = 0.005f * static_cast<float>(y - mLastMousePos.y);
 
        // Update the camera radius based on input.
        // 마우스 입력에 기초해서 궤도 카메라의 반지름을 갱신한다.
        mRadius += dx - dy;
 
        // Restrict the radius.
        // 반지름을 특정 범위로 제한한다.
        mRadius = MathHelper::Clamp(mRadius, 3.0f, 15.0f);
        
    }
 
    // 마우스 오른쪽 버튼을 누르고 있는 상태라면
    else if ((btnState & MK_RBUTTON) != 0)
    {
        // Make each pixel correspond to a quarter of a degree.
        // 1픽셀이 1/4도(디그리 단위)가 되게 한다.
        float dx = XMConvertToRadians(0.25f * static_cast<float>(x - mLastMousePos.x));
        float dy = XMConvertToRadians(0.25f * static_cast<float>(y - mLastMousePos.y));
        std::cout << "dx : " << dx << ",\t" << "dy : " << dy << std::endl;
 
        // Update angles based on input to orbit camera around box.
        // 마우스 입력에 기초한 각도로 상자 주변의 궤도 카메라를 갱신한다.
        mTheta -= dx;
        mPhi -= dy;
 
        std::cout << "mTheta : " << mTheta << ",\t" << "mPhi : " << mPhi << std::endl << std::endl;
 
        // Restrict the angle mPhi.
        // 각도를 mPhi로 한정한다.
        // 각도 제한이 없으면 카메라가 뒤집힐 수도 있으며, 카메라가 뒤집히게 되면
        // 상향 벡터의 방향(값)이 UpdateScene에서 설정한 값과 달라지게 되므로 도형이 뒤집히는 등의 문제가 발생할 수 있다.
        // ex: Pi - 0.1f에서 - 0.1f를 지우면 위에서 설명한 문제가 발생한다.
        // - 0.1f를 지울거라면 UpdateScene의 상향벡터 up을 조건에 따라 다르게 설정해주는 조건문을 주석에 작성해 두었으니
        // 코드를 수정해야 한다.
        mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
    }
 
    mLastMousePos.x = x;
    mLastMousePos.y = y;
}
 
// 정점버퍼, 색인버퍼 생성
void BoxApp::BuildGeometryBuffers()
{
    // Create vertex buffer
    Vertex vertices[] =
    {
        { XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4((const float*)&Colors::White)   },
        { XMFLOAT3(-1.0f, +1.0f, -1.0f), XMFLOAT4((const float*)&Colors::Black)   },
        { XMFLOAT3(+1.0f, +1.0f, -1.0f), XMFLOAT4((const float*)&Colors::Red)     },
        { XMFLOAT3(+1.0f, -1.0f, -1.0f), XMFLOAT4((const float*)&Colors::Green)   },
        { XMFLOAT3(-1.0f, -1.0f, +1.0f), XMFLOAT4((const float*)&Colors::Blue)    },
        { XMFLOAT3(-1.0f, +1.0f, +1.0f), XMFLOAT4((const float*)&Colors::Yellow)  },
        { XMFLOAT3(+1.0f, +1.0f, +1.0f), XMFLOAT4((const float*)&Colors::Cyan)    },
        { XMFLOAT3(+1.0f, -1.0f, +1.0f), XMFLOAT4((const float*)&Colors::Magenta) }
    };
 
    // 정점 버퍼를 서술하는 구조체를 채운다.
    D3D11_BUFFER_DESC vbd;
    vbd.Usage = D3D11_USAGE_IMMUTABLE;                        // 버퍼가 쓰이는 방식(여기서는 버퍼 생성 후 변경 없다는 의미)
    vbd.ByteWidth = sizeof(Vertex) * 8;                        // 생성할 정점 버퍼의 크기(바이트 단위)
    vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;                // 정점 버퍼의 경우 해당 플래그 사용하면 됨.
    vbd.CPUAccessFlags = 0;                                    // CPU가 버퍼에 접근하는 방식을 결정하는 플래그들 지정(버퍼 생성 이후 CPU가 버퍼 읽기, 쓰기를 하지 않는다면 0을 지정)
    vbd.MiscFlags = 0;                                        // 정점 버퍼에 대해서는 그냥 0 지정
    vbd.StructureByteStride = 0;                            // 구조적 버퍼에 저장된 원소 하나의 크기(바이트 단위) (구조적 버퍼를 위해서만 필요함. 그 외 모든 버퍼에 대해서는 0 지정)
 
    // 정점 버퍼를 초기화할 자료를 지정한다.
    D3D11_SUBRESOURCE_DATA vinitData;
    vinitData.pSysMem = vertices;                            // 정점 버퍼를 초기화할 자료를 담은 시스템 메모리 배열을 가리키는 포인터
 
    // vbd : 생성할 버퍼를 서술하는 구조체
    // vinitData : 버퍼를 초기화하는 데 사용할 자료
    // mBoxVB : 생성된 버퍼가 여기에 설정된다.
    HR(md3dDevice->CreateBuffer(&vbd, &vinitData, &mBoxVB));
 
 
    // Create the index buffer
 
    UINT indices[] = {
        // front face
        123,
        130,
 
        // back face
        465,
        476,
 
        // left face
        451,
        410,
 
        // right face
        326,
        367,
 
        // top face
        156,
        162,
 
        // bottom face
        403,
        437
    };
 
    // 색인 버퍼를 서술하는 구조체를 채운다.
    D3D11_BUFFER_DESC ibd;
    ibd.Usage = D3D11_USAGE_IMMUTABLE;
    ibd.ByteWidth = sizeof(UINT) * 36;
    ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = 0;
    ibd.MiscFlags = 0;
    ibd.StructureByteStride = 0;
 
    // 색인 버퍼를 초기화할 자료를 지정한다.
    D3D11_SUBRESOURCE_DATA iinitData;
    iinitData.pSysMem = indices;
 
    // 색인 버퍼를 생성한다.
    HR(md3dDevice->CreateBuffer(&ibd, &iinitData, &mBoxIB));
}
 
// 효과 파일 생성(셰이더 코드 컴파일)
void BoxApp::BuildFX()
{
    std::ifstream fin("fx/color.fxo"std::ios::binary);
 
    fin.seekg(0std::ios_base::end);
    int size = (int)fin.tellg();
    fin.seekg(0std::ios_base::beg);
    std::vector<char> compiledShader(size);
 
    fin.read(&compiledShader[0], size);
    fin.close();
 
    // compiledShader : 컴파일된 효과 자료를 가리키는 포인터
    // size : 컴파일된 효과 자료의 바이트 단위 크기
    // 0 : 효과 플래그(D3DX11CompileFromFile 함수의 Flags2에 지정한 것과 일치해야 함)
    // md3dDevice : Direct3D 11 장치를 가리키는 포인터
    // mFX : 생성된 효과 파일을 가리키는 포인터
    HR(D3DX11CreateEffectFromMemory(&compiledShader[0], size,
        0, md3dDevice, &mFX));
 
    // 효과 객체에 있는 기법 객체를 가리키는 포인터 얻어오기
    mTech = mFX->GetTechniqueByName("ColorTech");
 
    // 효과 객체를 통해서 상수 버퍼 변수에 대한 포인터 얻기
    mfxWorldViewProj = mFX->GetVariableByName("gWorldViewProj")->AsMatrix();
}
 
// 입력 배치 생성
void BoxApp::BuildVertexLayout()
{
    // Create the vertex input layout.
    // 입력 배치 서술 배열 생성
    D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
    {
        {"POSITION"0, DXGI_FORMAT_R32G32B32_FLOAT, 00, D3D11_INPUT_PER_VERTEX_DATA, 0},
        {"COLOR",    0, DXGI_FORMAT_R32G32B32A32_FLOAT, 012, D3D11_INPUT_PER_VERTEX_DATA, 0}
    };
 
    // 파이프라인 상태를 포함하는 효과 전달에 대해 설명하는 구조체
    D3DX11_PASS_DESC passDesc;
 
    // ID3DX11EffectTechnique::GetPassByIndex
    // =>  주어진 색인에 해당하는 패스를 나타내는 ID3DX11EffectPass 인터페이스를 가리키는 포인터를 돌려준다.
    // ID3DX11EffectPass::GetDesc
    // =>  리턴형은 HRESULT
    // =>  매개변수 passDesc : 전달 설명에 대한 포인터
    // =>  특정 버퍼에 대한 정보를 얻어온다(?)
    mTech->GetPassByIndex(0)->GetDesc(&passDesc);
 
    // 입력 배치 생성
    // vertexDesc : 정점 구조체를 서술하는 입력 배치 서술 배열
    // 2 : 입력 배치 서술 배열 원소의 개수
    // passDesc.pIAInputSignature : 정점 셰이더(입력 서명을 포함한)를 컴파일해서 얻은 바이트 코드를 가리키는 포인터
    // passDesc.IAInputSignatureSize : 얻은 바이트 코드의 크기(바이트 단위)
    // mInputLayout : 생성된 입력 배치를 이 포인터를 통해서 돌려준다.
    HR(md3dDevice->CreateInputLayout(vertexDesc, 2, passDesc.pIAInputSignature,
        passDesc.IAInputSignatureSize, &mInputLayout));
}
cs

 

Box 예제의 main 코드입니다.

코드를 분석하면서 최대한 주석으로 개인적으로 이해한 내용을 작성해 두었습니다.

 

 

BoxDemo의 실행 과정
  • BoxApp 클래스의 생성자를 통해 D3DApp 인스턴스 생성 및 멤버 변수 초기화

 

  • D3DApp::Init() 함수를 이용해서 응용 프로그램 주 창, Direct3D 초기화
  • 정점 버퍼, 색인 버퍼 생성

 

vertices 배열에 그리기를 원하는 기하구조에 맞게 정점의 위치 및 색상을 넣고, 해당 배열을 이용해 정점 버퍼를 생성한다.

indices 배열에 삼각형의 정점 감기 순서에 맞춰 생성할 색인들을 넣고, 해당 배열을 이용해 색인 버퍼를 생성한다.

 

  • 효과 파일 생성

 

효과 파일을 열고, 효과 객체에 있는 기법 객체를 가리키는 포인터를 얻어온다.

또한, 효과 파일에서 사용된 상수 버퍼의 변수들을 가리키는 포인터들도 얻어온다.

 

  • 입력 배치 생성(입력 배치 서술 배열, 입력 배치 생성)

 

-  입력 배치 생성시 효과 파일 정보가 필요하므로, 효과 파일 생성 후 입력 배치를 생성해야 한다.

 

  • theApp.Run(); // 여기서 theApp은 BoxApp 객체임

D3D 초기화, 정점 및 색인 버퍼 생성 등의 과정이 끝났으므로 프로그램 실행 시간, 화면 업데이트(카메라 이동 등), 화면에 그리기 등의 과정을 실행해야 한다.


-  BoxApp 클래스가 D3DApp 클래스 상속 받았으며 별도의 함수 오버라이딩 없었음. 

=>  D3DApp의 Run 함수가 실행된 것

 

  • BoxApp의 UpdateScene 함수 실행 => 시야 행렬 구축

-  카메라의 위치 및 바라보는 방향 값에 시야 행렬 구축

=>  카메라의 위치 및 바라보는 방향의 값에 따라 해당 3차원 장면을 그려냄


-  D3DApp 클래스의 순수가상함수인 UpdateScene을 BoxApp 클래스에서 오버라이딩함.
-  구면 좌표, 데카르트 좌표 정의 및 변환 참고 링크 : https://iskim3068.tistory.com/23
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=mindo1103&logNo=90155644065

  • BoxApp의 DrawScene 함수 실행

-  D3DApp 클래스의 순수가상함수인 DrawScene을 BoxApp클래스에서 오버라이딩함.
-  후면 버퍼 및 깊이ㆍ스텐실 버퍼 초기화


-  입력 배치를 장치 문맥에 묶어주기


-  기본도형 형성 방식(기본도형 위상구조)을 Direct3D에게 알려줌


-  정점 버퍼와 색인 버퍼를 실제 파이프라인에 공급하기 위해 버퍼를 장치의 한 입력 슬롯에 붙여(묶어)준다.


-  상수 버퍼의 변수들 갱신

=>  세계ㆍ뷰ㆍ투영 결합 행렬을 생성한 후 그렇게 만들어진 행렬을 효과 파일의 상수 버퍼 변수에 대입하는 것.

=>  정점 셰이더에서 정점을 동차 절단 공간으로 변환해주기 때문에 위와 같이 세계ㆍ뷰ㆍ투영 결합 행렬을 구해줘야 한다.

 

-  반복문으로 기법의 각 패스를 훑으면서 각 패스를 적용해서 후면버퍼에 기하구조 그리기

=>  효과 파일에서 적용한 셰이더 등은 이 과정에서 적용됨.


-  후면버퍼와 전면버퍼를 스왑해서 그림이 그려진 후면버퍼를 화면에 제시하기.

 

 

이벤트 처리함수 OnResize, OnMouseDown, OnMouseUp, OnMouseMove
  • OnResize

-  윈도우 창의 크기가 변경될 때 호출되는 메서드로, 윈도우 창의 크기가 변경되었다면 당연히 투영 행렬을 다시 계산해야 하기 때문에 해당 코드가 작성되어 있다.

 

  • OnMouseDown

-  SetCapture : 마우스 커서 좌표가 활성화된 윈도우 창을 벗어나더라도 계속해서 WM_MOUSEMOVE 메시지를 받기 위해 사용하는 함수

=>  SetCapture를 했다면 후에 ReleaseCapture를 호출해주어야 한다.
=>  자신이 SetCapture 함수를 호출하기 전에 다른 윈도우가 SetCapture 함수를 사용하여 마우스 메시지를 점유하고 있었다면 해당 윈도우 객체의 주소(HWND)를 반환합니다. 만약, 그런 윈도우가 없었다면 NULL을 반환하게 된다.
==>  이 반환 값은 임시 객체일 가능성이 있기 때문에 전역변수나 멤버변수에 저장하여 계속 사용할 경우 문제가 발생할 수 있다.
=>  ReleaseCapture 함수가 실패하면 0이 리턴된다.
-  참고 C++ - SetCapture() - 활성영역 외의 마우스 메세지 받기 (silverwolf.co.kr)

 

※ ReleaseCapture : SetCapture를 해제하는 함수(해당 함수를 호출하면 영역 밖에서 더이상 WM_MOUSEMOVE 메시지가 받아지지 않는다.)

 

  • OnMouseUp

 

  • OnMouseMove

-  마우스의 이동에 따른 카메라 이동 값을 계산하는 함수입니다.

-  마우스 좌클릭을 한 상태로 마우스를 움직이게 되면 확대, 축소

-  마우스 우클릭을 한 상태로 마우스를 움직이게 되면 중심점을 두고 카메라가 회전합니다.

 

 

 


 

 

 

개인적으로 이해한 내용을 바탕으로 작성하였기 때문에 틀린 내용이 있을 수 있습니다. 참고하실 때 주의 해주세요.

틀린 부분이나 이상한 부분이 있으면 댓글로 편하게 지적해주세요.

감사합니다!

반응형

'DirectX11 > 코드정리' 카테고리의 다른 글

[Directx11] 6장 연습문제(2)  (0) 2022.11.22
[Directx11] 6장 연습문제(1)  (0) 2022.11.17
[DirectX11] Skull, Waves 예제  (0) 2022.11.17
[DirectX11] Shapes 예제  (0) 2022.11.17
[DirectX11] Hills 예제  (0) 2022.11.17

댓글