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

[DirectX11] Shapes 예제

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
462
463
464
465
466
467
468
469
470
471
472
473
//***************************************************************************************
// ShapesDemo.cpp by Frank Luna (C) 2011 All Rights Reserved.
//
// Demonstrates drawing simple geometric primitives in wireframe mode.
//
// 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 "d3dApp.h"
#include "d3dx11Effect.h"
#include "GeometryGenerator.h"
#include "MathHelper.h"
 
struct Vertex
{
    XMFLOAT3 Pos;
    XMFLOAT4 Color;
};
 
class ShapesApp : public D3DApp
{
public:
    ShapesApp(HINSTANCE hInstance);
    ~ShapesApp();
 
    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* mVB;
    ID3D11Buffer* mIB;
 
    ID3DX11Effect* mFX;
    ID3DX11EffectTechnique* mTech;
    ID3DX11EffectMatrixVariable* mfxWorldViewProj;
 
    ID3D11InputLayout* mInputLayout;
 
    ID3D11RasterizerState* mWireframeRS;
 
    // Define transformations from local spaces to world space.
    // 국소 공간에서 세계 공간으로의 변환 행렬을 정의한다.
    XMFLOAT4X4 mSphereWorld[10];        // 구의 세계 행렬
    XMFLOAT4X4 mCylWorld[10];            // 원기둥의 세계 행렬
    XMFLOAT4X4 mBoxWorld;                // 상자의 세계 행렬
    XMFLOAT4X4 mGridWorld;                // 격자의 세계 행렬
    XMFLOAT4X4 mCenterSphere;            // 중앙 구의 세계 행렬
 
    XMFLOAT4X4 mView;                    // 시야 행렬
    XMFLOAT4X4 mProj;                    // 투영 행렬
 
    int mBoxVertexOffset;                // 연결된 정점 버퍼 안에서의 상자의 정점 오프셋
    int mGridVertexOffset;                // 연결된 정점 버퍼 안에서의 격자의 정점 오프셋
    int mSphereVertexOffset;            // 연결된 정점 버퍼 안에서의 구의 정점 오프셋
    int mCylinderVertexOffset;            // 연결된 정점 버퍼 안에서의 원기둥의 정점 오프셋
 
    UINT mBoxIndexOffset;                // 연결된 색인 버퍼 안에서의 상자의 시작 색인
    UINT mGridIndexOffset;                // 연결된 색인 버퍼 안에서의 격자의 시작 색인
    UINT mSphereIndexOffset;            // 연결된 색인 버퍼 안에서의 구의 시작 색인
    UINT mCylinderIndexOffset;            // 연결된 색인 버퍼 안에서의 원기둥의 시작 색인
 
    UINT mBoxIndexCount;                // 상자의 색인 개수
    UINT mGridIndexCount;                // 격자의 색인 개수
    UINT mSphereIndexCount;                // 구의 색인 개수
    UINT mCylinderIndexCount;            // 원기둥의 색인 개수
 
    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 );
#endif
 
    ShapesApp theApp(hInstance);
    
    if!theApp.Init() )
        return 0;
    
    return theApp.Run();
}
 
 
ShapesApp::ShapesApp(HINSTANCE hInstance)
: D3DApp(hInstance), mVB(0), mIB(0), mFX(0), mTech(0),
  mfxWorldViewProj(0), mInputLayout(0), mWireframeRS(0),
  mTheta(1.5f*MathHelper::Pi), mPhi(0.1f*MathHelper::Pi), mRadius(15.0f)
{
    mMainWndCaption = L"Shapes Demo";
    
    mLastMousePos.x = 0;
    mLastMousePos.y = 0;
 
    // 격자의 세계 행렬 생성 및 시야, 투영 행렬 생성
    XMMATRIX I = XMMatrixIdentity();
    XMStoreFloat4x4(&mGridWorld, I);
    XMStoreFloat4x4(&mView, I);
    XMStoreFloat4x4(&mProj, I);
 
    // 상자의 크기와 위치를 설정
    XMMATRIX boxScale = XMMatrixScaling(2.0f, 1.0f, 2.0f);
    XMMATRIX boxOffset = XMMatrixTranslation(0.0f, 0.5f, 0.0f);
    XMStoreFloat4x4(&mBoxWorld, XMMatrixMultiply(boxScale, boxOffset));
 
    // 중앙 구의 크기와 위치를 설정
    XMMATRIX centerSphereScale = XMMatrixScaling(2.0f, 2.0f, 2.0f);
    XMMATRIX centerSphereOffset = XMMatrixTranslation(0.0f, 2.0f, 0.0f);
    XMStoreFloat4x4(&mCenterSphere, XMMatrixMultiply(centerSphereScale, centerSphereOffset));
 
    // 원기둥과 원기둥 위의 구 위치 설정
    // 원기둥들은 다섯줄로 배치되는데, 하나의 줄은 두 개의 원기둥 + 구 쌍으로 이루어진다.
    for(int i = 0; i < 5++i)
    {
        XMStoreFloat4x4(&mCylWorld[i*2+0], XMMatrixTranslation(-5.0f, 1.5f, -10.0f + i*5.0f));
        XMStoreFloat4x4(&mCylWorld[i*2+1], XMMatrixTranslation(+5.0f, 1.5f, -10.0f + i*5.0f));
 
        XMStoreFloat4x4(&mSphereWorld[i*2+0], XMMatrixTranslation(-5.0f, 3.5f, -10.0f + i*5.0f));
        XMStoreFloat4x4(&mSphereWorld[i*2+1], XMMatrixTranslation(+5.0f, 3.5f, -10.0f + i*5.0f));
    }
}
 
ShapesApp::~ShapesApp()
{
    ReleaseCOM(mVB);
    ReleaseCOM(mIB);
    ReleaseCOM(mFX);
    ReleaseCOM(mInputLayout);
    ReleaseCOM(mWireframeRS);
}
 
bool ShapesApp::Init()
{
    if(!D3DApp::Init())
        return false;
 
    BuildGeometryBuffers();
    BuildFX();
    BuildVertexLayout();
 
    // 래스터화기
 
    // 기하구조를 와이어 프레임으로 생성함.(6.7절 235p)
    D3D11_RASTERIZER_DESC wireframeDesc;
 
    // 설정해줄 값들 이외 다른 값들은 모두 기본값으로 설정함.
    ZeroMemory(&wireframeDesc, sizeof(D3D11_RASTERIZER_DESC));
 
    wireframeDesc.FillMode = D3D11_FILL_WIREFRAME;                // 와이어 프레임 렌더링
    wireframeDesc.CullMode = D3D11_CULL_BACK;                    // 후면 삼각형을 선별해서 제외시킨다.
    wireframeDesc.FrontCounterClockwise = false;                // 시계방향이 전면
    
    // 책에 설명 없음(깊이 클리핑이 없다는 의미(= 깊이값에 의한 클리핑 처리를 할 것인가에 대하여))
    // false로 바꿔도 무슨 차이인지 모르겠음
    wireframeDesc.DepthClipEnable = true;                        
 
    // 래스터화기 단계 구성(ID3D11RasterizerState 인터페이스 생성)
    HR(md3dDevice->CreateRasterizerState(&wireframeDesc, &mWireframeRS));
 
    return true;
}
 
void ShapesApp::OnResize()
{
    D3DApp::OnResize();
 
    XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
    XMStoreFloat4x4(&mProj, P);
}
 
void ShapesApp::UpdateScene(float dt)
{
    // Convert Spherical to Cartesian coordinates.
    float x = mRadius*sinf(mPhi)*cosf(mTheta);
    float z = mRadius*sinf(mPhi)*sinf(mTheta);
    float y = mRadius*cosf(mPhi);
 
    // Build the view matrix.
    XMVECTOR pos    = XMVectorSet(x, y, z, 1.0f);
    XMVECTOR target = XMVectorZero();
    XMVECTOR up     = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
 
    XMMATRIX V = XMMatrixLookAtLH(pos, target, up);
    XMStoreFloat4x4(&mView, V);
}
 
void ShapesApp::DrawScene()
{
    md3dImmediateContext->ClearRenderTargetView(mRenderTargetView, reinterpret_cast<const float*>(&Colors::LightSteelBlue));
    md3dImmediateContext->ClearDepthStencilView(mDepthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0);
 
    md3dImmediateContext->IASetInputLayout(mInputLayout);
    md3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
 
    md3dImmediateContext->RSSetState(mWireframeRS);
 
    UINT stride = sizeof(Vertex);
    UINT offset = 0;
    md3dImmediateContext->IASetVertexBuffers(01&mVB, &stride, &offset);
    md3dImmediateContext->IASetIndexBuffer(mIB, DXGI_FORMAT_R32_UINT, 0);
 
    // Set constants
    // 상수들을 설정한다.
    
    XMMATRIX view  = XMLoadFloat4x4(&mView);
    XMMATRIX proj  = XMLoadFloat4x4(&mProj);
    XMMATRIX viewProj = view*proj;
 
    D3DX11_TECHNIQUE_DESC techDesc;
    mTech->GetDesc( &techDesc );
    for(UINT p = 0; p < techDesc.Passes; ++p)
    {
        // Draw the grid.
        // 격자를 그린다.
        XMMATRIX world = XMLoadFloat4x4(&mGridWorld);
        mfxWorldViewProj->SetMatrix(reinterpret_cast<float*>(&(world*viewProj)));
        mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext);
        md3dImmediateContext->DrawIndexed(mGridIndexCount, mGridIndexOffset, mGridVertexOffset);
 
        // Draw the box.
        // 상자를 그린다.
        world = XMLoadFloat4x4(&mBoxWorld);
        mfxWorldViewProj->SetMatrix(reinterpret_cast<float*>(&(world*viewProj)));
        mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext);
        md3dImmediateContext->DrawIndexed(mBoxIndexCount, mBoxIndexOffset, mBoxVertexOffset);
 
        // Draw center sphere.
        // 중앙의 구를 그린다.
        world = XMLoadFloat4x4(&mCenterSphere);
        mfxWorldViewProj->SetMatrix(reinterpret_cast<float*>(&(world*viewProj)));
        mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext);
        md3dImmediateContext->DrawIndexed(mSphereIndexCount, mSphereIndexOffset, mSphereVertexOffset);
 
        // Draw the cylinders.
        // 원기둥들을 그린다.
        for(int i = 0; i < 10++i)
        {
            world = XMLoadFloat4x4(&mCylWorld[i]);
            mfxWorldViewProj->SetMatrix(reinterpret_cast<float*>(&(world*viewProj)));
            mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext);
            md3dImmediateContext->DrawIndexed(mCylinderIndexCount, mCylinderIndexOffset, mCylinderVertexOffset);
        }
 
        // Draw the spheres.
        // 구들을 그린다(원기둥 위의 구를 그리는 것 같음)
        for(int i = 0; i < 10++i)
        {
            world = XMLoadFloat4x4(&mSphereWorld[i]);
            mfxWorldViewProj->SetMatrix(reinterpret_cast<float*>(&(world*viewProj)));
            mTech->GetPassByIndex(p)->Apply(0, md3dImmediateContext);
            md3dImmediateContext->DrawIndexed(mSphereIndexCount, mSphereIndexOffset, mSphereVertexOffset);
        }
    }
 
    HR(mSwapChain->Present(00));
}
 
void ShapesApp::OnMouseDown(WPARAM btnState, int x, int y)
{
    mLastMousePos.x = x;
    mLastMousePos.y = y;
 
    SetCapture(mhMainWnd);
}
 
void ShapesApp::OnMouseUp(WPARAM btnState, int x, int y)
{
    ReleaseCapture();
}
 
void ShapesApp::OnMouseMove(WPARAM btnState, int x, int y)
{
    if( (btnState & MK_LBUTTON) != 0 )
    {
        // Make each pixel correspond to a quarter of a degree.
        float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
        float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
 
        // Update angles based on input to orbit camera around box.
        mTheta += dx;
        mPhi   += dy;
 
        // Restrict the angle mPhi.
        mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi-0.1f);
    }
    else if( (btnState & MK_RBUTTON) != 0 )
    {
        // Make each pixel correspond to 0.01 unit in the scene.
        float dx = 0.01f*static_cast<float>(x - mLastMousePos.x);
        float dy = 0.01f*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, 200.0f);
    }
 
    mLastMousePos.x = x;
    mLastMousePos.y = y;
}
 
void ShapesApp::BuildGeometryBuffers()
{
    GeometryGenerator::MeshData box;
    GeometryGenerator::MeshData grid;
    GeometryGenerator::MeshData sphere;
    GeometryGenerator::MeshData cylinder;
 
    // 각 메시 데이터에 각각의 기하구조 생성 후 저장
    GeometryGenerator geoGen;
    geoGen.CreateBox(1.0f, 1.0f, 1.0f, box);
    geoGen.CreateGrid(20.0f, 30.0f, 6040, grid);
    geoGen.CreateSphere(0.5f, 2020, sphere);
    //geoGen.CreateGeosphere(0.5f, 2, sphere);
    geoGen.CreateCylinder(0.5f, 0.3f, 3.0f, 2020, cylinder);
 
    // Cache the vertex offsets to each object in the concatenated vertex buffer.
    // 연결된 정점 버퍼 안에서의 각 물체의 정점 오프셋을 저장해둔다.
    mBoxVertexOffset      = 0;
    mGridVertexOffset     = box.Vertices.size();
    mSphereVertexOffset   = mGridVertexOffset + grid.Vertices.size();
    mCylinderVertexOffset = mSphereVertexOffset + sphere.Vertices.size();
 
    // Cache the index count of each object.
    // 각 물체의 색인 개수를 저장해 둔다.
    mBoxIndexCount      = box.Indices.size();
    mGridIndexCount     = grid.Indices.size();
    mSphereIndexCount   = sphere.Indices.size();
    mCylinderIndexCount = cylinder.Indices.size();
 
    // Cache the starting index for each object in the concatenated index buffer.
    // 연결된 색인 버퍼에서 각 물체의 시작 색인을 저장해 둔다.
    mBoxIndexOffset      = 0;
    mGridIndexOffset     = mBoxIndexCount;
    mSphereIndexOffset   = mGridIndexOffset + mGridIndexCount;
    mCylinderIndexOffset = mSphereIndexOffset + mSphereIndexCount;
    
    UINT totalVertexCount = 
        box.Vertices.size() + 
        grid.Vertices.size() + 
        sphere.Vertices.size() +
        cylinder.Vertices.size();
 
    UINT totalIndexCount = 
        mBoxIndexCount + 
        mGridIndexCount + 
        mSphereIndexCount +
        mCylinderIndexCount;
 
    //
    // Extract the vertex elements we are interested in and pack the
    // vertices of all the meshes into one vertex buffer.
    // 
    // 필요한 정점 특성들을 추출하고, 모든 메시의 정점들을
    // 하나의 정점 버퍼에 넣는다.
    //
 
    std::vector<Vertex> vertices(totalVertexCount);
 
    XMFLOAT4 black(0.0f, 0.0f, 0.0f, 1.0f);
 
    UINT k = 0;
    for(size_t i = 0; i < box.Vertices.size(); ++i, ++k)
    {
        vertices[k].Pos   = box.Vertices[i].Position;
        vertices[k].Color = black;
    }
 
    for(size_t i = 0; i < grid.Vertices.size(); ++i, ++k)
    {
        vertices[k].Pos   = grid.Vertices[i].Position;
        vertices[k].Color = black;
    }
 
    for(size_t i = 0; i < sphere.Vertices.size(); ++i, ++k)
    {
        vertices[k].Pos   = sphere.Vertices[i].Position;
        vertices[k].Color = black;
    }
 
    for(size_t i = 0; i < cylinder.Vertices.size(); ++i, ++k)
    {
        vertices[k].Pos   = cylinder.Vertices[i].Position;
        vertices[k].Color = black;
    }
 
    D3D11_BUFFER_DESC vbd;
    vbd.Usage = D3D11_USAGE_IMMUTABLE;
    vbd.ByteWidth = sizeof(Vertex) * totalVertexCount;
    vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vbd.CPUAccessFlags = 0;
    vbd.MiscFlags = 0;
    D3D11_SUBRESOURCE_DATA vinitData;
    vinitData.pSysMem = &vertices[0];
    HR(md3dDevice->CreateBuffer(&vbd, &vinitData, &mVB));
 
    //
    // Pack the indices of all the meshes into one index buffer.
    // 모든 메시의 색인들을 하나의 색인 버퍼에 넣는다.
    //
 
    std::vector<UINT> indices;
    indices.insert(indices.end(), box.Indices.begin(), box.Indices.end());
    indices.insert(indices.end(), grid.Indices.begin(), grid.Indices.end());
    indices.insert(indices.end(), sphere.Indices.begin(), sphere.Indices.end());
    indices.insert(indices.end(), cylinder.Indices.begin(), cylinder.Indices.end());
 
    D3D11_BUFFER_DESC ibd;
    ibd.Usage = D3D11_USAGE_IMMUTABLE;
    ibd.ByteWidth = sizeof(UINT) * totalIndexCount;
    ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = 0;
    ibd.MiscFlags = 0;
    D3D11_SUBRESOURCE_DATA iinitData;
    iinitData.pSysMem = &indices[0];
    HR(md3dDevice->CreateBuffer(&ibd, &iinitData, &mIB));
}
 
void ShapesApp::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();
    
    HR(D3DX11CreateEffectFromMemory(&compiledShader[0], size
        0, md3dDevice, &mFX));
 
    mTech    = mFX->GetTechniqueByName("ColorTech");
    mfxWorldViewProj = mFX->GetVariableByName("gWorldViewProj")->AsMatrix();
}
 
void ShapesApp::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}
    };
 
    // Create the input layout
    D3DX11_PASS_DESC passDesc;
    mTech->GetPassByIndex(0)->GetDesc(&passDesc);
    HR(md3dDevice->CreateInputLayout(vertexDesc, 2, passDesc.pIAInputSignature, 
        passDesc.IAInputSignatureSize, &mInputLayout));
}
cs

 

이번 예제는 사각형, 원기둥, 구, 격자를 한 번에 출력하는 코드입니다. 이번 예제에서 분석해볼 부분은 2가지 입니다.

1. 각 도형 별 정점 및 색인 설정 방법

2. 각 도형 별 정점 및 색인들을 하나의 큰 정점버퍼와 색인버퍼에 연결하여 그리는 방법.

 

 

각 도형 별 정점 및 색인
  • 원기둥

-  구와 원기둥은 하늘 돔(sky dome) 그리기, 디버깅, 충돌 검출의 시각화, 지연 렌더링(deferred rendering) 등에 유용하다.

ex) 게임의 캐릭터를 구로 감싸면 충돌 검출이 제대로 일어나는지 눈으로 확인하기가 쉽다.

 

-  원기둥의 밑면 반지름과 윗면 반지름이 다를 경우, 해당 차이는 각 더미별로 일정하게 줄어든다.(선형이다)

-  또한 각 더미는 동일한 높이를 가진다.

=>  이 정보를 바탕으로 각 고리의 반지름을 구하고, 해당 반지름을 이용해서 정점들의 x,z값을 구할 수 있다.

=>  마찬가지로 각 더미는 동일한 높이를 가지므로 각 정점의 높이 값 또한 쉽게 구할 수 있다.

 

-  해당 내용들을 바탕으로 원기둥 옆면의 각 정점의 값을 설정해주는 코드이다.

-  각 고리의 x, z값은 cos, sin값을 이용해서 구한다.

 

-  원기둥 옆면의 색인들을 설정하는 코드이다. 격자와 비슷한 방식으로 구현되었으므로 쉽게 이해할 수 있을 것이다.

-  옆면의 정점 및 색인 생성이 끝났으므로 원기둥의 윗면과 밑면의 정점과 색인을 설정해 주어야 한다.

 

-  윗면, 밑면은 거의 동일한 방식이므로 윗면에 대해서만 알아보도록 하자.

-  옆면 정점을 설정할 때처럼 윗면을 생성하는데 필요한 최상단 고리를 하나 생성한다.

-  다음으로 윗면 중앙에 있는 정점을 설정한다.

=>  격자와 마찬가지로 원기둥의 중앙이 (0, 0, 0)임을 유의하자.

 

-  이후 색인을 생성한다.

-  밑면도 같은 방법으로 생성해주면 원기둥의 정점 및 색인 설정이 완료된다.

 

-  하나의 구를 반지름과 조각 개수 및 더미 개수로 정의 한다.

-  구의 경우 원기둥의 생성과 거의 일치합니다.

-  단, 원기둥은 고리들의 반지름이 각 더미 별로 일정하게 증가 및 감소하는데 반해 구는 고리들의 반지름이 삼각함수에 따라 비선형으로 변한다는 것에 유의해서 코드를 확인하면 됩니다.

 

  • 측지구(geosphere(= geodesic sphere))

-  일반적인 구의 삼각형들은 면적이 일정하지 않다.

=>  상황에 따라서는 이러한 특징이 단점이 되기도 한다.


-  측지구(geosphere(= geodesic sphere))는 면적이 거의 같고 변의 길이도 같은 삼각형들로 구를 근사한다.

-  측지구를 생성할 때에는 정이십면체에서 출발해서 각 삼각형을 세분(subdivision)한 후 새로 생긴 정점들을 주어진 반지름의 구에 투영한다.

=>  이런 과정을 반복해서 테셀레이션 수준을 높여 나가면 실제 구에 좀 더 가까운 측지구 메시가 만들어진다.

-  우선 정이십면체를 직접 정점 및 색인들을 지정해서 생성해준 후, 각 삼각형을 세분하여준다.

 

-  세분의 경우 주석과 함께 보면 전혀 어렵지 않게 이해할 수 있다.

-  각 변의 중점인 m0, m1, m2를 생성하고 중점들을 정점으로 추가해준 뒤, 정점 감기 순서에 맞춰 색인을 설정해주면 끝이다.

 

-  세분까지 끝났다면, 현재 임의의 크기의 측지구가 생성되어 있다.

-  해당 측지구를 단위 구 크기로 변경한 후(각 정점을 모두 정규화 한다) 원하는 크기의 반지름을 다시 각 정점에 모두 곱하여주면, 원하는 측지구를 얻을 수 있다.

 

 

각 도형 별 정점 및 색인들을 하나의 큰 정점버퍼와 색인버퍼에 연결하여 그리는 방법
  • 지금까지의 예제와 이번 예제의 핵심적인 차이점은 여러 개의 물체를 화면에 그린다는 것이다.

-  각 물체마다 세계 공간을 기준으로 한 물체의 국소 공간을 서술하는 세계 행렬이 있다.
-  이 예제에서 여러 개의 구와 원기둥을 그리긴 하지만 구와 원기둥의 기하구조 자체는 각각 하나 뿐이다.

=>  그냥 같은 구, 원기둥 메시를 세계 행렬을 달리 해서 여러 번 그리는 것일 뿐
=>  이를 인스턴싱이라고 부른다.

 

  • 예제는 생성한 정점 배열들과 색인 배열들을 연결해서, 모든 메시들을 하나의 정점 버퍼와 색인 버퍼에 담아서 사용한다.

-  하나의 물체를 그린다는 것은 정점, 색인 버퍼의 한 부분집합을 그리는 것을 뜻한다.
-  전체 기하구조의 한 부분집합만을 그리기 위해서는 세 가지 수량을 알아야 한다.

=>  1. 연결된 색인 버퍼 안에서의 각 물체의 시작 색인
=>  2. 물체 당 색인 개수
=>  3. 연결된 정점 버퍼에서 각 물체의 첫 정점에 해당하는 색인 오프셋
==>  3을 알아야 하는 이유는, 정점 배열들을 연결할 때 색인들을 그에 맞게 조정하지 않았기 때문이다.
==>  이는 각 물체의 첫 정점의 색인 오프셋을 알고 있다면 문제가 해결된다. DrawIndexed의 셋째 매개변수, 즉 기준 정점 위치로 지정하면 그리기 호출의 정점 버퍼 내의 모든 정점 인덱스에 그 오프셋이 더해져서 결과적으로 정확한 색인들이 적용된다.

 

  • 정점 버퍼 생성

 

  • 색인 버퍼 생성

 

  • 각 도형 별 세계 변환 행렬

-  그려진 도형들이 모두 같은 위치에 겹쳐지면 안 되므로 각 도형 별 세계 변환 행렬을 따로 설정해두어야 한다.

 

  • 각 도형 별로 그리기

-   각 도형 별로 세계ㆍ시야ㆍ투영 결합 행렬을 따로 만들어주고, DrawIndexed의 매개변수를 적절히 넣어주면 원하는 그림을 그릴 수 있다.

 

 

 


 

 

 

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

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

감사합니다!

반응형

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

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

댓글