【问题标题】:Adding Shadows to Parallax Occlusion Map向视差遮挡贴图添加阴影
【发布时间】:2019-03-10 16:26:12
【问题描述】:

我已经通过LearnOpengl 实现了视差遮挡映射,现在我想添加自身阴影,以便片段挤压在表面上投射阴影。我已经阅读了一些关于该主题的论文,但我承认它对我来说有点先进。据我了解,这与视差遮挡映射的过程相同,但从光的方向而不是视图方向。我尝试修改片段着色器,但阴影仍然不显示。

这就是我想要的样子。 http://www.cs.utah.edu/~sujin/courses/reports/cs6610/project-report/images/pom.png

这是修改片段着色器的结果。与仅使用视差遮挡贴图相比没有任何变化。

这是修改后的片段着色器。我已经标记了我添加到原始视差教程代码中的部分。

#version 330 core
in vec2 o_texCoord;
in vec3 o_worldPos;
in vec3 world_normal;
in vec3 world_tangent;

out vec4 fragColor;

uniform vec3 light_pos;
uniform sampler2D diffuseMap;
uniform sampler2D normalMap;
uniform sampler2D heightMap;
uniform vec3 viewPosition;
uniform float heightScale;

vec2 ParallaxMapping (vec2 texCoord, vec3 viewDir)
{
    float minLayers = 0;
    float maxLayers = 32;
    float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));
    float layerDepth = 1.0 / numLayers;

    float currentLayerDepth = 0;

    vec2 P = viewDir.xy / viewDir.z * heightScale;

    vec2 deltaTexCoords = P / numLayers;

    vec2 currentTexCoords = texCoord;

    float currentDepthMapValue = texture(heightMap, currentTexCoords).r;

    while (currentLayerDepth < currentDepthMapValue)
    {
        currentTexCoords -= deltaTexCoords;
        currentDepthMapValue = texture(heightMap, currentTexCoords).r;
        currentLayerDepth += layerDepth;
    }

    vec2 prevTexCoords = currentTexCoords + deltaTexCoords;
    float afterDepth = currentDepthMapValue - currentLayerDepth;
    float beforeDepth = texture(heightMap, prevTexCoords).r - currentLayerDepth + layerDepth;

    float weight = afterDepth / (afterDepth - beforeDepth);

    vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);

    return finalTexCoords;
}

// FUNCTION I ADDED FOR SHADOW CALCULATION
float ShadowCalc(vec2 texCoord, vec3 lightDir)
{
    float minLayers = 0;
    float maxLayers = 32;
    float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), lightDir)));

    float layerDepth = 1.0 / numLayers;

    float currentLayerDepth = 0;

    vec2 P = lightDir.xy / lightDir.z * heightScale;

    vec2 deltaTexCoords = P / numLayers;

    vec2 currentTexCoords = texCoord;

    float currentDepthMapValue = texture(heightMap, currentTexCoords).r;

    while (currentLayerDepth < currentDepthMapValue)
    {
        currentTexCoords -= deltaTexCoords;
        currentDepthMapValue = texture(heightMap, currentTexCoords).r;
        currentLayerDepth += layerDepth;
    }

    float r = currentDepthMapValue > currentLayerDepth ? 0.0 : 1.0;

    return r;
}

void main()
{
    mat3 TBN_norm = transpose(mat3(normalize(world_tangent),
                                   normalize(cross(world_normal, world_tangent)),
                                   normalize(world_normal)));
    vec3 viewDir = TBN_norm * normalize(o_worldPos - viewPosition);
    vec2 currentTex = ParallaxMapping(o_texCoord, viewDir);
    if (currentTex.x > 1.0 || currentTex.y > 1.0 || currentTex.x < 0.0 || currentTex.y < 0.0)
    {
        discard;
    }
    vec3 normal = texture(normalMap, currentTex).rgb;
    normal = normalize(normal * 2.0 - 1.0);
    vec3 lightDir = normalize(TBN_norm * light_pos - TBN_norm * o_worldPos);
    float dc = max(0.0, dot(lightDir, normal));

    // STUFF I ADDED FOR SHADOWS
    float shadow = 0;
    if (dc > 0)
    {
        shadow = ShadowCalc(currentTex, lightDir);
    }

    fragColor = shadow * dc * texture(diffuseMap, currentTex);
}

【问题讨论】:

    标签: c++ opengl glsl shader


    【解决方案1】:

    首先光源到纹理空间中片段的方向是:

    vec3 lightDir = TBN_norm * normalize(o_worldPos - light_pos);
    float dc = max(0.0, dot(-lightDir, normal));
    

    要检查片段是否处于自身阴影中,您必须从“视差”纹素开始跟踪光线到光源。

    float shadow = dc > 0.0 ? ShadowCalc(currentTex, lightDir) : 0.0;
    

    初始高度(currentLayerDepth)是当前片段的高度:

    float currentDepthMapValue = texture(heightMap, currentTexCoords).r;
    float currentLayerDepth = currentDepthMapValue;
    

    由于深度 mao 是一个逆深度图(1.0 低),如果任何层深度 (currentLayerDepth) 小于或等于当前高度 (currentDepthMapValue),则片段处于阴影中。如果达到最大深度(最小值 0.0),则必须中止采样。
    请注意,与ParallaxMapping 算法相比,深度递减 (currentLayerDepth -= layerDepth) 并且纹理样本取反方向 (currentTexCoords += deltaTexCoords):

    while (currentLayerDepth <= currentDepthMapValue && currentLayerDepth > 0.0)
    {
        currentTexCoords += deltaTexCoords;
        currentDepthMapValue = texture(heightMap, currentTexCoords).r;
        currentLayerDepth -= layerDepth;
    }
    float r = currentLayerDepth > currentDepthMapValue ? 0.0 : 1.0;
    

    由于除以 (P = lightDir.xy / lightDir.z) 中的 z 分量,PdeltaTexCoords 始终指向光源(当然在投影到纹理中)。
    如果lightDir 的 z 分量大于 0.0,则从背面照亮表面。这会导致提前中止:

    if ( lightDir.z >= 0.0 )
        return 0.0;
    

    完整的函数ShadowCalc 函数可能如下所示:

    float ShadowCalc(vec2 texCoord, vec3 lightDir)
    {
        if ( lightDir.z >= 0.0 )
            return 0.0;
    
        float minLayers = 0;
        float maxLayers = 32;
        float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), lightDir)));
    
        vec2 currentTexCoords = texCoord;
        float currentDepthMapValue = texture(heightMap, currentTexCoords).r;
        float currentLayerDepth = currentDepthMapValue;
    
        float layerDepth = 1.0 / numLayers;
        vec2 P = lightDir.xy / lightDir.z * heightScale;
        vec2 deltaTexCoords = P / numLayers;
    
        while (currentLayerDepth <= currentDepthMapValue && currentLayerDepth > 0.0)
        {
            currentTexCoords += deltaTexCoords;
            currentDepthMapValue = texture(heightMap, currentTexCoords).r;
            currentLayerDepth -= layerDepth;
        }
    
        float r = currentLayerDepth > currentDepthMapValue ? 0.0 : 1.0;
        return r;
    }
    

    【讨论】:

    • 我想我现在理解得更好了。软阴影的实现如何工作?
    猜你喜欢
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-30
    相关资源
    最近更新 更多