C++ Irrlicht:基于四个角坐标在三维空间中绘制二维图像
我想创建一个函数,用Irrlicht引擎在空间中定位一个自由浮动的二维光栅图像。其灵感来自R包rgl中的函数。在R中可以找到一个示例实现 输入数据应限于图像的路径和具有相应绘图矩形的四个角坐标的表格 我用irrlicht实现这一点的第一个、相当原始但最终失败的方法: 创建多维数据集:C++ Irrlicht:基于四个角坐标在三维空间中绘制二维图像,c++,3d,irrlicht,C++,3d,Irrlicht,我想创建一个函数,用Irrlicht引擎在空间中定位一个自由浮动的二维光栅图像。其灵感来自R包rgl中的函数。在R中可以找到一个示例实现 输入数据应限于图像的路径和具有相应绘图矩形的四个角坐标的表格 我用irrlicht实现这一点的第一个、相当原始但最终失败的方法: 创建多维数据集: ISceneNode * picturenode = scenemgr->addCubeSceneNode(); 展平一侧: picturenode->setScale(vector3df(1, 0
ISceneNode * picturenode = scenemgr->addCubeSceneNode();
展平一侧:
picturenode->setScale(vector3df(1, 0.001, 1));
将图像添加为纹理:
picturenode->setMaterialTexture(0, driver->getTexture("path/to/image.png"));
将展开的立方体放置在四个角坐标的中心位置。我只是用一个小函数position\u calc()
计算所有三个轴上的平均坐标
通过计算由四个角坐标定义的平面法线,对结果进行规格化,并尝试以某种方式将结果向量转换为旋转角度,来确定对象旋转
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;
}
#包括
#包括
#包括
使用名称空间Rcpp;
core::vector3df旋转计算(数据帧rcdf){
数值向量x=rcdf[“x”];
数值向量y=rcdf[“y”];
数值向量z=rcdf[“z”];
//Z轴
core::vector3df-zaxis(0,0,1);
//生成的图像是正常的
core::vector3df normal=normal_calc(rcdf);
//从原始图像的法线(即Z轴)计算旋转
//到结果图像的法线=>四元数P。
核::四元数p;
p、 从旋转到(zaxis,正常);
//从方法1中的图中取AB的中点,并用
//四元数P=>向量U。
core::vector3df单克隆抗体(0,0.5,0);
核:四元数m(MAB.X,MAB.Y,MAB.Z,0);
core::四元数rot=p*m*p.makeInverse();
核心:向量3df u(rot.X,rot.Y,rot.Z);
//计算从U到DE=>四元数Q中点的旋转
core::vector3df MDE(
(x(0)+x(1))/2,
(y(0)+y(1))/2,
(z(0)+z(1))/2
);
核::四元数q;
q、 从旋转到(u,MDE);
//按Q*P的顺序相乘,并转换为欧拉角
核::四元数f=q*p;
核心:矢量3df欧拉;
f、 托勒(欧拉);
//到一定程度
core::vector3df度(
euler.X*(180.0/M_-PI),
euler.Y*(180.0/M_-PI),
euler.Z*(180.0/M_-PI)
);
Rcout我已经想到了两种方法来做到这一点;这两种方法都不是非常优雅的——这是因为irlicht将我们限制在球面上
注意:以下假设rcdf
以原点为中心;这是为了使旋转计算更简单。不过,很容易修复:
计算rcdf的中心点(平移偏移量)
从rcdf的所有点中减去该值
执行以下步骤
将偏移添加回结果点
先决条件:缩放
这很简单;只需计算rcdf
中的宽度和高度与原始图像的比率,然后调用setScaling
方法1:矩阵求逆
为此,我们需要一个支持3x3矩阵的外部库,因为Irrlicht只有4x4(我相信)
我们需要求解将图像从X-Y旋转到rcdf
的矩阵方程。为此,我们在每个参考帧中需要3个点。其中两个点可以立即设置到图像的相邻角;第三个点必须指向图像平面之外(因为我们需要所有三维的数据来形成完整的基础)-为了计算它,只需将每个图像的法线乘以某个偏移常数(比如1)
(注意原始图像上的点已缩放)
因此,要求解的方程为:
(使用列表示法)Eigen
库提供了3x3矩阵和逆矩阵的实现
然后将该矩阵转换为球面极角:
方法2:
要计算要从方向向量A旋转到方向向量B的四元数,请执行以下操作:
计算从原始图像法线(即Z轴)到rcdf
法线=>四元数p
的旋转
从方法1中的图中取AB的中点,用四元数p
()=>向量U
旋转它
计算从U
到DE=>四元数Q
按Q*p的顺序相乘,并转换为欧拉角:
(不确定Irrlicht是否支持四元数)什么是rcdf
?我使用的是框架。它是一个DataFrame对象,在本例中表示一个有3列4行的表。四个角点的x、y和z坐标。对不起,我忘了描述这个。问题是只有两个球面坐标角;您需要第三个来指定旋转在法线周围的图像中,这被称为滚动。你至少能够使图像平面指向正确的方向吗?你的意思是我计算法线的函数是否正确?我实现了示例。我假设你知道如何实现它(非常简单)-在我们继续之前,我只是想检查一下。我的观点是法线本身不包含图像围绕它旋转的信息。这是一个数学概念,不是y中的错误
#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;
}