法线贴图和转换会中断我的照明

我有一个正常的映射问题。 对于通过ASSIMP库加载的每个模型,我都有纹理和正常纹理。 我正在ASSIMP库的帮助下计算每个对象上的切线向量,所以这些应该没问题。 这些对象与法线贴图完美配合,但只要我开始翻译其中一个对象(从而影响带翻译的模型矩阵),灯光就会失效。 正如您在图像上看到的那样,地板(沿y轴向下翻转)似乎失去了大部分漫射照明,并且其镜面光照方向错误(应该在灯泡和玩家位置之间)

法线映射出错了

这可能与正常矩阵有关(尽管翻译应该丢失),也许是在着色器中使用了错误的矩阵。 我没有想法,希望你能对这个问题有所了解。

顶点着色器:

#version 330

layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec3 tangent;
layout(location = 3) in vec3 color;
layout(location = 4) in vec2 texCoord;

// fragment pass through
out vec3 Position;
out vec3 Normal;
out vec3 Tangent;
out vec3 Color;
out vec2 TexCoord;

out vec3 TangentSurface2Light;
out vec3 TangentSurface2View;

uniform vec3 lightPos;
uniform vec3 playerPos;

// vertex transformation
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    mat3 normalMatrix = mat3(transpose(inverse(model))); 
    Position = vec3(model * vec4(position, 1.0)); 
    Normal = normalMatrix * normal;
    Tangent = tangent;
    Color = color;
    TexCoord = texCoord;

    gl_Position = projection * view * model * vec4(position, 1.0);

    // Calculate tangent matrix and calculate fragment bump mapping coord space.
    vec3 light = lightPos;
    vec3 n = normalize(normalMatrix * normal);
    vec3 t = normalize(normalMatrix * tangent);
    vec3 b = cross(n, t);
    // create matrix for tangent (from vertex to tangent-space)
    mat3 mat = mat3(t.x, b.x ,n.x, t.y, b.y ,n.y, t.z, b.z ,n.z);
    vec3 vector = normalize(light - Position);
    TangentSurface2Light = mat * vector;
    vector = normalize(playerPos - Position);
    TangentSurface2View = mat * vector;
}

片段着色器

    #version 330

in vec3 Position;
in vec3 Normal;
in vec3 Tangent;
in vec3 Color;
in vec2 TexCoord;

in vec3 TangentSurface2Light;
in vec3 TangentSurface2View;

out vec4 outColor;

uniform vec3 lightPos;
uniform vec3 playerPos;
uniform mat4 view;
uniform sampler2D texture0;
uniform sampler2D texture_normal; // normal

uniform float repeatFactor = 1;

void main()
{   
    vec4 texColor = texture(texture0, TexCoord * repeatFactor);
    vec4 matColor = vec4(Color, 1.0);
    vec3 light = vec3(vec4(lightPos, 1.0));
    float dist = length(light - Position);
    // float att = 1.0 / (1.0 + 0.01 * dist + 0.001 * dist * dist);
    float att = 1.0;
    // Ambient
    vec4 ambient = vec4(0.2);
    // Diffuse
    // vec3 surface2light = normalize(light - Position);
    vec3 surface2light = normalize(TangentSurface2Light);
    // vec3 norm = normalize(Normal); 
    vec3 norm = normalize(texture(texture_normal, TexCoord * repeatFactor).xyz * 2.0 - 1.0); 
    float contribution = max(dot(norm, surface2light), 0.0);
    vec4 diffuse = contribution * vec4(0.6);
    // Specular
    // vec3 surf2view = normalize(-Position); // Player is always at position 0
    vec3 surf2view = normalize(TangentSurface2View);
    vec3 reflection = reflect(-surface2light, norm); // reflection vector
    float specContribution = pow(max(dot(surf2view, reflection), 0.0), 32);
    vec4 specular = vec4(1.0) * specContribution;

    outColor = (ambient + (diffuse * att)+ (specular * pow(att, 3))) * texColor;
    // outColor = vec4(Color, 1.0) * texture(texture0, TexCoord);
}

编辑

编辑着色器代码来计算世界空间中的所有内容,而不是在世界和相机空间之间进行pingponging(更容易理解并且更少出错)。


你正在用矩阵进行奇怪的操作。 在VS中,你可以通过逆向视图世界来转换正常(即模型空间)。 这没有任何意义。 在世界空间中进行计算可能会更容易。 我有一些有效的示例代码,但它使用了一些不同的命名。

顶点着色器:

void main_vs(in A2V input, out V2P output) 
{
    output.position = mul(input.position, _worldViewProjection);
    output.normal = input.normal;
    output.binormal = input.binormal;
    output.tangent = input.tangent;
    output.positionWorld = mul(input.position, _world);
    output.tex = input.tex;
}

在这里,我们将位置转换为投影(屏幕) - 空间,TBN留在模型空间中,他们将在稍后使用。 我们也获得了照明评估的世界空间位置。

像素着色器:

void main_ps(in V2P input, out float4 output : SV_Target)
{
    float3x3 tbn = float3x3(input.tangent, -input.binormal, input.normal);

    //extract & decode normal:
    float3 texNormal = _normalTexture.Sample(_normalSampler, input.tex).xyz * 2 - 1;

    //now transform TBN-space texNormal to world space:
    float3 normal = mul(texNormal, tbn);
    normal = normalize(mul(normal, _world));

    float3 lightDirection = -_lightPosition.xyz;//directional
    float3 viewDirection = normalize(input.positionWorld - _camera);
    float3 reflectedLight = reflect(lightDirection, normal);

    float diffuseIntensity = dot(normal, lightDirection);
    float specularIntensity = max(0, dot(reflectedLight, viewDirection)*1.3);

    output = ((_ambient + diffuseIntensity * _diffuse) * _texture.Sample(_sampler, input.tex) 
        + pow(specularIntensity, 7) * float4(1,1,1,1)) * _lightColor;
}

在这里我使用定向光源,你应该做类似的事情

float3 lightDirection = normalize(input.positionWorld - _lightPosition.xyz);//omni

在这里,我们首先从纹理中获得正常,即在TBN空间中。 然后我们应用TBN矩阵将其转换为模型空间。 然后应用世界矩阵将其转换到世界空间,如果我们已经有了光照位置,眼睛等等

上面省略的其他一些着色器代码(DX11,但很容易翻译):

cbuffer ViewTranforms
{
    row_major matrix _worldViewProjection;
    row_major matrix _world;
    float3 _camera;
};

cbuffer BumpData
{
    float4 _ambient;
    float4 _diffuse;
};

cbuffer Textures
{
    texture2D _texture;
    SamplerState _sampler;

    texture2D _normalTexture;
    SamplerState _normalSampler;
};

cbuffer Light
{
    float4 _lightPosition;
    float4 _lightColor;
};

//------------------------------------

struct A2V
{
    float4 position : POSITION;
    float3 normal : NORMAL;
    float3 binormal : BINORMAL;
    float3 tangent : TANGENT;
    float2 tex : TEXCOORD;
};

struct V2P
{
    float4 position : SV_POSITION;
    float3 normal : NORMAL;
    float3 binormal : BINORMAL;
    float3 tangent : TANGENT;
    float3 positionWorld : NORMAL1;
    float2 tex : TEXCOORD;
};

此外,在这里我使用预先计算的binormal:你应该留下你的代码,计算它(通过交叉(正常,相切))。 希望这可以帮助。

链接地址: http://www.djcxy.com/p/73685.html

上一篇: Normal Mapping and translation disrupts my lighting

下一篇: No money on account after migrating to new Admob