【问题标题】:Normal mapping and phong shading with incorrect specular component具有不正确镜面反射分量的法线贴图和 phong 着色
【发布时间】:2014-03-26 11:44:47
【问题描述】:

我正在世界空间坐标中实现法线/凹凸贴图(我发现那些更容易使用)并且我的照明在没有法线贴图的情况下工作得很好,但是在引入法线贴图(以及使用 TBN 矩阵计算的新向量)时我的照明的镜面反射组件已关闭。

镜面反射分量不在相机和灯光之间,因此出现了问题。但是,查看我的代码我找不到任何问题。切线和双切线来自 ASSIMP 对象加载器,而 eyePos 和 lightPos 也在世界坐标中。

由于高光部分的光照看起来正确(显示了凹凸贴图),我认为它与切线空间变换有关?

这是一个演示问题的图片:

顶点着色器:

#version 330
layout (location = 0) in vec4 vertex;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec3 tangent;
layout(location = 3) in vec3 bitangent;
layout(location = 5) in vec2 texCoord;

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform vec3 lightPos; 
uniform vec3 eyePos;

out vec3 Position;
out vec2 TexCoord;

out vec3 tangentLightDir;
out vec3 tangentViewDir;

void main()
{
    gl_Position = projection * view * model * vertex;
    // Position
    Position = vec3(model * vertex);
    // Normal
    mat3 normalMat = transpose(inverse(mat3(model)));
    Normal = normalize(normalMat * normal);
    // Texture
    TexCoord = texCoord;

    // Normal mapping
    mat3 TBN = mat3(tangent, bitangent, Normal);
    TBN = transpose(TBN);
    // Get direction vectors:
    vec3 lightDir = normalize(lightPos - Position);
    vec3 viewDir = normalize(eyePos - Position); 
    // Now transform them to tangent space
    tangentLightDir = TBN * lightDir;
    tangentViewDir = TBN * viewDir;
}

片段着色器:

#version 330
in vec3 Position;
in vec2 TexCoord;

in vec3 tangentLightDir;
in vec3 tangentViewDir;

uniform sampler2D texture0;
uniform sampler2D texture_normal;

out vec4 outColor;

void main()
{
    // defaults
    vec4 ambient = vec4(0.1);
    vec4 diffuse = vec4(0.4);
    vec4 specular = vec4(0.5);
    vec4 texColor = texture(texture0, TexCoord);    

    // Phong shading
    vec3 LightDir = normalize(tangentLightDir);
    vec3 Norm = normalize(texture(texture_normal, TexCoord).xyz * 2.0 - 1.0);    

    vec3 ViewDir = normalize(tangentViewDir); 
    vec3 ReflectDir = reflect(-LightDir,Norm);
    float specularContribution = pow(max(dot(ViewDir, ReflectDir), 0.0), 32);
    // Calculate diffuse component
    vec4 I = diffuse * max(dot(LightDir, Norm), 0.0);
    diffuse = clamp(I, 0.0, 1.0);
    // Calculate specular component
    specular = specular * specularContribution;

    outColor = texColor * (diffuse + specular + ambient);
}

【问题讨论】:

  • 你把eyePos和lightPos转换成屏幕坐标了吗?
  • @Snowfish:它们在世界/全球空间坐标中,因为所有计算都是在世界/全球空间中完成的,这应该是正确的,对吧?
  • 我的错。看起来确实是 TBN 的问题。
  • 你通过 normalMat 转换法线,但是你对切线和双切线没有做同样的事情,所以你的 TBN 不正确。

标签: c++ opengl glsl lighting


【解决方案1】:
layout(location = 3) in vec3 bitangent;
layout(location = 5) in vec2 texCoord;

5是正确的位置吗?

关于 TBN 矩阵。你必须(比如 jhoffman0x)将 normalMat 矩阵乘以 tangentbitangent,归一化结果和之后TBN矩阵:

来自David Wolff - OpenGL 4.0 Shading Language Cookbook 的示例。顶点着色器:

#version 430

layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;
layout (location = 2) in vec2 VertexTexCoord;
layout (location = 3) in vec4 VertexTangent;

struct LightInfo {
  vec4 Position;  // Light position in eye coords.
  vec3 Intensity; // A,D,S intensity
};
uniform LightInfo Light;

out vec3 LightDir;
out vec2 TexCoord;
out vec3 ViewDir;

uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ProjectionMatrix;
uniform mat4 MVP;

void main()
{
    // Transform normal and tangent to eye space
    vec3 norm = normalize( NormalMatrix * VertexNormal );
    vec3 tang = normalize( NormalMatrix * vec3(VertexTangent) );
    // Compute the binormal
    vec3 binormal = normalize( cross( norm, tang ) ) * VertexTangent.w;

    // Matrix for transformation to tangent space
    mat3 toObjectLocal = mat3(
        tang.x, binormal.x, norm.x,
        tang.y, binormal.y, norm.y,
        tang.z, binormal.z, norm.z ) ;

    // Transform light direction and view direction to tangent space
    vec3 pos = vec3( ModelViewMatrix * vec4(VertexPosition,1.0) );
    LightDir = normalize( toObjectLocal * (Light.Position.xyz - pos) );

    ViewDir = toObjectLocal * normalize(-pos);

    TexCoord = VertexTexCoord;

    gl_Position = MVP * vec4(VertexPosition,1.0);
}

片段着色器:

#version 430

in vec3 LightDir;
in vec2 TexCoord;
in vec3 ViewDir;

layout(binding=0) uniform sampler2D ColorTex;
layout(binding=1) uniform sampler2D NormalMapTex;

struct LightInfo {
  vec4 Position;  // Light position in eye coords.
  vec3 Intensity; // A,D,S intensity
};
uniform LightInfo Light;

struct MaterialInfo {
  vec3 Ka;            // Ambient reflectivity
  vec3 Ks;            // Specular reflectivity
  float Shininess;    // Specular shininess factor
};
uniform MaterialInfo Material;

layout( location = 0 ) out vec4 FragColor;

vec3 phongModel( vec3 norm, vec3 diffR ) {
    vec3 r = reflect( -LightDir, norm );
    vec3 ambient = Light.Intensity * Material.Ka;
    float sDotN = max( dot(LightDir, norm), 0.0 );
    vec3 diffuse = Light.Intensity * diffR * sDotN;

    vec3 spec = vec3(0.0);
    if( sDotN > 0.0 )
        spec = Light.Intensity * Material.Ks *
               pow( max( dot(r,ViewDir), 0.0 ), Material.Shininess );

    return ambient + diffuse + spec;
}

void main() {
    // Lookup the normal from the normal map
    vec4 normal = 2.0 * texture( NormalMapTex, TexCoord ) - 1.0;

    vec4 texColor = texture( ColorTex, TexCoord );
    FragColor = vec4( phongModel(normal.xyz, texColor.rgb), 1.0 );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-09
    • 1970-01-01
    • 1970-01-01
    • 2016-01-20
    • 2013-12-03
    • 2019-10-21
    相关资源
    最近更新 更多