我正在努力在 3D 渲染应用程序中加载 gltf 模型,并尝试实现对法线贴图的支持。
在检查古董相机(其核心模型展示的一部分)时,我注意到它没有切线顶点属性。我对如何在没有任何顶点切线的对象上执行法线贴图感到有点困惑。
如果我发现模型没有任何顶点切线,我应该在加载该模型时尝试近似它们吗?是否有另一种方法可以在不使用切线空间和 TBN 矩阵的情况下利用法线贴图?
我尝试过近似每个顶点的切线,如下所示:
glm::vec3 t = glm::cross(normal, glm::vec3(1.0f, 0.0f, 0.0f));
glm::vec3 t2 = glm::cross(normal, glm::vec3(0.0f, 1.0f, 0.0f));
glm::vec3 t3 = glm::cross(normal, glm::vec3(0.0f, 0.0f, 1.0f));
if (glm::length(t2) > glm::length(t)) {
t = t2;
}
if (glm::length(t3) > glm::length(t)) {
t = t3;
}
tangent = glm::normalize(t);
但这会导致基于模型的不同行为(加载简单立方体时的行为很奇怪,但在更复杂的模型上似乎是正确的行为)。
我觉得分享我的着色器代码(hlsl)可能是值得的,所以这是我在顶点着色器中计算 TBN 矩阵的方法:
vec3 T = normalize(vec3(pushConstant.modelMatrix * vec4(in_tangent, 0.0)));
vec3 N = normalize(vec3(pushConstant.modelMatrix * vec4(in_normal, 0.0)));
T = normalize(T - dot(T, N) * N); // Reorthogonalize T with respect to N
vec3 B = normalize(cross(N, T)); // Prob don't need to normalize bc T & N are normalized
out_fragmentTBN = mat3(T, B, N);
这是我在片段着色器中使用 TBN 矩阵计算法线的方法:
// get the normal displacement from the normal map
vec3 normalDisplacement = texture(
sampler2D(
baseColorTextures[pushConstant.normalTextureID],
baseColorTextureSampler
),
in_baseColorTextureCoordinate
).rgb;
// convert it to be [-1, 1] from [0, 1]
normalDisplacement = normalize((normalDisplacement * 2.0) - 1.0);
// convert it to tangent space
vec3 normal = normalize(in_fragmentTBN * normalDisplacement);
解决了这个问题。使用 MikkTSpace 计算顶点切线(如果不存在)。这是存储库的链接:https://github.com/mmikk/MikkTSpace.git