538人阅读 评论(0)

# 第二十六课 法线纹理

## 背景

1. 将 tangent 向量传入到顶点着色器中；
2. 将 tangent 向量变换到世界坐标系中并传入到片元着色器；
3. 在片元着色器中使用 tangent 向量和法线向量（都处于世界坐标系下）来计算出 bitangent 向量；
4. 通过 tangent-bitangent-normal 矩阵生成一个将法线信息变换到世界坐标系中的变换矩阵；
5. 从法线纹理中采样得到法线信息；
6. 通过使用上述的矩阵将法线信息变换到世界坐标系中；
7. 继续和往常一样进行光照计算。

## 代码

(mesh.h:33)
struct Vertex
{
Vector3f m_pos;
Vector2f m_tex;
Vector3f m_normal;
Vector3f m_tangent;
Vertex() {}
Vertex( const Vector3f& pos,
const Vector2f& tex,
const Vector3f& normal,
const Vector3f& Tangent )
{
m_pos = pos;
m_tex = tex;
m_normal = normal;
m_tangent = Tangent;
}
}; 

for (unsigned int i = 0 ; i <  Indices.size() ; i += 3) {
Vertex& v0 = Vertices[Indices[i]];
Vertex& v1 = Vertices[Indices[i+1]];
Vertex& v2 = Vertices[Indices[i+2]];
Vector3f Edge1 = v1.m_pos - v0.m_pos;
Vector3f Edge2 = v2.m_pos - v0.m_pos;
float DeltaU1 = v1.m_tex.x - v0.m_tex.x;
float DeltaV1 = v1.m_tex.y - v0.m_tex.y;
float DeltaU2 = v2.m_tex.x - v0.m_tex.x;
float DeltaV2 = v2.m_tex.y - v0.m_tex.y;
float f = 1.0f / (DeltaU1 * DeltaV2 - DeltaU2 * DeltaV1);
Vector3f Tangent, Bitangent;
Tangent.x = f * (DeltaV2 * Edge1.x - DeltaV1 * Edge2.x);
Tangent.y = f * (DeltaV2 * Edge1.y - DeltaV1 * Edge2.y);
Tangent.z = f * (DeltaV2 * Edge1.z - DeltaV1 * Edge2.z);
Bitangent.x = f * (-DeltaU2 * Edge1.x - DeltaU1 * Edge2.x);
Bitangent.y = f * (-DeltaU2 * Edge1.y - DeltaU1 * Edge2.y);
Bitangent.z = f * (-DeltaU2 * Edge1.z - DeltaU1 * Edge2.z);
v0.m_tangent += Tangent;
v1.m_tangent += Tangent;
v2.m_tangent += Tangent;
}
for (unsigned int i = 0 ; i < Vertices.size() ; i++) {
Vertices[i].m_tangent.Normalize();
} 

(mesh.cpp:195)
void Mesh::Render()
{
...
glEnableVertexAttribArray(3);
for (unsigned int i = 0 ; i < m_Entries.size() ; i++) {
...
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)32);
}
...
glDisableVertexAttribArray(3);
} 

(lighting.vs)
layout (location = 0) in vec3 Position;
layout (location = 1) in vec2 TexCoord;
layout (location = 2) in vec3 Normal;
layout (location = 3) in vec3 Tangent;
uniform mat4 gWVP;
uniform mat4 gLightWVP;
uniform mat4 gWorld;
out vec4 LightSpacePos;
out vec2 TexCoord0;
out vec3 Normal0;
out vec3 WorldPos0;
out vec3 Tangent0;
void main()
{
gl_Position = gWVP * vec4(Position, 1.0);
LightSpacePos = gLightWVP * vec4(Position, 1.0);
TexCoord0 = TexCoord;
Normal0 = (gWorld * vec4(Normal, 0.0)).xyz;
Tangent0 = (gWorld * vec4(Tangent, 0.0)).xyz;
WorldPos0 = (gWorld * vec4(Position, 1.0)).xyz;
} 

(lighting.fs:132)
vec3 CalcBumpedNormal()
{
vec3 Normal = normalize(Normal0);
vec3 Tangent = normalize(Tangent0);
Tangent = normalize(Tangent - dot(Tangent, Normal) * Normal);
vec3 Bitangent = cross(Tangent, Normal);
vec3 BumpMapNormal = texture(gNormalMap, TexCoord0).xyz;
BumpMapNormal = 2.0 * BumpMapNormal - vec3(1.0, 1.0, 1.0);
vec3 NewNormal;
mat3 TBN = mat3(Tangent, Bitangent, Normal);
NewNormal = TBN * BumpMapNormal;
NewNormal = normalize(NewNormal);
return NewNormal;
}
void main()
{
vec3 Normal = CalcBumpedNormal();
... 

1. ‘bricks.jpg’ 是颜色纹理；
2. ‘normal_map.jpg’ 是从 ‘bricks.jpg’ 纹理中生成的法线纹理；
3. ‘normal_up.jpg’ 是一个也是一个发现纹理，但是这个纹理中所有发现都是朝上的。使用这个纹理作为法线纹理时，场景的效果就像没有使用法线纹理技术一样， 我们可以通过绑定这个纹理来使得我们的法线纹理失效（尽管效率不是很高）。你可以通过按 ‘b’ 键在法线纹理和普通纹理之间的切换。

## 操作结果

0
0

* 以上用户言论只代表其个人观点，不代表CSDN网站的观点或立场
个人资料
• 访问：17629次
• 积分：431
• 等级：
• 排名：千里之外
• 原创：0篇
• 转载：0篇
• 译文：26篇
• 评论：1条
文章分类
评论排行
最新评论