昨晚終于把點陰影(深度CubeMap)程式調通了,思想不難,基本就是在上節定向光陰影基礎上稍作修改,但是CG程式不太方便Debug,需要輸出中間效果圖進行判斷,耽擱了一會兒,
程序如下:
1、將深度渲染到CubeMap上
為了以后使用方便,在Texture檔案中擴展功能,添加一個生成CubeMap的函式
GLuint WKS::CubeMap::GenDepthCubeMap(GLuint width, GLuint height) { glGenTextures(1, &this->textureID); glBindTexture(GL_TEXTURE_CUBE_MAP, this->textureID); for (GLuint i = 0; i < 6; i++) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); } glBindTexture(GL_TEXTURE_CUBE_MAP, 0); return this->textureID; }
同樣為了以后方便,在DefferredShading檔案中擴展功能,添加附加深度CubeMap到幀緩沖的函式
(注:暫時遇到一點奇怪的問題,同時添加顏色緩沖紋理和2D深度緩沖紋理(或深度緩沖物件RBO)是沒有問題的,但是如果是深度CubeMap,同時再添加顏色緩沖紋理就會報錯,現在沒找到解決辦法,不過做陰影渲染只需要深度CubeMap,額……)
void DeferredShading::setupDepthBufferByCubeMap(GLuint texId) { this->BindGBuffer(); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texId, 0); //檢查幀緩沖是否完整 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) std::cout << "ERROR::FRAMEBUFFER:: Depth CubeMap is not added to FrameBuffer correctly!" << std::endl; else std::cout << "Successful:: Depth CubeMap is added to FrameBuffer correctly" << std::endl; this->BindDefaultBuffer(); }
既然渲染深度到CubeMap,那么就需要6個方向的view矩陣,并傳入shader,故新建了個ShadowMap檔案完成這些操作,
//ShadowMap.h #pragma once #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include "../BaseFile/Shader.h" class ShadowMap { public: ShadowMap(); ~ShadowMap(); void updateLightSpaceMatrix(glm::vec3 lightPos); void transmitMat2Shader(Shader* shader); private: void setup(); private: glm::mat4 shadowProj; std::vector<glm::mat4> shadowTransforms; };
//ShadowMap.cpp #include "./ShadowMap.h" ShadowMap::ShadowMap() { this->setup(); } ShadowMap::~ShadowMap() { } void ShadowMap::setup() { this->shadowProj = glm::perspective(glm::radians(90.0f), 800.0f / 800, 1.0f, 100.0f); } void ShadowMap::updateLightSpaceMatrix(glm:: vec3 lightPos) { this->shadowTransforms.clear(); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0))); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0))); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, 1.0))); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, -1.0, 0.0), glm::vec3(0.0, 0.0, -1.0))); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 0.0, 1.0), glm::vec3(0.0, -1.0, 0.0))); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 0.0, -1.0), glm::vec3(0.0, -1.0, 0.0))); } void ShadowMap::transmitMat2Shader(Shader* shader) { shader->use(); for (int i = 0; i < 6; i++) { std::string name = "shadowMatrices["+std::to_string(i)+"]"; shader->setMat4(name, this->shadowTransforms[i]); } }
現在來看看著色器咋樣的^_^
我們不必在 OpenGL 程式中控制 View ,渲染六遍,將六個方向的深度分別渲染到 CubeMap 的各個面上,幾何著色器可以幫助完成這一點,幾何著色器中有一個內建變數 gl_Layer ,可以控制當前渲染的圖元輸出到CubeMap哪一個面,故我們只需要將每個圖元在幾何著色器中渲染六次,且每次指定輸出到一個面,當然得配合傳入的對應的 view * projection 矩陣,這樣就實作渲染六個方向的深度到CubeMap,
- 頂點著色器:只需將頂點坐標變換到世界坐標(乘以 model matrix),輸出到幾何著色器,
#version 330 core layout (location = 0) in vec3 position; uniform mat4 model; void main() { gl_Position = model * vec4(position, 1.0); }
- 幾何著色器:需要傳入六個view*projection矩陣,通過 gl_Layer 內建變數生成每個方向的深度圖,
#version 330 core layout (triangles) in; layout (triangle_strip, max_vertices=18) out; uniform mat4 shadowMatrices[6]; out vec4 FragPos; // FragPos from GS (output per emitvertex) void main() { for(int face = 0; face < 6; ++face) { gl_Layer = face; // built-in variable that specifies to which face we render. for(int i = 0; i < 3; ++i) // for each triangle's vertices { FragPos = gl_in[i].gl_Position; gl_Position = shadowMatrices[face] * FragPos; EmitVertex(); } EndPrimitive(); } }
- 片段著色器:傳入光源位置、遠平面距離,計算 當前片元到光源的距離 / 遠平面距離,輸出到深度值,
#version 330 core in vec4 FragPos; uniform vec3 lightPos; uniform float far_plane; void main() { // get distance between fragment and light source float lightDistance = length(FragPos.xyz - lightPos); // map to [0;1] range by dividing by far_plane lightDistance = lightDistance / far_plane; // write this as modified depth gl_FragDepth = lightDistance; }
這樣就完成了深度CubeMap生成,
為了測驗深度CubeMap是否正確,可以用天空盒的方式顯示生成的CubeMap,
當然了也可以在后續的渲染陰影中,用采樣CubeMap的深度值代替顏色值顯示深度,這樣還可以稍作修改顯示實際的深度值(當前片元與光源的距離值),兩者直接對比,可以檢測第一步(First Pass)是否有問題,
展示一下我實作的采樣CubeMap深度值顯示(左圖)與 實際深度值顯示(右圖)的對比:

2、使用深度CubeMap渲染全方位陰影
這一部分就很簡單了,很往常渲染基本一樣,只需要添加陰影判斷,
在片段著色器中傳入深度CubeMap:
uniform samplerCube shadowMap;
計算當前的片元的深度,并判斷是否在陰影中:
float ShadowCalculation(vec3 fragPos) { vec3 light2Frag=fragPos-spotLight.position; float closestDepth = texture(shadowMap, light2Frag).r; closestDepth*=far_plane; float currentDepth=length(light2Frag); float shadow = currentDepth-0.05f > closestDepth ? 1.0 : 0.0; return shadow; }
使用這個陰影判斷值計算光照值:
color=vec4(result*(1.0f-shadow)+ambient,1.0f);
效果圖:

OK,至此完成了Shadow Map的總結啦 ^_^,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/2089.html
標籤:其他
上一篇:實作一個簡單的解釋器(4)
下一篇:DOS下查看驅動版本號
