gpt4 book ai didi

c++ - OpenGL 阴影贴图 - 阴影贴图纹理根本没有被采样?

转载 作者:太空宇宙 更新时间:2023-11-04 12:56:23 24 4
gpt4 key购买 nike

我目前正在处理一个 OpenGL 项目,我正试图让阴影贴图正常工作。我可以达到将阴影贴图渲染成纹理的程度,但渲染时它似乎并未应用于风景。这是我的代码中最重要的部分:

阴影贴图顶点着色器,基本上是一个简单的直通着色器(也做一些额外的事情,比如法线,但这不应该让你分心);它基本上只是变换顶点,以便从光的角度看到它们(它是定向光,但由于我们需要假设一个位置,它基本上是一个很远的点):

#version 430 core

layout(location = 0) in vec3 v_position;
layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec3 v_texture;
layout(location = 3) in vec4 v_color;

out vec3 f_texture;
out vec3 f_normal;
out vec4 f_color;

uniform mat4 modelMatrix;
uniform mat4 depthViewMatrix;
uniform mat4 depthProjectionMatrix;

// Shadow map vertex shader.
void main() {
mat4 mvp = depthProjectionMatrix * depthViewMatrix * modelMatrix;
gl_Position = mvp * vec4(v_position, 1.0);

// Passing attributes on to the fragment shader
f_texture = v_texture;
f_normal = (transpose(inverse(modelMatrix)) * vec4(v_normal, 1.0)).xyz;
f_color = v_color;
}

将深度值写入纹理的阴影贴图片段着色器:

#version 430 core

layout(location = 0) out float fragmentDepth;

in vec3 f_texture;
in vec3 f_normal;
in vec4 f_color;

uniform vec3 lightDirection;
uniform sampler2DArray texSampler;

// Shadow map fragment shader.
void main() {
fragmentDepth = gl_FragCoord.z;
}

实际渲染场景的顶点着色器,但也从灯光的角度(阴影坐标)计算当前顶点的位置,以与深度纹理进行比较;它还应用偏置矩阵,因为坐标不在正确的 [0, 1] 采样间隔中:

#version 430 core

layout(location = 0) in vec3 v_position;
layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec3 v_texture;
layout(location = 3) in vec4 v_color;

out vec3 f_texture;
out vec3 f_normal;
out vec4 f_color;
out vec3 f_shadowCoord;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

uniform mat4 depthViewMatrix;
uniform mat4 depthProjectionMatrix;

// Simple vertex shader.
void main() {
mat4 mvp = projectionMatrix * viewMatrix * modelMatrix;
gl_Position = mvp * vec4(v_position, 1.0);


// This bias matrix adjusts the projection of a given vertex on a texture to be within 0 and 1 for proper sampling
mat4 depthBias = mat4(0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0);

mat4 depthMVP = depthProjectionMatrix * depthViewMatrix * modelMatrix;
mat4 biasedDMVP = depthBias * depthMVP;

// Passing attributes on to the fragment shader
f_shadowCoord = (biasedDMVP * vec4(v_position, 1.0)).xyz;
f_texture = v_texture;
f_normal = (transpose(inverse(modelMatrix)) * vec4(v_normal, 1.0)).xyz;
f_color = v_color;
}

应用纹理数组中的纹理并接收深度纹理(统一采样器 2D shadowMap)并检查片段是否在某物后面的片段着色器:

#version 430 core

in vec3 f_texture;
in vec3 f_normal;
in vec4 f_color;
in vec3 f_shadowCoord;

out vec4 color;

uniform vec3 lightDirection;
uniform sampler2D shadowMap;
uniform sampler2DArray tileTextureArray;

// Very basic fragment shader.
void main() {
float visibility = 1.0;
if (texture(shadowMap, f_shadowCoord.xy).z < f_shadowCoord.z) {
visibility = 0.5;
}

color = texture(tileTextureArray, f_texture) * visibility;
}

最后:渲染多个 block 以生成阴影贴图然后渲染应用了阴影贴图的场景的函数:

// Generating the shadow map
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);

m_shadowShader->bind();
glViewport(0, 0, 1024, 1024);
glDisable(GL_CULL_FACE);

glm::vec3 lightDir = glm::vec3(1.0f, -0.5f, 1.0f);
glm::vec3 sunPosition = FPSCamera::getPosition() - lightDir * 64.0f;
glm::mat4 depthViewMatrix = glm::lookAt(sunPosition, FPSCamera::getPosition(), glm::vec3(0, 1, 0));
glm::mat4 depthProjectionMatrix = glm::ortho<float>(-100.0f, 100.0f, -100.0f, 100.0f, 0.1f, 800.0f);

m_shadowShader->setUniformMatrix("depthViewMatrix", depthViewMatrix);
m_shadowShader->setUniformMatrix("depthProjectionMatrix", depthProjectionMatrix);

for (Chunk *chunk : m_chunks) {
m_shadowShader->setUniformMatrix("modelMatrix", chunk->getModelMatrix());
chunk->drawElements();
}

m_shadowShader->unbind();
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// Normal draw call
m_chunkShader->bind();
glEnable(GL_CULL_FACE);
glViewport(0, 0, Window::getWidth(), Window::getHeight());
glm::mat4 viewMatrix = FPSCamera::getViewMatrix();
glm::mat4 projectionMatrix = FPSCamera::getProjectionMatrix();

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glActiveTexture(GL_TEXTURE1);
m_textures->bind();
m_chunkShader->setUniformMatrix("depthViewMatrix", depthViewMatrix);
m_chunkShader->setUniformMatrix("depthProjectionMatrix", depthProjectionMatrix);
m_chunkShader->setUniformMatrix("viewMatrix", viewMatrix);
m_chunkShader->setUniformMatrix("projectionMatrix", projectionMatrix);
m_chunkShader->setUniformVec3("lightDirection", lightDir);
m_chunkShader->setUniformInteger("shadowMap", 0);
m_chunkShader->setUniformInteger("tileTextureArray", 1);

for (Chunk *chunk : m_chunks) {
m_chunkShader->setUniformMatrix("modelMatrix", chunk->getModelMatrix());
chunk->drawElements();
}

大部分代码应该是不言自明的,我绑定(bind)了一个附加了纹理的 FBO,我们对帧缓冲区进行了正常的渲染调用,它被渲染成纹理,然后我试图将它传递到正常渲染的着色器。我已经测试了纹理是否正确生成并且确实如此:请在此处查看生成的阴影贴图
See the generated shadow map here

然而,在渲染场景时,我看到的就是这个。
this
没有应用阴影,可见度到处都是 1.0。我还使用了一个调试上下文,它可以正常工作并在有任何错误时记录错误,但它似乎完全没问题,没有警告或错误,所以我在这里做了一些非常错误的事情。顺便说一下,我使用的是 OpenGL 4.3。

希望你们中的一个能帮我解决这个问题,我以前从来没有用过阴影贴图,这是我最接近的一次,哈哈。提前致谢。

最佳答案

通常 mat4 OpenGL 变换矩阵如下所示:

( X-axis.x, X-axis.y, X-axis.z, 0 )
( Y-axis.x, Y-axis.y, Y-axis.z, 0 )
( Z-axis.x, Z-axis.y, Z-axis.z, 0 )
( trans.x, trans.y, trans.z, 1 )

所以你的 depthBias 矩阵,你用来从规范化的设备坐标(在 [-1, 1] 范围内)转换为纹理坐标(在 [0, 1] 范围内),应该看起来像这个:

mat4 depthBias = mat4(0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0);

或者这个:

mat4 depthBias = mat4(
vec4( 0.5, 0.0, 0.0, 0.0 ),
vec4( 0.0, 0.5, 0.0, 0.0 ),
vec4( 0.0, 0.0, 0.5, 0.0 ),
vec4( 0.5, 0.5, 0.5, 1.0 ) );


通过模型矩阵、 View 矩阵和投影矩阵变换顶点位置后,顶点位置位于裁剪空间 ( homogeneous coordinates ) 中。您必须从剪辑空间转换为规范化设备坐标(范围 [-1, 1] 中的 cartesian coordinates)。这可以通过除以 homogeneous coordinatew 组件来完成。 :

mat4 depthMVP  = depthProjectionMatrix * depthViewMatrix * modelMatrix;
vec4 clipPos = depthMVP * vec4(v_position, 1.0);
vec4 ndcPos = vec4(clipPos.xyz / clipPos.w, 1.0);
f_shadowCoord = (depthBias * ndcPos).xyz;


深度纹理只有一个 channel 。如果您从深度纹理读取数据,则数据包含在 vector 的 x(或 r)分量中。

像这样调整片段着色器代码:

if ( texture(shadowMap, f_shadowCoord.xy).x < f_shadowCoord.z) 
visibility = 0.5;

Image Format Khronos 集团的规范说:

Image formats do not have to store each component. When the shader samples such a texture, it will still resolve to a 4-value RGBA vector. The components not stored by the image format are filled in automatically. Zeros are used if R, G, or B is missing, while a missing Alpha always resolves to 1.


进一步了解:


解决方案的补充:

这是解决方案的一个重要部分,但还需要另一个步骤来正确渲染阴影贴图。第二个错误是使用错误的纹理组件与 f_shadowCoord.z 进行比较:它应该是

texture(shadowMap, f_shadowCoord.xy).r

代替

texture(shadowMap, f_shadowCoord.xy).z

关于c++ - OpenGL 阴影贴图 - 阴影贴图纹理根本没有被采样?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46478178/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com