【问题标题】:How to rotate a 3D tringle flat against the wall?如何将 3D 三角形平面旋转靠在墙上?
【发布时间】:2010-09-14 05:34:55
【问题描述】:

我正在处理 3D 网格数据,其中有很多 3D 三角形,我需要旋转它们以消除 Z 值,将其转换为 2D 三角形。

使用这个 2D 三角形,我正在做一些矢量计算。

完成工作后,我需要将其旋转回原来的角度,以便旧点恢复到原来的位置,以适应 3D 网格。


编辑:这是我正在使用的代码。
我不知道如何反转旋转。

输入

var p1:Object, p2:Object, p3:Object;

找正常人脸

var norm:Object = calcNormal(p1,p2,p3);

根据法线求旋转角度

sinteta = -norm.y / Math.sqrt(norm.x * norm.x + norm.y * norm.y);
costeta = norm.x / Math.sqrt(norm.x * norm.x + norm.y * norm.y);
sinfi = -Math.sqrt(norm.x * norm.x + norm.y * norm.y);
cosfi = norm.z;

绕 Z 旋转,然后绕 Y 旋转以与 z 平面对齐。

lx = costeta * cosfi;
ly = -sinteta * cosfi;
lz = sinfi;

mx = sinteta;
my = costeta;
mz = 0;

nx = -sinfi * costeta;
ny = sinfi * sinteta;
nz = cosfi;

var np1:Object = {};
np1.x=p1.x*lx + p1.y*ly + p1.z*lz;
np1.y=p1.x*mx + p1.y*my + p1.z*mz;
np1.z=p1.x*nx + p1.y*ny + p1.z*nz;

var np2:Object = {};
np2.x=p2.x*lx + p2.y*ly + p2.z*lz;
np2.y=p2.x*mx + p2.y*my + p2.z*mz;
np2.z=p2.x*nx + p2.y*ny + p2.z*nz;

var np3:Object = {};
np3.x=p3.x*lx + p3.y*ly + p3.z*lz;
np3.y=p3.x*mx + p3.y*my + p3.z*mz;
np3.z=p3.x*nx + p3.y*ny + p3.z*nz;

【问题讨论】:

  • 不确定我是否理解了这个问题。你能举一个简单的例子来说明如何旋转一个简单的多边形吗?

标签: 3d rotation geometry


【解决方案1】:

使用plane equation 确定平面的法线。然后,确定代表normal to the z axis 的旋转的quaternion。旋转多边形,做你的工作,然后将它旋转回来。

通过从 'w' = 0 的向量创建四元数,可以通过四元数旋转向量:

v = (x, y, z) q = (w=0, x, y, z)

旋转 q2,

rv = q2 * q * q2 ^ -1

要将 rv 转换为点,请删除 w(即 0)。

要再次旋转,请使用

q2 ^ -1 * rv * q

其中 q2 ^ -1 是 q2 的逆或共轭。

编辑 2

适用于 C++ 代码,但这里是我的 Vector3d 和 Quaternion 类的工作方式(简化):

class Vector3d {
  //...
  double x, y, z;
  //...
  // functions here e.g. dot (dot product), cross (cross product)
};

class Quaternion {
  //...
  double w, x, y, z;
  //...
  Quaternion inverse() const { // also equal to conjugate for unit quaternions
    return Quaternion (w, -x, -y, -z);
  }

  static Quaternion align(const Vector3d v1, const Vector3d v2) {
    Vector3d bisector = (v1 + v2).normalize();
    double cosHalfAngle = v1.dot(bisector);
    Vector3d cross;

    if(cosHalfAngle == 0.0) {
      cross = v1.cross(bisector);
    } else {
      cross = v1.cross(Vector3d(v2.z, v2.x, v2.y)).normalize();
    }

    return Quaternion(cosHalfAngle, cross.x, cross.y, cross.z);
  }

  Quaternion operator *(const Quaternion &q) const {
    Quaternion r;

    r.w = w * q.w - x * q.x - y * q.y - z * q.z;
    r.x = w * q.x + x * q.w + y * q.z - z * q.y;
    r.y = w * q.y + y * q.w + z * q.x - x * q.z;
    r.z = w * q.z + z * q.w + x * q.y - y * q.x;

    return r;
  }
};

因此,使用这种数学方法,您的想法是使用“align”方法创建一个四元数,该方法表示从平面法线到 z 轴的旋转(即 v1 是平面法线 [归一化],v2 是 z 轴单位向量)——我们称之为 Q。要旋转每个点 p,您将为该点创建一个四元数 q,旋转它 qr,然后将 q 转换回一个点 p2,如下所示:

q = Quaternion(0, p.x, p.y, p.z);
qr = Q * q * Q.inverse();
p2 = Vector3d(qr.x, qr.y, qr.z);

要再次旋转 p2,请执行以下操作:

q = Quaternion(0, p2.x, p2.y, p2.z);
qr = Q.inverse() * q * Q;
p = Vector3d(qr.x, qr.y, qr.z);

【讨论】:

  • 请注意,对于许多操作,尤其是布尔操作,简单地投影到 x/y 平面(忽略 z 或将其设置为 0)将产生相同的结果 - 但可能仍需要转换结果'返回'。
  • 感谢您的回答,sje,我已经实现了您所说的,但我面临一个问题:我不知道如何将点旋转回默认位置。
【解决方案2】:

旋转三角形几乎肯定是错误的方法。如果您的意图是修改三角形,那么您应该只在其当前 (3d) 坐标系中执行操作。如果您的意图不是修改三角形,那么您不需要将其旋转回来。如果您不知道如何在其当前坐标系中执行您想要的操作,请提出该问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-19
    • 1970-01-01
    • 2020-01-01
    • 1970-01-01
    • 2021-03-27
    • 2018-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多