Matrix 旋转任意平面以进行z轴对齐

Matrix 旋转任意平面以进行z轴对齐,matrix,3d,rotation,Matrix,3d,Rotation,如果我错了,请纠正我,但是 给定任意源平面的法线以及应用所需旋转后平面的法线: Vector3F sourceNormal = (x, y, z).normalize() Vector3F desiredNormal = (0, 0, 1).normalize() 1) 我们可以通过两条法线的叉积找到“旋转轴” Vector3F rotationAxis = Vector3F.cross(sourceNormal, desiredNormal).normalize() 2) 我们可以通过两条

如果我错了,请纠正我,但是

给定任意源平面的法线以及应用所需旋转后平面的法线:

Vector3F sourceNormal = (x, y, z).normalize()
Vector3F desiredNormal = (0, 0, 1).normalize()
1) 我们可以通过两条法线的叉积找到“旋转轴”

Vector3F rotationAxis = Vector3F.cross(sourceNormal, desiredNormal).normalize()
2) 我们可以通过两条法线的点积的弧余弦来求“旋转角度”

// Thanks nico - it was there in my project source, but it was omitted here.
float theta = Math.acos(Vector3F.dot(sourceNormal, desiredNormal))
3) 我们可以将旋转应用于一组点,以便将源平面定向到所需平面

float[] rotationMatrix = new float[16];

// X component
rotationMatrix[5] = rotationMatrix[10] = (float)Math.cos(theta);
rotationMatrix[9] = (float)Math.sin(theta);
rotationMatrix[6] = -rotationMatrix[9];

// Y component
rotationMatrix[0] = rotationMatrix[10] = (float)Math.cos(theta);
rotationMatrix[2] = (float)Math.sin(theta);
rotationMatrix[8] = -rotationMatrix[2];

// Z component
rotationMatrix[0] = rotationMatrix[5] = (float)Math.cos(theta);
rotationMatrix[1] = (float)Math.sin(theta);
rotationMatrix[4] = -rotationMatrix[1];

for(Point3F point : polygon)
{
    float x = pt.getX();
    float y = pt.getY();
    float z = pt.getZ();
    float[] xs = new float[3];
    float[] ys = new float[3];
    float[] zs = new float[3];
    for(int j = 0; j < 3; ++j)
    {
    xs[j] = rotationMatrix[j] * x;
    ys[j] = rotationMatrix[j + 4] * y;
    zs[j] = rotationMatrix[j + 8] * z;
    }
    x = 0; y = 0; z = 0;
    for(int j = 0; j < 3; ++j)
    {
    x += xs[j];
    y += ys[j];
    z += zs[j];
    }
    pt.set(x, y, z);
}
指出:

(-124.960010, -88.105451, 24.185812)
(-107.108590, -88.105451, 24.185812)
(-107.108590, -105.237051, 12.0929052)
(-124.960010, -105.237051, 12.0929052)
如果我不得不猜测的话,我会说我对点的旋转应用得不正确……也许我对本文()中的旋转矩阵的解释不正确

谢谢你的意见

…假设这是设置旋转矩阵的正确方法,则输出仍然不正确:

Vector3F axis = Vector3F.cross(sourceNormal, desiredNormal).normalize();
float angle = (float) Math.acos(p.normal.dot(new Vector3F(0, 0, 1)));
float s = (float)Math.sin(angle);
float c = (float)Math.cos(angle);
float x = axis.getX(), y = axis.getY(), z = axis.getZ();
float[] matrix = new float[16];
matrix[0] = x * x * (1 - c) + c;
matrix[1] = x * y * (1 - c) - (z * s);
matrix[2] = x * z * (1 - c) + (y * s);

matrix[4] = y * x * (1 - c) + (z * s);
matrix[5] = y * y * (1 - c) + c;
matrix[6] = y * z * (1 - c) - (x * s);

matrix[8] = x * z * (1 - c) - (y * s);
matrix[9] = y * z * (1 - c) + (x * s);
matrix[10] = z * z * (1 - c) + c;


float nx = x * matrix[0] + y * matrix[1] + z * matrix[2];
float ny = x * matrix[4] + y * matrix[5] + z * matrix[6];
float nz = x * matrix[8] + y * matrix[9] + z * matrix[10];

In: (-56.00, 56.01, -16.02)
In: (-48.00, 56.01, -16.02)
In: (-48.00, 72.01, -8.02)
In: (-56.00, 72.01, -8.02)
Out: (-51.270340, 46.887921, -25.5108342)
Out: (-43.9460070, 46.887921, -25.5108342)
Out: (-43.9460070, 62.798761, -21.5554182)
Out: (-51.270340, 62.798761, -21.5554182)

你的旋转矩阵是错误的

需要根据您链接到的维基百科文章第10节(“轴和角度的旋转矩阵”)中的公式组合旋转

该矩阵的简化版本也可在该功能的手册页中找到


注意:除非你一遍又一遍地重复这个循环,否则你不需要使用
acos(dotp)
只需要再次使用它的
cos
sin
。直接使用点积作为
cos(theta)
,并使用关系
sin(theta)^2=1-cos(theta)^2
来计算
sin(theta)
最终,出现了许多问题。Alnitak解决了绝大多数问题,我刚刚找到了最后一个

简言之,以下是错误的:

1) 矩阵创建

2) 矩阵乘法

3) 浮点截断

即使这可能是一个骇客的解决方案,对我来说也没问题。工作剪在下面

Vector3F axis = new Vector3F(p.normal);
// Seems to work when adding precision...but NOT with (0, 0, 1)
Vector3F target = new Vector3F(0.000000000000000001f, 0.000000000000001f, 1.0f);
axis.cross(target);
axis.normalize();
float angle = (float) Math.acos(p.normal.dot(new Vector3F(0, 0, 1)));
float s = (float) Math.sin(angle);
float c = (float) Math.cos(angle);
float x = axis.getX(), y = axis.getY(), z = axis.getZ();
float[] matrix = new float[16];
matrix[0] = x * x * (1 - c) + c;
matrix[1] = x * y * (1 - c) - (z * s);
matrix[2] = x * z * (1 - c) + (y * s);
matrix[4] = y * x * (1 - c) + (z * s);
matrix[5] = y * y * (1 - c) + c;
matrix[6] = y * z * (1 - c) - (x * s);
matrix[8] = x * z * (1 - c) - (y * s);
matrix[9] = y * z * (1 - c) + (x * s);
matrix[10] = z * z * (1 - c) + c;

float nx = x * matrix[0] + y * matrix[1] + z * matrix[2];
float ny = x * matrix[4] + y * matrix[5] + z * matrix[6];
float nz = x * matrix[8] + y * matrix[9] + z * matrix[10];

// triangulate (now 2D) polygon
// Rotate the points back
angle = -angle;
s = (float) Math.sin(angle);
c = (float) Math.cos(angle);
matrix[0] = x * x * (1 - c) + c;
matrix[1] = x * y * (1 - c) - (z * s);
matrix[2] = x * z * (1 - c) + (y * s);
matrix[4] = y * x * (1 - c) + (z * s);
matrix[5] = y * y * (1 - c) + c;
matrix[6] = y * z * (1 - c) - (x * s);
matrix[8] = x * z * (1 - c) - (y * s);
matrix[9] = y * z * (1 - c) + (x * s);
matrix[10] = z * z * (1 - c) + c;
nx = x * matrix[0] + y * matrix[1] + z * matrix[2];
ny = x * matrix[4] + y * matrix[5] + z * matrix[6];
nz = x * matrix[8] + y * matrix[9] + z * matrix[10];
// All's well that ends well

1) 这是错误的。你没有测试它吗?通过“测试它”,我收集到的唯一确凿的证据是最终的输出是不正确的。感谢您指出(至少)流程中的一个缺陷。我会调查的。然而,如果我完全错了,请让我知道。@Beta:为什么错了?我能看到的唯一问题是,
acos
theta
的计算中丢失了。此外,请确保
a=b=c
语法导致您期望的结果。并不是所有的编程语言都这样解释。你的旋转矩阵看起来太简单了——请看,我已经用一个假定正确的旋转矩阵更新了这个问题。但是,输出仍然不正确……因此,要么我再次将矩阵弄错,要么出现了另一个问题。感谢您迄今为止的帮助。我还应该提到,这不是性能关键的代码。它仅用于转换工具中,用于三角化某些3D模型(希望在打包到应用程序之前作为一次性操作)。它所要做的就是工作。@LukeA.Leber我看不到任何明显的错误(尽管如果您排除对
axis.getX()
等的重复调用,它会简化代码)。答案现在至少看起来是合理的(向量长度看起来是一致的)。@LukeA.Leber可能是你的矩阵乘法代码,第一次检查时看起来有点奇怪。@LukeA.Leber我建议你用手写出矩阵乘法(例如
float nx=x*m[0]+y*m[1]+z*m[2]
)-它应该只需要三行这样的代码。我建议您尝试我的提示,不要执行
acos
,然后执行
cos
,看看它是否解决了您的精度问题。
Vector3F axis = new Vector3F(p.normal);
// Seems to work when adding precision...but NOT with (0, 0, 1)
Vector3F target = new Vector3F(0.000000000000000001f, 0.000000000000001f, 1.0f);
axis.cross(target);
axis.normalize();
float angle = (float) Math.acos(p.normal.dot(new Vector3F(0, 0, 1)));
float s = (float) Math.sin(angle);
float c = (float) Math.cos(angle);
float x = axis.getX(), y = axis.getY(), z = axis.getZ();
float[] matrix = new float[16];
matrix[0] = x * x * (1 - c) + c;
matrix[1] = x * y * (1 - c) - (z * s);
matrix[2] = x * z * (1 - c) + (y * s);
matrix[4] = y * x * (1 - c) + (z * s);
matrix[5] = y * y * (1 - c) + c;
matrix[6] = y * z * (1 - c) - (x * s);
matrix[8] = x * z * (1 - c) - (y * s);
matrix[9] = y * z * (1 - c) + (x * s);
matrix[10] = z * z * (1 - c) + c;

float nx = x * matrix[0] + y * matrix[1] + z * matrix[2];
float ny = x * matrix[4] + y * matrix[5] + z * matrix[6];
float nz = x * matrix[8] + y * matrix[9] + z * matrix[10];

// triangulate (now 2D) polygon
// Rotate the points back
angle = -angle;
s = (float) Math.sin(angle);
c = (float) Math.cos(angle);
matrix[0] = x * x * (1 - c) + c;
matrix[1] = x * y * (1 - c) - (z * s);
matrix[2] = x * z * (1 - c) + (y * s);
matrix[4] = y * x * (1 - c) + (z * s);
matrix[5] = y * y * (1 - c) + c;
matrix[6] = y * z * (1 - c) - (x * s);
matrix[8] = x * z * (1 - c) - (y * s);
matrix[9] = y * z * (1 - c) + (x * s);
matrix[10] = z * z * (1 - c) + c;
nx = x * matrix[0] + y * matrix[1] + z * matrix[2];
ny = x * matrix[4] + y * matrix[5] + z * matrix[6];
nz = x * matrix[8] + y * matrix[9] + z * matrix[10];
// All's well that ends well