// 使用DirectX 9來繪圖 void RenderFrameDX9(void) { LPDIRECT3DDEVICE9 device = GutGetGraphicsDeviceDX9(); Matrix4x4 view_matrix = g_Control.GetViewMatrix(); Matrix4x4 world_matrix = g_Control.GetObjectMatrix(); Matrix4x4 ident_matrix; ident_matrix.Identity(); device->BeginScene(); // 消除畫面 device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_RGBA(30, 30, 30, 255), 1.0f, 0); // light position & orientation Vector4 light_pos(5.0f, 0.0f, 5.0f); Vector4 light_lookat(0.0f, 0.0f, 0.0f); Vector4 light_up(0.0f, 1.0f, 0.0f); // light matrix Matrix4x4 light_view = GutMatrixLookAtRH(light_pos, light_lookat, light_up); Matrix4x4 light_world_view = world_matrix * light_view; Matrix4x4 shadow_matrix; // 建立shadow volume if ( g_bDirectionalLight ) { g_ShadowVolume.BuildShadowVolume_DirectionalLight(light_world_view, 20.0f, true); shadow_matrix = light_view; shadow_matrix.FastInvert(); } else { g_ShadowVolume.BuildShadowVolume_PointLight(light_pos, world_matrix, 20.0f, true); shadow_matrix.Identity(); } // 畫出空間中的茶壼 { device->SetTransform(D3DTS_PROJECTION, (D3DMATRIX *) &g_projection_matrix); device->SetTransform(D3DTS_VIEW, (D3DMATRIX *) &view_matrix); device->SetTransform(D3DTS_WORLD, (D3DMATRIX *) &world_matrix); g_Model_DX9.Render(); } // 畫出墻壁 { device->SetTransform(D3DTS_WORLD, (D3DMATRIX *) &ident_matrix); sModelMaterial_DX9 material; material.m_Material.Diffuse.r = 0.0f; material.m_Material.Diffuse.g = 0.0f; material.m_Material.Diffuse.b = 1.0f; material.m_Material.Diffuse.a = 1.0f; material.Submit(); device->SetFVF(D3DFVF_XYZ); device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, g_Quad, sizeof(Vertex_VT)); } device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); device->SetRenderState(D3DRS_STENCILENABLE, TRUE); device->SetRenderState(D3DRS_STENCILREF, 0x01); device->SetRenderState(D3DRS_STENCILMASK, 0xff); // 在Stencil Buffer上標示出陰影區域 { sModelMaterial_DX9 material; material.m_bCullFace = false; material.Submit(); // 套用矩陣 device->SetTransform(D3DTS_WORLD, (D3DMATRIX *) &shadow_matrix); // 設定頂點資料格式 device->SetFVF(D3DFVF_XYZ); device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); // cw stencil setting device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR); // ccw stencil setting device->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_ALWAYS); device->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_DECR); // disable color write device->SetRenderState(D3DRS_COLORWRITEENABLE, 0); // 畫出Shadow Volume device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, g_ShadowVolume.m_iNumShadowVolumeFaces, g_ShadowVolume.m_pShadowVolume, sizeof(Vector4)); // 恢復更新framebuffer device->SetRenderState(D3DRS_COLORWRITEENABLE, 0xff); device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); device->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_KEEP); } // 畫出陰影 { sModelMaterial_DX9 material; material.m_bCullFace = false; material.Submit(); device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR); device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); // 套用矩陣 device->SetTransform(D3DTS_PROJECTION, (D3DMATRIX *) &ident_matrix); device->SetTransform(D3DTS_VIEW, (D3DMATRIX *) &ident_matrix); device->SetTransform(D3DTS_WORLD, (D3DMATRIX *) &ident_matrix); // 只更新stencil buffer上值為1的像素 device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL); device->SetRenderState(D3DRS_STENCILREF, 0x01); // 使用黑色再畫一次墻壁 device->SetRenderState(D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(0, 0, 0,255) ); device->SetFVF(D3DFVF_XYZ); device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, g_FullScreenQuad, sizeof(Vertex_VT)); } device->SetRenderState(D3DRS_STENCILENABLE, FALSE); // 觀察shadow volume, 除錯用. if ( g_bDrawShadowVolume ) { device->SetTransform(D3DTS_PROJECTION, (D3DMATRIX *) &g_projection_matrix); device->SetTransform(D3DTS_VIEW, (D3DMATRIX *) &view_matrix); device->SetTransform(D3DTS_WORLD, (D3DMATRIX *) &shadow_matrix); sModelMaterial_DX9 material; material.m_bCullFace = false; material.Submit(); device->SetRenderState(D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(255, 255, 255, 255) ); device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, g_ShadowVolume.m_iNumShadowVolumeFaces, g_ShadowVolume.m_pShadowVolume, sizeof(Vector4)); device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); } // 恢復更新zbuffer device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); // 把顏色來源還原為 diffuse * texture device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); // 宣告所有的繪圖指令都下完了 device->EndScene(); // 把背景backbuffer的畫面呈現出來 device->Present( NULL, NULL, NULL, NULL ); }
int main(int argc, char **args) { const char *ctm_filepath = (argc > 1) ? args[1] : "teapot.ctm"; trackback_state_initialize(camera_rotation); trackback_state_initialize(light_rotation); current_trackball_state = &camera_rotation; if (!glfwInit()) { std::cerr << "Failed to initialize GLFW" << std::endl; exit(EXIT_FAILURE); } int depth_bits = 16; if (!glfwOpenWindow(640, 480, 0, 0, 0, 0, depth_bits, 0, GLFW_WINDOW)) { std::cerr << "Failed to open GLFW window" << std::endl; glfwTerminate(); exit(EXIT_FAILURE); } glfwGetWindowSize(&screen_width, &screen_height); glfwSetWindowSizeCallback(resize); glfwSetKeyCallback(keyboard); glfwSetMouseButtonCallback(mouse); glfwSetMousePosCallback(motion); glfwSetWindowTitle("Spinning Teapot"); glfwEnable(GLFW_STICKY_KEYS); glfwSwapInterval(1); // Shaders shader_program_t phong_shader; build_shader_program(phong_shader, "phong.vs", "phong.fs"); shader_program_t rect_shader; build_shader_program(rect_shader, "rect.vs", "rect.fs"); shader_program_t render_buffer_shader; build_shader_program(render_buffer_shader, "render_buffer.vs", "render_buffer.fs"); shader_program_t bump_shader; build_shader_program(bump_shader, "bump.vs", "bump.fs"); //--- Mesh Objects mesh_t mesh_floor; load_mesh_cube(mesh_floor); mesh_object_t floor; if (! build_mesh_object(mesh_floor, floor) ) { glfwTerminate(); exit(EXIT_FAILURE); } mesh_t mesh_plane; load_mesh_plane(mesh_plane); mesh_object_t plane; if (! build_mesh_object(mesh_plane, plane) ) { glfwTerminate(); exit(EXIT_FAILURE); } mesh_t mesh_teapot; if (! load_mesh_from_file(ctm_filepath, mesh_teapot) ) { glfwTerminate(); exit(EXIT_FAILURE); } compute_tangent_vectors(mesh_teapot); mesh_object_t teapot; if (! build_mesh_object(mesh_teapot, teapot) ) { glfwTerminate(); exit(EXIT_FAILURE); } //--- Texture const char *texture_filepath = "checker.tga"; texture_t tex; tex.unit_id = 1; if (! build_texutre_from_file(texture_filepath, tex)) { std::cout << "Failed to load texture: " << texture_filepath << std::endl; glfwTerminate(); exit(EXIT_FAILURE); } //--- FBO texture_t depth_tex_buffer; int depth_tex_width = 2 * screen_width; int depth_tex_height = 2 * screen_height; depth_tex_buffer.unit_id = 2; GLuint fb_handle; create_framebuffer_and_depth_texture(depth_tex_width, depth_tex_height, depth_tex_buffer, &fb_handle); // Scene settings glm::vec3 camera_position(0.0f, 0.0f, 5.0f); glm::vec3 camera_center(0.0f, 0.0f, 0.0f); glm::vec3 camera_up(0.0f, 1.0f, 0.0f); glm::mat4 view_matrix = glm::lookAt(camera_position, camera_center, camera_up); // from world to camera glm::mat4 light_pov_matrix; glm::mat4 bias( 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f ); teapot.material.diffuse = glm::vec3(0.0f, 1.0f, 1.0f); teapot.material.specular = glm::vec3(0.8f); teapot.material.shininess = 128.0f; teapot.textures.push_back(tex); teapot.textures.push_back(depth_tex_buffer); floor.material.diffuse = glm::vec3(1.0f, 1.0f, 1.0f); floor.material.specular = glm::vec3(0.8f); floor.material.shininess = 2.0f; floor.textures.push_back(depth_tex_buffer); plane.textures.push_back(depth_tex_buffer); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); do { //--- Transform glm::vec3 light_position = glm::mat3_cast(light_rotation.orientation) * glm::vec3(0.0f, 5.0f, 0.0f); glm::vec3 light_center(0.0f, 0.0f, 0.0f); glm::vec3 light_up(0.0f, 0.0f, 1.0f); glm::mat4 light_view_matrix = glm::lookAt(light_position, light_center, light_up); teapot.matrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.5f, 0.0f)); floor.matrix = glm::scale(glm::mat4(1.0f), glm::vec3(2.0f, 0.05f, 2.0f)); plane.matrix = glm::scale(glm::mat4(1.0f), glm::vec3(screen_width, screen_height, 1.0f)); //--- Render glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_handle); { __projection_matrix = glm::perspective(30.0f, (float) screen_width / (float) screen_height, 0.5f, 30.0f); __view_matrix = light_view_matrix; light_pov_matrix = bias * __projection_matrix * light_view_matrix; glClear(GL_DEPTH_BUFFER_BIT); glClearDepth(1.0f); glViewport(0, 0, depth_tex_width, depth_tex_height); teapot.shader_program = &render_buffer_shader; teapot.shader_program->bind(); render_object(teapot); teapot.shader_program->release(); floor.shader_program = &render_buffer_shader; floor.shader_program->bind(); render_object(floor); floor.shader_program->release(); } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); #ifdef DEPTH_BUFFER_DEBUG { __projection_matrix = glm::ortho(0.0f, (float)screen_width, 0.0f, (float)screen_height, 0.5f, 1.0f); __view_matrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -1.0f)); glDisable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glViewport(0, 0, screen_width, screen_height); plane.shader_program = &rect_shader; plane.shader_program->bind(); plane.shader_program->set_uniform_value("texture2", depth_tex_buffer.unit_id); render_object(plane); plane.shader_program->release(); glEnable(GL_DEPTH_TEST); } #endif #ifndef DEPTH_BUFFER_DEBUG { glCullFace(GL_BACK); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, screen_width, screen_height); __projection_matrix = glm::perspective(camera_fovy, (float) screen_width / (float) screen_height, 1.0f, 30.0f); __view_matrix = view_matrix * glm::mat4_cast(camera_rotation.orientation); #ifdef USE_BUMP_MAPPING teapot.shader_program = &bump_shader; teapot.shader_program->bind(); teapot.shader_program->set_uniform_value("light_world_position", light_position); teapot.shader_program->set_uniform_value("surface_color", glm::vec3(0.7f, 0.6f, 0.18f)); teapot.shader_program->set_uniform_value("bump_density", 16.0f); teapot.shader_program->set_uniform_value("bump_size", 0.15f); teapot.shader_program->set_uniform_value("specular_factor", 0.5f); render_object(teapot); teapot.shader_program->release(); #else teapot.shader_program = &phong_shader; teapot.shader_program->bind(); teapot.shader_program->set_uniform_value("light_world_position", light_position); teapot.shader_program->set_uniform_value("light_pov_matrix", light_pov_matrix); teapot.shader_program->set_uniform_value("texture1", tex.unit_id); teapot.shader_program->set_uniform_value("texture2", depth_tex_buffer.unit_id); render_object(teapot); teapot.shader_program->release(); #endif floor.shader_program = &phong_shader; floor.shader_program->bind(); floor.shader_program->set_uniform_value("light_world_position", light_position); floor.shader_program->set_uniform_value("light_pov_matrix", light_pov_matrix); floor.shader_program->set_uniform_value("texture2", depth_tex_buffer.unit_id); render_object(floor); floor.shader_program->release(); } #endif glfwSwapBuffers(); } while (glfwGetKey(GLFW_KEY_ESC) != GLFW_PRESS && glfwGetWindowParam(GLFW_OPENED)); glfwTerminate(); return 0; }