HTML/CSS中的3D模型;计算三角形的欧拉旋转

3

TLDR; 给定三角形顶点和法向量(都在单位空间中),如何计算三角形在世界空间中的X、Y、Z欧拉旋转角度?

我试图在HTML中显示一个3D模型 - 使用实际的HTML标签和CSS变换。我已经将OBJ文件加载到了Javascript类实例中。

该模型经过三角剖分。我的第一个目标只是将三角形显示为平面(HTML元素是矩形) - 我将稍后使用CSS剪切路径“剪切”出三角形形状。

我真的很难理解并正确地旋转模型的三角形。

我认为旋转矩阵可以帮助我,但我唯一接触过旋转矩阵的情况是当我已经有旋转向量并且需要将其转换并发送到WebGL时。这次没有WebGL(或教程)可以让事情变得更简单。

以下摘录显示了面的创建/“渲染”。我正在使用面法线作为旋转角度,但我知道这是错误的。

for (const face of _obj.faces) {

  const vertices = face.vertices.map(_index => _obj.vertices[_index]);

  const center = [
    (vertices[0][0] + vertices[1][0] + vertices[2][0]) / 3,
    (vertices[0][1] + vertices[1][1] + vertices[2][1]) / 3,
    (vertices[0][2] + vertices[1][2] + vertices[2][2]) / 3
  ];

  // Each vertex has a normal but I am just picking the first vertex' normal
  // to use as the 'face normal'.

  const normals = face.normals.map(_index => _obj.normals[_index]);
  const normal = normals[0];

  // HTML element creation code goes here; reference is 'element'.

  // Set face position (unit space)

  element.style.setProperty('--posX', center[0]);
  element.style.setProperty('--posY', center[1]);
  element.style.setProperty('--posZ', center[2]);

  // Set face rotation, converting to degrees also.

  const rotation = [
    normal[0] * toDeg,
    normal[1] * toDeg,
    normal[2] * toDeg,
  ];

  element.style.setProperty('--rotX', rotation[0]);
  element.style.setProperty('--rotY', rotation[1]);
  element.style.setProperty('--rotZ', rotation[2]);
}

CSS首先沿X,Y,Z轴进行平移,然后按顺序在X、Y、Z轴上进行旋转。

我认为我需要将三角形的旋转“分解”成单独的轴旋转,即先绕X轴旋转,然后绕Y轴旋转,最后绕Z轴旋转,以便根据模型面获得正确的旋转。

我意识到法向量给了我一个方向,但并没有围绕它自身旋转的角度-我需要计算出这个角度。我认为我必须确定一条三角形边缘上的向量,并将其与法向量叉乘,但我不太清楚。

我花了几个小时查看SO上类似的问题,但我聪明不到足以理解或使它们适用于我。

是否可以不使用LaTeX方程式描述所需步骤?我擅长于伪代码编写,但我的数学技能严重不足。

完整代码在此处:https://whoshotdk.co.uk/cssfps/(请查看HTML源代码),生成网格函数位于第422行。

OBJ文件在此处:https://whoshotdk.co.uk/cssfps/data/model/test.obj,Blender文件在此处:https://whoshotdk.co.uk/cssfps/data/model/test.blend

该网格只是一个倾斜的单一平面,在我的示例中(错误地)以粉色显示。

世界设置为-X向左,-Y向上,-Z进入屏幕。

谢谢!

1个回答

0
如果您有一个平面并希望将其旋转到与某个法线方向相同,您需要计算该平面法向量和所需法向量之间的角度。两个三维向量之间的欧拉角可能很复杂,但在这种情况下,初始平面法线应始终相同,因此我将假设平面法线始终指向正X,以使数学计算更简单。
您还可能希望在平移之前进行旋转,以便一切都更容易,因为您将围绕坐标系原点旋转。
通过取通用的三维旋转矩阵(所有三个三维旋转矩阵相乘,您可以在Wikipedia页面上找到它)并将其应用于向量(1,0,0),然后可以获得旋转该初始向量到向量(x,y,z)所需的三个角度a、b和c的方程式。结果如下:
x = cos(a)*cos(b)
y = sin(a)*cos(b)
z = -sin(b)
然后重新排列这些方程以找到a、b和c,这将是您需要的三个角度(分别是rotation数组的三个值)。

a = atan(y/x)

b = asin(-z)

c = 0

因此,在您的代码中,它看起来像:

const rotation = [
    Math.atan2(normal[1], normal[0]) * toDeg,
    Math.asin(-normal[2]) * toDeg,
    0
];

可能需要使用不同的旋转矩阵(如果旋转顺序不是您预期的)或不同的起始向量(尽管您可以使用此方法,然后进行额外的90度旋转,例如,如果每个平面实际上都从正Y方向开始)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接