如何在缺乏切线顶点属性的对象上使用法线贴图?

问题描述 投票:0回答:1

我正在努力在 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);
graphics rendering textures vulkan hlsl
1个回答
0
投票

解决了这个问题。使用 MikkTSpace 计算顶点切线(如果不存在)。这是存储库的链接:https://github.com/mmikk/MikkTSpace.git

© www.soinside.com 2019 - 2024. All rights reserved.