我们以检阅着色器代码作为开始:
| 以下是引用片段: /********************************************************************************** Vertex shader that does diffuse lighting. **********************************************************************************/ matrix g_view_matrix; matrix g_view_proj_matrix; vector g_ambient_material; vector g_diffuse_material; vector g_dir_to_light; // the direction to the light source // Global variables used to hold the ambient light intensity (ambient light the light // source emits) and the diffuse light intensity (diffuse light the light source emits). // These variables are initialized here in the shader. const vector DIFFUSE_LIGHT_INTENSITY = {0.5f, 0.5f, 0.5f, 1.0f}; const vector AMBIENT_LIGHT_INTENSITY = {2.0f, 2.0f, 1.0f, 1.0f}; struct sVertexInput { vector position : POSITION; vector normal : NORMAL; }; struct sVertexOutput { vector position : POSITION; vector diffuse : COLOR; }; /////////////////////////////////////////////////////////////////////////////////////////////// sVertexOutput main(sVertexInput vertex_input) { sVertexOutput vertex_output = (sVertexOutput) 0; // transform position to homogeneous clip space vertex_output.position = mul(vertex_input.position, g_view_proj_matrix); // Transform lights and normals to view space. // Set w components to zero since we're transforming vectors here and not points. g_dir_to_light.w = 0.0f; vertex_input.normal.w = 0.0f; g_dir_to_light = mul(g_dir_to_light, g_view_matrix); vertex_input.normal = mul(vertex_input.normal, g_view_matrix); // compute cosine of the angle between light and normal float scalar = dot(g_dir_to_light, vertex_input.normal); // Recall that if the angle between the surface and light is greater than 90 degrees // the surface recieves no light. Thus, if the angle is greater than 90 degrees we set // scalar to zero so that the surface will not be lit. if(scalar < 0.0f) scalar = 0.0f; // Ambient light reflected is computed by performing a component wise multiplication with // the ambient material vector and the ambient light intensity vector. // // Diffuse light reflected is computed by performing a component wise multiplication with // the diffuse material vector and the diffuse light intensity vector. // Further we scale each component by the shading scalar s, which shades the color based on // how much light the vertex received from the light source. // // The sum of both the ambient and diffuse components gives us our final vertex color. vertex_output.diffuse = (g_ambient_material * AMBIENT_LIGHT_INTENSITY) + (scalar * (g_diffuse_material * DIFFUSE_LIGHT_INTENSITY)); return vertex_output; } 执行程序: /************************************************************************************************** Demonstrates diffuse lighting using a vertex shader. You will have to switch to the REF device to run this sample if your hardware does not support shaders. Or you can use software vertex processing: D3DCREATE_SOFTWARE_VERTEXPROCESSING. **************************************************************************************************/ #include "d3dUtility.h" #pragma warning(disable : 4100) const int WIDTH = 640; const int HEIGHT = 480; IDirect3DDevice9* g_device; ID3DXMesh* g_teapot_mesh; IDirect3DVertexShader9* g_vertex_shader; ID3DXConstantTable* g_constant_table; D3DXHANDLE g_view_matrix_handle; D3DXHANDLE g_view_proj_matrix_handle; D3DXHANDLE g_ambient_material_handle; D3DXHANDLE g_diffuse_material_handle; D3DXHANDLE g_dir_to_light_handle; D3DXMATRIX g_proj_matrix; //////////////////////////////////////////////////////////////////////////////////////////////////// bool setup() { D3DXCreateTeapot(g_device, &g_teapot_mesh, NULL); // compile shader ID3DXBuffer* shader_buffer; ID3DXBuffer* error_buffer; HRESULT hr = D3DXCompileShaderFromFile("DiffuseShader.cxx", NULL, NULL, "main", "vs_1_1", D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, &shader_buffer, &error_buffer, &g_constant_table); // output any error messages if(error_buffer) { MessageBox(NULL, (char*)error_buffer->GetBufferPointer(), "ERROR", MB_OK); safe_release(error_buffer); } if(FAILED(hr)) { MessageBox(NULL, "D3DXCreateEffectFromFile() - FAILED", "ERROR", MB_OK); return false; } hr = g_device->CreateVertexShader((DWORD*) shader_buffer->GetBufferPointer(), &g_vertex_shader); if(FAILED(hr)) { MessageBox(NULL, "CreateVertexShader - FAILED", "ERROR", MB_OK); return false; } safe_release(shader_buffer); // get handles g_view_matrix_handle = g_constant_table->GetConstantByName(NULL, "g_view_matrix"); g_view_proj_matrix_handle = g_constant_table->GetConstantByName(NULL, "g_view_proj_matrix"); g_ambient_material_handle = g_constant_table->GetConstantByName(NULL, "g_ambient_material"); g_diffuse_material_handle = g_constant_table->GetConstantByName(NULL, "g_diffuse_material"); g_dir_to_light_handle = g_constant_table->GetConstantByName(NULL, "g_light_direction"); // // set shader constants // // light direction D3DXVECTOR4 dir_to_light(-0.57f, 0.57f, -0.57f, 0.0f); g_constant_table->SetVector(g_device, g_dir_to_light_handle, &dir_to_light); // materials D3DXVECTOR4 ambient_material(1.0f, 1.0f, 0.5f, 1.0f); D3DXVECTOR4 diffuse_material(1.0f, 1.0f, 0.5f, 1.0f); g_constant_table->SetVector(g_device, g_ambient_material_handle, &ambient_material); g_constant_table->SetVector(g_device, g_diffuse_material_handle, &diffuse_material); g_constant_table->SetDefaults(g_device); // set the projection matrix D3DXMatrixPerspectiveFovLH(&g_proj_matrix, D3DX_PI/4.0f, (float)WIDTH/HEIGHT, 1.0f, 1000.0f); //g_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////// void cleanup() { safe_release(g_teapot_mesh); safe_release(g_vertex_shader); safe_release(g_constant_table); } /////////////////////////////////////////////////////////////////////////////////////////////////////// bool display(float time_delta) { static float angle = (3.0f * D3DX_PI) / 2.0f; static float height = 3.0f; if(GetAsyncKeyState(VK_LEFT) & 0x8000f) angle -= 0.5f * time_delta; if(GetAsyncKeyState(VK_RIGHT) & 0x8000f) angle += 0.5f * time_delta; if(GetAsyncKeyState(VK_UP) & 0x8000f) height += 5.0f * time_delta; if(GetAsyncKeyState(VK_DOWN) & 0x8000f) height -= 5.0f * time_delta; D3DXVECTOR3 position(cosf(angle) * 7.0f, height, sinf(angle) * 7.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX view_matrix; D3DXMatrixLookAtLH(&view_matrix, &position, &target, &up); D3DXMATRIX view_proj_matrix = view_matrix * g_proj_matrix; g_constant_table->SetMatrix(g_device, g_view_proj_matrix_handle, &view_proj_matrix); // render now g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0); g_device->BeginScene(); g_device->SetVertexShader(g_vertex_shader); g_teapot_mesh->DrawSubset(0); g_device->EndScene(); g_device->Present(NULL, NULL, NULL, NULL); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////// LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM word_param, LPARAM long_param) { switch(msg) { case WM_DESTROY: PostQuitMessage(0); break; case WM_KEYDOWN: if(word_param == VK_ESCAPE) DestroyWindow(hwnd); break; } return DefWindowProc(hwnd, msg, word_param, long_param); } /////////////////////////////////////////////////////////////////////////////////////////////////////// int WINAPI WinMain(HINSTANCE inst, HINSTANCE, PSTR cmd_line, int cmd_show) { if(! init_d3d(inst, WIDTH, HEIGHT, true, D3DDEVTYPE_HAL, &g_device)) { MessageBox(NULL, "init_d3d() - failed.", 0, MB_OK); return 0; } if(! setup()) { MessageBox(NULL, "Steup() - failed.", 0, MB_OK); return 0; } enter_msg_loop(display); cleanup(); g_device->Release(); return 0; } 运行截图: |
setup函数执行下列任务:
创建茶壶网格
编译顶点着色器
根据已编译代码创建顶点着色器
通过常量表获取着色器程序中的几个变量的句柄
通过常量表初始化着色器的这几个变量
注意:对于本应用程序,我们的顶点结构不需要任何自由顶点格式没有的额外的分量。
display函数非常简单。它检测用户输入(这里指的是用户输入的传入着色器程序的变量),并相应的更新视图矩阵。但是,因为我们在着色器中执行这个视图矩阵变换,所以我们还必须更新着色器中的视图矩阵变量。我们用常量表完成这件事情。
关注此文的读者还看过: