Irrlicht:根据四个角坐标在 3D space 中绘制 2D 图像
Irrlicht: draw 2D image in 3D space based on four corner coordinates
我想创建一个函数来使用 Irrlicht 引擎在 space 中定位自由浮动的 2D 光栅图像。其灵感来自函数 rgl::show2d in the R package rgl. An example implementation in R can be found 。
输入数据应限于图像路径和 table 以及相应绘图矩形的四个角坐标。
我用 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,因为 quaternions 在 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;
}
结果几乎正确,但是在一个轴上的旋转是错误的。有没有办法解决这个问题,或者我的实施存在固有缺陷?
这就是现在的结果。这些点标记了预期的角点。
我想到了两种方法来做到这一点;两者都不是很优雅 - Irrlicht 将我们限制在球形极地并没有帮助。
注意。下面假设 rcdf
以原点为中心;这是为了让旋转计算更直接一些。虽然很容易修复:
- 计算
rcdf
的中心点(平移偏移量)
- 从
rcdf
的所有点中减去这个
- 执行以下步骤
- 将偏移量加回结果点。
先决条件:缩放
这很简单;只需计算 rcdf
中的宽度和高度与原始图像的比率,然后调用 setScaling
.
方法一:矩阵求逆
为此我们需要一个支持 3x3 矩阵的外部库,因为 Irrlicht 只有 4x4(我相信)。
我们需要求解将图像从 X-Y 旋转到 rcdf
的矩阵方程。为此,我们需要在每个参考系中 3 个点 。其中两个我们可以立即设置为图像的 adjacent 个角;第三个必须指向图像平面之外(因为我们需要所有三个维度的数据来形成一个完整的基础)——所以要计算它,只需将每个图像的法线乘以某个偏移常数(比如 1)即可。
(注意原图上的点已经缩放)
因此要求解的方程为:
(使用列表示法)。 Eigen
库提供了 3x3 矩阵和逆矩阵的实现。
然后将这个矩阵转换为球面极角:https://www.learnopencv.com/rotation-matrix-to-euler-angles/
方法二:
计算四元数从方向向量A旋转到B:Finding quaternion representing the rotation from one vector to another
计算从原图的法线(即Z轴)到rcdf
的法线=>四元数[=18的旋转=].
从方法一的图中取AB的中点,用四元数旋转P
(http://www.geeks3d.com/20141201/how-to-rotate-a-vertex-by-a-quaternion-in-glsl/) => 向量 U
。
计算U
到DE中点的旋转=>四元数Q
按Q * P
的顺序相乘,转换为欧拉角:https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
(不确定 Irrlicht 是否支持四元数)
我想创建一个函数来使用 Irrlicht 引擎在 space 中定位自由浮动的 2D 光栅图像。其灵感来自函数 rgl::show2d in the R package rgl. An example implementation in R can be found
输入数据应限于图像路径和 table 以及相应绘图矩形的四个角坐标。
我用 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,因为 quaternions 在 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;
}
结果几乎正确,但是在一个轴上的旋转是错误的。有没有办法解决这个问题,或者我的实施存在固有缺陷?
这就是现在的结果。这些点标记了预期的角点。
我想到了两种方法来做到这一点;两者都不是很优雅 - Irrlicht 将我们限制在球形极地并没有帮助。
注意。下面假设 rcdf
以原点为中心;这是为了让旋转计算更直接一些。虽然很容易修复:
- 计算
rcdf
的中心点(平移偏移量)
- 从
rcdf
的所有点中减去这个
- 执行以下步骤
- 将偏移量加回结果点。
先决条件:缩放
这很简单;只需计算 rcdf
中的宽度和高度与原始图像的比率,然后调用 setScaling
.
方法一:矩阵求逆
为此我们需要一个支持 3x3 矩阵的外部库,因为 Irrlicht 只有 4x4(我相信)。
我们需要求解将图像从 X-Y 旋转到 rcdf
的矩阵方程。为此,我们需要在每个参考系中 3 个点 。其中两个我们可以立即设置为图像的 adjacent 个角;第三个必须指向图像平面之外(因为我们需要所有三个维度的数据来形成一个完整的基础)——所以要计算它,只需将每个图像的法线乘以某个偏移常数(比如 1)即可。
(注意原图上的点已经缩放)
因此要求解的方程为:
(使用列表示法)。 Eigen
库提供了 3x3 矩阵和逆矩阵的实现。
然后将这个矩阵转换为球面极角:https://www.learnopencv.com/rotation-matrix-to-euler-angles/
方法二:
计算四元数从方向向量A旋转到B:Finding quaternion representing the rotation from one vector to another
计算从原图的法线(即Z轴)到
rcdf
的法线=>四元数[=18的旋转=].从方法一的图中取AB的中点,用四元数旋转
P
(http://www.geeks3d.com/20141201/how-to-rotate-a-vertex-by-a-quaternion-in-glsl/) => 向量U
。计算
U
到DE中点的旋转=>四元数Q
按
Q * P
的顺序相乘,转换为欧拉角:https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
(不确定 Irrlicht 是否支持四元数)