Normal display and translation disrupt my lighting

I have a normal display problem. I have a texture and a normal texture for each model loaded through the ASSIMP library. I compute tangent vectors on each object using the ASSIMP library, so they must be accurate. Objects work fine with normal display, but as soon as I start translating one of the objects (thus affecting the matrix of the model with translations), the lighting is interrupted. As you can see in the image, the floor (which translates along the y axis) seems to lose most of its diffused lighting, and its mirror lighting is in the wrong direction (it should be between the light bulb and the player’s position)

Normal mapping gone wrong

This may have something to do with the normal matrix (although translations must be lost), maybe something with the wrong matrix used in shaders. I was out of ideas and hoped that you could shed light on this problem.

Vertex shader:

#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(tx, bx ,nx, ty, by ,ny, tz, bz ,nz); vec3 vector = normalize(light - Position); TangentSurface2Light = mat * vector; vector = normalize(playerPos - Position); TangentSurface2View = mat * vector; } 

Fragment shader

  #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); } 

EDIT

Edited the shader code to calculate everything in world space, instead of ping pong between the world and camera space (easier to understand and reduce the likelihood of errors).

+7
c ++ opengl glsl lighting bump-mapping
source share
1 answer

You do strange manipulations with matrices. In VS, you are transforming the normal (i.e. model-space) inverse world of representations. That doesn't make any sense. It may be easier to do calculations in world space. I have some working code example, but it uses a slightly different name.

Vertex shader:

 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; } 

Here we transform the position into the projection (screen) space, TBN remains in the model space, they will be used later. We also get the position of the world space for lighting assessment.

Pixel Shader:

 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; } 

Here I use directional light, you should do something like

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

Here we first have a normal texture, that is, in a TBN space. Then we use the TBN matrix to transform it into a model space. Then apply the matrix of the world to transform it into world space, if we already had the position of light, eyes, etc.

Some other shader codes omitted above (DX11, but easy to translate):

 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; }; 

In addition, here I use pre-computed binormal: you must leave your code that computes it (via cross (normal, tangent)). Hope this helps.

+4
source share

All Articles