17.5.4 轮廓边顶点着色器代码
我们现在呈现渲染轮廓边的顶点着色器代码。这个着色器的主要任务就是确定传入的顶点是否在轮廓边上。如果是,顶点着色器就以一定的值,沿顶点法线的方向偏移顶点。
| 以下是引用片段: /************************************************************************************* Vertex shader that draws the outline edges of a mesh. *************************************************************************************/ matrix g_world_view; matrix g_proj; static vector BLACK = {0.0f, 0.0f, 0.0f, 0.0f}; struct sVertexInput { vector position : POSITION; vector normal : NORMAL0; vector face_normal_1 : NORMAL1; vector face_normal_2 : NORMAL2; }; struct sVertexOutput { vector position : POSITION; vector diffuse : COLOR; }; //////////////////////////////////////////////////////////////////////////////////////////////////// sVertexOutput main(sVertexInput input) { sVertexOutput output = (sVertexOutput) 0; // transform position to view space input.position = mul(input.position, g_world_view); // Compute a vector in the direction of the vertex from the eye. // Recall the eye is at the origin in view space - eye is just camera position. vector eye_to_vertex = input.position; // Transform normals to view space. // !! Important, set w components to zero since we're transforming vectors. // Assume there are no scalings in the world matrix as well. input.normal.w = 0.0f; input.face_normal_1.w = 0.0f; input.face_normal_2.w = 0.0f; input.normal = mul(input.normal, g_world_view); input.face_normal_1 = mul(input.face_normal_1, g_world_view); input.face_normal_2 = mul(input.face_normal_2, g_world_view); // compute the cosine of the angles between the eye_to_vertex vector and the face normals float dot0 = dot(eye_to_vertex, input.face_normal_1); float dot1 = dot(eye_to_vertex, input.face_normal_2); // If cosines are different signs (positive/negative) than we are on a outline edge. // Do the signs differ? if((dot0 * dot1) < 0.0f) { // Yes, then this vertex is on a outline edge, offset the vertex position by some scalar // in the direction of the vertex normal, which scalar value designate outline's tickness. input.position += 0.1f * input.normal; } // transform to homogeneous clip space output.position = mul(input.position, g_proj); output.diffuse = BLACK; // set outline color return output; } 执行程序: /************************************************************************************************** Demonstrates cartoon rendering with outline edges using a vertex shader. Note that you will have to switch to the REF device to view this sample if your graphics card does not support vertex shaders. Or you can use software vertex processing: D3DCREATE_SOFTWARE_VERTEXPROCESSING. **************************************************************************************************/ #include "d3dUtility.h" #include "OutlineEdges.h" #pragma warning(disable : 4100) #define MESH_TEAPOT 0 #define MESH_SPHERE 1 #define MESH_TORUS 2 #define MESH_CYLINDER 3 #define NUM_MESH 4 const int WIDTH = 640; const int HEIGHT = 480; IDirect3DDevice9* g_device; IDirect3DVertexShader9* g_vertex_shader; ID3DXConstantTable* g_constant_table; IDirect3DTexture9* g_shade_texture; ID3DXMesh* g_meshes[NUM_MESH]; D3DXMATRIX g_world_matrices[NUM_MESH]; D3DXVECTOR4 g_mesh_colors[NUM_MESH]; D3DXMATRIX g_proj_matrix; D3DXHANDLE g_world_view_handle; D3DXHANDLE g_world_view_proj_handle; D3DXHANDLE g_color_handle; D3DXHANDLE g_dir_to_light_handle; cOutlineEdges* g_mesh_outlines[NUM_MESH]; IDirect3DVertexShader9* g_outline_shader; ID3DXConstantTable* g_outline_constant_table; D3DXHANDLE g_outline_world_view_handle; D3DXHANDLE g_outline_proj_handle; //////////////////////////////////////////////////////////////////////////////////////////////////// bool setup() { // create geometry and compute corresponding world matrix and color for each mesh ID3DXBuffer* adj_buffer[NUM_MESH]; D3DXCreateTeapot(g_device, &g_meshes[MESH_TEAPOT], &adj_buffer[MESH_TEAPOT]); D3DXCreateSphere(g_device, 1.0f, 20, 20, &g_meshes[MESH_SPHERE], &adj_buffer[MESH_SPHERE]); D3DXCreateTorus(g_device, 0.5f, 1.0f, 20, 20, &g_meshes[MESH_TORUS], &adj_buffer[MESH_TORUS]); D3DXCreateCylinder(g_device, 0.5f, 0.5f, 2.0f, 20, 20, &g_meshes[MESH_CYLINDER], &adj_buffer[MESH_CYLINDER]); D3DXMatrixTranslation(&g_world_matrices[MESH_TEAPOT], 0.0f, 2.0f, 0.0f); D3DXMatrixTranslation(&g_world_matrices[MESH_SPHERE], 0.0f, -2.0f, 0.0f); D3DXMatrixTranslation(&g_world_matrices[MESH_TORUS], -3.0f, 0.0f, 0.0f); D3DXMatrixTranslation(&g_world_matrices[MESH_CYLINDER], 3.0f, 0.0f, 0.0f); g_mesh_colors[MESH_TEAPOT] = D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f); g_mesh_colors[MESH_SPHERE] = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f); g_mesh_colors[MESH_TORUS] = D3DXVECTOR4(0.0f, 0.0f, 1.0f, 1.0f); g_mesh_colors[MESH_CYLINDER] = D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f); // allocate mesh outlines g_mesh_outlines[MESH_TEAPOT] = new cOutlineEdges(g_device, g_meshes[MESH_TEAPOT], adj_buffer[MESH_TEAPOT]); g_mesh_outlines[MESH_SPHERE] = new cOutlineEdges(g_device, g_meshes[MESH_SPHERE], adj_buffer[MESH_SPHERE]); g_mesh_outlines[MESH_TORUS] = new cOutlineEdges(g_device, g_meshes[MESH_TORUS], adj_buffer[MESH_TORUS]); g_mesh_outlines[MESH_CYLINDER] = new cOutlineEdges(g_device, g_meshes[MESH_CYLINDER], adj_buffer[MESH_CYLINDER]); safe_release(adj_buffer[MESH_TEAPOT]); safe_release(adj_buffer[MESH_SPHERE]); safe_release(adj_buffer[MESH_TORUS]); safe_release(adj_buffer[MESH_CYLINDER]); // compile cartoon shader ID3DXBuffer* shader_buffer; ID3DXBuffer* error_buffer; HRESULT hr = D3DXCompileShaderFromFile("ToonShader.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); // compile outline shader ID3DXBuffer* outline_shader_buffer; ID3DXBuffer* outline_error_buffer; hr = D3DXCompileShaderFromFile("OutlineShader.cxx", NULL, NULL, "main", "vs_1_1", D3DXSHADER_DEBUG, &outline_shader_buffer, &outline_error_buffer, &g_outline_constant_table); // output any error messages if(outline_error_buffer) { MessageBox(NULL, (char*) outline_error_buffer->GetBufferPointer(), "ERROR", MB_OK); safe_release(outline_error_buffer); } if(FAILED(hr)) { MessageBox(NULL, "D3DXCompileShaderFromFile() - FAILED", "ERROR", MB_OK); return false; } hr = g_device->CreateVertexShader((DWORD*) outline_shader_buffer->GetBufferPointer(), &g_outline_shader); if(FAILED(hr)) { MessageBox(NULL, "CreateVertexShader - FAILED", "ERROR", MB_OK); return false; } safe_release(outline_shader_buffer); // load textures D3DXCreateTextureFromFile(g_device, "toonshade.bmp", &g_shade_texture); g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); g_device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); // disable mipmap // get handles g_world_view_handle = g_constant_table->GetConstantByName(NULL, "g_world_view"); g_world_view_proj_handle = g_constant_table->GetConstantByName(NULL, "g_world_view_proj"); g_color_handle = g_constant_table->GetConstantByName(NULL, "g_color"); g_dir_to_light_handle = g_constant_table->GetConstantByName(NULL, "g_dir_to_light"); g_outline_world_view_handle = g_outline_constant_table->GetConstantByName(NULL, "g_world_view"); g_outline_proj_handle = g_outline_constant_table->GetConstantByName(NULL, "g_proj"); // set shader constants 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); g_constant_table->SetDefaults(g_device); g_outline_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() { for(int i = 0; i < NUM_MESH; i++) { safe_release(g_meshes[i]); safe_delete(g_mesh_outlines[i]); } safe_release(g_shade_texture); safe_release(g_vertex_shader); safe_release(g_constant_table); safe_release(g_outline_shader); safe_release(g_outline_constant_table); } /////////////////////////////////////////////////////////////////////////////////////////////////////// bool display(float time_delta) { static float angle = (3.0f * D3DX_PI) / 2.0f; static float height = 5.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); // render now g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xFFFFFFFF, 1.0f, 0); g_device->BeginScene(); // draw cartoon g_device->SetVertexShader(g_vertex_shader); g_device->SetTexture(0, g_shade_texture); D3DXMATRIX world_view, world_view_proj; for(int i = 0; i < NUM_MESH; i++) { world_view = g_world_matrices[i] * view_matrix; world_view_proj = g_world_matrices[i] * view_matrix * g_proj_matrix; g_constant_table->SetMatrix(g_device, g_world_view_handle, &world_view); g_constant_table->SetMatrix(g_device, g_world_view_proj_handle, &world_view_proj); g_constant_table->SetVector(g_device, g_color_handle, &g_mesh_colors[i]); g_meshes[i]->DrawSubset(0); } // draw outlines g_device->SetVertexShader(g_outline_shader); g_device->SetTexture(0, NULL); // !! Important, do not cull back faces. g_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); for(int i = 0; i < NUM_MESH; i++) { world_view = g_world_matrices[i] * view_matrix; g_outline_constant_table->SetMatrix(g_device, g_outline_world_view_handle, &world_view); g_outline_constant_table->SetMatrix(g_device, g_outline_proj_handle, &g_proj_matrix); g_mesh_outlines[i]->render(); } // restore to cull back faces with counterclockwise vertices g_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); 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; } |

关注此文的读者还看过: