视差映射期间奇怪的分层效果

Weird Layered Effect During Parallax Mapping

我正在按照 LearnOpenGL 指南进行操作,并正在尝试实施 Steep Parallax Mapping。

除了我的砖墙似乎有明显的可见层,而指南中的照片没有显示任何层外,一切似乎都很好。我试图使用这段代码来视差世界的地形,但这些奇怪的层似乎也出现在那里,所以我希望找到解决这个问题的办法。

Layered wall photo

[1

Photo of how it should look

这是我修改过的顶点着色器

#version 300 es

in vec4 vPosition; // aPos
in vec2 texCoord; // aTexCoords
in vec4 vNormal; // aNormal
in vec4 vTangent; // aTangent

uniform mat4 model_view;
uniform mat4 projection;
uniform vec4 light_position;

out vec2 ftexCoord;
out vec3 vT;
out vec3 vN;
out vec4 position;
out vec3 FragPos;
out vec3 TangentLightPos;
out vec3 TangentViewPos;
out vec3 TangentFragPos;

void
main()
{
    // Normal variables
    vN = normalize(model_view * vNormal).xyz;
    vT = normalize(model_view * vTangent).xyz;

    vec4 veyepos = model_view*vPosition;
    position = veyepos;

    ftexCoord = texCoord;

    // Displacement variables
    vec3 bi = cross(vT, vN);

    FragPos = vec3(model_view * vPosition).xyz;

    vec3 T = normalize(mat3(model_view) * vTangent.xyz);
    vec3 B = normalize(mat3(model_view) * bi);
    vec3 N = normalize(mat3(model_view) * vNormal.xyz);
    mat3 TBN = transpose(mat3(T, B, N));

    TangentLightPos = TBN * light_position.xyz;
    TangentViewPos = TBN * vPosition.xyz;
    TangentFragPos = TBN * FragPos;

    gl_Position = projection * model_view * vPosition;
}

我修改过的片段着色器在这里

#version 300 es

precision highp float;

in vec2 ftexCoord;
in vec3 vT; //parallel to surface in eye space
in vec3 vN; //perpendicular to surface in eye space
in vec4 position;
in vec3 FragPos;
in vec3 TangentLightPos;
in vec3 TangentViewPos;
in vec3 TangentFragPos;

uniform int mode;
uniform vec4 light_position;
uniform vec4 light_color;
uniform vec4 ambient_light;
uniform sampler2D colorMap;
uniform sampler2D normalMap;
uniform sampler2D depthMap;

out vec4  fColor;

// STEEP PARALLAX MAPPING
vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir)
{
    // number of depth layers
    const float minLayers = 8.0;
    const float maxLayers = 32.0;
    float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));
    // calculate the size of each layer
    float layerDepth = 1.0 / numLayers;
    // depth of current layer
    float currentLayerDepth = 0.0;
    // the amount to shift the texture coordinates per layer (from vector P)
    vec2 P = viewDir.xy / viewDir.z * 0.1;
    vec2 deltaTexCoords = P / numLayers;

    // get initial values
    vec2 currentTexCoords = texCoords;
    float currentDepthMapValue = texture(depthMap, currentTexCoords).r;

    while(currentLayerDepth < currentDepthMapValue)
    {
        // shift texture coordinates along direction of P
        currentTexCoords -= deltaTexCoords;
        // get depthmap value at current texture coordinates
        currentDepthMapValue = texture(depthMap, currentTexCoords).r;
        // get depth of next layer
        currentLayerDepth += layerDepth;
    }

    return currentTexCoords;
}

void main()
{
    // DO NORMAL MAPPING
    if (mode == 0) {
        vec3 T = normalize(vT);
        vec3 N = normalize(vN);

        vec3 bi = cross(T, N);

        mat4 changeOfCoord = mat4(vec4(T, 0), vec4(bi, 0), vec4(N, 0), vec4(0, 0, 0, 1));

        vec3 L = normalize(light_position - position).xyz;
        vec3 E = normalize(-position).xyz;

        vec4 text = vec4(texture(normalMap, ftexCoord) * 2.0 - 1.0);

        vec4 eye = changeOfCoord * text;

        vec4 amb = texture(colorMap, ftexCoord) * ambient_light;

        vec4 diff = max(0.0, dot(L, eye.xyz)) * light_color * texture(colorMap, ftexCoord);

        fColor = amb + diff;
    } else if (mode == 1) { // DO PARALLAX MAPPING
        // offset texture coordinates with Parallax Mapping
        vec3 viewDir = normalize(TangentViewPos - TangentFragPos);
        vec2 texCoords = ftexCoord;
        texCoords = ParallaxMapping(ftexCoord,  viewDir);

        // discard samples outside of the default texture coordinate space
        if(texCoords.x > 1.0 || texCoords.y > 1.0 || texCoords.x < 0.0 || texCoords.y < 0.0)
        discard;

        // obtain normal from normal map
        vec3 normal = texture(normalMap, texCoords).rgb;

        //values stored in normal texture is [0,1] range, we need [-1, 1] range
        normal = normalize(normal * 2.0 - 1.0);

        // get diffuse color
        vec3 color = texture(colorMap, texCoords).rgb;
        // ambient
        vec3 ambient = 0.1 * color;
        // diffuse
        vec3 lightDir = normalize(TangentLightPos - TangentFragPos);
        float diff = max(dot(lightDir, normal), 0.0);
        vec3 diffuse = diff * color;
        // specular
        vec3 reflectDir = reflect(lightDir, normal);
        vec3 halfwayDir = normalize(lightDir + viewDir);
        float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);

        vec3 specular = vec3(0.2) * spec;
        fColor = vec4(ambient + diffuse + 0.0, 1.0);
    }


}

锐角的图层是视差贴图的常见效果。要改善结果,您必须增加样本数量或实施视差遮挡映射(如本教程底部所述):

// STEEP PARALLAX MAPPING
vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir)
{
    // number of depth layers
    const float minLayers = 8.0;
    const float maxLayers = 32.0;
    float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));
    // calculate the size of each layer
    float layerDepth = 1.0 / numLayers;
    // depth of current layer
    float currentLayerDepth = 0.0;
    // the amount to shift the texture coordinates per layer (from vector P)
    vec2 P = viewDir.xy / viewDir.z * 0.1;
    vec2 deltaTexCoords = P / numLayers;

    // get initial values
    vec2 currentTexCoords = texCoords;
    float currentDepthMapValue = texture(depthMap, currentTexCoords).r;

    while(currentLayerDepth < currentDepthMapValue)
    {
        // shift texture coordinates along direction of P
        currentTexCoords -= deltaTexCoords;
        // get depthmap value at current texture coordinates
        currentDepthMapValue = texture(depthMap, currentTexCoords).r;
        // get depth of next layer
        currentLayerDepth += layerDepth;
    }

    // get texture coordinates before collision (reverse operations)
    vec2 prevTexCoords = currentTexCoords + deltaTexCoords;

    // get depth after and before collision for linear interpolation
    float afterDepth  = currentDepthMapValue - currentLayerDepth;
    float beforeDepth = texture(depthMap, prevTexCoords).r - currentLayerDepth + layerDepth;

    // interpolation of texture coordinates
    float weight = afterDepth / (afterDepth - beforeDepth);
    vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);

    return finalTexCoords;
}

顺便说一句,向量似乎是倒置的。通常,双切线是 Cross product of the normal vector and the tangent in a Right-handed 系统。但这取决于位移纹理。

vec3 bi = cross(vT, vN);

vec3 bi = cross(vN, vT);

进一步查看:
Bump Mapping with javascript and glsl
Normal, Parallax and Relief mapping
Demo