我有一个正常的映射问题.我在通过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); }
编辑
解决方法
你正在用矩阵进行奇怪的操作.在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)) * _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:你应该留下你的代码来计算它(通过交叉(正常,切线)).希望这可以帮助.