1

我正在尝试根据此文档实现 .3ds 导入器,并且我已经接近需要计算顶点法线的阶段,因为 .3ds 文件不提供此类。这是Java代码:

/* Sctructure of vertex array is {x0, y0, z0, x1, y1, z1...}
*  
*  Basically, MathUtils.generateNormal_f(x0,y0,z0, x1,y1,z1, x2,y2,z2) is cross
*  product between (x1-x0, y1-y0, z1-z0) and (x2-x0, y2-y0, z2-z0) */

normals = new float[this.vertex.length]; //every vertex has it's own normal
int n = 0;
for (int i=0; i<this.index.length; i++){
    float[] Normal = MathUtils.generateNormal_f( //getting xyz coords of 1 normal
            vertex[index[i]*3], vertex[index[i]*3+1], vertex[index[i]*3+2], 
            vertex[index[++i]*3], vertex[index[i]*3+1], vertex[index[i]*3+2], 
            vertex[index[++i]*3], vertex[index[i]*3+1], vertex[index[i]*3+2]);

    normals[n++] = Normal[0];
    normals[n++] = Normal[1];
    normals[n++] = Normal[2];
}

方法MathUtils.generateNormal_f(...)经过测试并且工作正常。此代码的结果如下所示(第一张图片)。例如,在第二张图像中,模型的每个法线都是相同的并且指向光源。

问题是:如何正确计算法线?

生成的法线 每个顶点都有 (1,0,0) 法线

4

2 回答 2

1

你的法线可能是倒置的。

我不太记得 3ds 格式,但请检查您是否可以从文件中导出和导入法线,而不是计算它们。

PS也不要像这样使用魔法:

vertex[index[i]*3], vertex[index[i]*3+1], vertex[index[i]*3+2], 
vertex[index[++i]*3], vertex[index[i]*3+1], vertex[index[i]*3+2], 
vertex[index[++i]*3], vertex[index[i]*3+1], vertex[index[i]*3+2]

根据参数评估的顺序,您将获得不同的结果。调用正常计算时最好明确使用 [i]、[i+1]、[i+2]...

于 2013-07-07T16:24:01.697 回答
0

据我所知,此信息是正确的,并且对我有用。对于平面上的任意 3 点 A、B 和 C,如果我们从 A 开始,然后是 B,最后是 C,法线将是:

其中 (B - A) 和 (C - B) 分别减去两个向量,X 符号表示求两个向量的叉积。点的顺序非常重要,它决定了我们的法线方向。如果 A、B 和 C 以逆时针方向组织,则它们的法线将面向实体外部。如果您想知道什么是叉积,那么对于任何点 P 和 Q,它们的叉积将是:

对法线向量经常做的另一件事是对其进行归一化。这样做是使法线向量的大小等于 1,以便更容易使用。这是等式:

其中点表示点积。如果您不知道点积是什么,请允许我通过以下方式进行说明。对于任何点 P 和 Q,它们的点积(标量值)为:

现在您有了表面法线,您可以通过平均共享该顶点的任何表面的法线来正确计算每个顶点的顶点法线。我没有那个公式,但我知道有两种方法可以找到顶点法线:加权和非加权。加权方法涉及计算每个表面的面积,而非加权方法则不涉及。

希望这些信息对您有所帮助。我把剩下的留给你或其他任何人,因为剩下的信息超出了我的范围。也许我会回来对这个问题进行更多研究。

于 2013-07-08T02:30:05.073 回答