-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLightShader.cpp
More file actions
378 lines (309 loc) · 10.8 KB
/
LightShader.cpp
File metadata and controls
378 lines (309 loc) · 10.8 KB
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
#include "LightShader.h"
LightShader::LightShader()
{
m_vertexShader = 0;
m_pixelShader = 0;
m_layout = 0;
m_matrixBuffer = 0;
m_sampleState = 0;
m_lightBuffer = 0;
}
LightShader::LightShader(const LightShader& other)
{
}
LightShader::~LightShader()
{
}
bool LightShader::initialize(ID3D11Device* device, HWND hwnd)
{
bool result;
// 정점 및 픽셀 셰이더를 초기화합니다.
result = initializeShader(device, hwnd, const_cast<WCHAR*>(L"../Engine/LightVertexShader.hlsl"), const_cast<WCHAR*>(L"../Engine/LightPixelShader.hlsl"));
if (!result)
{
return false;
}
return true;
}
void LightShader::shutdown()
{
// 정점 및 픽셀 셰이더와 관련 개체를 종료합니다.
shutdownShader();
return;
}
bool LightShader::render(ID3D11DeviceContext* deviceContext, int indexCount, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix, ID3D11ShaderResourceView* texture, D3DXVECTOR3 lightDirection, D3DXVECTOR4 diffuseColor)
{
bool result;
// 렌더링에 사용할 셰이더 파라미터를 설정합니다.
result = setShaderParameters(deviceContext, worldMatrix, viewMatrix, projectionMatrix, texture, lightDirection, diffuseColor);
if (!result)
{
return false;
}
// 이제 준비된 버퍼를 셰이더로 렌더링 하십시오.
renderShader(deviceContext, indexCount);
return true;
}
bool LightShader::initializeShader(ID3D11Device* device, HWND hwnd, WCHAR* vsFilename, WCHAR* psFilename)
{
HRESULT result;
// 정점 셰이더 코드를 컴파일합니다.
ID3D10Blob* vertexShaderBuffer = 0;
ID3D10Blob* errorMessage = 0;
result = D3DX11CompileFromFile(vsFilename, NULL, NULL, "LightVertexShader", "vs_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, NULL, &vertexShaderBuffer, &errorMessage, NULL);
if (FAILED(result))
{
// 셰이더가 컴파일에 실패한 경우 오류 메시지에 무언가를 기록해야 합니다.
if (errorMessage)
{
outputShaderErrorMessage(errorMessage, hwnd, vsFilename);
}
// 오류 메시지에 아무 것도 없다면 바로 셰이더 파일 자체를 찾을 수 없는 것입니다.
else
{
MessageBox(hwnd, vsFilename, L"Missing Shader File", MB_OK);
}
return false;
}
// 픽셀 셰이더 코드를 컴파일합니다.
ID3D10Blob* pixelShaderBuffer = 0;
result = D3DX11CompileFromFile(psFilename, NULL, NULL, "LightPixelShader", "ps_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, NULL, &pixelShaderBuffer, &errorMessage, NULL);
if (FAILED(result))
{
// 셰이더가 컴파일에 실패한 경우 오류 메시지에 무언가를 기록해야 합니다.
if (errorMessage)
{
outputShaderErrorMessage(errorMessage, hwnd, psFilename);
}
// 오류 메시지에 아무 것도 없다면 바로 셰이더 파일 자체를 찾을 수 없는 것입니다.
else
{
MessageBox(hwnd, psFilename, L"Missing Shader File", MB_OK);
}
return false;
}
// 버퍼에서 정점 셰이더를 생성합니다.
result = device->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), NULL, &m_vertexShader);
if (FAILED(result))
{
return false;
}
// 버퍼에서 픽셀 셰이더를 생성합니다.
result = device->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(), pixelShaderBuffer->GetBufferSize(), NULL, &m_pixelShader);
if (FAILED(result))
{
return false;
}
// 정점 입력 레이아웃 설명을 생성합니다.
// 이 설정은 Model 클래스의 VertexType구조와 셰이더의 구조와 일치해야 합니다.
D3D11_INPUT_ELEMENT_DESC polygonLayout[3];
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;
polygonLayout[1].SemanticName = "TEXCOORD";
polygonLayout[1].SemanticIndex = 0;
polygonLayout[1].Format = DXGI_FORMAT_R32G32_FLOAT;
polygonLayout[1].InputSlot = 0;
polygonLayout[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[1].InstanceDataStepRate = 0;
polygonLayout[2].SemanticName = "NORMAL";
polygonLayout[2].SemanticIndex = 0;
polygonLayout[2].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[2].InputSlot = 0;
polygonLayout[2].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[2].InstanceDataStepRate = 0;
// 레이아웃에서 요소의 수를 가져옵니다.
unsigned int numElements = sizeof(polygonLayout) / sizeof(polygonLayout[0]);
// 정점 입력 레이아웃을 생성합니다.
result = device->CreateInputLayout(polygonLayout, numElements, vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), &m_layout);
if (FAILED(result))
{
return false;
}
// 정점 셰이더 버퍼와 픽셀 셰이더 버퍼가 더 이상 필요하지 않으므로 해제합니다.
vertexShaderBuffer->Release();
vertexShaderBuffer = 0;
pixelShaderBuffer->Release();
pixelShaderBuffer = 0;
// 텍스처 샘플 상태 설명을 생성합니다.
D3D11_SAMPLER_DESC samplerDesc;
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
samplerDesc.BorderColor[0] = 0;
samplerDesc.BorderColor[1] = 0;
samplerDesc.BorderColor[2] = 0;
samplerDesc.BorderColor[3] = 0;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
// 텍스처 샘플링 상태를 생성합니다.
result = device->CreateSamplerState(&samplerDesc, &m_sampleState);
if (FAILED(result))
{
return false;
}
// 정점 셰이더에 있는 동적 행렬 상수 버퍼의 설명을 설정합니다.
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;
// 이 클래스 내에서 정점 셰이더 상수 버퍼에 액세스 할 수 있도록 상수 버퍼 포인터를 생성합니다.
result = device->CreateBuffer(&matrixBufferDesc, NULL, &m_matrixBuffer);
if (FAILED(result))
{
return false;
}
// 픽셀 셰이더에 있는 조명 동적 상수 버퍼의 설명을 설정합니다.
// D3D1_BIN_CONSTANT_BUFFER또는 CreateBuffer를 사용하는 경우에는 바이트 폭이 항상 16배여야 합니다.
D3D11_BUFFER_DESC lightBufferDesc;
lightBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
lightBufferDesc.ByteWidth = sizeof(LightBufferType);
lightBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
lightBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
lightBufferDesc.MiscFlags = 0;
lightBufferDesc.StructureByteStride = 0;
// 이 클래스 내에서 정점 셰이더 상수 버퍼에 액세스 할 수 있도록 상수 버퍼 포인터를 생성합니다.
result = device->CreateBuffer(&lightBufferDesc, NULL, &m_lightBuffer);
if (FAILED(result))
{
return false;
}
return true;
}
void LightShader::shutdownShader()
{
// 조명 상수 버퍼를 분리합니다.
if (m_lightBuffer)
{
m_lightBuffer->Release();
m_lightBuffer = 0;
}
// Samplerstate를 해제합니다.
if (m_sampleState)
{
m_sampleState->Release();
m_sampleState = 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;
}
return;
}
void LightShader::outputShaderErrorMessage(ID3D10Blob* errorMessage, HWND hwnd, WCHAR* shaderFilename)
{
// 오류 메시지 텍스트 버퍼에 대한 포인터를 가져옵니다.
char* compileErrors = (char*)(errorMessage->GetBufferPointer());
// 메시지의 길이를 확인합니다.
unsigned long bufferSize = errorMessage->GetBufferSize();
// 오류 메시지를 기록할 파일을 엽니다.
ofstream fout;
fout.open("shader-error.txt");
// 오류 메시지를 작성합니다.
for (unsigned long i = 0; i < bufferSize; ++i)
{
fout << compileErrors[i];
}
// 파일을 닫습니다.
fout.close();
// 오류 메시지를 해제합니다.
errorMessage->Release();
errorMessage = 0;
// 화면에 메시지를 팝업 하여 텍스트 파일 컴파일 오류를 확인하도록 사용자에게 알립니다.
MessageBox(hwnd, L"Error compiling shader. Check shader-error.txt for message.", shaderFilename, MB_OK);
return;
}
bool LightShader::setShaderParameters(ID3D11DeviceContext* deviceContext, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix, ID3D11ShaderResourceView* texture, D3DXVECTOR3 lightDirection, D3DXVECTOR4 diffuseColor)
{
HRESULT result;
// 셰이더를 위해 행렬을 준비시키기 위해 행렬을 옮깁니다.
D3DXMatrixTranspose(&worldMatrix, &worldMatrix);
D3DXMatrixTranspose(&viewMatrix, &viewMatrix);
D3DXMatrixTranspose(&projectionMatrix, &projectionMatrix);
// 일정 버퍼에 쓸 수 있도록 잠그십시오.
D3D11_MAPPED_SUBRESOURCE mappedResource;
result = deviceContext->Map(m_matrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
{
return false;
}
// 상수 버퍼의 데이터에 대한 포인터를 가져옵니다.
MatrixBufferType* dataPtr = (MatrixBufferType*)mappedResource.pData;
// 행렬을 상수 버퍼에 복사합니다.
dataPtr->world = worldMatrix;
dataPtr->view = viewMatrix;
dataPtr->projection = projectionMatrix;
// 상수 버퍼의 잠금을 해제합니다.
deviceContext->Unmap(m_matrixBuffer, 0);
// 정점 셰이더에 상수 버퍼의 위치를 설정합니다.
unsigned int bufferNumber = 0;
// 이제 업데이트된 값으로 정점 셰이더에 상수 버퍼를 설정합니다.
deviceContext->VSSetConstantBuffers(bufferNumber, 1, &m_matrixBuffer);
// 픽셀 셰이더의 셰이더 텍스처 리소스를 설정합니다.
deviceContext->PSSetShaderResources(0, 1, &texture);
// 라이트 상수 버퍼에 쓸 수 있도록 잠급니다.
result = deviceContext->Map(m_lightBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
{
return false;
}
// 정전 버퍼의 데이터에 대한 포인터를 가져옵니다.
LightBufferType* dataPtr2 = (LightBufferType*)mappedResource.pData;
// 조명 변수를 상수 버퍼에 복사합니다.
dataPtr2->diffuseColor = diffuseColor;
dataPtr2->lightDirection = lightDirection;
dataPtr2->padding = 0.0f;
// 상수 버퍼의 잠금을 해제합니다.
deviceContext->Unmap(m_lightBuffer, 0);
// 픽셀 셰이더에서 라이트 상수 버퍼의 위치를 설정합니다.
bufferNumber = 0;
// 마지막으로 픽셀 셰이더의 조명 상수 버퍼가 업데이트된 값으로 설정합니다.
deviceContext->PSSetConstantBuffers(bufferNumber, 1, &m_lightBuffer);
return true;
}
void LightShader::renderShader(ID3D11DeviceContext* deviceContext, int indexCount)
{
// 정점 입력 레이아웃을 설정합니다.
deviceContext->IASetInputLayout(m_layout);
// 이 삼각형을 렌더링 하는 데 사용할 정점 및 픽셀 셰이더를 설정합니다.
deviceContext->VSSetShader(m_vertexShader, NULL, 0);
deviceContext->PSSetShader(m_pixelShader, NULL, 0);
// 픽셀 셰이더에서 Sampler state를 설정합니다.
deviceContext->PSSetSamplers(0, 1, &m_sampleState);
// 삼각형을 그립니다.
deviceContext->DrawIndexed(indexCount, 0, 0);
return;
}