我正在尝试根据this documentation实现.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(...)
测试并正常运行。该代码的结果可以在下面看到(第一张图片)。例如,在第二张图像中,模型的每个法线都是相同的,并指向光源。
问题是:如何正确计算法线?
答案 0 :(得分:1)
你的法线可能会倒转。
我不太清楚3ds格式,但检查是否可以从文件中导出和导入法线而不是计算它们。
P.S。也不要像这样使用魔法:
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] ......
答案 1 :(得分:0)
据我所知,此信息是正确的,这对我有用。对于平面上的任何3点A,B和C,正常情况下,如果我们从A开始,然后是B,最后是C,则将是:
其中(B-A)和(C-B)各减去两个向量,X符号表示找到两个向量的叉积。点的顺序非常重要,决定了我们的正常方向。如果A,B和C按逆时针方向组织,则它们的法线将面向实体外。如果你想知道什么是交叉产品,那么对于任何点P和Q,它们的交叉产品将是:
通常对法向量进行的另一件事是它被归一化。这样做是为了使法向量的大小等于1,以便更容易使用。这是等式:
点表示点积。如果您不知道点产品是什么,请允许我通过以下说明。对于任何点P和Q,它们的点积(标量值)是:
现在您有了曲面法线,您可以通过平均分配该顶点的任何曲面的法线来正确计算每个顶点的顶点法线。我没有那个公式,但我知道有两种方法可以找到顶点法线:加权和非加权。加权方法涉及计算每个表面的面积,而非加权方法则不计算。
希望这些信息对您有所帮助。我把剩下的留给你或其他任何人,因为剩下的信息超出了我的境界。也许我会回来再研究一下这个问题。