-
Notifications
You must be signed in to change notification settings - Fork 13
/
Sky.cpp
257 lines (225 loc) · 8.92 KB
/
Sky.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 "Sky.h"
#include "WICTextureLoader.h"
#include "DDSTextureLoader.h"
using namespace DirectX;
Sky::Sky(
const wchar_t* cubemapDDSFile,
std::shared_ptr<Mesh> mesh,
std::shared_ptr<SimpleVertexShader> skyVS,
std::shared_ptr<SimplePixelShader> skyPS,
Microsoft::WRL::ComPtr<ID3D11SamplerState> samplerOptions,
Microsoft::WRL::ComPtr<ID3D11Device> device,
Microsoft::WRL::ComPtr<ID3D11DeviceContext> context)
{
// Save params
this->skyMesh = mesh;
this->device = device;
this->context = context;
this->samplerOptions = samplerOptions;
this->skyVS = skyVS;
this->skyPS = skyPS;
// Init render states
InitRenderStates();
// Load texture
CreateDDSTextureFromFile(device.Get(), cubemapDDSFile, 0, skySRV.GetAddressOf());
}
Sky::Sky(
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> cubeMap,
Microsoft::WRL::ComPtr<ID3D11SamplerState> samplerOptions,
Microsoft::WRL::ComPtr<ID3D11Device> device,
Microsoft::WRL::ComPtr<ID3D11DeviceContext> context) :
skySRV(cubeMap),
samplerOptions(samplerOptions),
device(device),
context(context)
{
// Init render states
InitRenderStates();
}
Sky::Sky(
const wchar_t* right,
const wchar_t* left,
const wchar_t* up,
const wchar_t* down,
const wchar_t* front,
const wchar_t* back,
std::shared_ptr<Mesh> mesh,
std::shared_ptr<SimpleVertexShader> skyVS,
std::shared_ptr<SimplePixelShader> skyPS,
Microsoft::WRL::ComPtr<ID3D11SamplerState> samplerOptions,
Microsoft::WRL::ComPtr<ID3D11Device> device,
Microsoft::WRL::ComPtr<ID3D11DeviceContext> context)
{
// Save params
this->skyMesh = mesh;
this->device = device;
this->context = context;
this->samplerOptions = samplerOptions;
this->skyVS = skyVS;
this->skyPS = skyPS;
// Init render states
InitRenderStates();
// Create texture from 6 images
skySRV = CreateCubemap(right, left, up, down, front, back);
}
Sky::Sky(
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> right,
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> left,
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> up,
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> down,
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> front,
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> back,
std::shared_ptr<Mesh> mesh,
std::shared_ptr<SimpleVertexShader> skyVS,
std::shared_ptr<SimplePixelShader> skyPS,
Microsoft::WRL::ComPtr<ID3D11SamplerState> samplerOptions,
Microsoft::WRL::ComPtr<ID3D11Device> device,
Microsoft::WRL::ComPtr<ID3D11DeviceContext> context)
{
// Save params
this->skyMesh = mesh;
this->device = device;
this->context = context;
this->samplerOptions = samplerOptions;
this->skyVS = skyVS;
this->skyPS = skyPS;
// Init render states
InitRenderStates();
// Create texture from 6 images
skySRV = CreateCubemap(right, left, up, down, front, back);
}
Sky::~Sky()
{
}
void Sky::Draw(std::shared_ptr<Camera> camera)
{
// Change to the sky-specific rasterizer state
context->RSSetState(skyRasterState.Get());
context->OMSetDepthStencilState(skyDepthState.Get(), 0);
// Set the sky shaders
skyVS->SetShader();
skyPS->SetShader();
// Give them proper data
skyVS->SetMatrix4x4("view", camera->GetView());
skyVS->SetMatrix4x4("projection", camera->GetProjection());
skyVS->CopyAllBufferData();
// Send the proper resources to the pixel shader
skyPS->SetShaderResourceView("skyTexture", skySRV);
skyPS->SetSamplerState("samplerOptions", samplerOptions);
// Set mesh buffers and draw
skyMesh->SetBuffersAndDraw(context);
// Reset my rasterizer state to the default
context->RSSetState(0); // Null (or 0) puts back the defaults
context->OMSetDepthStencilState(0, 0);
}
void Sky::InitRenderStates()
{
// Rasterizer to reverse the cull mode
D3D11_RASTERIZER_DESC rastDesc = {};
rastDesc.CullMode = D3D11_CULL_FRONT; // Draw the inside instead of the outside!
rastDesc.FillMode = D3D11_FILL_SOLID;
rastDesc.DepthClipEnable = true;
device->CreateRasterizerState(&rastDesc, skyRasterState.GetAddressOf());
// Depth state so that we ACCEPT pixels with a depth == 1
D3D11_DEPTH_STENCIL_DESC depthDesc = {};
depthDesc.DepthEnable = true;
depthDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
depthDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
device->CreateDepthStencilState(&depthDesc, skyDepthState.GetAddressOf());
}
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> Sky::CreateCubemap(
const wchar_t* right,
const wchar_t* left,
const wchar_t* up,
const wchar_t* down,
const wchar_t* front,
const wchar_t* back)
{
// Load the 6 textures into an array.
// - We need references to the TEXTURES, not the SHADER RESOURCE VIEWS!
// - Specifically NOT generating mipmaps, as we don't need them for the sky!
// - Order matters here! +X, -X, +Y, -Y, +Z, -Z
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> textures[6] = {};
CreateWICTextureFromFile(device.Get(), right, 0, textures[0].GetAddressOf());
CreateWICTextureFromFile(device.Get(), left, 0, textures[1].GetAddressOf());
CreateWICTextureFromFile(device.Get(), up, 0, textures[2].GetAddressOf());
CreateWICTextureFromFile(device.Get(), down, 0, textures[3].GetAddressOf());
CreateWICTextureFromFile(device.Get(), front, 0, textures[4].GetAddressOf());
CreateWICTextureFromFile(device.Get(), back, 0, textures[5].GetAddressOf());
// Send back the SRV, which is what we need for our shaders
return CreateCubemap(textures[0], textures[1], textures[2], textures[3], textures[4], textures[5]);
}
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> Sky::CreateCubemap(
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> right,
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> left,
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> up,
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> down,
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> front,
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> back)
{
// Load the 6 textures into an array.
// - We need references to the TEXTURES, not the SHADER RESOURCE VIEWS!
// - Order matters here! +X, -X, +Y, -Y, +Z, -Z
ID3D11Resource* textures[6] = {};
right.Get()->GetResource(&textures[0]);
left.Get()->GetResource(&textures[1]);
up.Get()->GetResource(&textures[2]);
down.Get()->GetResource(&textures[3]);
front.Get()->GetResource(&textures[4]);
back.Get()->GetResource(&textures[5]);
// We'll assume all of the textures are the same color format and resolution,
// so get the description of the first shader resource view
D3D11_TEXTURE2D_DESC faceDesc = {};
((ID3D11Texture2D*)textures[0])->GetDesc(&faceDesc);
// Describe the resource for the cube map, which is simply
// a "texture 2d array". This is a special GPU resource format,
// NOT just a C++ array of textures!!!
D3D11_TEXTURE2D_DESC cubeDesc = {};
cubeDesc.ArraySize = 6; // Cube map!
cubeDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; // We'll be using as a texture in a shader
cubeDesc.CPUAccessFlags = 0; // No read back
cubeDesc.Format = faceDesc.Format; // Match the loaded texture's color format
cubeDesc.Width = faceDesc.Width; // Match the size
cubeDesc.Height = faceDesc.Height; // Match the size
cubeDesc.MipLevels = 1; // Only need 1
cubeDesc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; // This should be treated as a CUBE, not 6 separate textures
cubeDesc.Usage = D3D11_USAGE_DEFAULT; // Standard usage
cubeDesc.SampleDesc.Count = 1;
cubeDesc.SampleDesc.Quality = 0;
// Create the actual texture resource
Microsoft::WRL::ComPtr<ID3D11Texture2D> cubeMapTexture;
device->CreateTexture2D(&cubeDesc, 0, &cubeMapTexture);
// Loop through the individual face textures and copy them,
// one at a time, to the cube map texure
for (int i = 0; i < 6; i++)
{
// Calculate the subresource position to copy into
unsigned int subresource = D3D11CalcSubresource(
0, // Which mip (zero, since there's only one)
i, // Which array element?
1); // How many mip levels are in the texture?
// Copy from one resource (texture) to another
context->CopySubresourceRegion(
cubeMapTexture.Get(), // Destination resource
subresource, // Dest subresource index (one of the array elements)
0, 0, 0, // XYZ location of copy
textures[i], // Source resource
0, // Source subresource index (we're assuming there's only one)
0); // Source subresource "box" of data to copy (zero means the whole thing)
}
// At this point, all of the faces have been copied into the
// cube map texture, so we can describe a shader resource view for it
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Format = cubeDesc.Format; // Same format as texture
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; // Treat this as a cube!
srvDesc.TextureCube.MipLevels = 1; // Only need access to 1 mip
srvDesc.TextureCube.MostDetailedMip = 0; // Index of the first mip we want to see
// Make the SRV
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> cubeSRV;
device->CreateShaderResourceView(cubeMapTexture.Get(), &srvDesc, cubeSRV.GetAddressOf());
// Clean up our extra texture refs
for (int i = 0; i < 6; i++)
textures[i]->Release();
// Send back the SRV, which is what we need for our shaders
return cubeSRV;
}