我一直在尝试使用OpenGL实现法线贴图。我已经实现了它的最基本版本,但继续尝试实现REAL Normal Mapping,它涉及计算每个顶点的Bi-Tangents和Tangets。我开始实现片段和顶点着色器,如下所示:
顶点着色器:
#version 330 core
in vec4 in_Position;
in vec2 in_Coordinates;
in vec3 in_Normal;
in vec3 tangent;
in vec3 bitangent;
out vec2 ex_textCoord;
out VS_OUT{
vec3 FragPos;
vec3 Normal;
vec3 TangentLightPos;
vec3 TangentViewPos;
vec3 TangentFragPos;
} vs_out;
uniform mat4 ModelMatrix;
uniform vec4 VertColor;
uniform SharedMatrices
{
mat4 ViewMatrix;
mat4 ProjectionMatrix;
};
uniform vec4 plane;
uniform vec3 lightPos;
uniform vec3 viewPos;
void main(void)
{
vec4 worldPosition = ModelMatrix * in_Position;
gl_Position = ProjectionMatrix * ViewMatrix * worldPosition;
vs_out.FragPos = vec3(ModelMatrix * in_Position);
ex_textCoord = in_Coordinates;
mat3 normalMatrix = transpose(inverse(mat3(ModelMatrix)));
vs_out.Normal = normalMatrix * in_Normal;
vec3 T = normalize(vec3(ModelMatrix * vec4(tangent, 0.0)));
vec3 N = normalize(vec3(ModelMatrix * vec4(in_Normal, 0.0)));
T = normalize(T - dot(T, N) * N);
vec3 B = cross(T, N);
mat3 TBN = transpose(mat3(T, B, N));
vs_out.TangentLightPos = TBN * lightPos;
vs_out.TangentViewPos = TBN * viewPos;
vs_out.TangentFragPos = TBN * vec3(worldPosition);
gl_ClipDistance[0] = dot(worldPosition, plane);
}
片段着色器:
#version 330 core
out vec4 color;
in vec2 ex_textCoord;
in VS_OUT{
vec3 FragPos;
vec3 Normal;
vec3 TangentLightPos;
vec3 TangentViewPos;
vec3 TangentFragPos;
} fs_in;
uniform sampler2D screenTexture; //Diffuse Texture
uniform sampler2D normalTexture; //Normal Mapping Texture
uniform bool normalMapping; //Enable or Disable Normal Mapping
uniform vec3 lightPosition;
uniform vec3 lightColour;
void main()
{
vec3 normal = texture(normalTexture, ex_textCoord).rgb;
normal = normalize(normal * 2.0 - 1.0);
vec3 Normalcolor = texture(screenTexture, ex_textCoord).rgb;
//Ambient Light
vec3 ambient = 0.1 * Normalcolor;
//Diffuse Light
vec3 lightDir = normalize(fs_in.TangentLightPos - fs_in.TangentFragPos);
float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = diff * Normalcolor;
//Specular Light
vec3 viewDir = normalize(fs_in.TangentViewPos - fs_in.TangentFragPos);
vec3 reflectDir = reflect(-lightDir, normal);
vec3 halfwayDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);
vec3 specular = vec3(0.2) * spec;
color = vec4(ambient + diffuse + specular, 1.0f);
}
现在着色器看起来很老实,我已经看到了示例代码片段,我的着色器与它们似乎是1:1。现在要么问题出在光照中(我有点怀疑它,但它有可能)或者它是我计算切线和双切线的方式,我在加载网格时会这样做,如下所示:
Vec3 pos1, pos2, pos3, pos4, tangent1, bitangent1, edge1, edge2, normal;
Vec2 uv1, uv2, uv3, uv4, deltaUV1, deltaUV2;
for (int i = 0; i <= TempMeshRef->vertexIdx.size() - 3; i += 1) {
pos1 = TempMeshRef->vertexData[TempMeshRef->vertexIdx[i]-1];
pos2 = TempMeshRef->vertexData[TempMeshRef->vertexIdx[i+1]-1];
pos3 = TempMeshRef->vertexData[TempMeshRef->vertexIdx[i+2]-1];
//pos4 = TempMeshRef->vertexData[TempMeshRef->vertexIdx[i+3]-1];
uv1 = TempMeshRef->texcoordData[TempMeshRef->texcoordIdx[i]-1];
uv2 = TempMeshRef->texcoordData[TempMeshRef->texcoordIdx[i+1]-1];
uv3 = TempMeshRef->texcoordData[TempMeshRef->texcoordIdx[i+2]-1];
//uv4 = TempMeshRef->texcoordData[TempMeshRef->texcoordIdx[i+3]-1];
normal = TempMeshRef->normalData[TempMeshRef->normalIdx[i]-1];
//Triangle 1
edge1 = pos2 - pos1;
edge2 = pos3 - pos1;
deltaUV1 = uv2 - uv1;
deltaUV2 = uv3 - uv1;
GLfloat f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
tangent1.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
tangent1.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
tangent1.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
tangent1 = Normalized(tangent1);
TempMeshRef->tangentData.push_back(tangent1);
bitangent1.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
bitangent1.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
bitangent1.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
bitangent1 = Normalized(bitangent1);
TempMeshRef->biTangentData.push_back(bitangent1);
现在,为了让您观察我所拥有的结果,他们就是以下Bug