【问题标题】:Weird view/light behaviour with normal mapping带有法线贴图的奇怪视图/灯光行为
【发布时间】:2014-06-22 05:48:48
【问题描述】:

我正在尝试实现正常/陡峭视差映射,但我得到了一些奇怪的伪影。看起来视图和光向量在转换为切线空间时会发生扭曲,这会导致光照和视差的 uv 偏移不正确。

顶点着色器来源:

// parallax.vert


#version 330

// Some drivers require the following
precision highp float;
//per vertex inputs stored on GPU memory
in vec3 in_Position;
in vec3 in_Normal;
in vec4 tangent;
//per mesh data sent at rendering time
uniform mat4 model; //object to world space transformations
uniform mat4 view;  //world to eye space transformations
uniform mat4 projection; //eye space to screen space
uniform mat3 normalMat; //for transforming normals in 

uniform vec4 lightPosition; //light position in world space
uniform vec3 eyePosition; //eye position in world space

//outputs to fragment shader

in vec2 in_TexCoord;

// multiply each vertex position by the MVP matrix
// and find V, L, and TBN Matrix vectors for the fragment shader
out VertexData
{
    vec3 ts_L; //view vector tangent space
    vec3 ts_V; //light vector tangent space
    vec2 ex_TexCoord;
    float dist;
}       vertex;

void main(void) 
{
    //view space position for lighting calculations
    vec3 position = ( ( view * model ) * vec4( in_Position,1.0 ) ).xyz;
    //calculate view vector and light vector in view space
    vec3 ex_V = -position;
    vec3 ex_L = ( view * vec4( lightPosition.xyz,1.0 ) ).xyz - position;

    vertex.ex_TexCoord = in_TexCoord;

    //now calculate tbn matrix
    //calculate biTangent, in view space
    vec3 normal = normalMat*in_Normal;
    vec3 tan = normalMat * tangent.xyz;
    vec3 bitangent = normalize( cross( normal, tan.xyz ) * tangent.w );

    //fragment stage will need this value for calculating light attenuation
    vertex.dist = length( ex_L );

    //calculate transpose tangent space matrix, as we are doing everything in T space in fragment stage
    mat3 transTBN = transpose( mat3( tan, bitangent, normal ) );

    //transform view space vertex view & light vectors into tangent space
    vertex.ts_V = normalize( transTBN * ex_V  );
    vertex.ts_L = normalize( transTBN * ex_L );

    gl_Position = projection * vec4(position,1.0);

}

片段着色器来源:

// parallax.frag
#version 330

// Some drivers require the following
precision highp float;

struct lightStruct
{
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    vec4 position;
    float radius;
};

struct materialStruct
{
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    vec4 emissive;
    float shininess;
};
//uniforms sent at render time
uniform lightStruct light;
uniform materialStruct material;
uniform vec2 scaleBias;

//texture information
uniform sampler2D colourMap;
uniform sampler2D normalMap;
uniform sampler2D specularMap;
uniform sampler2D heightMap;
uniform sampler2D glossMap;

//inputs from vertex shader stage
in VertexData
{
    vec3 ts_L; //view vector tangent space
    vec3 ts_V; //light vector tangent space
    vec2 ex_TexCoord;
    float dist;
}   vertex;

//final fragment colour
layout(location = 0) out vec4 out_Color;

void main(void) {

    //calculate halfway vector for blinn phong
    vec3 Half = normalize( vertex.ts_V + vertex.ts_L );
    //and create some temporary types algorithm will need
    vec2 texCoord;
    vec3 diffuseTexel ;
    vec3 specularTexel;
    float gloss;
    vec3 normal;

    //first sample texel value from height map
    float height = texture( heightMap, vertex.ex_TexCoord.st ).r;

    //-----------------------------------------------
    // steep parallax
    float start = 1.0;
    int numsteps = 50;
    float step = 1.0/numsteps;
    vec2 offset = vertex.ex_TexCoord;
    vec2 delta = -vertex.ts_V.xy * scaleBias.r / (vertex.ts_V.z * numsteps);

    for (int i = 0; i < numsteps; i++)
    {
        if(height < start)
        {
            start-=step;
            offset+=delta;
            height = texture(heightMap,offset).r;
        }
        else
        {
            texCoord = offset;
            break;
        }
    }

    //---------------------------------------------------
    //normal maps are encoded with values between 0.0 and 0.5 being negative, so need to remove the encoding.
    //sample textures
    diffuseTexel = texture(colourMap,texCoord.st).rgb;

    specularTexel = texture(specularMap,texCoord.st).rgb;

    normal = normalize(texture(normalMap,texCoord.st).rgb * 2.0 - 1.0);

    gloss = texture(glossMap,texCoord.st).r;


    //--------------------------------------------------
    //Lighting -- Blinn/Phong Lighting with specular, normal and gloss mapping
    float lambert = max( dot (normal, vertex.ts_L ), 0.0 );

    vec3 litColour = vec3(0.0,0.0,0.0);

    //if light is worth calculating
    if (lambert > 0.0)
    {
        vec3 R = normalize(-reflect(vertex.ts_L,normal));
        float specularPower = pow(max(dot(R,Half),0.0),material.shininess);
        litColour += light.diffuse.xyz * material.diffuse.xyz  * lambert;
        litColour += light.specular.xyz * material.specular.xyz * specularPower * gloss;
        float attenuation = 1.0 + (0.01 * vertex.dist*vertex.dist) + (0.01 * vertex.dist);
        attenuation = 1.0/attenuation;

        litColour *= attenuation;
    }

    out_Color = vec4( litColour *diffuseTexel*(specularTexel) ,1.0);
}

正态矩阵的计算方法是

transpose( inverse( modelview ) );

我可能遗漏了一些非常明显的东西,但我看不到它,如果能提供一些意见,我将不胜感激。

更新:

我已经修改为基于世界空间向量执行光照和偏移,现在产生了以下结果:

现在照明是正确的,当从接近表面法线的地方观察时,视差很好,但是......

随着视角和法线之间的角度增加,视差变得非常奇怪。

再次感谢您在这方面的帮助。

【问题讨论】:

    标签: glsl parallax lighting


    【解决方案1】:

    vec3 ex_V = -position;

    这不应该是: vec3 ex_V = eyePosition - position;

    【讨论】:

    • 如果我根据世界空间位置执行光照,您的版本是正确的,但正如 cmets 所示,我正在视图空间中执行光照计算(预转换为切线空间)。
    猜你喜欢
    • 2022-09-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2019-01-10
    • 1970-01-01
    • 2018-01-17
    • 1970-01-01
    相关资源
    最近更新 更多