具有法线贴图的奇怪视图/光行为

时间:2014-06-08 10:02:36

标签: glsl parallax lighting

我试图实现正常/陡峭的视差贴图,但我得到了一些奇怪的人工制品。它看起来像视图和&当光矢量被转换为切线空间时,它们会被扭曲,导致光照和视差的紫外偏移是不正确的。

image showing distortion of lighting and uv offset, and showing light position

顶点着色器源:

// 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 ) );

我可能错过了一些非常明显的东西,但我无法看到它,并会对一些意见表示感谢。

更新

我已经修改过以执行照明&amp;基于世界空间向量的偏移,现已产生以下结果: enter image description here

照明现在是正确的,从近距离表面看法时视差很好,但...... enter image description here

视角与视角之间的角度正常增加,视差非常奇怪。

我再次感激你的帮助。

1 个答案:

答案 0 :(得分:0)

vec3 ex_V = -position;

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