如何正确制作阴影贴图的深度立方体贴图?
我已编写代码将我的场景对象渲染为格式为GL_DEPTH_COMPONENT的立方体贴图纹理,然后在着色器中使用此纹理来确定片段是否被直接点亮,以用于阴影目的.但是,我的立方体贴图看起来像黑色.我想我没有充分设置我的FBO或渲染上下文,但没有看到缺少的内容.
在兼容性配置文件中使用GL 3.3. 这是我创建FBO和立方体贴图纹理的代码: glGenFramebuffers(1,&fboShadow); glGenTextures(1,&texShadow); glBindTexture(GL_TEXTURE_CUBE_MAP,texShadow); for (int sideId = 0; sideId < 6; sideId++) { // Make sure GL knows what this is going to be. glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + sideId,GL_DEPTH_COMPONENT,512,GL_FLOAT,NULL); } // Don't interpolate depth value sampling. Between occluder and occludee there will // be an instant jump in depth value,not a linear transition. glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_T,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_CUBE_MAP,0); 我的完整渲染功能如下所示: void render() { // --- MAKE DEPTH CUBEMAP --- // Set shader program for depth testing glUseProgram(progShadow); // Get the light for which we want to generate a depth cubemap PointLight p = pointLights.at(0); // Bind our framebuffer for drawing; clean it up glBindFramebuffer(GL_DRAW_FRAMEBUFFER,fboShadow); glClear(GL_DEPTH_BUFFER_BIT); // Make 1:1-ratio,90-degree view frustum for a 512x512 texture. glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(90.0,1,16.0,16384.0); glViewport(0,512); glMatrixMode(GL_MODELVIEW); // Set modelview and projection matrix uniforms setShadowUniforms(); // Need 6 renderpasses to complete each side of the cubemap for (int sideId = 0; sideId < 6; sideId++) { // Attach depth attachment of current framebuffer to level 0 of currently relevant target of texShadow cubemap texture. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_CUBE_MAP_POSITIVE_X + sideId,texShadow,0); // All is fine. GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { std::cout << "Shadow FBO is broken with code " << status << std::endl; } // Push modelview matrix stack because we need to rotate and move camera every time glPushMatrix(); // This does a switch-case with glRotatefs rotateCameraForSide(GL_TEXTURE_CUBE_MAP_POSITIVE_X + sideId); // Render from light's position. glTranslatef(-p.getX(),-p.getY(),-p.getZ()); // Render all objects. for (ObjectList::iterator it = objectList.begin(); it != objectList.end(); it++) { (*it)->render(); } glPopMatrix(); } // --- RENDER SCENE --- // Bind default framebuffer glBindFramebuffer(GL_FRAMEBUFFER,0); // Setup proper projection matrix with 70 degree vertical FOV and ratio according to window frame dimensions. glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(70.0,((float)vpWidth) / ((float)vpHeight),vpWidth,vpHeight); glUseProgram(prog); glMatrixMode(GL_MODELVIEW); glPushMatrix(); applyCameraPerspective(); // My PointLight class has both a position (world space) and renderPosition (camera space) Vec3f variable; // The lights' renderPositions get transformed with the modelview matrix by this. updateLights(); // And here,among other things,the lights' camera space coordinates go to the shader. setUniforms(); // Render all objects for (ObjectList::iterator it = objectList.begin(); it != objectList.end(); it++) { // Object texture goes to texture unit 0 GLuint usedTexture = glTextureList.find((*it)->getTextureName())->second; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,usedTexture); glUniform1i(textureLoc,0); // Cubemap goes to texture unit 1 glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_CUBE_MAP,texShadow); glUniform1i(shadowLoc,1); (*it)->render(); } glPopMatrix(); frameCount++; } 用于渲染深度值的着色器程序(“progShadow”)很简单. 顶点着色器: #version 330 in vec3 position; uniform mat4 modelViewMatrix,projectionMatrix; void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1); } 片段着色器: #version 330 void main() { // OpenGL sets the depth anyway. Nothing to do here. } 最终渲染的着色器程序(“prog”)有一个片段着色器,看起来像这样: #version 330 #define MAX_LIGHTS 8 in vec3 fragPosition; in vec3 fragNormal; in vec2 fragTexCoordinates; out vec4 fragColor; uniform sampler2D colorTexture; uniform samplerCubeShadow shadowCube; uniform uint activeLightCount; struct Light { vec3 position; vec3 diffuse; float cAtt; float lAtt; float qAtt; }; // Index 0 to (activeLightCount - 1) need to be the active lights. uniform Light lights[MAX_LIGHTS]; void main() { vec3 lightColor = vec3(0,0); vec3 normalFragmentToLight[MAX_LIGHTS]; float distFragmentToLight[MAX_LIGHTS]; float distEyeToFragment = length(fragPosition); // Accumulate all light in "lightColor" variable for (uint i = uint(0); i < activeLightCount; i++) { normalFragmentToLight[i] = normalize(lights[i].position - fragPosition); distFragmentToLight[i] = distance(fragPosition,lights[i].position); float attenuation = (lights[i].cAtt + lights[i].lAtt * distFragmentToLight[i] + lights[i].qAtt * pow(distFragmentToLight[i],2.0)); float dotProduct = dot(fragNormal,normalFragmentToLight[i]); lightColor += lights[i].diffuse * max(dotProduct,0.0) / attenuation; } // Shadow mapping only for light at index 0 for now. float distOccluderToLight = texture(shadowCube,vec4(normalFragmentToLight[0],1)); // My geometries use inches as units,hence a large bias of 1 bool isLit = (distOccluderToLight + 1) < distFragmentToLight[0]; fragColor = texture2D(colorTexture,fragTexCoordinates) * vec4(lightColor,1.0f) * int(isLit); } 我已经验证所有均匀位置变量都设置为适当的值(即不是-1). 值得注意的是,在链接之前我没有为“progShadow”调用glBindFragDataLocation(),因为该着色器不应该写入颜色值. 看到任何明显错误的地方? 解决方法
对于阴影贴图,深度缓冲内部格式非常重要(太小而且看起来很糟糕,太大而你吃内存带宽).您应该使用大小的格式(例如GL_DEPTH_COMPONENT24)来保证一定的大小,否则实现将选择它想要的任何内容.至于调试立方体贴图阴影贴图,最简单的做法是将场景绘制到每个立方体面并输出颜色而不是深度.然后,在当前尝试使用立方体贴图来采样深度的位置,将采样的颜色写入fragColor.您可以通过这种方式立即排除查看问题.
然而,还有一个更严重的问题.您正在使用samplerCubeShadow,但尚未为立方体贴图设置GL_TEXTURE_COMPARE_MODE.尝试使用此采样器类型从深度纹理进行采样并且没有GL_TEXTURE_COMPARE_MODE = GL_COMPARE_REF_TO_TEXTURE将产生未定义的结果.即使您确实正确设置了此模式,纹理坐标的第4个组件也会用作深度比较参考 – 常量值1.0不是您想要的. 同样,深度缓冲区不存储线性距离,您无法直接比较此处计算的距离: distFragmentToLight[i] = distance(fragPosition,lights[i].position); 相反,这样的事情是必要的: float VectorToDepth (vec3 Vec) { vec3 AbsVec = abs(Vec); float LocalZcomp = max(AbsVec.x,max(AbsVec.y,AbsVec.z)); // Replace f and n with the far and near plane values you used when // you drew your cube map. const float f = 2048.0; const float n = 1.0; float NormZComp = (f+n) / (f-n) - (2*f*n)/(f-n)/LocalZcomp; return (NormZComp + 1.0) * 0.5; } float LightDepth = VectorToDepth (fragPosition - lights [i].position); float depth_compare = texture(shadowCube,LightDepth)); *浮动VectorToDepth(vec3 Vec)的代码从Omnidirectional shadow mapping with depth cubemap借来 现在depth_compare将是介于0.0(完全在阴影中)和1.0(完全没有阴影)之间的值.如果启用了线性纹理过滤,硬件将在4个点采样深度,并可能为您提供2×2 PCF过滤的形式.如果您有最近的纹理过滤,那么它将是1.0或0.0. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |