DirectX最振奋人心的一点就是,取消了所有固定管线,功能全部用shader来做。这样就再也不需要受到各种功能上的限制的束缚了。譬如opengl旧版本的时候,可以输入多个贴图,然后每一层的贴图给一个blend function,搞得好生复杂。到了后来,大家都不用固定管线了。现在DirectX11直接取消了固定管线,API反而简洁了许多,也不会有各种鸟事发生。
上图:
这里使用的功能有
1:顶点缓冲区和索引缓冲区
2:像素点光源(每一个像素分别计算,而不是在顶点计算完插值)
3:CubeMap+多层贴图混合
4:渲染到贴图(动态生成CubeMap)
代码上传在了
Vczh Library++ 3.0的Candidate目录里面(Candidate\Simulator\DirectX\Beginning\Beginning.sln)
下面贴出中间那个球的shader:
1 cbuffer MatrixBuffer : register(b0)
2 {
3 matrix worldMatrix;
4 matrix viewMatrix;
5 matrix projectionMatrix;
6 float4 lightPosition;
7 float4 lightColor;
8 float4 lightProperty; //(minimumDistance, minimumStrenght, _, _)
9 float4 environmentColor;
10 };
11
12 Texture2D shaderTexture : register(t0);
13 SamplerState shaderSampler : register(s0);
14 TextureCube cubeMap : register(t1);
15
16 struct VIn
17 {
18 float4 position : POSITION;
19 float3 normal : NORMAL;
20 float2 texcoord0 : TEXCOORD0;
21 };
22
23 struct PIn
24 {
25 float4 position : SV_POSITION;
26 float4 worldPosition : POSITION0;
27 float3 worldNormal : NORMAL0;
28 float4 viewPosition : POSITION1;
29 float3 viewNormal : NORMAL1;
30 float2 texcoord0 : TEXCOORD0;
31 };
32
33 PIn VShader(VIn input)
34 {
35 PIn output;
36 input.position.w = 1.0f;
37
38 output.position = mul(input.position, worldMatrix);
39 output.worldPosition = output.position;
40 output.position = mul(output.position, viewMatrix);
41 output.viewPosition = output.position;
42 output.position = mul(output.position, projectionMatrix);
43
44 output.worldNormal = mul(input.normal, (float3x3)worldMatrix);
45 output.worldNormal = normalize(output.worldNormal);
46 output.viewNormal = mul(output.worldNormal, (float3x3)viewMatrix);
47 output.viewNormal = normalize(output.viewNormal);
48
49 output.texcoord0 = input.texcoord0;
50
51 return output;
52 }
53
54 float4 PShader(PIn input) : SV_TARGET
55 {
56 float3 cubeMapNormal = reflect(input.viewPosition.xyz/input.viewPosition.w, input.viewNormal);
57 float4 cubeMapColor = cubeMap.Sample(shaderSampler, cubeMapNormal);
58 float4 textureColor = shaderTexture.Sample(shaderSampler, input.texcoord0);
59 float4 materialColor = textureColor*0.4 + cubeMapColor*0.6;
60
61 float4 lightDirection = lightPosition-input.worldPosition;
62 float lightCos = max(0, dot(normalize(lightDirection), input.worldNormal));
63 float lightDistance = length(lightDirection);
64 float lightStrength = lightCos/max(1, (lightDistance*lightDistance)/lightProperty.x)*lightProperty.y;
65 float4 diffuseColor = environmentColor+lightColor*float4(lightStrength,lightStrength,lightStrength,1);
66
67 float4 color = materialColor*diffuseColor;
68 return color;
69 }
为了便于调试和修改,我还封装了一个简单的DirectX11的库(Candidate\Simulator\DirectX\Beginning\Shared)。当然现在功能肯定还不够全面。下面是使用这个小库写的渲染上面的图的代码:
1 #include "ModelBuilder.h"
2 #include "..\..\..\..\..\Library\Pointer.h"
3
4 using namespace vl;
5
6 struct ConstantBufferType
7 {
8 D3DXMATRIX world;
9 D3DXMATRIX view;
10 D3DXMATRIX projection;
11 D3DXVECTOR4 lightPosition;
12 D3DXCOLOR lightColor;
13 float lightMinimunDistanceSquare;
14 float lightMinimumStrenght;
15 float unused0[2];
16 D3DXCOLOR environmentColor;
17 };
18
19 struct World
20 {
21 private:
22 const DirectXEnvironment* env;
23 int clientWidth, clientHeight;
24 D3DXMATRIX viewMatrix, worldMatrix[4];
25
26 DirectXConstantBuffer<ConstantBufferType> constantBuffer;
27 DirectXDepthBuffer depthBuffer;
28 DirectXWindowRenderTarget windowRenderTarget;
29 DirectXRenderer renderer;
30 DirectXViewport viewport;
31
32 DirectXTextureBuffer cubeMapTextures;
33 Ptr<DirectXTextureRenderTarget> cubeMapRenderTargets[6];
34 DirectXDepthBuffer cubeMapDepthBuffer;
35 DirectXCubeMapReference cubeMap;
36
37 DirectXVertexBuffer<LightVertex> lightGeometry;
38 DirectXVertexBuffer<ColorVertex> cube1;
39 DirectXVertexBuffer<TextureVertex> cube2, sphere;
40
41 DirectXShader<LightVertex> lightShader;
42 DirectXShader<ColorVertex> colorShader;
43 DirectXShader<TextureVertex> textureShader;
44 DirectXTextureBuffer textureColumn;
45 DirectXTextureBuffer textureEarth;
46 DirectXSamplerBuffer textureSampler;
47 DirectXShader<TextureVertex> cubeShader;
48
49 void WriteConstantBuffer(int worldMatrixIndex)
50 {
51 D3DXMatrixTranspose(&constantBuffer->world, &worldMatrix[worldMatrixIndex]);
52 D3DXMatrixTranspose(&constantBuffer->view, &viewMatrix);
53 D3DXMatrixTranspose(&constantBuffer->projection, &viewport.projectionMatrix);
54 constantBuffer.Update();
55 }
56 public:
57 World(const DirectXEnvironment* _env, int _clientWidth, int _clientHeight)
58 :env(_env)
59 ,clientWidth(_clientWidth), clientHeight(_clientHeight)
60 ,constantBuffer(_env)
61 ,depthBuffer(_env), windowRenderTarget(_env), renderer(_env), viewport(_env)
62 ,cubeMapTextures(_env), cubeMapDepthBuffer(_env), cubeMap(_env)
63 ,lightGeometry(_env) ,cube1(_env) ,cube2(_env) ,sphere(_env)
64 ,lightShader(_env) ,colorShader(_env) ,textureShader(_env)
65 ,textureColumn(_env) ,textureEarth(_env) ,textureSampler(_env)
66 ,cubeShader(_env)
67 {
68 {
69 depthBuffer.Update(clientWidth, clientHeight);
70 cubeMapDepthBuffer.Update(512, 512);
71 cubeMapTextures.Update(512, 512, 6, true);
72 for(int i=0;i<6;i++)
73 {
74 cubeMapRenderTargets[i]=new DirectXTextureRenderTarget(_env);
75 cubeMapRenderTargets[i]->Update(&cubeMapTextures, i);
76 }
77 cubeMap.Update(&cubeMapTextures);
78 }
79 BuildLightGeometry(lightGeometry);
80 BuildColorCube(cube1);
81 BuildTextureCube(cube2);
82 BuildTextureSphere(sphere);
83 {
84 lightShader.Fill(L"LightShader.txt", L"VShader", L"PShader")
85 .Field(L"POSITION", &LightVertex::Position)
86 ;
87
88 colorShader.Fill(L"ColorShader.txt", L"VShader", L"PShader")
89 .Field(L"POSITION", &ColorVertex::Position)
90 .Field(L"NORMAL", &ColorVertex::Normal)
91 .Field(L"COLOR", &ColorVertex::Color)
92 ;
93
94 textureShader.Fill(L"TextureShader.txt", L"VShader", L"PShader")
95 .Field(L"POSITION", &TextureVertex::Position)
96 .Field(L"NORMAL", &TextureVertex::Normal)
97 .Field(L"TEXCOORD", &TextureVertex::Texcoord0)
98 ;
99
100 textureColumn.Update(L"TextureColumn.jpg");
101 textureEarth.Update(L"earth.bmp");
102 textureSampler.Update(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_WRAP, D3DXCOLOR(1, 1, 1, 1));
103
104 cubeShader.Fill(L"CubeShader.txt", L"VShader", L"PShader")
105 .Field(L"POSITION", &TextureVertex::Position)
106 .Field(L"NORMAL", &TextureVertex::Normal)
107 .Field(L"TEXCOORD", &TextureVertex::Texcoord0)
108 ;
109 }
110 {
111 {
112 D3DXMATRIX scaling;
113 D3DXMatrixScaling(&scaling, 1.4f, 1.4f, 1.4f);
114
115 D3DXMatrixTranslation(&worldMatrix[0], -2, 0, 0);
116 D3DXMatrixMultiply(&worldMatrix[0], &worldMatrix[0], &scaling);
117 D3DXMatrixTranslation(&worldMatrix[1], 2, 0, 0);
118 D3DXMatrixMultiply(&worldMatrix[1], &worldMatrix[1], &scaling);
119 }
120 {
121 D3DXMATRIX matrix;
122 D3DXMatrixScaling(&worldMatrix[2], 0.2f, 0.2f, 0.2f);
123
124 D3DXMatrixTranslation(&matrix, 4.7f, 0, 0);
125 D3DXMatrixMultiply(&worldMatrix[2], &worldMatrix[2], &matrix);
126
127 D3DXMatrixRotationY(&matrix, (float)D3DX_PI/4);
128 D3DXMatrixMultiply(&worldMatrix[2], &worldMatrix[2], &matrix);
129
130 D3DXMatrixRotationX(&matrix, (float)D3DX_PI/5);
131 D3DXMatrixMultiply(&worldMatrix[2], &worldMatrix[2], &matrix);
132 }
133 {
134 D3DXMatrixScaling(&worldMatrix[3], 1.0f, 1.0f, 1.0f);
135 }
136 }
137 {
138 constantBuffer->lightPosition=D3DXVECTOR4(0, 0, 0, 1);
139 D3DXVec4Transform(&constantBuffer->lightPosition, &constantBuffer->lightPosition, &worldMatrix[2]);
140 constantBuffer->lightColor=D3DXCOLOR(0.7f, 0.7f, 0.7f, 1.0f);
141 constantBuffer->lightMinimunDistanceSquare=9;
142 constantBuffer->lightMinimumStrenght=3;
143 constantBuffer->environmentColor=D3DXCOLOR(0.3f, 0.3f, 0.3f, 1.0f);
144 }
145 }
146
147 ~World()
148 {
149 }
150
151 void Render()
152 {
153 {
154 D3DXVECTOR3 ats[]=
155 {
156 D3DXVECTOR3( 1, 0, 0),
157 D3DXVECTOR3(-1, 0, 0),
158 D3DXVECTOR3( 0, 1, 0),
159 D3DXVECTOR3( 0, -1, 0),
160 D3DXVECTOR3( 0, 0, 1),
161 D3DXVECTOR3( 0, 0, -1),
162 };
163 D3DXVECTOR3 ups[]=
164 {
165 D3DXVECTOR3( 0, 1, 0),
166 D3DXVECTOR3( 0, 1, 0),
167 D3DXVECTOR3( 0, 0, -1),
168 D3DXVECTOR3( 0, 0, 1),
169 D3DXVECTOR3( 0, 1, 0),
170 D3DXVECTOR3( 0, 1, 0),
171 };
172 for(int i=0;i<6;i++)
173 {
174 D3DXMatrixLookAtLH(&viewMatrix, &D3DXVECTOR3(0, 0, 0), &ats[i], &ups[i]);
175 renderer.SetRenderTarget(cubeMapRenderTargets[i].Obj(), &cubeMapDepthBuffer);
176 viewport.SetViewport(512, 512, (float)D3DX_PI/2, 0.1f, 100.0f);
177 cubeMapRenderTargets[i]->Clear(D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));
178 cubeMapDepthBuffer.Clear();
179
180 constantBuffer.VSBindToRegisterBN(0);
181 constantBuffer.PSBindToRegisterBN(0);
182
183 WriteConstantBuffer(0);
184 cube1.SetCurrentAndRender(&colorShader);
185
186 WriteConstantBuffer(1);
187 textureColumn.PSBindToRegisterTN(0);
188 textureSampler.PSBindToRegisterSN(0);
189 cube2.SetCurrentAndRender(&textureShader);
190
191 WriteConstantBuffer(2);
192 lightGeometry.SetCurrentAndRender(&lightShader);
193 }
194 }
195 {
196 D3DXMatrixLookAtLH(&viewMatrix, &D3DXVECTOR3(0, 0, -10), &D3DXVECTOR3(0, 0, 1), &D3DXVECTOR3(0, 1, 0));
197 renderer.SetRenderTarget(&windowRenderTarget, &depthBuffer);
198 viewport.SetViewport(clientWidth, clientHeight, (float)D3DX_PI/4, 0.1f, 100.0f);
199 windowRenderTarget.Clear(D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));
200 depthBuffer.Clear();
201
202 constantBuffer.VSBindToRegisterBN(0);
203 constantBuffer.PSBindToRegisterBN(0);
204
205 WriteConstantBuffer(0);
206 cube1.SetCurrentAndRender(&colorShader);
207
208 WriteConstantBuffer(1);
209 textureColumn.PSBindToRegisterTN(0);
210 textureSampler.PSBindToRegisterSN(0);
211 cube2.SetCurrentAndRender(&textureShader);
212
213 WriteConstantBuffer(2);
214 lightGeometry.SetCurrentAndRender(&lightShader);
215
216 WriteConstantBuffer(3);
217 textureEarth.PSBindToRegisterTN(0);
218 textureSampler.PSBindToRegisterSN(0);
219 cubeMap.PSBindToRegisterTN(1);
220 sphere.SetCurrentAndRender(&cubeShader);
221 }
222 env->swapChain->Present(0, 0);
223 }
224
225 void Rotate(float x, float y)
226 {
227 D3DXMATRIX rotation;
228 D3DXMatrixRotationYawPitchRoll(&rotation, -x, -y, 0);
229 D3DXMatrixMultiply(&worldMatrix[0], &worldMatrix[0], &rotation);
230 D3DXMatrixMultiply(&worldMatrix[1], &worldMatrix[1], &rotation);
231 D3DXMatrixMultiply(&worldMatrix[3], &worldMatrix[3], &rotation);
232 }
233 };
234 World* world=0;
235 int oldX=0;
236 int oldY=0;
237 bool mouseTracking=false;
238
239 void CALLBACK DirectXProcIdle()
240 {
241 if(world)
242 {
243 world->Render();
244 }
245 }
246
247 LRESULT CALLBACK DirectXProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool& callDefWindowProc)
248 {
249 switch(uMsg)
250 {
251 case WM_SHOWWINDOW:
252 {
253 if(wParam==TRUE)
254 {
255 if(!world)
256 {
257 SIZE size=WindowGetClient(hwnd);
258 const DirectXEnvironment* env=CreateDirectXEnvironment(hwnd);
259 world=new World(env, size.cx, size.cy);
260 }
261 }
262 }
263 break;
264 case WM_DESTROY:
265 {
266 if(world)
267 {
268 delete world;
269 world=0;
270 DestroyDirectXEnvironment();
271 }
272 }
273 break;
274 case WM_LBUTTONDOWN:
275 {
276 SetCapture(hwnd);
277 WindowMouseInfo info(wParam, lParam, false);
278 oldX=info.x;
279 oldY=info.y;
280 mouseTracking=true;
281 }
282 break;
283 case WM_MOUSEMOVE:
284 {
285 if(mouseTracking)
286 {
287 WindowMouseInfo info(wParam, lParam, false);
288
289 int offsetX=info.x-oldX;
290 int offsetY=info.y-oldY;
291 float rotateX=(float)D3DX_PI*offsetX/200;
292 float rotateY=(float)D3DX_PI*offsetY/200;
293 world->Rotate(rotateX, rotateY);
294
295 oldX=info.x;
296 oldY=info.y;
297 }
298 }
299 break;
300 case WM_LBUTTONUP:
301 {
302 ReleaseCapture();
303 mouseTracking=false;
304 }
305 break;
306 }
307 return 0;
308 }