我正在使用C++和现代OpenGL(3.3)开发3D游戏.我现在正致力于光照和阴影渲染,并且我已经成功实现了方向阴影贴图.在阅读了游戏要求后,我决定要点光影映射.在做了一些研究之后,我发现要做全向阴影贴图,我会做类似于定向阴影贴图的事情,但是使用立方体贴图.
我以前没有立方体贴图的知识,但我对它们的理解是立方体贴图是六个纹理,无缝连接.我做了一些环顾四周但不幸的是我很难找到关于现代OpenGL主题的权威"教程".我首先寻找教程,从头到尾解释它,因为我认真地努力学习源代码片段或概念,但我尝试过.
以下是我对这个想法的一般理解,减去技术性.请指正.
glBindTexture(GL_TEXTURE_CUBE_MAP, shadowmap).立方体贴图使用以下属性设置:
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Run Code Online (Sandbox Code Playgroud)(这也类似于定向阴影贴图)
现在glTexImage2D()迭代六次,每次面部一次.我这样做:
for (int face = 0; face < 6; face++) // Fill each face of the shadow cubemap
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_DEPTH_COMPONENT32F , 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
Run Code Online (Sandbox Code Playgroud)通过调用将纹理附加到帧缓冲区
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowmap, 0);
Run Code Online (Sandbox Code Playgroud)当要渲染场景时,它将以两个过程渲染,如定向阴影贴图.
glCullFace(GL_FRONT)计算所有六个视图的光视图矩阵.我是通过创建glm :: mat4和push_back()矩阵的向量来实现的,如下所示:
// Create the six view matrices …Run Code Online (Sandbox Code Playgroud)我遇到了背面(光线)和阴影贴图的问题,我似乎无法通过.我仍处于优化引擎的相对早期阶段,但是我似乎无法实现这一点,即使手动调整这一块几何形状,它仍然看起来像垃圾.
它是一个瘦墙,通过约5个不同的墙块"弯曲".当我创建我的深度图时,我正在剔除前脸(对光线).这肯定有帮助,但是墙的另一侧的正面似乎是导致z战斗/投射阴影.

截图上的一些注释:
正如这里提到的那样,你得出的结论是,你不应该遮住光线背面的多边形.我正在努力解决这个问题,因为我不想将面法线一直传递到片段着色器以排除那里真正的背面 - 但是如果有人觉得这是最好的/唯一的解决方案这种几何形状就是我必须要做的.考虑到管道如何不容易/明显地通过面法线通过它让我觉得这不是阻力最小的路径.请注意,我传递的法线是顶点法线,以允许边缘周围更柔和的光照效果(可能包括非阴影和阴影表面).
请注意,我有一些讨厌的透视别名,但我希望我接下来的步骤是在级联阴影贴图上工作,但是如果不解决这个问题,我觉得我只是推迟了不可避免的事情,因为我已经把视图作为手工收紧了我能做到最好(或者我认为).
无论如何我觉得我错过了什么,所以如果你有任何想法或帮助,将非常感激!
编辑
需要明确的是,根据光线的来源,墙壁在技术上不应该是阴影.

下面是阴影关闭的图像.这只是使用顶点法线来计算漫反射光照 - 它不漂亮(太多几何体是可见的),但它确实显示某些边缘有些可见.

所以是的,墙应该在阴影中,但我希望我可以让平滑效果更好,所以边缘可以有一些漫射光.如果我需要将它完全放在阴影中,那么如果它的阴影贴图将它置于阴影中,或者我的代码专门将它置于阴影中,因为面部法线不在,我对此很好 - 但将面部正常通过到我的顶点/片段着色器似乎不是阻力最小的路径.
也许这些将有助于更好地说明我的问题,或者可能揭示我缺少的一些基本理解.
编辑#2
我在下面加入了深度纹理.你可以在左下方看到有问题的墙,从截图中你可以看到我如何将深度值修剪为~0.4-> 1.这意味着该墙的深度值从0.4范围开始.所以它没有完美地剪裁它,但它的接近.这看起来合情合理吗?我很确定它是一个完整的24或32位深度缓冲区,是iOS上的DEPTH_COMPONENT扩展.对于@starmole,这有助于确定我的投影中是否存在缩放误差?你认为我的地图覆盖的尺寸/面积是否太大,因此如果它靠近它可能有帮助吗?

我已经实现了基本的阴影映射算法,但只使用一个灯就能正常工作.
我想渲染一个带有以下两个点光源的场景:
如果我单独渲染两个灯,我会得到以下结果:
使用Light_1渲染:

使用Light_2渲染:

但两者合起来看起来像这样:

正如您所看到的,第一个阴影似乎正确渲染,但它低于light_2的阴影,这是不正确的.总结一下情况,我的盒子纹理与纹理单元0绑定.阴影深度纹理从纹理单元1绑定,如果有多个深度纹理(所以至少有两个ligths,如这个例子),绑定到纹理单元1 + 1(GL_TEXTURE1 + 1).这是代表我所说的代码:
for (int idy = 0; idy < this->m_pScene->getLightList().size(); idy++)
[...]
Light *light = this->m_pScene->getLightList()[idy];
FrameBuffer *frameBuffer = light->getFrameBuffer();
glActiveTexture(GL_TEXTURE1 + idy);
glBindTexture(GL_TEXTURE_2D, frameBuffer->getTexture()->getTextureId()); //To unbind
shaderProgram->setUniform(std::string("ShadowMatrix[").append(Convertor::toString<int> (idy)).append("]").c_str(), this->m_pScene->getLightList()[idy]->getBiasViewPerspectiveMatrix() * modelMatrix);
shaderProgram->setUniform(std::string("ShadowMap[").append(Convertor::toString<int>(idy)).append("]").c_str(), (int)idy + 1);
Run Code Online (Sandbox Code Playgroud)
在我们的案例中它对应于:
shaderProgram->setUniform("ShadowMatrix[0]", <shadow_matrix_light_1>);
shaderProgram->setUniform("ShadowMap[0]", 1); (GL_TEXTURE1)
shaderProgram->setUniform("ShadowMatrix[1]", <shadow_matrix_light_2>);
shaderProgram->setUniform("ShadowMap[1]", 2); (GL_TEXTURE2)
Run Code Online (Sandbox Code Playgroud)
顶点着色器如下(仅适用于2个灯光):
#version 400
#define MAX_SHADOW_MATRIX 10
#define MAX_SHADOW_COORDS 10
layout (location = 0) in vec4 VertexPosition;
layout (location …Run Code Online (Sandbox Code Playgroud) 我所在的快速背景(确保我们在同一页面上,如果我失踪/假设有些愚蠢的话,进行健全检查):
这是我目前正在做的事情:
在我最终渲染过程的片段着色器(实际计算最终碎片值的那个)中,我从光源的角度来看传递的MVP矩阵,来自所述传递的深度纹理(又名"阴影贴图"),和我的几何缓冲区中的位置/法线/颜色纹理.
据我所知,我需要找到当前片段位置对应的阴影贴图的UV.我通过以下方式做到这一点:
//Bring position value at fragment (in world space) to screen space from lights POV
vec4 UVinShadowMap = (lightProjMat * lightViewMat * vec4(texture(pos_tex, UV).xyz,1.0)).xy;
//Convert screen space to 'texture space' (from -1to1 to 0to1)
UVinShadowMap = (UVinShadowMap+1)/2;
Run Code Online (Sandbox Code Playgroud)
现在我已经拥有了这个紫外线,我可以从光的pov中获得深刻的"深度"
float depFromLightPOV = texture2D(shadowMap, UVinShadowMap).r;
Run Code Online (Sandbox Code Playgroud)
并将其与当前片段的位置与光线之间的距离进行比较:
float actualDistance = distance(texture2D(pos_tex, UV).xyz, lightPos);
Run Code Online (Sandbox Code Playgroud)
问题来自于"深度"存储在值0-1中,实际距离是世界坐标.我试图手动进行转换,但无法让它工作.在网上搜索,看起来像我应该这样做的方式是使用sampler2DShadow ......
所以这是我的问题:
我需要做什么改变才能使用shadow2D?shadow2D甚至做了什么?它只是或多或少的自动转换 - 从深度到世界的纹理?我可以使用相同的深度纹理吗?或者我需要以不同的方式渲染深度纹理?我将什么传递给shadow2D?我想检查片段的世界空间位置?或者和以前一样的紫外线?
如果所有这些问题都可以在一个简单的文档页面中得到解答,我很乐意,如果有人可以发布这个问题.但我发誓,我一直在寻找几个小时,找不到任何简单的说什么与shadow2D发生了什么!
谢谢!
我正在使用CML和使用SFML的OpenGL 3.2开发3D游戏.我一直在努力实现点光影映射.到目前为止,我所做的似乎符合我所学到的和我见过的例子,但仍然没有阴影.
我所做的是按照我使用它的确切顺序编写一个简单的所有代码列表,但不是完整的源代码,只有相关的代码(因为我的项目分为几个类):
Omnidirectional shadow mapping
C++
- Initialization
-- Use shadow pass shader program
-- Generate + bind the shadow frame buffer
glGenFramebuffers(1, &shadowFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, shadowFrameBuffer);
-- Generate a texture
glGenTextures(1, &shadowMap);
-- Bind texture as cubemap
glBindTexture(GL_TEXTURE_CUBE_MAP);
-- Set texture parameters
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);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-- Generate empty 1024 x 1024 for every face of the cube
for (int face = 0; face < 6; …Run Code Online (Sandbox Code Playgroud) 我已经创建了一个自定义着色器,可以使用具有4种不同纹理的BlendMap,但我无法使用阴影/闪电效果来处理它.
我在这里错过了什么?或者是否有其他方法可以实现相同的功能?
下面的网格创建方法显示所有纹理正确混合.
// Creates the ground
function CreateGround() {
var uniforms = THREE.UniformsUtils.merge([
THREE.UniformsLib["lights"],
THREE.UniformsLib["shadowmap"],
{
TextureBackground: { type: "t", value: null },
TextureR: { type: "t", value: null },
TextureG: { type: "t", value: null },
TextureB: { type: "t", value: null },
TextureBlendMap: { type: "t", value: null }
}]);
var shaderMaterial;
try {
shaderMaterial = new THREE.ShaderMaterial({
lights: true,
uniforms: uniforms,
vertexShader: BlendMapVertexShader,
fragmentShader: BlendMapFragmentShader
});
} catch (e) {
alert("Error 'CreateGround' : GPU Shader couldn't …Run Code Online (Sandbox Code Playgroud) shader vertex-shader fragment-shader three.js shadow-mapping
据我所知,阴影映射是通过从光的角度渲染场景来创建深度图来完成的.然后,您从摄像机的POV重新渲染场景,并为场景中的每个点(GLSL中的片段)计算从那里到光源的距离; 如果它与阴影贴图中的相匹配,那么它就在光线下,否则它就在阴影中.
我只是阅读本教程,以了解如何使用点/全向光进行阴影贴图.
根据第12.2.2节,它说:
我们为所有光源使用单个阴影贴图
然后根据12.3.6说:
1)计算从当前像素到光源的平方距离.
...
4)将计算出的距离值与获取的阴影贴图值进行比较,以确定我们是否处于阴影中.
这大致与我上面所述的相同.
我没有得到的是,如果我们将所有灯光都烘焙成一张阴影贴图,那么我们需要将哪些灯光与之比较?烘焙到地图上的距离不应该与任何东西相对应,因为它是所有灯光的混合,不是吗?
我确定我错过了一些东西,但希望有人可以向我解释.
此外,如果我们使用单个阴影贴图,我们如何将其混合用于所有光源?
对于单个光源,阴影贴图仅存储最近物体与光的距离(即深度图),但对于多个光源,它包含什么?
我一直在尝试实现阴影贴图.虽然我认为我现在已经接近了,但我已经陷入了一种奇怪的效果(如下图所示):

如您所见,阴影区域显得太小.对立方体本身也有不寻常的影响.
正在渲染的几何体是尺寸为100.0的方形平面上的尺寸为1.0的立方体.场景包含一个聚光灯,其角度(从一侧到另一侧)为0.5弧度,范围为100.0.该聚光灯围绕y轴旋转并调整其旋转以查看原点.
我设置了帧缓冲和深度纹理(512 x 512),如下所示:
// Create and configure the depth texture.
glGenTextures(1, &m_depthTexture);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
GLfloat border[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, (void*)0);
// Assign the depth texture to texture channel 0.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
// Create and configure the framebuffer.
glGenFramebuffers(1, &m_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, …Run Code Online (Sandbox Code Playgroud) 我一直在阅读阴影贴图,并找到了以下教程:
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/
直到作者开始讨论"阴影痤疮"神器时,我才有意义.他们用下图解释原因(没有文字):

我仍然很难理解究竟是什么原因导致阴影痤疮以及为什么添加偏见会修复它.
似乎阴影贴图的分辨率对痤疮没有影响.之后怎么样了?也许漂浮精度,还是别的?
我正在尝试制作基本的阴影贴图,但是由于某些原因,它无法正确渲染。
我使用平面着色器渲染房屋:
int shadowMapWidth = WINDOW_SIZE_X * (int)SHADOW_MAP_RATIO;
int shadowMapHeight = WINDOW_SIZE_Y * (int)SHADOW_MAP_RATIO;
// Rendering into the shadow texture.
glActiveTexture(GL_TEXTURE0);
CALL_GL(glBindTexture(GL_TEXTURE_2D, shadowTexture));
// Bind the framebuffer.
CALL_GL(glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO));
//Clear it
CALL_GL(glClear(GL_DEPTH_BUFFER_BIT));
CALL_GL(glViewport(0, 0, shadowMapWidth, shadowMapHeight));
CALL_GL(glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
//Render stuff
flatShader.use();
flatShader["baseColor"] = glm::vec4(1.0f,1.0f,1.0f,1.0f);
flatShader["pvm"] = projectionMatrix*pointLight.viewMatrix*cursor.modelMatrix;
cursor.draw(); //binds the vao and draws
// Revert for the scene.
CALL_GL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
CALL_GL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
CALL_GL(glViewport(0, 0, WINDOW_SIZE_X, WINDOW_SIZE_Y));
Run Code Online (Sandbox Code Playgroud)
注意,我只渲染房子。我不在深度缓冲通道中渲染地板。
接下来,我使用以下着色器对渲染表示地板的四边形:
/* [VERT] */
#version 330
in vec3 …Run Code Online (Sandbox Code Playgroud)