Thinking Different




Terrain 10 - 스카이 돔



원문 : http://www.rastertek.com/tertut10.html



 이번 DirectX 11 지형 튜토리얼에서는 스카이 돔을 구현하는 방법에 대해 설명합니다. 이는 지형의 배경에 어울릴 수 있는 그라데이션 색 하늘을 생성하는데 그 방법은 지형을 중심으로 하는 구 모양의 모델을 만들고 색상을 입혀 마치 하늘처럼 보이도록 하게 합니다.


스카이 돔을 구현하려면 먼저 스카이 돔 모델이 필요합니다. 이 튜토리얼에서는 Maya에 들어가서 반경이 2.0과 20인 구를 만들었습니다. 그 다음 삼각형을 분할하여 .obj 형식의 모델로 내보냅니다. DirectX 11 튜토리얼 섹션에서는 마야에서 기본 .obj 모델로드 및 렌더링을 다루므로 이러한 튜토리얼을 보지 못했다면 해당 듀토리얼([DirectX11] Tutorial 8 - 마야 2011 모델 불러오기)을 먼저 선행해 보시기 바랍니다. 또한 픽셀 쉐이더가 그 크기 값에 의존하기 때문에 반경 2.0이 매우 중요합니다.




스카이 돔을 사용하기 위한 다음 단계는 항상 카메라 포지션이 스카이 돔을 렌더링해야 한다는 것입니다. 이 방법은 스카이 돔이 어디로 이동하든 관계없이 항상 카메라를 둘러 쌉니다. 우리는 카메라가 각 프레임에 위치하도록 하고 스카이 돔을 카메라 위치의 중앙에 맞추어 프레임을 시작한 다음 프레임을 렌더링함으로써 이 작업을 수행합니다.


세 번째 단계는 스카이 돔을 렌더링 할 때 뒷표면 컬링을 끌 필요가 있다는 것입니다. 우리는 항상 스카이 돔 안에 있기 때문에 잘못된 방향을 향하고 있게 되면 그래픽 카드는 다각형을 도려냅니다. 그래서 우리는 다른 래스터 상태를 사용하여 뒷표면 컬링을 끄고, 스카이 돔을 렌더링 한 다음 원래의 래스터 상태를 다시 활성화하여 뒷표면 컬링을 다시 되돌립니다.


네 번째 단계는 렌더링 전에 Z 버퍼를 비활성화해야 한다는 것입니다. 우리가 그것을 끄지 않으면 우리는 스카이 돔 바깥에 아무것도 볼 수 없고 오직 안에 있는 것만 볼 수 있습니다. 우리가 렌더링하기 전에 Z 버퍼를 끄면 거리에 상관없이 모든 것을 덮어 쓰는 백 버퍼에 스카이 돔 전체를 그릴 수 있습니다. 이것은 또한 지형 또는 다른 것을 렌더링하기 전에 스카이 돔을 렌더링해야 하는 이유이기도 합니다. 스카이 돔이 렌더링되면 Z 버퍼를 다시 켜서 다른 모든 것이 다시 깊이에 따라 렌더링되도록 합니다.


다섯 번째이자 마지막 단계는 쉐이더에서 구현됩니다. 픽셀 쉐이더에서 스카이 돔을 렌더링 할 픽셀의 현재 위치를 전달합니다. 이 위치의 Y 좌표를 높이로 취급합니다. 그리고 구체의 반경이 2.0이기 때문에 스카이 돔의 상단으로 + 1.0f, 스카이 돔의 바닥으로 -1.0f로 변환됩니다. 높이가 +1.0과 -1.0 사이임을 알기 때문에 두 가지 색상 사이의 보간 값으로 높이를 사용하여 스카이 돔을 채색하여 하늘색 그라디언트를 만들 수 있습니다.


이제 이 튜토리얼의 코드 섹션에서 SkyDomeClass 및 SkyDomeShaderClass라는 두 개의 새로운 클래스를 추가했습니다. 또한 skydome 버텍스와 픽셀 쉐이더 HLSL 프로그램을 추가했습니다. SkyDomeClass는 기본적으로 스카이 돔의 구형 모델과 그라디언트의 두 가지 색상을 캡슐화합니다. SkyDomeShaderClass는 스카이 돔 모델 렌더링에 사용됩니다.



먼저 SkyDomeClass 코드부터 시작하도록 하겠습니다.


Skydomeclass.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
#pragma once
 
 
class SkyDomeClass
{
private:
    struct ModelType
    {
        float x, y, z;
        float tu, tv;
        float nx, ny, nz;
    };
 
    struct VertexType
    {
        XMFLOAT3 position;
    };
 
public:
    SkyDomeClass();
    SkyDomeClass(const SkyDomeClass&);
    ~SkyDomeClass();
 
    bool Initialize(ID3D11Device*);
    void Shutdown();
    void Render(ID3D11DeviceContext*);
 
    int GetIndexCount();
    XMFLOAT4 GetApexColor();
    XMFLOAT4 GetCenterColor();
 
private:
    bool LoadSkyDomeModel(const char*);
    void ReleaseSkyDomeModel();
 
    bool InitializeBuffers(ID3D11Device*);
    void ReleaseBuffers();
    void RenderBuffers(ID3D11DeviceContext*);
 
private:
    ModelType* m_model = nullptr;
    int m_vertexCount = 0;
    int m_indexCount = 0;
    ID3D11Buffer* m_vertexBuffer = nullptr; 
    ID3D11Buffer* m_indexBuffer = nullptr;
    XMFLOAT4 m_apexColor;
    XMFLOAT4 m_centerColor;
};
cs



Skydomeclass.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
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
#include "stdafx.h"
#include "skydomeclass.h"
 
#include <fstream>
using namespace std;
 
 
SkyDomeClass::SkyDomeClass()
{
}
 
 
SkyDomeClass::SkyDomeClass(const SkyDomeClass& other)
{
}
 
 
SkyDomeClass::~SkyDomeClass()
{
}
 
 
bool SkyDomeClass::Initialize(ID3D11Device* device)
{
    // 스카이 돔 모델 정보를 읽어옵니다.
    if(!LoadSkyDomeModel("../Dx11Terrain_10/data/skydome.txt"))
    {
        return false;
    }
 
    // 스카이 돔을 정점에 로드하고 렌더링을 위해 인덱스 버퍼를 로드합니다.
    if(!InitializeBuffers(device))
    {
        return false;
    }
 
    // 스카이 돔 꼭대기에 색상을 설정합니다.
    m_apexColor = XMFLOAT4(0.0f, 0.15f, 0.66f, 1.0f);
    
    // 스카이 돔의 중심에 색상을 설정합니다.
    m_centerColor =  XMFLOAT4(0.81f, 0.38f, 0.66f, 1.0f);
    
    return true;
}
 
 
void SkyDomeClass::Shutdown()
{
    // 스카이 돔 렌더링에 사용된 정점 및 인덱스 버퍼를 해제합니다.
    ReleaseBuffers();
 
    // 스카이 돔 모델을 해제합니다.
    ReleaseSkyDomeModel();
}
 
 
void SkyDomeClass::Render(ID3D11DeviceContext* deviceContext)
{
    // 스카이 돔을 렌더링 합니다.
    RenderBuffers(deviceContext);
}
 
 
int SkyDomeClass::GetIndexCount()
{
    return m_indexCount;
}
 
 
XMFLOAT4 SkyDomeClass::GetApexColor()
{
    return m_apexColor;
}
 
 
XMFLOAT4 SkyDomeClass::GetCenterColor()
{
    return m_centerColor;
}
 
 
bool SkyDomeClass::LoadSkyDomeModel(const char* filename)
{
    // 모델 파일을 엽니다.
    ifstream fin;
    fin.open(filename);
    
    // 파일을 열 수 없으면 종료합니다.
    if(fin.fail())
    {
        return false;
    }
 
    // 버텍스 카운트의 값까지 읽는다.
    char input = 0;
    fin.get(input);
    while(input != ':')
    {
        fin.get(input);
    }
 
    // 버텍스 카운트를 읽는다.
    fin >> m_vertexCount;
 
    // 인덱스의 수를 정점 수와 같게 설정합니다.
    m_indexCount = m_vertexCount;
 
    // 읽어 들인 정점 개수를 사용하여 모델을 만듭니다.
    m_model = new ModelType[m_vertexCount];
    if(!m_model)
    {
        return false;
    }
 
    // 데이터의 시작 부분까지 읽는다.
    fin.get(input);
    while(input != ':')
    {
        fin.get(input);
    }
    fin.get(input);
    fin.get(input);
 
    // 버텍스 데이터를 읽습니다.
    for(int i=0; i<m_vertexCount; i++)
    {
        fin >> m_model[i].x >> m_model[i].y >> m_model[i].z;
        fin >> m_model[i].tu >> m_model[i].tv;
        fin >> m_model[i].nx >> m_model[i].ny >> m_model[i].nz;
    }
 
    // 모델 파일을 닫는다.
    fin.close();
 
    return true;
}
 
 
void SkyDomeClass::ReleaseSkyDomeModel()
{
    if(m_model)
    {
        delete [] m_model;
        m_model = 0;
    }
}
 
 
bool SkyDomeClass::InitializeBuffers(ID3D11Device* device)
{
    // 정점 배열을 만듭니다.
    VertexType* vertices = new VertexType[m_vertexCount];
    if(!vertices)
    {
        return false;
    }
 
    // 인덱스 배열을 만듭니다.
    unsigned long* indices = new unsigned long[m_indexCount];
    if(!indices)
    {
        return false;
    }
 
    // 정점 배열과 인덱스 배열을 데이터로 로드합니다.
    for(int i=0; i<m_vertexCount; i++)
    {
        vertices[i].position = XMFLOAT3(m_model[i].x, m_model[i].y, m_model[i].z);
        indices[i] = i;
    }
 
    // 정점 버퍼의 구조체를 설정한다.
    D3D11_BUFFER_DESC vertexBufferDesc;
    vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    vertexBufferDesc.ByteWidth = sizeof(VertexType) * m_vertexCount;
    vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = 0;
    vertexBufferDesc.MiscFlags = 0;
    vertexBufferDesc.StructureByteStride = 0;
 
    // subresource 구조에 정점 데이터에 대한 포인터를 제공합니다.
    D3D11_SUBRESOURCE_DATA vertexData;
    vertexData.pSysMem = vertices;
    vertexData.SysMemPitch = 0;
    vertexData.SysMemSlicePitch = 0;
 
    // 이제 마침내 정점 버퍼를 만듭니다.
    if(FAILED(device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer)))
    {
        return false;
    }
 
    // 인덱스 버퍼의 구조체를 설정합니다.
    D3D11_BUFFER_DESC indexBufferDesc;
    indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount;
    indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    indexBufferDesc.CPUAccessFlags = 0;
    indexBufferDesc.MiscFlags = 0;
    indexBufferDesc.StructureByteStride = 0;
 
    // 하위 리소스 구조에 인덱스 데이터에 대한 포인터를 제공합니다.
    D3D11_SUBRESOURCE_DATA indexData;
    indexData.pSysMem = indices;
    indexData.SysMemPitch = 0;
    indexData.SysMemSlicePitch = 0;
 
    // 인덱스 버퍼를 만듭니다.
    if(FAILED(device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer)))
    {
        return false;
    }
 
    // 이제 버텍스와 인덱스 버퍼가 생성되고로드 된 배열을 해제하십시오.
    delete [] vertices;
    vertices = 0;
 
    delete [] indices;
    indices = 0;
 
    return true;
}
 
 
void SkyDomeClass::ReleaseBuffers()
{
    // 인덱스 버퍼를 해제합니다.
    if(m_indexBuffer)
    {
        m_indexBuffer->Release();
        m_indexBuffer = 0;
    }
 
    // 버텍스 버퍼를 해제한다.
    if(m_vertexBuffer)
    {
        m_vertexBuffer->Release();
        m_vertexBuffer = 0;
    }
}
 
 
void SkyDomeClass::RenderBuffers(ID3D11DeviceContext* deviceContext)
{
    // 정점 버퍼 보폭 및 오프셋을 설정합니다.
    unsigned int stride = sizeof(VertexType); 
    unsigned int offset = 0;
    
    // 렌더링 할 수 있도록 입력 어셈블러에서 정점 버퍼를 활성으로 설정합니다.
    deviceContext->IASetVertexBuffers(01&m_vertexBuffer, &stride, &offset);
 
    // 렌더링 할 수 있도록 입력 어셈블러에서 인덱스 버퍼를 활성으로 설정합니다.
    deviceContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);
 
    // 이 꼭지점 버퍼에서 렌더링되어야하는 프리미티브 유형을 설정합니다.이 경우에는 삼각형입니다.
    deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
cs



스카이 돔 버텍스 쉐이더 프로그램은 매우 간단합니다. 우리는 평소와 같이 정규 위치를 전송하지만, domePosition이라는 두 번째 변수에서 수정되지 않은 픽셀 셰이더로 위치를 전송합니다.


Skydome_vs.hlsl


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
////////////////////////////////////////////////////////////////////////////////
// Filename: skydome_vs.hlsl
////////////////////////////////////////////////////////////////////////////////
 
 
/////////////
// GLOBALS //
/////////////
cbuffer MatrixBuffer
{
    matrix worldMatrix;
    matrix viewMatrix;
    matrix projectionMatrix;
};
 
 
//////////////
// TYPEDEFS //
//////////////
struct VertexInputType
{
    float4 position : POSITION;
};
 
struct PixelInputType
{
    float4 position : SV_POSITION;
    float4 domePosition : TEXCOORD0;
};
 
 
////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
////////////////////////////////////////////////////////////////////////////////
PixelInputType SkyDomeVertexShader(VertexInputType input)
{
    PixelInputType output;
    
 
    // 적절한 행렬 계산을 위해 위치 벡터를 4 단위로 변경합니다.
    input.position.w = 1.0f;
 
    // 월드, 뷰 및 투영 행렬에 대한 정점의 위치를 ​​계산합니다.
    output.position = mul(input.position, worldMatrix);
    output.position = mul(output.position, viewMatrix);
    output.position = mul(output.position, projectionMatrix);
    
    // 수정되지 않은 위치를 픽셀 쉐이더로 보낸다.
    output.domePosition = input.position;
 
    return output;
}
cs



픽셀 쉐이더는 우리가 스카이 돔 렌더링의 모든 실제 작업을 수행하는 곳입니다. 먼저 GradientBuffer는 꼭지점과 중심 색을 설정하여 그라디언트를 만들 수 있는 두 가지 색상을 갖게됩니다. 픽셀 쉐이더 함수에서 현재 돔의 위치를 결정하기 위해 현재 픽셀의 높이를 취합니다. 이 높이를 보간 값으로 사용하고 꼭지점과 중심색 사이의 보간을 수행합니다. 높이 값이 높을수록 정점 색상이 더 많이 나타납니다. 높이 값이 낮을수록 센터 색이 더 많이 표시됩니다.


또한 구의 반지름은 2.0 이었으므로 픽셀 쉐이더에서 -1.0f에서 + 1.0f 범위를 얻을 수 있습니다. 다른 반경을 사용한다면 여기에 있는 값을 변경하거나 자신의 상수 버퍼에서 보내야 합니다.


Skydome_ps.hlsl


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
////////////////////////////////////////////////////////////////////////////////
// Filename: skydome_ps.hlsl
////////////////////////////////////////////////////////////////////////////////
 
 
/////////////
// GLOBALS //
/////////////
cbuffer GradientBuffer
{
    float4 apexColor;
    float4 centerColor;
};
 
 
//////////////
// TYPEDEFS //
//////////////
struct PixelInputType
{
    float4 position : SV_POSITION;
    float4 domePosition : TEXCOORD0;
};
 
 
////////////////////////////////////////////////////////////////////////////////
// Pixel Shader
////////////////////////////////////////////////////////////////////////////////
float4 SkyDomePixelShader(PixelInputType input) : SV_TARGET
{
    // 이 픽셀이 있는 스카이 돔에서 위치를 결정합니다.
    float height = input.domePosition.y;
 
    // 값의 범위는 -1.0f에서 + 1.0f이므로 양수 값만 변경하십시오.
    if(height < 0.0)
    {
        height = 0.0f;
    }
 
    // 스카이 돔에서 픽셀의 높이를 기준으로 정점과 중심을 보정하여 그라디언트 색상을 결정합니다.
    float4 outputColor = lerp(centerColor, apexColor, height);
 
    return outputColor;
}
cs



Skydomeshaderclass.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
#pragma once
 
class SkyDomeShaderClass : public AlignedAllocationPolicy<16>
{
private:
    struct MatrixBufferType
    {
        XMMATRIX world;
        XMMATRIX view;
        XMMATRIX projection;
    };
 
    struct GradientBufferType
    {
        XMFLOAT4 apexColor;
        XMFLOAT4 centerColor;
    };
 
public:
    SkyDomeShaderClass();
    SkyDomeShaderClass(const SkyDomeShaderClass&);
    ~SkyDomeShaderClass();
 
    bool Initialize(ID3D11Device*, HWND);
    void Shutdown();
    bool Render(ID3D11DeviceContext*, int, XMMATRIX, XMMATRIX, XMMATRIX, XMFLOAT4, XMFLOAT4);
 
private:
    bool InitializeShader(ID3D11Device*, HWND, const WCHAR*, const WCHAR*);
    void ShutdownShader();
    void OutputShaderErrorMessage(ID3D10Blob*, HWND, const WCHAR*);
 
    bool SetShaderParameters(ID3D11DeviceContext*, XMMATRIX, XMMATRIX, XMMATRIX, XMFLOAT4, XMFLOAT4);
    void RenderShader(ID3D11DeviceContext*, int);
 
private:
    ID3D11VertexShader * m_vertexShader = nullptr;
    ID3D11PixelShader* m_pixelShader = nullptr;
    ID3D11InputLayout* m_layout = nullptr;
    ID3D11Buffer* m_matrixBuffer = nullptr;
    ID3D11Buffer* m_gradientBuffer = nullptr;
};
cs



Skydomeshaderclass.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
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
#include "stdafx.h"
#include "skydomeshaderclass.h"
 
 
SkyDomeShaderClass::SkyDomeShaderClass()
{
}
 
 
SkyDomeShaderClass::SkyDomeShaderClass(const SkyDomeShaderClass& other)
{
}
 
 
SkyDomeShaderClass::~SkyDomeShaderClass()
{
}
 
 
bool SkyDomeShaderClass::Initialize(ID3D11Device* device, HWND hwnd)
{
    // 정점 및 픽셀 쉐이더를 초기화합니다.
    return InitializeShader(device, hwnd, L"../Dx11Terrain_10/skydome_vs.hlsl", L"../Dx11Terrain_10/skydome_ps.hlsl");
}
 
 
void SkyDomeShaderClass::Shutdown()
{
    // 버텍스 및 픽셀 쉐이더와 관련된 객체를 종료합니다.
    ShutdownShader();
}
 
 
bool SkyDomeShaderClass::Render(ID3D11DeviceContext* deviceContext, int indexCount, XMMATRIX worldMatrix, XMMATRIX viewMatrix, 
                                XMMATRIX projectionMatrix, XMFLOAT4 apexColor, XMFLOAT4 centerColor)
{
    // 렌더링에 사용할 셰이더 매개 변수를 설정합니다.
    if(!SetShaderParameters(deviceContext, worldMatrix, viewMatrix, projectionMatrix, apexColor, centerColor))
    {
        return false;
    }
 
    // 준비한 버퍼를 셰이더로 렌더링 합니다.
    RenderShader(deviceContext, indexCount);
 
    return true;
}
 
 
bool SkyDomeShaderClass::InitializeShader(ID3D11Device* device, HWND hwnd, const WCHAR* vsFilename, const WCHAR* psFilename)
{
    ID3D10Blob* errorMessage = nullptr;
 
    // 버텍스 쉐이더 코드를 컴파일한다.
    ID3D10Blob* vertexShaderBuffer = nullptr;
    if (FAILED(D3DCompileFromFile(vsFilename, NULL, NULL, "SkyDomeVertexShader""vs_5_0", D3D10_SHADER_ENABLE_STRICTNESS,
 0&vertexShaderBuffer, &errorMessage)))
    {
        // 셰이더 컴파일 실패시 오류메시지를 출력합니다.
        if (errorMessage)
        {
            OutputShaderErrorMessage(errorMessage, hwnd, vsFilename);
        }
        // 컴파일 오류가 아니라면 셰이더 파일을 찾을 수 없는 경우입니다.
        else
        {
            MessageBox(hwnd, vsFilename, L"Missing Shader File", MB_OK);
        }
 
        return false;
    }
 
    // 픽셀 쉐이더 코드를 컴파일한다.
    ID3D10Blob* pixelShaderBuffer = nullptr;
    if (FAILED(D3DCompileFromFile(psFilename, NULL, NULL, "SkyDomePixelShader""ps_5_0", D3D10_SHADER_ENABLE_STRICTNESS,
 0&pixelShaderBuffer, &errorMessage)))
    {
        // 셰이더 컴파일 실패시 오류메시지를 출력합니다.
        if (errorMessage)
        {
            OutputShaderErrorMessage(errorMessage, hwnd, psFilename);
        }
        // 컴파일 오류가 아니라면 셰이더 파일을 찾을 수 없는 경우입니다.
        else
        {
            MessageBox(hwnd, psFilename, L"Missing Shader File", MB_OK);
        }
 
        return false;
    }
 
    // 버퍼로부터 정점 셰이더를 생성한다.
    if (FAILED(device->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), NULL,
 &m_vertexShader)))
    {
        return false;
    }
 
    // 버퍼에서 픽셀 쉐이더를 생성합니다.
    if (FAILED(device->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(), pixelShaderBuffer->GetBufferSize(), NULL,
 &m_pixelShader)))
    {
        return false;
    }
 
    // 정점 입력 레이아웃 구조체를 설정합니다.
    // 이 설정은 ModelClass와 셰이더의 VertexType 구조와 일치해야합니다.
    D3D11_INPUT_ELEMENT_DESC polygonLayout[1];
    polygonLayout[0].SemanticName = "POSITION";
    polygonLayout[0].SemanticIndex = 0;
    polygonLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
    polygonLayout[0].InputSlot = 0;
    polygonLayout[0].AlignedByteOffset = 0;
    polygonLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
    polygonLayout[0].InstanceDataStepRate = 0;
 
    // 레이아웃의 요소 수를 가져옵니다.
    UINT numElements = sizeof(polygonLayout) / sizeof(polygonLayout[0]);
 
    // 정점 입력 레이아웃을 만듭니다.
    if (FAILED(device->CreateInputLayout(polygonLayout, numElements,
        vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), &m_layout)))
    {
        return false;
    }
 
    // 더 이상 사용되지 않는 정점 셰이더 퍼버와 픽셀 셰이더 버퍼를 해제합니다.
    vertexShaderBuffer->Release();
    vertexShaderBuffer = 0;
 
    pixelShaderBuffer->Release();
    pixelShaderBuffer = 0;
 
    // 버텍스 쉐이더에있는 동적 행렬 상수 버퍼의 구조체를 설정합니다.
    D3D11_BUFFER_DESC matrixBufferDesc;
    matrixBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    matrixBufferDesc.ByteWidth = sizeof(MatrixBufferType);
    matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    matrixBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    matrixBufferDesc.MiscFlags = 0;
    matrixBufferDesc.StructureByteStride = 0;
 
    // 이 클래스 내에서 정점 셰이더 상수 버퍼에 액세스 할 수 있도록 상수 버퍼 포인터를 만듭니다.
    if (FAILED(device->CreateBuffer(&matrixBufferDesc, NULL, &m_matrixBuffer)))
    {
        return false;
    }
 
    // 픽셀 쉐이더에있는 그라데이션 동적 상수 버퍼의 설명을 설정합니다.
    // D3D11_BIND_CONSTANT_BUFFER를 사용하면 ByteWidth가 항상 16의 배수 여야하며 그렇지 않으면 CreateBuffer가 실패합니다.
    D3D11_BUFFER_DESC gradientBufferDesc;
    gradientBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    gradientBufferDesc.ByteWidth = sizeof(GradientBufferType);
    gradientBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    gradientBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    gradientBufferDesc.MiscFlags = 0;
    gradientBufferDesc.StructureByteStride = 0;
 
    // 이 클래스 내에서 정점 셰이더 상수 버퍼에 액세스 할 수 있도록 상수 버퍼 포인터를 만듭니다.
    if (FAILED(device->CreateBuffer(&gradientBufferDesc, NULL, &m_gradientBuffer)))
    {
        return false;
    }
 
    return true;
}
 
 
void SkyDomeShaderClass::ShutdownShader()
{
    // 그라데이션 동적 상수 버퍼를 해제합니다.
    if(m_gradientBuffer)
    {
        m_gradientBuffer->Release();
        m_gradientBuffer = 0;
    }
 
    // 행렬 상수 버퍼를 해제합니다.
    if (m_matrixBuffer)
    {
        m_matrixBuffer->Release();
        m_matrixBuffer = 0;
    }
 
    // 레이아웃을 해제합니다.
    if(m_layout)
    {
        m_layout->Release();
        m_layout = 0;
    }
 
    // 픽셀 쉐이더를 해제합니다.
    if (m_pixelShader)
    {
        m_pixelShader->Release();
        m_pixelShader = 0;
    }
 
    // 버텍스 쉐이더를 해제합니다.
    if (m_vertexShader)
    {
        m_vertexShader->Release();
        m_vertexShader = 0;
    }
}
 
 
void SkyDomeShaderClass::OutputShaderErrorMessage(ID3D10Blob* errorMessage, HWND hwnd, const WCHAR* shaderFilename)
{
    // 에러 메시지를 출력창에 표시합니다.
    OutputDebugStringA(reinterpret_cast<const char*>(errorMessage->GetBufferPointer()));
 
    // 에러 메세지를 반환합니다.
    errorMessage->Release();
    errorMessage = 0;
 
    // 컴파일 에러가 있음을 팝업 메세지로 알려줍니다.
    MessageBox(hwnd, L"Error compiling shader.", shaderFilename, MB_OK);
}
 
 
bool SkyDomeShaderClass::SetShaderParameters(ID3D11DeviceContext* deviceContext, XMMATRIX worldMatrix, XMMATRIX viewMatrix, 
                                XMMATRIX projectionMatrix, XMFLOAT4 apexColor, XMFLOAT4 centerColor)
{
    // 행렬을 transpose하여 셰이더에서 사용할 수 있게 합니다
    worldMatrix = XMMatrixTranspose(worldMatrix);
    viewMatrix = XMMatrixTranspose(viewMatrix);
    projectionMatrix = XMMatrixTranspose(projectionMatrix);
 
    // 상수 버퍼의 내용을 쓸 수 있도록 잠급니다.
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    if (FAILED(deviceContext->Map(m_matrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0&mappedResource)))
    {
        return false;
    }
 
    // 상수 버퍼의 데이터에 대한 포인터를 가져옵니다.
    MatrixBufferType* dataPtr = (MatrixBufferType*)mappedResource.pData;
 
    // 상수 버퍼에 행렬을 복사합니다.
    dataPtr->world = worldMatrix;
    dataPtr->view = viewMatrix;
    dataPtr->projection = projectionMatrix;
 
    // 상수 버퍼의 잠금을 풉니다.
    deviceContext->Unmap(m_matrixBuffer, 0);
 
    // 정점 셰이더에서의 상수 버퍼의 위치를 설정합니다.
    unsigned bufferNumber = 0;
 
    // 마지막으로 정점 셰이더의 상수 버퍼를 바뀐 값으로 바꿉니다.
    deviceContext->VSSetConstantBuffers(bufferNumber, 1&m_matrixBuffer);
 
    // 조명 상수 버퍼를 잠글 수 있도록 기록한다.
    if (FAILED(deviceContext->Map(m_gradientBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0&mappedResource)))
    {
        return false;
    }
 
    // 상수 버퍼의 데이터에 대한 포인터를 가져옵니다.
    GradientBufferType* dataPtr2 = (GradientBufferType*)mappedResource.pData;
 
    // 조명 변수를 상수 버퍼에 복사합니다.
    dataPtr2->apexColor = apexColor;
    dataPtr2->centerColor = centerColor;
 
    // 상수 버퍼의 잠금을 해제합니다.
    deviceContext->Unmap(m_gradientBuffer, 0);
 
    // 픽셀 쉐이더에서 광원 상수 버퍼의 위치를 ​​설정합니다.
    bufferNumber = 0;
 
    // 마지막으로 픽셀 쉐이더에 텍스처 정보 상수 버퍼를 업데이트 된 값으로 설정합니다.
    deviceContext->PSSetConstantBuffers(bufferNumber, 1&m_gradientBuffer);
 
    return true;
}
 
 
void SkyDomeShaderClass::RenderShader(ID3D11DeviceContext* deviceContext, int indexCount)
{
    // 정점 입력 레이아웃을 설정합니다.
    deviceContext->IASetInputLayout(m_layout);
 
    // 삼각형을 그릴 정점 셰이더와 픽셀 셰이더를 설정합니다.
    deviceContext->VSSetShader(m_vertexShader, NULL, 0);
    deviceContext->PSSetShader(m_pixelShader, NULL, 0);
 
    // 삼각형을 그립니다.
    deviceContext->DrawIndexed(indexCount, 00);
}
cs






D3DClass가 표면 컬링을 다시 켜고 끌 수 있도록 업데이트되었습니다.


D3dclass.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
#pragma once
 
class D3DClass : public AlignedAllocationPolicy<16>
{
public:
    D3DClass();
    D3DClass(const D3DClass&);
    ~D3DClass();
 
    bool Initialize(intintbool, HWND, boolfloatfloat);
    void Shutdown();
 
    void BeginScene(floatfloatfloatfloat);
    void EndScene();
 
    ID3D11Device* GetDevice();
    ID3D11DeviceContext* GetDeviceContext();
 
    void GetProjectionMatrix(XMMATRIX&);
    void GetWorldMatrix(XMMATRIX&);
    void GetOrthoMatrix(XMMATRIX&);
 
    void GetVideoCardInfo(char*int&);
 
    void TurnZBufferOn();
    void TurnZBufferOff();
    void TurnOnAlphaBlending();
    void TurnOffAlphaBlending();
    void TurnOnCulling();
    void TurnOffCulling();
 
private:
    bool m_vsync_enabled = false;
    int m_videoCardMemory = 0;
    char m_videoCardDescription[128= { 0, };
    IDXGISwapChain* m_swapChain = nullptr;
    ID3D11Device* m_device = nullptr;
    ID3D11DeviceContext* m_deviceContext = nullptr;
    ID3D11RenderTargetView* m_renderTargetView = nullptr;
    ID3D11Texture2D* m_depthStencilBuffer = nullptr;
    ID3D11DepthStencilState* m_depthStencilState = nullptr;
    ID3D11DepthStencilView* m_depthStencilView = nullptr;
    ID3D11RasterizerState* m_rasterState = nullptr;
    ID3D11RasterizerState* m_rasterStateNoCulling = nullptr;
    XMMATRIX m_projectionMatrix;
    XMMATRIX m_worldMatrix;
    XMMATRIX m_orthoMatrix;
    
    ID3D11DepthStencilState* m_depthDisabledStencilState = nullptr;
    ID3D11BlendState* m_alphaEnableBlendingState = nullptr;
    ID3D11BlendState* m_alphaDisableBlendingState = nullptr;
};
cs



D3dclass.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
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
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
#include "stdafx.h"
#include "d3dclass.h"
 
 
D3DClass::D3DClass()
{
}
 
 
D3DClass::D3DClass(const D3DClass& other)
{
}
 
 
D3DClass::~D3DClass()
{
}
 
 
bool D3DClass::Initialize(int screenWidth, int screenHeight, bool vsync, HWND hwnd, bool fullscreen,
    float screenDepth, float screenNear)
{
    // 수직동기화 상태를 저장합니다
    m_vsync_enabled = vsync;
 
    // DirectX 그래픽 인터페이스 팩토리를 생성합니다
    IDXGIFactory* factory = nullptr;
    if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory)))
    {
        return false;
    }
 
    // 팩토리 객체를 사용하여 첫번째 그래픽 카드 인터페이스 어뎁터를 생성합니다
    IDXGIAdapter* adapter = nullptr;
    if (FAILED(factory->EnumAdapters(0&adapter)))
    {
        return false;
    }
 
    // 출력(모니터)에 대한 첫번째 어뎁터를 지정합니다.
    IDXGIOutput* adapterOutput = nullptr;
    if (FAILED(adapter->EnumOutputs(0&adapterOutput)))
    {
        return false;
    }
 
    // 출력 (모니터)에 대한 DXGI_FORMAT_R8G8B8A8_UNORM 표시 형식에 맞는 모드 수를 가져옵니다
    unsigned int numModes = 0;
    if (FAILED(adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, NULL)))
    {
        return false;
    }
 
    // 가능한 모든 모니터와 그래픽카드 조합을 저장할 리스트를 생성합니다
    DXGI_MODE_DESC* displayModeList = new DXGI_MODE_DESC[numModes];
    if (!displayModeList)
    {
        return false;
    }
 
    // 이제 디스플레이 모드에 대한 리스트를 채웁니다
    if (FAILED(adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes,
 displayModeList)))
    {
        return false;
    }
 
    // 이제 모든 디스플레이 모드에 대해 화면 너비/높이에 맞는 디스플레이 모드를 찾습니다.
    // 적합한 것을 찾으면 모니터의 새로고침 비율의 분모와 분자 값을 저장합니다.
    unsigned int numerator = 0;
    unsigned int denominator = 0;
    for (unsigned int i = 0; i<numModes; i++)
    {
        if (displayModeList[i].Width == (unsigned int)screenWidth)
        {
            if (displayModeList[i].Height == (unsigned int)screenHeight)
            {
                numerator = displayModeList[i].RefreshRate.Numerator;
                denominator = displayModeList[i].RefreshRate.Denominator;
            }
        }
    }
 
    // 비디오카드의 구조체를 얻습니다
    DXGI_ADAPTER_DESC adapterDesc;
    if (FAILED(adapter->GetDesc(&adapterDesc)))
    {
        return false;
    }
 
    // 비디오카드 메모리 용량 단위를 메가바이트 단위로 저장합니다
    m_videoCardMemory = (int)(adapterDesc.DedicatedVideoMemory / 1024 / 1024);
 
    // 비디오카드의 이름을 저장합니다
    size_t stringLength = 0;
    if (wcstombs_s(&stringLength, m_videoCardDescription, 128, adapterDesc.Description, 128!= 0)
    {
        return false;
    }
 
    // 디스플레이 모드 리스트를 해제합니다
    delete[] displayModeList;
    displayModeList = 0;
 
    // 출력 어뎁터를 해제합니다
    adapterOutput->Release();
    adapterOutput = 0;
 
    // 어뎁터를 해제합니다
    adapter->Release();
    adapter = 0;
 
    // 팩토리 객체를 해제합니다
    factory->Release();
    factory = 0;
 
    // 스왑체인 구조체를 초기화합니다
    DXGI_SWAP_CHAIN_DESC swapChainDesc;
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
 
    // 백버퍼를 1개만 사용하도록 지정합니다
    swapChainDesc.BufferCount = 1;
 
    // 백버퍼의 넓이와 높이를 지정합니다
    swapChainDesc.BufferDesc.Width = screenWidth;
    swapChainDesc.BufferDesc.Height = screenHeight;
 
    // 32bit 서페이스를 설정합니다
    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
 
    // 백버퍼의 새로고침 비율을 설정합니다
    if (m_vsync_enabled)
    {
        swapChainDesc.BufferDesc.RefreshRate.Numerator = numerator;
        swapChainDesc.BufferDesc.RefreshRate.Denominator = denominator;
    }
    else
    {
        swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
        swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
    }
 
    // 백버퍼의 사용용도를 지정합니다
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
 
    // 랜더링에 사용될 윈도우 핸들을 지정합니다
    swapChainDesc.OutputWindow = hwnd;
 
    // 멀티샘플링을 끕니다
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
 
    // 창모드 or 풀스크린 모드를 설정합니다
    if (fullscreen)
    {
        swapChainDesc.Windowed = false;
    }
    else
    {
        swapChainDesc.Windowed = true;
    }
 
    // 스캔 라인 순서 및 크기를 지정하지 않음으로 설정합니다.
    swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
 
    // 출력된 다음 백버퍼를 비우도록 지정합니다
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
 
    // 추가 옵션 플래그를 사용하지 않습니다
    swapChainDesc.Flags = 0;
 
    // 피처레벨을 DirectX 11 로 설정합니다
    D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
 
    // 스왑 체인, Direct3D 장치 및 Direct3D 장치 컨텍스트를 만듭니다.
    if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL0&featureLevel, 1,
        D3D11_SDK_VERSION, &swapChainDesc, &m_swapChain, &m_device, NULL&m_deviceContext)))
    {
        return false;
    }
 
    // 백버퍼 포인터를 얻어옵니다
    ID3D11Texture2D* backBufferPtr = nullptr;
    if (FAILED(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr)))
    {
        return false;
    }
 
    // 백 버퍼 포인터로 렌더 타겟 뷰를 생성한다.
    if (FAILED(m_device->CreateRenderTargetView(backBufferPtr, NULL&m_renderTargetView)))
    {
        return false;
    }
 
    // 백버퍼 포인터를 해제합니다
    backBufferPtr->Release();
    backBufferPtr = 0;
 
    // 깊이 버퍼 구조체를 초기화합니다
    D3D11_TEXTURE2D_DESC depthBufferDesc;
    ZeroMemory(&depthBufferDesc, sizeof(depthBufferDesc));
 
    // 깊이 버퍼 구조체를 작성합니다
    depthBufferDesc.Width = screenWidth;
    depthBufferDesc.Height = screenHeight;
    depthBufferDesc.MipLevels = 1;
    depthBufferDesc.ArraySize = 1;
    depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    depthBufferDesc.SampleDesc.Count = 1;
    depthBufferDesc.SampleDesc.Quality = 0;
    depthBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    depthBufferDesc.CPUAccessFlags = 0;
    depthBufferDesc.MiscFlags = 0;
 
    // 설정된 깊이버퍼 구조체를 사용하여 깊이 버퍼 텍스쳐를 생성합니다
    if (FAILED(m_device->CreateTexture2D(&depthBufferDesc, NULL&m_depthStencilBuffer)))
    {
        return false;
    }
 
    // 스텐실 상태 구조체를 초기화합니다
    D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
    ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
 
    // 스텐실 상태 구조체를 작성합니다
    depthStencilDesc.DepthEnable = true;
    depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
 
    depthStencilDesc.StencilEnable = true;
    depthStencilDesc.StencilReadMask = 0xFF;
    depthStencilDesc.StencilWriteMask = 0xFF;
 
    // 픽셀 정면의 스텐실 설정입니다
    depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
    depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
 
    // 픽셀 뒷면의 스텐실 설정입니다
    depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
    depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
 
    // 깊이 스텐실 상태를 생성합니다
    if (FAILED(m_device->CreateDepthStencilState(&depthStencilDesc, &m_depthStencilState)))
    {
        return false;
    }
 
    // 깊이 스텐실 상태를 설정합니다
    m_deviceContext->OMSetDepthStencilState(m_depthStencilState, 1);
 
    // 깊이 스텐실 뷰의 구조체를 초기화합니다
    D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
    ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));
 
    // 깊이 스텐실 뷰 구조체를 설정합니다
    depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    depthStencilViewDesc.Texture2D.MipSlice = 0;
 
    // 깊이 스텐실 뷰를 생성합니다
    if (FAILED(m_device->CreateDepthStencilView(m_depthStencilBuffer, &depthStencilViewDesc, &m_depthStencilView)))
    {
        return false;
    }
 
    // 렌더링 대상 뷰와 깊이 스텐실 버퍼를 출력 렌더 파이프 라인에 바인딩합니다
    m_deviceContext->OMSetRenderTargets(1&m_renderTargetView, m_depthStencilView);
 
    // 그려지는 폴리곤과 방법을 결정할 래스터 구조체를 설정합니다
    D3D11_RASTERIZER_DESC rasterDesc;
    rasterDesc.AntialiasedLineEnable = false;
    rasterDesc.CullMode = D3D11_CULL_BACK;
    rasterDesc.DepthBias = 0;
    rasterDesc.DepthBiasClamp = 0.0f;
    rasterDesc.DepthClipEnable = true;
    rasterDesc.FillMode = D3D11_FILL_SOLID;
    rasterDesc.FrontCounterClockwise = false;
    rasterDesc.MultisampleEnable = false;
    rasterDesc.ScissorEnable = false;
    rasterDesc.SlopeScaledDepthBias = 0.0f;
 
    // 방금 작성한 구조체에서 래스터 라이저 상태를 만듭니다
    if (FAILED(m_device->CreateRasterizerState(&rasterDesc, &m_rasterState)))
    {
        return false;
    }
 
    // 이제 래스터 라이저 상태를 설정합니다
    m_deviceContext->RSSetState(m_rasterState);
 
    // 배면 컬링을 해제하는 래스터 구조체를 설정합니다.
    rasterDesc.AntialiasedLineEnable = false;
    rasterDesc.CullMode = D3D11_CULL_NONE;
    rasterDesc.DepthBias = 0;
    rasterDesc.DepthBiasClamp = 0.0f;
    rasterDesc.DepthClipEnable = true;
    rasterDesc.FillMode = D3D11_FILL_SOLID;
    rasterDesc.FrontCounterClockwise = false;
    rasterDesc.MultisampleEnable = false;
    rasterDesc.ScissorEnable = false;
    rasterDesc.SlopeScaledDepthBias = 0.0f;
 
    // 도려내지 않는 래스터 라이저 상태를 만듭니다.
    if(FAILED(m_device->CreateRasterizerState(&rasterDesc, &m_rasterStateNoCulling)))
    {
        return false;
    }
    
    // 렌더링을 위해 뷰포트를 설정합니다
    D3D11_VIEWPORT viewport;
    viewport.Width = (float)screenWidth;
    viewport.Height = (float)screenHeight;
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;
    viewport.TopLeftX = 0.0f;
    viewport.TopLeftY = 0.0f;
 
    // 뷰포트를 생성합니다
    m_deviceContext->RSSetViewports(1&viewport);
 
    // 투영 행렬을 설정합니다
    float fieldOfView = XM_PI / 4.0f;
    float screenAspect = (float)screenWidth / (float)screenHeight;
 
    // 3D 렌더링을 위한 투영 행렬을 만듭니다
    m_projectionMatrix = XMMatrixPerspectiveFovLH(fieldOfView, screenAspect, screenNear, screenDepth);
 
    // 월드 행렬을 항등 행렬로 초기화합니다
    m_worldMatrix = XMMatrixIdentity();
 
    // 2D 렌더링을 위한 직교 투영 행렬을 만듭니다
    m_orthoMatrix = XMMatrixOrthographicLH((float)screenWidth, (float)screenHeight, screenNear, screenDepth);
    
    // 매개 변수를 설정하기 전에 두 번째 깊이 스텐실 상태를 지웁니다.
    D3D11_DEPTH_STENCIL_DESC depthDisabledStencilDesc;
    ZeroMemory(&depthDisabledStencilDesc, sizeof(depthDisabledStencilDesc));
 
    // 이제 2D 렌더링을위한 Z 버퍼를 끄는 두 번째 깊이 스텐실 상태를 만듭니다. 유일한 차이점은
    // DepthEnable을 false로 설정하면 다른 모든 매개 변수는 다른 깊이 스텐실 상태와 동일합니다.
    depthDisabledStencilDesc.DepthEnable = false;
    depthDisabledStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    depthDisabledStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
    depthDisabledStencilDesc.StencilEnable = true;
    depthDisabledStencilDesc.StencilReadMask = 0xFF;
    depthDisabledStencilDesc.StencilWriteMask = 0xFF;
    depthDisabledStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    depthDisabledStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
    depthDisabledStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    depthDisabledStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
    depthDisabledStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    depthDisabledStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
    depthDisabledStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    depthDisabledStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
 
    // 장치를 사용하여 상태를 만듭니다.
    if(FAILED(m_device->CreateDepthStencilState(&depthDisabledStencilDesc, &m_depthDisabledStencilState)))
    {
        return false;
    }
    
    // 블렌드 상태 구조체를 초기화 합니다.
    D3D11_BLEND_DESC blendStateDescription;
    ZeroMemory(&blendStateDescription, sizeof(D3D11_BLEND_DESC));
 
    // 알파 지원 블렌드 상태 구조체를 설정합니다.
    blendStateDescription.RenderTarget[0].BlendEnable = TRUE;
    blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
    blendStateDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
    blendStateDescription.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
    blendStateDescription.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
    blendStateDescription.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
    blendStateDescription.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
    blendStateDescription.RenderTarget[0].RenderTargetWriteMask = 0x0f;
 
    // 설명을 사용하여 혼합 상태를 만듭니다.
    if(FAILED(m_device->CreateBlendState(&blendStateDescription, &m_alphaEnableBlendingState)))
    {
        return false;
    }
 
    // 알파블렌드 설정을 해제합니다.
    blendStateDescription.RenderTarget[0].BlendEnable = FALSE;
 
    // 알파블렌드 상태값을 생성합니다.
    if(FAILED(m_device->CreateBlendState(&blendStateDescription, &m_alphaDisableBlendingState)))
    {
        return false;
    }
 
    return true;
}
 
 
void D3DClass::Shutdown()
{
    // 종료 전 윈도우 모드로 설정하지 않으면 스왑 체인을 해제 할 때 예외가 발생합니다.
    if (m_swapChain)
    {
        m_swapChain->SetFullscreenState(falseNULL);
    }
 
    if(m_alphaEnableBlendingState)
    {
        m_alphaEnableBlendingState->Release();
        m_alphaEnableBlendingState = 0;
    }
 
    if(m_alphaDisableBlendingState)
    {
        m_alphaDisableBlendingState->Release();
        m_alphaDisableBlendingState = 0;
    }
 
    if(m_depthDisabledStencilState)
    {
        m_depthDisabledStencilState->Release();
        m_depthDisabledStencilState = 0;
    }
 
    if(m_rasterStateNoCulling)
    {
        m_rasterStateNoCulling->Release();
        m_rasterStateNoCulling = 0;
    }
 
    if (m_rasterState)
    {
        m_rasterState->Release();
        m_rasterState = 0;
    }
 
    if (m_depthStencilView)
    {
        m_depthStencilView->Release();
        m_depthStencilView = 0;
    }
 
    if (m_depthStencilState)
    {
        m_depthStencilState->Release();
        m_depthStencilState = 0;
    }
 
    if (m_depthStencilBuffer)
    {
        m_depthStencilBuffer->Release();
        m_depthStencilBuffer = 0;
    }
 
    if (m_renderTargetView)
    {
        m_renderTargetView->Release();
        m_renderTargetView = 0;
    }
 
    if (m_deviceContext)
    {
        m_deviceContext->Release();
        m_deviceContext = 0;
    }
 
    if (m_device)
    {
        m_device->Release();
        m_device = 0;
    }
 
    if (m_swapChain)
    {
        m_swapChain->Release();
        m_swapChain = 0;
    }
}
 
 
void D3DClass::BeginScene(float red, float green, float blue, float alpha)
{
    // 버퍼를 지울 색을 설정합니다
    float color[4= { red, green, blue, alpha };
 
    // 백버퍼를 지웁니다
    m_deviceContext->ClearRenderTargetView(m_renderTargetView, color);
 
    // 깊이 버퍼를 지웁니다
    m_deviceContext->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
}
 
 
void D3DClass::EndScene()
{
    // 렌더링이 완료되었으므로 화면에 백 버퍼를 표시합니다.
    if (m_vsync_enabled)
    {
        // 화면 새로 고침 비율을 고정합니다.
        m_swapChain->Present(10);
    }
    else
    {
        // 가능한 빠르게 출력합니다
        m_swapChain->Present(00);
    }
}
 
 
ID3D11Device* D3DClass::GetDevice()
{
    return m_device;
}
 
 
ID3D11DeviceContext* D3DClass::GetDeviceContext()
{
    return m_deviceContext;
}
 
 
void D3DClass::GetProjectionMatrix(XMMATRIX& projectionMatrix)
{
    projectionMatrix = m_projectionMatrix;
}
 
 
void D3DClass::GetWorldMatrix(XMMATRIX& worldMatrix)
{
    worldMatrix = m_worldMatrix;
}
 
 
void D3DClass::GetOrthoMatrix(XMMATRIX& orthoMatrix)
{
    orthoMatrix = m_orthoMatrix;
}
 
 
void D3DClass::GetVideoCardInfo(char* cardName, int& memory)
{
    strcpy_s(cardName, 128, m_videoCardDescription);
    memory = m_videoCardMemory;
}
 
 
void D3DClass::TurnZBufferOn()
{
    // 렌더 타겟 뷰와 깊이 스텐실 버퍼를 출력 렌더 파이프 라인에 바인딩합니다.
    m_deviceContext->OMSetDepthStencilState(m_depthStencilState, 1);
}
 
 
void D3DClass::TurnZBufferOff()
{
    // 뷰포트를 설정합니다.
    m_deviceContext->OMSetDepthStencilState(m_depthDisabledStencilState, 1);
}
 
 
void D3DClass::TurnOnAlphaBlending()
{
    // 혼합 요소를 설정합니다.
    float blendFactor[4= { 0.0f, 0.0f, 0.0f, 0.0f };
    
    // 알파 블렌딩을 켭니다.
    m_deviceContext->OMSetBlendState(m_alphaEnableBlendingState, blendFactor, 0xffffffff);
}
 
 
void D3DClass::TurnOffAlphaBlending()
{
    // 혼합 요소를 설정합니다.
    float blendFactor[4= { 0.0f, 0.0f, 0.0f, 0.0f };
    
    // 알파 블렌딩을 끕니다.
    m_deviceContext->OMSetBlendState(m_alphaDisableBlendingState, blendFactor, 0xffffffff);
}
 
 
void D3DClass::TurnOnCulling()
{
    // 컬링 래스터 라이저 상태를 설정합니다.
    m_deviceContext->RSSetState(m_rasterState);
}
 
 
void D3DClass::TurnOffCulling()
{
    // 뒷면 없음 컬링 래스터 라이저 상태를 설정합니다.
    m_deviceContext->RSSetState(m_rasterStateNoCulling);
}
cs



Applicationclass.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
#pragma once
 
/////////////
// GLOBALS //
/////////////
const bool FULL_SCREEN = false;
const bool VSYNC_ENABLED = true;
const float SCREEN_DEPTH = 1000.0f;
const float SCREEN_NEAR = 0.1f;
 
 
class D3DClass;
class InputClass;
class CameraClass;
class TerrainClass;
 
class TimerClass;
class PositionClass;
class FpsClass;
class CpuClass;
class FontShaderClass;
class TextClass;
class TerrainShaderClass;
class LightClass;
class SkyDomeClass;
class SkyDomeShaderClass;
 
 
class ApplicationClass
{
public:
    ApplicationClass();
    ApplicationClass(const ApplicationClass&);
    ~ApplicationClass();
 
    bool Initialize(HINSTANCE, HWND, intint);
    void Shutdown();
    bool Frame();
 
private:
    bool HandleInput(float);
    bool RenderGraphics();
 
private:
    InputClass* m_Input = nullptr;
    D3DClass* m_Direct3D = nullptr;
    CameraClass* m_Camera = nullptr;
    TerrainClass* m_Terrain = nullptr;
    TimerClass* m_Timer = nullptr;
    PositionClass* m_Position = nullptr;
    FpsClass* m_Fps = nullptr;
    CpuClass* m_Cpu = nullptr;
    FontShaderClass* m_FontShader = nullptr;
    TextClass* m_Text = nullptr;
    TerrainShaderClass* m_TerrainShader = nullptr;
    LightClass* m_Light = nullptr;
    SkyDomeClass* m_SkyDome = nullptr;
    SkyDomeShaderClass* m_SkyDomeShader = nullptr;
};
cs



Applicationclass.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
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
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
#include "stdafx.h"
#include "inputclass.h"
#include "d3dclass.h"
#include "cameraclass.h"
#include "terrainclass.h"
#include "timerclass.h"
#include "positionclass.h"
#include "fpsclass.h"
#include "cpuclass.h"
#include "fontshaderclass.h"
#include "textclass.h"
#include "terrainshaderclass.h"
#include "lightclass.h"
#include "skydomeclass.h"
#include "skydomeshaderclass.h"
#include "ApplicationClass.h"
 
 
ApplicationClass::ApplicationClass()
{
}
 
 
ApplicationClass::ApplicationClass(const ApplicationClass& other)
{
}
 
 
ApplicationClass::~ApplicationClass()
{
}
 
 
bool ApplicationClass::Initialize(HINSTANCE hinstance, HWND hwnd, int screenWidth, int screenHeight)
{
    // 입력 개체를 생성합니다.
    m_Input = new InputClass;
    if(!m_Input)
    {
        return false;
    }
 
    // 입력 개체를 초기화 합니다.
    bool result = m_Input->Initialize(hinstance, hwnd, screenWidth, screenHeight);
    if(!result)
    {
        MessageBox(hwnd, L"Could not initialize the input object.", L"Error", MB_OK);
        return false;
    }
 
    // Direct3D 개체를 생성합니다.
    m_Direct3D = new D3DClass;
    if(!m_Direct3D)
    {
        return false;
    }
 
    // Direct3D 개체를 초기화 합니다.
    result = m_Direct3D->Initialize(screenWidth, screenHeight, VSYNC_ENABLED, hwnd, FULL_SCREEN, SCREEN_DEPTH, SCREEN_NEAR);
    if(!result)
    {
        MessageBox(hwnd, L"Could not initialize DirectX 11.", L"Error", MB_OK);
        return false;
    }
 
    // 카메라 객체를 생성합니다.
    m_Camera = new CameraClass;
    if(!m_Camera)
    {
        return false;
    }
 
    // 2D 사용자 인터페이스 렌더링을 위해 카메라로 기본 뷰 행렬을 초기화 합니다.
    XMMATRIX baseViewMatrix;
    m_Camera->SetPosition(XMFLOAT3(0.0f, 0.0f, -1.0f));
    m_Camera->Render();
    m_Camera->GetViewMatrix(baseViewMatrix);
 
    // 카메라의 초기 위치를 설정합니다.
    XMFLOAT3 camera = XMFLOAT3(50.0f, 2.0f, -7.0f);
    m_Camera->SetPosition(camera);
 
    // 지형 객체를 생성합니다.
    m_Terrain = new TerrainClass;
    if(!m_Terrain)
    {
        return false;
    }
 
    // 지형 객체를 초기화 합니다.
    result = m_Terrain->Initialize(m_Direct3D->GetDevice(), "../Dx11Terrain_10/data/heightmap01.bmp",
  L"../Dx11Terrain_10/data/dirt01.dds",
  "../Dx11Terrain_10/data/colorm01.bmp");
    if(!result)
    {
        MessageBox(hwnd, L"Could not initialize the terrain object.", L"Error", MB_OK);
        return false;
    }
 
    // 타이머 객체를 생성합니다.
    m_Timer = new TimerClass;
    if(!m_Timer)
    {
        return false;
    }
 
    // 타이머 객체를 초기화 합니다.
    result = m_Timer->Initialize();
    if(!result)
    {
        MessageBox(hwnd, L"Could not initialize the timer object.", L"Error", MB_OK);
        return false;
    }
 
    // 위치 개체를 생성합니다.
    m_Position = new PositionClass;
    if(!m_Position)
    {
        return false;
    }
 
    // 뷰어의 초기 위치를 초기 카메라 위치와 동일하게 설정합니다.
    m_Position->SetPosition(camera);
 
    // fps 객체를 생성합니다.
    m_Fps = new FpsClass;
    if(!m_Fps)
    {
        return false;
    }
 
    // fps 객체를 초기화 합니다.
    m_Fps->Initialize();
 
    // cpu 객체를 생성합니다.
    m_Cpu = new CpuClass;
    if(!m_Cpu)
    {
        return false;
    }
 
    // cpu 객체를 초기화 합니다.
    m_Cpu->Initialize();
 
    // 폰트 셰이더 객체를 생성합니다.
    m_FontShader = new FontShaderClass;
    if(!m_FontShader)
    {
        return false;
    }
 
    // 폰트 셰이더 객체를 초기화 합니다.
    result = m_FontShader->Initialize(m_Direct3D->GetDevice(), hwnd);
    if(!result)
    {
        MessageBox(hwnd, L"Could not initialize the font shader object.", L"Error", MB_OK);
        return false;
    }
 
    // 텍스트 객체를 생성합니다.
    m_Text = new TextClass;
    if(!m_Text)
    {
        return false;
    }
 
    // 텍스트 객체를 초기화 합니다.
    result = m_Text->Initialize(m_Direct3D->GetDevice(), m_Direct3D->GetDeviceContext(), hwnd, screenWidth,
 screenHeight, baseViewMatrix);
    if(!result)
    {
        MessageBox(hwnd, L"Could not initialize the text object.", L"Error", MB_OK);
        return false;
    }
 
    // 비디오 카드 정보를 가져옵니다.
    char videoCard[128= { 0, };
    int videoMemory = 0;
    m_Direct3D->GetVideoCardInfo(videoCard, videoMemory);
 
    // 텍스트 객체에 비디오 카드 정보를 설정합니다.
    result = m_Text->SetVideoCardInfo(videoCard, videoMemory, m_Direct3D->GetDeviceContext());
    if(!result)
    {
        MessageBox(hwnd, L"Could not set video card info in the text object.", L"Error", MB_OK);
        return false;
    }
 
    // 지형 쉐이더 객체를 생성합니다.
    m_TerrainShader = new TerrainShaderClass;
    if(!m_TerrainShader)
    {
        return false;
    }
 
    // 지형 쉐이더 객체를 초기화 합니다.
    result = m_TerrainShader->Initialize(m_Direct3D->GetDevice(), hwnd);
    if(!result)
    {
        MessageBox(hwnd, L"Could not initialize the terrain shader object.", L"Error", MB_OK);
        return false;
    }
 
    // 조명 객체를 생성합니다.
    m_Light = new LightClass;
    if(!m_Light)
    {
        return false;
    }
 
    // 조명 객체를 초기화 합니다.
    m_Light->SetAmbientColor(XMFLOAT4(0.05f, 0.05f, 0.05f, 1.0f));
    m_Light->SetDiffuseColor(XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f));
    m_Light->SetDirection(XMFLOAT3(-0.5f, -1.0f, 0.0f));
 
    // 스카이 돔 객체를 생성합니다.
    m_SkyDome = new SkyDomeClass;
    if(!m_SkyDome)
    {
        return false;
    }
 
    // 스카이 돔 객체를 초기화 합니다.
    result = m_SkyDome->Initialize(m_Direct3D->GetDevice());
    if(!result)
    {
        MessageBox(hwnd, L"Could not initialize the sky dome object.", L"Error", MB_OK);
        return false;
    }
 
    // 스카이 돔 쉐이더 객체를 생성합니다.
    m_SkyDomeShader = new SkyDomeShaderClass;
    if(!m_SkyDomeShader)
    {
        return false;
    }
 
    // 스카이 돔 쉐이더 객체를 초기화 합니다.
    result = m_SkyDomeShader->Initialize(m_Direct3D->GetDevice(), hwnd);
    if(!result)
    {
        MessageBox(hwnd, L"Could not initialize the sky dome shader object.", L"Error", MB_OK);
        return false;
    }
 
    return true;
}
 
 
void ApplicationClass::Shutdown()
{
    // 스카이 돔 쉐이더 객체를 해제합니다.
    if(m_SkyDomeShader)
    {
        m_SkyDomeShader->Shutdown();
        delete m_SkyDomeShader;
        m_SkyDomeShader = 0;
    }
 
    // 스카이 돔 객체를 해제합니다.
    if(m_SkyDome)
    {
        m_SkyDome->Shutdown();
        delete m_SkyDome;
        m_SkyDome = 0;
    }
 
    // 조명 객체를 해제합니다.
    if(m_Light)
    {
        delete m_Light;
        m_Light = 0;
    }
 
    // 지형 쉐이더 객체를 해제합니다.
    if(m_TerrainShader)
    {
        m_TerrainShader->Shutdown();
        delete m_TerrainShader;
        m_TerrainShader = 0;
    }
 
    // 텍스트 객체를 해제합니다.
    if(m_Text)
    {
        m_Text->Shutdown();
        delete m_Text;
        m_Text = 0;
    }
 
    // 폰트 쉐이더 객체를 해제합니다..
    if(m_FontShader)
    {
        m_FontShader->Shutdown();
        delete m_FontShader;
        m_FontShader = 0;
    }
 
    // cpu 객체를 해제합니다.
    if(m_Cpu)
    {
        m_Cpu->Shutdown();
        delete m_Cpu;
        m_Cpu = 0;
    }
 
    // fps 객체를 해제합니다.
    if(m_Fps)
    {
        delete m_Fps;
        m_Fps = 0;
    }
 
    // 위치 객체를 해제합니다.
    if(m_Position)
    {
        delete m_Position;
        m_Position = 0;
    }
 
    // 타이머 객체를 해제합니다.
    if(m_Timer)
    {
        delete m_Timer;
        m_Timer = 0;
    }
 
    // 지형 객체를 해제합니다.
    if(m_Terrain)
    {
        m_Terrain->Shutdown();
        delete m_Terrain;
        m_Terrain = 0;
    }
 
    // 카메라 객체를 해제합니다.
    if(m_Camera)
    {
        delete m_Camera;
        m_Camera = 0;
    }
 
    // D3D 객체를 해제합니다.
    if (m_Direct3D)
    {
        m_Direct3D->Shutdown();
        delete m_Direct3D;
        m_Direct3D = 0;
    }
 
    // 입력 객체를 해제합니다.
    if(m_Input)
    {
        m_Input->Shutdown();
        delete m_Input;
        m_Input = 0;
    }
}
 
 
bool ApplicationClass::Frame()
{
    // 사용자 입력을 읽습니다.
    bool result = m_Input->Frame();
    if(!result)
    {
        return false;
    }
    
    // 사용자가 ESC를 눌렀을 때 응용 프로그램을 종료 할 것인지 확인합니다.
    if(m_Input->IsEscapePressed() == true)
    {
        return false;
    }
 
    // 시스템 통계를 업데이트 합니다.
    m_Timer->Frame();
    m_Fps->Frame();
    m_Cpu->Frame();
 
    // 텍스트 개체에서 FPS 값을 업데이트 합니다.
    result = m_Text->SetFps(m_Fps->GetFps(), m_Direct3D->GetDeviceContext());
    if(!result)
    {
        return false;
    }
    
    // 텍스트 개체의 CPU 사용값을 업데이트 합니다.
    result = m_Text->SetCpu(m_Cpu->GetCpuPercentage(), m_Direct3D->GetDeviceContext());
    if(!result)
    {
        return false;
    }
 
    // 프레임 입력 처리를 수행합니다.
    result = HandleInput(m_Timer->GetTime());
    if(!result)
    {
        return false;
    }
 
    // 그래픽을 렌더링 합니다.
    result = RenderGraphics();
    if(!result)
    {
        return false;
    }
 
    return result;
}
 
 
bool ApplicationClass::HandleInput(float frameTime)
{
    XMFLOAT3 pos = XMFLOAT3(0.0f, 0.0f, 0.0f);
    XMFLOAT3 rot = XMFLOAT3(0.0f, 0.0f, 0.0f);
 
 
    // 갱신된 위치를 계산하기 위한 프레임 시간을 설정합니다.
    m_Position->SetFrameTime(frameTime);
 
    // 입력을 처리합니다.
    m_Position->TurnLeft(m_Input->IsLeftPressed());
    m_Position->TurnRight(m_Input->IsRightPressed());
    m_Position->MoveForward(m_Input->IsUpPressed());
    m_Position->MoveBackward(m_Input->IsDownPressed());
    m_Position->MoveUpward(m_Input->IsAPressed());
    m_Position->MoveDownward(m_Input->IsZPressed());
    m_Position->LookUpward(m_Input->IsPgUpPressed());
    m_Position->LookDownward(m_Input->IsPgDownPressed());
    
    // 시점 위치 / 회전을 가져옵니다.
    m_Position->GetPosition(pos);
    m_Position->GetRotation(rot);
 
    // 카메라의 위치를 ​​설정합니다.
    m_Camera->SetPosition(pos);
    m_Camera->SetRotation(rot);
 
    // 텍스트 개체의 위치 값을 업데이트 합니다.
    if(!m_Text->SetCameraPosition(pos, m_Direct3D->GetDeviceContext()))
    {
        return false;
    }
 
    // 텍스트 객체의 회전 값을 업데이트 합니다.
    if(!m_Text->SetCameraRotation(rot, m_Direct3D->GetDeviceContext()))
    {
        return false;
    }
 
    return true;
}
 
 
bool ApplicationClass::RenderGraphics()
{
    XMMATRIX worldMatrix, viewMatrix, projectionMatrix, orthoMatrix;
    XMFLOAT3 cameraPosition;
 
    // 장면을 지웁니다.
    m_Direct3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f);
 
    // 카메라의 위치에 따라 뷰 행렬을 생성합니다.
    m_Camera->Render();
 
    // 카메라 및 Direct3D 객체에서 월드, 뷰, 투영 및 ortho 행렬을 가져옵니다.
    m_Direct3D->GetWorldMatrix(worldMatrix);
    m_Camera->GetViewMatrix(viewMatrix);
    m_Direct3D->GetProjectionMatrix(projectionMatrix);
    m_Direct3D->GetOrthoMatrix(orthoMatrix);
 
    // 카메라 위치를 얻는다.
    cameraPosition = m_Camera->GetPosition();
 
    // 스카이 돔을 카메라 위치를 중심으로 변환합니다.
    worldMatrix = XMMatrixTranslation(cameraPosition.x, cameraPosition.y, cameraPosition.z);
 
    // 표면 컬링을 끕니다.
    m_Direct3D->TurnOffCulling();
 
    // Z 버퍼를 끈다.
    m_Direct3D->TurnZBufferOff();
 
    // 스카이 돔 셰이더를 사용하여 하늘 돔을 렌더링합니다.
    m_SkyDome->Render(m_Direct3D->GetDeviceContext());
    m_SkyDomeShader->Render(m_Direct3D->GetDeviceContext(), m_SkyDome->GetIndexCount(), worldMatrix, viewMatrix,
 projectionMatrix, m_SkyDome->GetApexColor(), m_SkyDome->GetCenterColor());
 
    // 다시 표면 컬링을 되돌립니다.
    m_Direct3D->TurnOnCulling();
 
    // Z 버퍼를 다시 켭니다.
    m_Direct3D->TurnZBufferOn();
 
    // 월드 행렬을 재설정합니다.
    m_Direct3D->GetWorldMatrix(worldMatrix);
    
    // 지형 버퍼를 렌더링 합니다.
    m_Terrain->Render(m_Direct3D->GetDeviceContext());
 
    // 지형 셰이더를 사용하여 지형을 렌더링 합니다.
    if(!m_TerrainShader->Render(m_Direct3D->GetDeviceContext(), m_Terrain->GetIndexCount(), worldMatrix, viewMatrix,
 projectionMatrix, m_Light->GetAmbientColor(), m_Light->GetDiffuseColor(), m_Light->GetDirection(),
 m_Terrain->GetTexture()))
    {
        return false;
    }
 
    // 모든 2D 렌더링을 시작하려면 Z 버퍼를 끕니다.
    m_Direct3D->TurnZBufferOff();
        
    // 텍스트를 렌더링하기 전에 알파 블렌딩을 켭니다.
    m_Direct3D->TurnOnAlphaBlending();
 
    // 텍스트 사용자 인터페이스 요소를 렌더링 합니다.
    if(!m_Text->Render(m_Direct3D->GetDeviceContext(), m_FontShader, worldMatrix, orthoMatrix))
    {
        return false;
    }
 
    // 텍스트를 렌더링 한 후 알파 블렌딩을 끕니다.
    m_Direct3D->TurnOffAlphaBlending();
 
    // 모든 2D 렌더링이 완료되었으므로 Z 버퍼를 다시 켭니다.
    m_Direct3D->TurnZBufferOn();
 
    // 렌더링 된 장면을 화면에 표시합니다.
    m_Direct3D->EndScene();
 
    return true;
}
cs



출력 화면




마치면서


우리는 매우 간단한 쉐이더와 낮은 폴리곤 구 객체를 사용하여 지형에 대한 하늘색 배경을 갖게 되었습니다.



연습문제


1. 코드를 컴파일하고 프로그램을 실행하십시오. PageUp 및 PageDown 키를 사용하여 스카이 돔 색상 그라데이션을 확인하십시오.


2. skydomeclass.cpp 파일의 초기화 함수 내에서 정점 및 중심 색을 변경하여 색 그라데이션에 미치는 영향을 확인합니다.


3. 컬링 래스터 상태의 채우기 모드를 뒷면이 없는 D3D11_FILL_WIREFRAME으로 설정하여 스카이 돔이 카메라와 함께 어떻게 움직이는지 확인하십시오.


4. 스카이 돔에서 여러 그라데이션을 만듭니다. 예를 들어 +1.0에서 +0.5까지의 그래디언트가 있고, 그 다음 하나는 +0.25에서 +0.0까지이고, 하나는 0.0과 그 이하의 것입니다. height 변수를 사용하여 여러 if 문을 만든 다음 GradientBuffer 상수 버퍼를 확장하여 픽셀 쉐이더에 여러 그라디언트 색상을 제공합니다.


5. 그래디언트가 위에서 아래가 아닌 오른쪽에서 왼쪽으로 보이도록 픽셀 셰이더를 수정합니다.


6. 하루 중 시간별 그라디언트 색상 목록을 만듭니다. 그런 다음 시간을 추적하고 해당 시간의 현재 그라디언트로 쉐이더를 업데이트하는 시스템을 만듭니다. 전환 속도를 볼 수 있도록 시간을 단축하십시오. 갑작스런 그라데이션 전환으로 인한 팝핑 효과를 방지하려면 각 시간 점에서 30 초의 전환 / 보간을 수행해야 할 수도 있습니다.


7. 스카이 돔에 사용 된 구의 다각형 수를 늘리거나 줄이고, 그라디언트와 돔 모양에 미치는 영향을 관찰하십시오.



소스코드


소스코드 : Dx11Terrain_10.zip