我想创建一个函数,使用Irrlicht引擎在空间中定位自由浮动的2D光栅图像。这个的灵感来自R包rgl中的函数x/y
。可以在rgl::show2d中找到R中的示例实现。
输入数据应限制在图像的路径和具有相应绘图矩形的四个角坐标的表格。
我的第一个,非常原始的,最后不成功的方法来实现这个与irrlicht:
创建一个多维数据集:
ISceneNode * picturenode = scenemgr->addCubeSceneNode();
扁平化一面:
picturenode->setScale(vector3df(1, 0.001, 1));
将图像添加为纹理:
picturenode->setMaterialTexture(0, driver->getTexture("path/to/image.png"));
将扁平立方体放置在四个角坐标的中心位置。我只用一个小函数position_calc()
来计算所有三个轴上的平均坐标。
vector3df position = position_calc(rcdf); picturenode->setPosition(position);
通过计算由四个角坐标定义的平面的法线确定对象旋转,对结果进行标准化并尝试以某种方式将结果向量转换为旋转角度。
vector3df normal = normal_calc(rcdf);
vector3df angles = (normal.normalize()).getSphericalCoordinateAngles();
picturenode->setRotation(angles);
此解决方案不会产生预期结果。轮换计算错误。使用这种方法,我也无法将图像正确地缩放到它的角坐标。
如何修复我的工作流程?或者有一个更好的方法来实现这一目标,我不知道Irrlicht?
编辑:感谢@spug,我相信我几乎就在那里。我尝试实现他的方法2,因为已经在Irrlicht中可用了。这就是我想出来计算轮换的原因:
#include <Rcpp.h>
#include <irrlicht.h>
#include <math.h>
using namespace Rcpp;
core::vector3df rotation_calc(DataFrame rcdf) {
NumericVector x = rcdf["x"];
NumericVector y = rcdf["y"];
NumericVector z = rcdf["z"];
// Z-axis
core::vector3df zaxis(0, 0, 1);
// resulting image's normal
core::vector3df normal = normal_calc(rcdf);
// calculate the rotation from the original image's normal (i.e. the Z-axis)
// to the resulting image's normal => quaternion P.
core::quaternion p;
p.rotationFromTo(zaxis, normal);
// take the midpoint of AB from the diagram in method 1, and rotate it with
// the quaternion P => vector U.
core::vector3df MAB(0, 0.5, 0);
core::quaternion m(MAB.X, MAB.Y, MAB.Z, 0);
core::quaternion rot = p * m * p.makeInverse();
core::vector3df u(rot.X, rot.Y, rot.Z);
// calculate the rotation from U to the midpoint of DE => quaternion Q
core::vector3df MDE(
(x(0) + x(1)) / 2,
(y(0) + y(1)) / 2,
(z(0) + z(1)) / 2
);
core::quaternion q;
q.rotationFromTo(u, MDE);
// multiply in the order Q * P, and convert to Euler angles
core::quaternion f = q * p;
core::vector3df euler;
f.toEuler(euler);
// to degrees
core::vector3df degrees(
euler.X * (180.0 / M_PI),
euler.Y * (180.0 / M_PI),
euler.Z * (180.0 / M_PI)
);
Rcout << "degrees: " << degrees.X << ", " << degrees.Y << ", " << degrees.Z << std::endl;
return degrees;
}
结果几乎正确,但是一个轴上的旋转是错误的。有没有办法解决这个问题,还是我的实施本身存在缺陷?
现在结果如何。这些点标志着预期的角点。
答案 0 :(得分:1)
我想过两种方法可以做到这一点;既不是非常优雅 - 没有帮助Irrlicht将我们限制在球形极地。
NB。以下假设rcdf
以原点为中心;这是为了使旋转计算更简单一些。虽然容易修复:
rcdf
rcdf
先决条件:缩放
这很容易;只需计算rcdf
与原始图片的宽度和高度比率,然后拨打setScaling
。
方法1:矩阵反转
为此,我们需要一个支持3x3矩阵的外部库,因为Irrlicht只有4x4(我相信)。
我们需要解决将图像从X-Y旋转到rcdf
的矩阵方程。为此,我们在每个参考框架中需要 3分。其中两个我们可以立即设置为图像的相邻角;第三个必须指出图像的平面(因为我们需要所有三维中的数据形成一个完整的基础) - 所以要计算它,只需将每个图像的法线乘以一些偏移常数(比如1)。
(注意原始图像上的点已经缩放)
因此要解决的等式是:
(使用列表示法)。 Eigen
库提供了3x3矩阵的实现和反向。
然后将此矩阵转换为球面极角:https://www.learnopencv.com/rotation-matrix-to-euler-angles/
方法2:
计算四元数从方向向量A旋转到B:Finding quaternion representing the rotation from one vector to another
计算从原始图像的法线(即Z轴)到rcdf
的法线=&gt;的旋转。四元数P
。
从方法1的图表中取 AB 的中点,并使用四元数P
(http://www.geeks3d.com/20141201/how-to-rotate-a-vertex-by-a-quaternion-in-glsl/)旋转它=&GT;向量U
。
计算从U
到 DE =&gt;中点的转数四元数Q
按Q * P
的顺序相乘,并转换为欧拉角:https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
(不确定Irrlicht是否支持四元数)