我试图想象一个以原点为中心的点云。我也希望有一个用户控制的旋转,我找到了弧球。
rMat是模型矩阵,传递给着色器。
inline QVector3D getArcballVector(const QPoint& pt, int width, int height)
{
QVector3D P = QVector3D(1.0*pt.x ()/width * 2 - 1.0,
1.0*pt.y ()/height * 2 - 1.0,
0);
P.setY (-P.y ());
float OP_squared = P.lengthSquared ();
if (OP_squared <= 1)
P.setZ (std::sqrt(1 - OP_squared)); // Pythagore
else
P.normalize (); // nearest point
return P;
}
void PointCloud::mouseMoveEvent(QMouseEvent * e)
{
if(e->buttons ()==Qt::LeftButton)
{
if(!rotPos.isNull () && rotPos!=e->pos ())
{
//rotate using an arcBall for freeform rotation
QVector3D vec1 = getArcballVector (rotPos, width (), height ());
QVector3D vec2 = getArcballVector (e->pos (), width (), height ());
//use bisector to get half-angle cos and sin from dot and cross product
// for quaternion initialisation
QVector3D vec3 = vec1+vec2;
vec3.normalize ();
QVector3D rotaxis = QVector3D::crossProduct (vec1, vec3);
double cos = QVector3D::dotProduct (vec1, vec3);
QQuaternion quat (cos,rotaxis);
quat.normalize ();
//we want to left-multiply rMat with quat but that isn't available
//so we'll have to do it the long way around
QMatrix4x4 rot;
rot.rotate (quat);
rMat=rot*rMat;
updateGL ();
}
rotPos=e->pos ();
}
}
void PointCloud::mousePressEvent(QMouseEvent *e)
{
if(e->buttons ()==Qt::LeftButton)
{
rotPos=e->pos ();
}
}需要指出的一点是,大多数弧球例子都使用acos来获得轴角表示的旋转角度,并使用它创建矩阵,并且在传递时只提到使用四元数(如果它们确实使用四元数,它们最终仍然使用轴角)。我发现,我可以直接利用第一个向量的点和交叉积与两个向量的平分线(vec3)求出四元数。
有什么明显的低效吗?我可以将更新代码移到QTimer激活的插槽中,但是程序的使用使得用户在集中注意力在路上时,大多忽略了屏幕。
发布于 2014-11-27 11:22:08
经过一些研究后,我发现直接从双四元数获得半四元数的效率略高:
QVector3D rotaxis = QVector3D::crossProduct (vec1, vec2);
double cos = QVector3D::dotProduct (vec1, vec2);
// rotaxis and cos describe the double quat
// add 1 to cos so normalizing will 0.5 lerp between the null quat and the double quat
QQuaternion quat (1+cos,rotaxis);
quat.normalize ();这样就省去了平分线的规范化。
旋转矩阵可以由一个非单位四元数来构造,而不需要首先对其进行规范化。您必须提供自己的函数才能做到这一点,因为Qt算法假设单位四元数:
inline QMatrix4x4 quatToMat(QQuaternion q)
{
//based on algorithm on wikipedia
// http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion
float w = q.scalar ();
float x = q.x();
float y = q.y();
float z = q.z();
float n = q.lengthSquared();
float s = n == 0? 0 : 2 / n;
float wx = s * w * x, wy = s * w * y, wz = s * w * z;
float xx = s * x * x, xy = s * x * y, xz = s * x * z;
float yy = s * y * y, yz = s * y * z, zz = s * z * z;
float m[16] = { 1 - (yy + zz), xy + wz , xz - wy ,0,
xy - wz , 1 - (xx + zz), yz + wx ,0,
xz + wy , yz - wx , 1 - (xx + yy),0,
0 , 0 , 0 ,1 };
QMatrix4x4 result = QMatrix4x4(m,4,4);
result.optimize ();
return result;
}使用它可以消除mouseMoveEvent中的所有规范化,除了获取arcballVectors本身。
https://codereview.stackexchange.com/questions/51205
复制相似问题