如何计算二十面体的法线?

时间:2015-04-07 09:45:51

标签: javascript webgl

我想计算二十面体的法线,其原点为{0.0,0.0,0.0},但我不知道该怎么做!

例如,当我之前构造一个立方体时,获取法线非常简单,因为立方体的每个面都与x,y或z轴平行,并且包含顶点和法线的数组看起来很像那样:

var vertices = [
  -1.0, -1.0,  1.0,    1.0, -1.0,  1.0,
   1.0,  1.0,  1.0,   -1.0,  1.0,  1.0,

  -1.0, -1.0, -1.0,   -1.0,  1.0, -1.0,
   1.0,  1.0, -1.0,    1.0, -1.0, -1.0,

  -1.0,  1.0, -1.0,   -1.0,  1.0,  1.0,
   1.0,  1.0,  1.0,    1.0,  1.0, -1.0,

  -1.0, -1.0, -1.0,    1.0, -1.0, -1.0,
   1.0, -1.0,  1.0,   -1.0, -1.0,  1.0,

   1.0, -1.0, -1.0,    1.0,  1.0, -1.0,
   1.0,  1.0,  1.0,    1.0, -1.0,  1.0,

  -1.0, -1.0, -1.0,   -1.0, -1.0,  1.0,
  -1.0,  1.0,  1.0,   -1.0,  1.0, -1.0
];

var normals = [
   0.0,  0.0,  1.0,    0.0,  0.0,  1.0,
   0.0,  0.0,  1.0,    0.0,  0.0,  1.0,

   0.0,  0.0, -1.0,    0.0,  0.0, -1.0,
   0.0,  0.0, -1.0,    0.0,  0.0, -1.0,

   0.0,  1.0,  0.0,    0.0,  1.0,  0.0,
   0.0,  1.0,  0.0,    0.0,  1.0,  0.0,

   0.0, -1.0,  0.0,    0.0, -1.0,  0.0,
   0.0, -1.0,  0.0,    0.0, -1.0,  0.0,

   1.0,  0.0,  0.0,    1.0,  0.0,  0.0,
   1.0,  0.0,  0.0,    1.0,  0.0,  0.0,

  -1.0,  0.0,  0.0,   -1.0,  0.0,  0.0,
  -1.0,  0.0,  0.0,   -1.0,  0.0,  0.0
];

但是现在,在我的二十面体上工作,事情变得有点复杂......

编辑1:

按照给出答案的说明,我试图用这种方式计算法线:

首先,我将顶点存储在多维数组中,如下所示:

var r = (1 + Math.sqrt(5)) / 2;

var triangles = [

  [ [-1.0, r, 0.0],   [0.0, 1.0, r],      [1.0, r, 0.0] ],
  [ [1.0, r, 0.0],    [0.0, 1.0, -r],    [-1.0, r, 0.0] ],
  [ [1.0, r, 0.0],    [0.0, 1.0, r],      [r, 0.0, 1.0] ],
  [ [1.0, r, 0.0],    [r, 0.0, -1.0],    [0.0, 1.0, -r] ],
  [ [r, 0.0, -1.0],   [1.0, r, 0.0],      [r, 0.0, 1.0] ],
  [ [-1.0, -r, 0.0],  [1.0, -r, 0.0],    [0.0, -1.0, r] ],
  [ [-1.0, -r, 0.0],  [0.0, -1.0, -r],   [1.0, -r, 0.0] ],
  [ [-1.0, -r, 0.0],  [0.0, -1.0, r],    [-r, 0.0, 1.0] ],
  [ [-1.0, -r, 0.0],  [-r, 0.0, -1.0],  [0.0, -1.0, -r] ],
  [ [-r, 0.0, 1.0],   [-r, 0.0, -1.0],  [-1.0, -r, 0.0] ],
  [ [-1.0, r, 0.0],   [-r, 0.0, 1.0],     [0.0, 1.0, r] ],
  [ [-1.0, r, 0.0],   [0.0, 1.0, -r],   [-r, 0.0, -1.0] ],
  [ [-1.0, r, 0.0],   [-r, 0.0, -1.0],   [-r, 0.0, 1.0] ],
  [ [1.0, -r, 0.0],   [r, 0.0, 1.0],     [0.0, -1.0, r] ],
  [ [1.0, -r, 0.0],   [0.0, -1.0, -r],   [r, 0.0, -1.0] ],
  [ [1.0, -r, 0.0],   [r, 0.0, -1.0],     [r, 0.0, 1.0] ],
  [ [0.0, -1.0, -r],  [-r, 0.0, -1.0],   [0.0, 1.0, -r] ],
  [ [0.0, -1.0, -r],  [0.0, 1.0, -r],    [r, 0.0, -1.0] ],
  [ [0.0, 1.0, r],    [-r, 0.0, 1.0],    [0.0, -1.0, r] ],
  [ [0.0, 1.0, r],    [0.0, -1.0, r],     [r, 0.0, 1.0] ]

];

然后,基于给定的答案,我写了这个函数来计算法线......

var normals = [ ];

triangles.forEach(function (triangle) {
  var v1 = triangle[0],
      v2 = triangle[1],
      v3 = triangle[2];
  var p12 = new Array(3);
  p12[0] = v2[0] - v1[0];
  p12[1] = v2[1] - v1[1];
  p12[2] = v2[2] - v1[2];
  var p23 = new Array(3);
  p23[0] = v3[0] - v2[0];
  p23[1] = v3[1] - v2[1];
  p23[2] = v3[2] - v2[2];
  var cp = new Array(3);
  var x1 = p12[0],
      y1 = p12[1],
      z1 = p12[2];
  var x2 = p23[0],
      y2 = p23[1],
      z2 = p23[2];
  cp[0] = y1 * z2 - z1 * y2;
  cp[1] = z1 * x2 - x1 * z2;
  cp[2] = x1 * y2 - y1 * x2;
  var x = Math.pow(cp[0], 2),
      y = Math.pow(cp[1], 2),
      z = Math.pow(cp[2], 2);
  var len = Math.sqrt(x + y + z);
  var normal = new Array(3);
  normal[0] = cp[0] / len;
  normal[1] = cp[1] / len;
  normal[2] = cp[2] / len;
  for (var i = 0; i < 3; i++) {
    normals.push(normal);
  }
});

...最后打开并使用它们:

var unpackedNormals = [ ];

for (var n in normals) {
  unpackedNormals = unpackedNormals.concat(normals[n]);
}

var vertexNormalData = unpackedNormals;

但不知怎的,它不会像它应该的那样工作!

我可以在屏幕上看到二十面体,但表面上三角形的光照似乎是完全错误的。

我使用前面提到的立方体函数运行相同的程序而不是构造二十面体的那个程序,并且它完全正常工作,所以我认为错误必须位于这个新函数中以计算法线。

也许有人知道我做错了什么?

我会感谢任何帮助!

PS:请原谅我的英语不好。

编辑2:问题解决了!

我改变了三角形数组中矢量的顺序,现在所有的三角形都表现得像它们应该的那样!

我也在这篇文章中更新了三角形数组,因此现在进一步向上剪切表示正确的顺序,AFAIK。

2 个答案:

答案 0 :(得分:1)

如果您只对结果感兴趣,下面是我从Blender导出的具有三角形顶点,纹理和法线的Wavefront icosahedron.obj文件。

stringdist

答案 1 :(得分:0)

我认为你需要的是&#34;交叉产品&#34;,两个载体的载体产品。叉积将始终垂直于两个向量定义的平面。

http://en.wikipedia.org/wiki/Cross_product

对于二十面体的每个三角形,您都有描述边的向量(例如,如果v1,v2和v3是描述顶点的向量,则边是p12 = v2-v1,p23 = v3-v2和p31 = v1 -V3)。您的法线将是归一化的三个向量中的两个的除叉(除以它的模数),例如

n123 = (p12 x p23) / (|p12 x p23|)

你应该知道的有用的东西:

  • 两个载体的差异

    p12 = v2 - v1 = [x2, y2, z2] - [x1, y1, z1] = [x2-x1, y2-y1, z2-z1]
    
  • 载体的模量(长度):

    |v| = |[x, y, z]| = sqrt(x^2 + y^2 + z^2)
    

希望这有帮助。