首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >即使阴影映射被正确呈现,阴影计算也是不正确的。

即使阴影映射被正确呈现,阴影计算也是不正确的。
EN

Stack Overflow用户
提问于 2022-08-08 21:55:33
回答 1查看 163关注 0票数 2

我试图渲染一个单一方向光源在Vulkan产生的基本阴影。

问题是,我得到的结果是没有意义的(至少对我来说)。

阴影映射输出

这是由呈现在世界空间中的四角体上的深度传递所产生的结果。

深度值似乎是正确的。由于右下角的几何部分被着色到更深的颜色,就像预期的那样,因为它们更接近光的视图。也没有出现任何精确性或裁剪问题。

用于呈现调试四角体的着色器代码如下:

代码语言:javascript
运行
复制
# VERT
#version 450 core

layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec2 a_UV;
layout(location = 2) in vec3 a_Normal;
layout(location = 3) in vec3 a_Tangent;
layout(location = 4) in vec3 a_Bitangent;

layout(location = 0) out vec2 v_UV;

layout(binding = 0) uniform ModelMat
{
    mat4 Matrix;
} Model;

layout(binding = 1) uniform ProjMatrix
{
    mat4 Matrix;
} Proj;

layout(binding = 2) uniform viewMatrix
{
    mat4 Matrix;
} View;

void main()
{
    v_UV = a_UV;
    gl_Position = Proj.Matrix * View.Matrix * Model.Matrix * vec4(a_Position, 1.0);
}

# FRAGMENT
#version 450 core

layout(location = 0) out vec4 FragColor;
layout(location = 0) in vec2 v_UV;

layout(binding = 3) uniform sampler2D depthMap;

void main()
{
    float depthValue = texture(depthMap, v_UV).r;
    //FragColor = vec4(vec3(depthValue), 1.0);
    if(depthValue < 1.0)
    {
        depthValue = (depthValue / 1.0) * 0.2;
    }
    FragColor =  vec4(vec3(depthValue, 0.0, 0.0), 1.0);
    
}

这里有几件事要注意:

  1. 除了"a_Position“和"a_UV”之外,没有使用其他属性,但无论如何,我都会将它们传递给着色器。晚些时候再做清理。我正试着让阴影先起作用。
  2. 我不是将MVP矩阵存储在一个单一的统一缓冲区中,而是单独传递它们。因为我不想传递矩阵,它不会一次又一次地改变每一个帧。

将阴影映射的最近深度值呈现到几何图形上

我已经尝试过从其他讨论中学到的一些调试技巧。

我将阴影映射中的采样值呈现到模型上,这为我提供了以下结果:

模型

从相反的角度。

从模型内部关闭。

  • 投影和视图矩阵:
代码语言:javascript
运行
复制
float near_plane = 20.0f;
float far_plane = 60.0f;
glm::mat4 lightView = glm::lookAt(directionalLightPosition, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 lightProjectionMatrix = glm::ortho(-40.0f, 40.0f, -40.0f, 40.0f, near_plane, far_plane);
  • 定向光定位:
代码语言:javascript
运行
复制
glm::vec3 directionalLightPosition = glm::vec3(30.0f, 30.0f, 30.0f);
  • 片段着色器(最接近深度值的输出):
代码语言:javascript
运行
复制
#version 430 core

// INs
layout(location = 0) in vec3 v_Pos;
layout(location = 1) in vec2 v_UV;
layout(location = 2) in vec3 v_Normal;
layout(location = 3) in vec4 v_FragPosLightSpace;
layout(location = 4) in vec3 v_DirLightPos;
layout(location = 5) in mat3 v_TBN;



layout(binding = 5) uniform CameraPosition
{
    vec3 pos;
} camPos;

layout(binding = 6) uniform PointLightPosition
{
    vec3 pos;
} pointLightPos;

layout(binding = 7) uniform sampler2D u_DiffuseSampler;
layout(binding = 8) uniform sampler2D u_NormalSampler;
layout(binding = 9) uniform sampler2D u_RoughnessMetallicSampler;
layout(binding = 10) uniform sampler2D u_DirectionalShadowMap;


layout(location = 0) out vec4 FragColor;
void main()
{
 // BLINN PHONG
    vec3 N = texture(u_NormalSampler, v_UV).rgb;
    N = N * 2.0 - 1.0;
    N = normalize(v_TBN * N);
    
    vec3 color = texture(u_DiffuseSampler, v_UV).rgb;
    vec3 normal = N;
    vec3 lightColor = vec3(0.3);
    // ambient
    vec3 ambient = 0.05 * lightColor;
    
    // diffuse
    vec3 lightDir = normalize(v_DirLightPos - v_Pos);
    float diff = max(dot(lightDir, normal), 0.0);
    vec3 diffuse = diff * lightColor;
    // specular
    vec3 viewDir = normalize(camPos.pos - v_Pos);
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = 0.0;
    vec3 halfwayDir = normalize(lightDir + viewDir);  
    spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
    vec3 specular = spec * lightColor;    
    // calculate shadow
    

    //SHADOW
    //vec3 projCoords = v_FragPosLightSpace.xyz / v_FragPosLightSpace.w;
    vec3 projCoords = v_FragPosLightSpace.xyz;
    vec3 altCoords = projCoords * 0.5 + 0.5;
    float closestDepth = texture(u_DirectionalShadowMap, altCoords.xy).r; 
    float bias = 0.005;
    float currentDepth = projCoords.z;
    float shadow = (currentDepth - bias) > closestDepth  ? 1.0 : 0.0;


    vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;    
    
    FragColor = vec4(vec3(closestDepth), 1.0);
}

好了!注意:取消注释行//vec3 projCoords = v_FragPosLightSpace.xyz / v_FragPosLightSpace.w;并注释掉行vec3 projCoords = v_FragPosLightSpace.xyz;使模型完全变成白色(1.0f深度)。

  • 弗特色德:
代码语言:javascript
运行
复制
#version 450

// INs
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec2 a_UV;
layout(location = 2) in vec3 a_Normal;
layout(location = 3) in vec3 a_Tangent;
layout(location = 4) in vec3 a_Bitangent;

//OUTs
layout(location = 0) out vec3 v_Pos;
layout(location = 1) out vec2 v_UV;
layout(location = 2) out vec3 v_Normal;
layout(location = 3) out vec4 v_FragPosLightSpace;
layout(location = 4) out vec3 v_DirLightPos;
layout(location = 5) out mat3 v_TBN;

layout(binding = 0) uniform ModelMatrix
{
    mat4 ModelMat;
} Model;

layout(binding = 1) uniform ViewMatrix
{
    mat4 ViewMat;
} View;

layout(binding = 2) uniform ProjectionMatrix
{
    mat4 ProjMat;
} Proj;

layout(binding = 3) uniform DirectionalLightPosition
{
    vec3 pos;
} dirLightPos;

layout(binding = 4) uniform light
{
    mat4 Matrix;
} lightViewProj;


void main()
{

    v_UV        = a_UV;
    v_Pos       = vec3(Model.ModelMat * vec4(a_Position, 1.0));
    v_Normal    = mat3(Model.ModelMat) * a_Normal;   

    mat3 normalMatrix = transpose(mat3(Model.ModelMat));

    vec3 T      = normalize(normalMatrix * a_Tangent);
    vec3 N      = normalize(normalMatrix * a_Normal);
    vec3 B      = normalize(normalMatrix * a_Bitangent);

    T           = normalize(T - dot(T, N) * N);

    v_TBN       = mat3(T, B, N);
    gl_Position = Proj.ProjMat * View.ViewMat * Model.ModelMat * vec4(a_Position, 1.0);

    v_FragPosLightSpace = (lightViewProj.Matrix * Model.ModelMat) * vec4(v_Pos, 1.0);

    
    v_DirLightPos = dirLightPos.pos;

我在这里的思考过程:

  • 我希望几何图形上的颜色类似于影子地图。但由于某种原因,图像的一半突然变成了更深的颜色。这一现象可以更好地在第三张图像中看到,在第三张图像中,相机放在模型的走廊内。您可以看到阴影地图断裂的确切点,并绘制一条线,在中间切割模型。
  • 有趣的是,一半的图像看起来都有正确的值。

有正常照明计算的场景

另一张来自不同角度的照片

其他地方寻找罪犯

  • 我对我的通行证有点怀疑。以下是代码:
代码语言:javascript
运行
复制
VkAttachmentDescription depthAttachmentDescription;
        VkAttachmentReference depthAttachmentRef;

        depthAttachmentDescription.format = VK_FORMAT_D16_UNORM;
        depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
        depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
        depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
        depthAttachmentDescription.flags = 0;
        depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
        depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
        depthAttachmentDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
        depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;

        depthAttachmentRef.attachment = 0;
        depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

        VkSubpassDescription subpass{};
        subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
        subpass.colorAttachmentCount = 0;
        subpass.pColorAttachments = 0;
        subpass.pDepthStencilAttachment = &depthAttachmentRef;

        std::array<VkSubpassDependency, 2> dependencies;

        dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
        dependencies[0].dstSubpass = 0;
        dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
        dependencies[0].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
        dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
        dependencies[0].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
        dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

        dependencies[1].srcSubpass = 0;
        dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
        dependencies[1].srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
        dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
        dependencies[1].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
        dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
        dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

        VkRenderPassCreateInfo renderPassInfo{};
        renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
        renderPassInfo.attachmentCount = 1;
        renderPassInfo.pAttachments = &depthAttachmentDescription;
        renderPassInfo.subpassCount = 1;
        renderPassInfo.pSubpasses = &subpass;
        renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size());
        renderPassInfo.pDependencies = dependencies.data();

        VkRenderPass renderPass;

        ASSERT(vkCreateRenderPass(VulkanApplication::GetVKDevice(), &renderPassInfo, nullptr, &renderPass) == VK_SUCCESS, "Failed to create a render pass.");
  • 在我看来,要么是阴影地图是用不正确的坐标采样的,要么是一个小的Vulkan错误,比如选择影子地图的格式VK_FORMAT_D16_UNORM
  • 影子地图会因为Vulkan而被翻转吗?用倒置的超音波进行取样会有帮助吗?虽然我已经试过了,但也许我做错了什么。

任何指点都会受到赞赏。别对我太客气了,我在这方面很新。谢谢!

编辑

我设法调试了一下情况,现在情况看起来好多了。但是阴影仍然不起作用。

我改变的是:

  • 这行v_FragPosLightSpace = (lightViewProj.Matrix * Model.ModelMat) * vec4(v_Pos, 1.0);在我的顶点着色器是不正确的。我去掉了多余的* Model.ModelMat乘法。
  • 我用来呈现阴影映射的管道错误地解释了影子映射。具体而言,视口部分:
代码语言:javascript
运行
复制
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = (float)m_CI.ViewportHeight;
viewport.width = (float)m_CI.ViewportWidth;
viewport.height = -(float)m_CI.ViewportHeight;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;

出于某种原因,我试图翻转视口,并将阴影呈现为那样。上述代码已转换为以下代码:

代码语言:javascript
运行
复制
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float)m_CI.ViewportWidth;
viewport.height = (float)m_CI.ViewportHeight;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;

我现在用矩阵乘法翻转深度图,同时设置投影矩阵:

代码语言:javascript
运行
复制
glm::mat4 clip = glm::mat4(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.0f, 0.0f, 0.5f, 1.0f);

glm::mat4 lightProjectionMatrix = clip * glm::ortho(-20.0f, 20.0f, -20.0f, 20.0f, near_plane, far_plane);

这就解决了阴影地图的方向/颠倒问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-11 21:33:29

我已经成功地让阴影起作用了!如果有人和我犯同样的错误,我会在这里发个答复。Vulkan是一种不同的动物,社区可以利用他们所能得到的所有信息。

所以就这样说:

错误/更改数字1)我不知道这会产生多大的影响,但我已经将投影矩阵从正字法改为透视法。MVP的整个设置如下:

代码语言:javascript
运行
复制
glm::vec3 directionalLightPosition = glm::vec3(200.0f, 000.0f, 0.0f);
float near_plane = 50.0f;
float far_plane = 1000.0f;


glm::mat4 lightView = glm::lookAt(directionalLightPosition, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 lightProjectionMatrix = glm::perspective(glm::radians(45.0f), 1.0f, near_plane, far_plane);
glm::mat4 lightModel = glm::mat4(1.0f);
glm::mat4 depthMVP;
depthMVP = lightProjectionMatrix * lightView * lightModel;

错误2),这是与Vulkan有关的错误。我把不正确的数据传递给我的顶点着色器。我在我的树形着色器中有以下布局:

代码语言:javascript
运行
复制
layout(binding = 0) uniform ModelMatrix
{
    mat4 ModelMat;
} Model;

layout(binding = 1) uniform ViewMatrix
{
    mat4 ViewMat;
} View;

layout(binding = 2) uniform ProjectionMatrix
{
    mat4 ProjMat;
} Proj;

layout(binding = 3) uniform DirectionalLightPosition
{
    vec3 pos;
} dirLightPos;

layout(binding = 4) uniform light
{
    mat4 Matrix;
} lightViewProj;

绑定号3和4在主机中由于某种原因被交换。我试图传递绑定3到4的数据,反之亦然。这显然是一个毁灭性的错误。这个程序给了我一些类似于我在问题中分享的深度图的图像,这是一个奇迹。

错误/改变数字3) Vulkan的Y轴被翻转,Z范围减半。我在写着色器时没有考虑到这一点。我很快地看了Sascha的影子映射例子,我看到他将方向光的MVP矩阵与偏置矩阵相乘。

我的顶点着色器现在看起来是这样的:

代码语言:javascript
运行
复制
#version 450

// INs
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec2 a_UV;
layout(location = 2) in vec3 a_Normal;
layout(location = 3) in vec3 a_Tangent;
layout(location = 4) in vec3 a_Bitangent;

//OUTs
layout(location = 0) out vec3 v_Pos;
layout(location = 1) out vec2 v_UV;
layout(location = 2) out vec3 v_Normal;
layout(location = 3) out vec4 v_FragPosLightSpace;
layout(location = 4) out vec3 v_DirLightPos;
layout(location = 5) out mat3 v_TBN;

layout(binding = 0) uniform ModelMatrix
{
    mat4 ModelMat;
} Model;

layout(binding = 1) uniform ViewMatrix
{
    mat4 ViewMat;
} View;

layout(binding = 2) uniform ProjectionMatrix
{
    mat4 ProjMat;
} Proj;

layout(binding = 3) uniform depthMVP
{
    mat4 Matrix;
} lightMVP;

layout(binding = 4) uniform DirectionalLightPosition
{
    vec3 pos;
} dirLightPos;


const mat4 bias = mat4( 
  0.5, 0.0, 0.0, 0.0,
  0.0, 0.5, 0.0, 0.0,
  0.0, 0.0, 1.0, 0.0,
  0.5, 0.5, 0.0, 1.0 );

void main()
{
    v_UV                = a_UV;
    v_Pos               = vec3(Model.ModelMat * vec4(a_Position, 1.0));
    v_Normal            = mat3(Model.ModelMat) * a_Normal;   

    mat3 normalMatrix   = transpose(mat3(Model.ModelMat));

    vec3 T              = normalize(normalMatrix * a_Tangent);
    vec3 N              = normalize(normalMatrix * a_Normal);
    vec3 B              = normalize(normalMatrix * a_Bitangent);

    T                   = normalize(T - dot(T, N) * N);

    v_TBN               = mat3(T, B, N);
    v_FragPosLightSpace = bias * lightMVP.Matrix * Model.ModelMat * vec4(a_Position, 1.0);
    v_DirLightPos       = dirLightPos.pos;

    gl_Position = Proj.ProjMat * View.ViewMat * Model.ModelMat * vec4(a_Position, 1.0);
}
  • 注意v_FragPosLightSpace = bias * lightMVP.Matrix * Model.ModelMat * vec4(a_Position, 1.0);部分

碎片着色器是笔直的。我不打算分享整个事情,因为我已经切换到PBR,它是冗长的,但重要的部分如下:

代码语言:javascript
运行
复制
float shadow = 1.0;
vec4 shadowCoords = v_FragPosLightSpace / v_FragPosLightSpace.w;
if( texture( u_DirectionalShadowMap, shadowCoords.xy ).r < shadowCoords.z - 0.005 )
{
    shadow = 0.0;
}
  • 注意,这里没有深度范围转换,因为Vulkan的Z范围已经在0,1之间,与OpenGL不同。我们只需要一个透视除法,剩下的就是基本的阴影计算。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73284425

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档