【发布时间】:2017-12-03 16:06:23
【问题描述】:
我正在使用 LWJGL 开发 3D OpenGL 引擎。我设法用 Assimp 完成了模型导入部分,现在正在处理法线映射。 幸运的是,Assimp 可以为我计算切线空间,但它不能正常工作。 这是一张图片,它是如何在 sponza 模型上工作的:
这是从 TBN 矩阵可视化的 T:
代码在顶点着色器中如下所示:
mat3 normalMatrix = transpose(inverse(mat3(transformationMatrix)));
vec3 T = normalize(normalMatrix * tangent);
vec3 N = normalize(normalMatrix * normal);
T = normalize(T - dot(T, N) * N);
vec3 B = normalize(normalMatrix * bitangent);
if (dot(cross(N, T), B) < 0.0){
T = T * -1.0;
}
TBN = transpose(mat3(T, B, N));
它检查模型是否具有对称 UV,并修复它。 我认为这会导致问题,因为 TBN 中的 B 看起来更糟。
几周后,我尝试自己计算切线和副切线,但我的副切线看起来比 Assimps 差:
private void generateTangentBitangent(){
for(int i = 0; i < indices.size(); i+=3){
Vector3f v0 = new Vector3f (vertices.get(indices.get(i)).getPos());
Vector3f v1 = new Vector3f (vertices.get(indices.get(i+1)).getPos());
Vector3f v2 = new Vector3f (vertices.get(indices.get(i+2)).getPos());
Vector2f uv0 = new Vector2f (vertices.get(indices.get(i)).getTextureCoord());
Vector2f uv1 = new Vector2f (vertices.get(indices.get(i+1)).getTextureCoord());
Vector2f uv2 = new Vector2f (vertices.get(indices.get(i+2)).getTextureCoord());
Vector3f e1 = new Vector3f (v1.sub(v0));
Vector3f e2 = new Vector3f (v2.sub(v0));
Vector2f deltaUV1 = new Vector2f (uv1.sub(uv0));
Vector2f deltaUV2 = new Vector2f (uv2.sub(uv0));
float r = (float) (1.0f / (deltaUV1.x() * deltaUV2.y() - deltaUV1.y() * deltaUV2.x()));
Vector3f tangent = new Vector3f ((e1.mul(deltaUV2.y()).sub(e2.mul(deltaUV1.y()))).mul(r));
//System.out.println(tangent);
Vector3f bitangent = new Vector3f ((e2.mul(deltaUV1.x()).sub(e1.mul(deltaUV2.x()))).mul(r));
if(vertices.get(indices.get(i)).getTangent() == null)
vertices.get(indices.get(i)).setTangent(new Vector3f(0,0,0));
if(vertices.get(indices.get(i)).getBitangent() == null)
vertices.get(indices.get(i)).setBitangent(new Vector3f(0,0,0));
if(vertices.get(indices.get(i+1)).getTangent() == null)
vertices.get(indices.get(i+1)).setTangent(new Vector3f(0,0,0));
if(vertices.get(indices.get(i+1)).getBitangent() == null)
vertices.get(indices.get(i+1)).setBitangent(new Vector3f(0,0,0));
if(vertices.get(indices.get(i+2)).getTangent() == null)
vertices.get(indices.get(i+2)).setTangent(new Vector3f(0,0,0));
if(vertices.get(indices.get(i+2)).getBitangent() == null)
vertices.get(indices.get(i+2)).setBitangent(new Vector3f(0,0,0));
vertices.get(indices.get(i)).getTangent().add(tangent);
vertices.get(indices.get(i)).getBitangent().add(bitangent);
vertices.get(indices.get(i+1)).getTangent().add(tangent);
vertices.get(indices.get(i+1)).getBitangent().add(bitangent);
vertices.get(indices.get(i+2)).getTangent().add(tangent);
vertices.get(indices.get(i+2)).getBitangent().add(bitangent);
}
for (int i = 0 ; i < vertices.size() ; i++) {
vertices.get(i).getTangent().normalize();
vertices.get(i).getBitangent().normalize();
}
}
谁能帮我看看是什么原因造成的?
【问题讨论】:
-
tangent和bitangent必须转换为transformationMatrix,而不是normalMatrix。然后,您的所有检查都不是必需的。究竟是什么问题?你展示的图片本身看起来并没有错。我们需要查看参数化和坐标系,看看它们是否有意义。 -
如果我用 mat3(transformationMatrix) 转换它,我得到相同的结果,normalMatrix 只是transformationMatrix 的逆和转置。当我尝试使用对称模型时,UV 的方向错误,这就是我需要检查它的原因。问题是,切线和双切线计算错误。在第二张图片中,您可以看到每个标志中都有 2 个“渐变”。还有更多错误,像这样:imgur.com/a/AOYDQ
-
最好将 TBN 渲染为向量(每个顶点 3 行)而不是像素颜色。但是为此,您需要添加调试渲染代码(除非使用几何着色器通道,否则您不能在着色器中执行此操作....)希望您使用原点设置为
(0,0,0)的矩阵转换向量,否则您将抵消它们(如点)使其价值无效 -
问题 #1) 只是为了确保:您在使用 Assimp 导入资产时是否指定了
aiProcess_CalcTangentSpace标志? -
问题 #2)
T = normalize(T - dot(T, N) * N);在着色器中的用途是什么?
标签: java opengl glsl game-engine lwjgl