我一直在尝试使用OpenGL实现法线贴图。我已经实现了它的最基本版本,但继续尝试实现 REAL 法线贴图,该法涉及为每个顶点计算Bi-Tangent和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;
vec4 LightVec;
vec4 ViewVec;
} 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);
mat4 TBN4 = mat4(
vec4(T, 0.0),
vec4(B, 0.0),
vec4(N, 0.0),
worldPosition
);
mat4 invTBN4 = inverse(TBN4);
vs_out.LightVec = invTBN4 * vec4(normalize(lightPos - worldPosition.xyz), 0.0);
vs_out.ViewVec = invTBN4 * vec4(normalize(viewPos - worldPosition.xyz), 0.0);
//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;
vec4 LightVec;
vec4 ViewVec;
} 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
vec4 lightDir = normalize(fs_in.LightVec);
float diff = max(dot(vec3(lightDir), normal), 0.0);
vec3 diffuse = diff * Normalcolor;
//Specular Light
vec4 viewDir = normalize(fs_in.ViewVec);
vec3 reflectDir = reflect(vec3(-lightDir), normal);
vec4 halfwayDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(normal, vec3(halfwayDir)), 0.0), 32.0);
vec3 specular = vec3(0.2) * spec;
color = vec4(ambient + diffuse + specular, 1.0f);
}
现在诚实地说,着色器对我来说似乎还不错,我一直在看一些示例代码,而我的着色器似乎与它们是1:1的。现在问题出在照明上(我有点怀疑,但是有可能),或者是我计算切线和Bi-Tangent的方式,我在加载网格时会这样做,如下所示:
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);
现在,为了让您观察我得到的结果,它们是以下错误:
之所以认为这与灯光无关,是因为根据我计算切线和切线的方式,或多或少的片段被“启发”了