要点:
我在3D空间中给出了一系列点,我想从任何视角分析它们。我试图弄清楚如何在WPF中重现OpenGL的“Look At”功能。我希望鼠标移动X,Y来分别操纵相机的Phi和Theta球面坐标,这样当我移动鼠标时,相机就会围绕点云的质心(通常是原点)进行轨道运动,这将代表Look At的目标
我做了什么:
我已经制作了以下代码,但到目前为止它并没有按照我的意愿行事:
internal static Matrix3D CalculateLookAt(Vector3D eye, Vector3D at = new Vector3D(), Vector3D up = new Vector3D())
{
if (Math.Abs(up.Length - 0.0) < double.Epsilon) up = new Vector3D(0, 1, 0);
var zaxis = (at - eye);
zaxis.Normalize();
var xaxis = Vector3D.CrossProduct(up, zaxis);
xaxis.Normalize();
var yaxis = Vector3D.CrossProduct(zaxis, xaxis);
return new Matrix3D(
xaxis.X, yaxis.X, zaxis.X, 0,
xaxis.Y, yaxis.Y, zaxis.Y, 0,
xaxis.Z, yaxis.Z, zaxis.Z, 0,
Vector3D.DotProduct(xaxis, -eye), Vector3D.DotProduct(yaxis, -eye), Vector3D.DotProduct(zaxis, -eye), 1
);
}
我从这个链接获得了算法:http://msdn.microsoft.com/en-us/library/bb205342(VS.85).aspx
然后我使用以下方法将返回的矩阵应用于所有点:
var vector = new Vector3D(p.X, p.Y, p.Z);
var projection = Vector3D.Multiply(vector, _camera); // _camera is the LookAt Matrix
if (double.IsNaN(projection.X)) projection.X = 0;
if (double.IsNaN(projection.Y)) projection.Y = 0;
if (double.IsNaN(projection.Z)) projection.Z = 0;
return new Point(
(dispCanvas.ActualWidth * projection.X / 320),
(dispCanvas.ActualHeight * projection.Y / 240)
);
我正在计算所有点的中心作为at
向量,我一直在eye
处设置我的初始(center.X,center.Y,center.Z + 100)
向量,距离所有点都很远
然后我移动鼠标并应用以下代码来获得球面坐标并将其放入CalculateLookAt
函数:
var center = GetCenter(_points);
var pos = e.GetPosition(Canvas4); //e is of type MouseButtonEventArgs
var delta = _previousPoint - pos;
double r = 100;
double theta = delta.Y * Math.PI / 180;
double phi = delta.X * Math.PI / 180;
var x = r * Math.Sin(theta) * Math.Cos(phi);
var y = r * Math.Cos(theta);
var z = -r * Math.Sin(theta) * Math.Sin(phi);
_camera = MathHelper.CalculateLookAt(new Vector3D(center.X * x, center.Y * y, center.Z * z), new Vector3D(center.X, center.Y, center.Z));
UpdateCanvas(); // Redraws the points on the canvas using the new _camera values
结论:
这不会使相机围绕这些点进行轨道运行。所以要么我对如何使用Look At功能的理解是关闭的,要么我的数学不正确。
非常感谢任何帮助。
答案 0 :(得分:4)
Vector3D
不会在仿射空间中转换。 Vector3D
将不会翻译,因为它是一个矢量,它不存在于仿射空间(即具有平移分量的3D矢量空间)中,仅在矢量空间中。您需要Point3D
:
var m = new Matrix3D(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
10, 10, 10, 1);
var v = new Point3D(1, 1, 1);
var r = Point3D.Multiply(v, m); // 11,11,11
请注意,您的假定答案也不正确,因为每个组件的答案应为10 + 1
,因为您的向量为[1,1,1]
。
答案 1 :(得分:-2)
嗯,事实证明Matrix3D库有一些有趣的问题。
我注意到Vector3D.Multiply(vector, matrix)
不会翻译矢量。
例如:
var matrixTest = new Matrix3D(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
10, 10, 10, 1
);
var vectorTest = new Vector3D(1, 1, 1);
var result = Vector3D.Multiply(vectorTest, matrixTest);
// result = {1,1,1}, should be {11,11,11}
我最终不得不重写一些基本的矩阵数学函数,以使代码工作。
除逻辑方面外,一切正常,基本数学(由Matrix3D库处理)是问题所在。
这是修复。将所有Vector3D.Multiply
方法调用替换为:
public static Vector3D Vector3DMultiply(Vector3D vector, Matrix3D matrix)
{
return new Vector3D(
vector.X * matrix.M11 + vector.Y * matrix.M12 + vector.Z * matrix.M13 + matrix.OffsetX,
vector.X * matrix.M21 + vector.Y * matrix.M22 + vector.Z * matrix.M23 + matrix.OffsetY,
vector.X * matrix.M31 + vector.Y * matrix.M32 + vector.Z * matrix.M33 + matrix.OffsetZ
);
}
一切正常!