在了解了很多有关转换的知识之后,该为我的应用实现轨迹球了。
我知道我必须从起点到单击鼠标的位置创建一个矢量,然后再从起点到释放鼠标的位置创建一个矢量。

我的问题是,我是否必须将(x,y)像素坐标转换为世界坐标,还是我应该在图像空间中做所有事情(考虑图像空间是场景的2D投影)以像素为单位)?

编辑

Richie Sams的答案是一个很好的答案。但是,我认为我采用的方法略有不同,如果我错了或者我误会了某些东西,请纠正我。

在我的应用程序中,我有一个SimplePerspectiveCamera类,该类接收相机,我们正在查看的position向量,position of the target向量,upfovyaspectRationear距离。现在,如果要放大/缩小,请更新视野并更新投影矩阵。如果要平移,请移动摄像机的位置,并按鼠标产生的增量查看。

最后,对于旋转,我可以使用角度轴变换或四元数。为此,我将像素坐标保存在按下鼠标的位置,然后在鼠标移动时也保存像素坐标。

对于每对坐标,我可以根据给定的坐标来计算Z值球体的公式,即sqrt(1-x ^ 2-y ^ 2),然后计算出从fartarget以及从PointMousePressedtarget的向量,进行乘积运算以获得旋转轴并使用任何方法计算新的相机位置。

但是,我最大的疑问是(x,y,z)值是以像素坐标给出的,当我使用PointMouseMoved计算矢量时,世界坐标中的一点。坐标系的这种混合不影响我尝试做的旋转结果吗?

评论

“轨迹球”是否意味着像在3D建模应用程序中一样围绕物体旋转的摄像机?如果是这样,我认为通常是通过跟踪2D鼠标坐标并为相机旋转映射x = yaw,y = pitch来完成的。

@NathanReed另一个选项是基于轴角度的,您将2个鼠标点投影到(虚拟)球体上,然后找到从一个到另一个的旋转。

@NathanReed是的,这就是轨迹球的意思,我认为它是CG社区中的通用名称。

@ratchetfreak是的,我的方法考虑了基于轴角度的旋转。我的疑问是是否需要将2D鼠标坐标映射到世界坐标。我知道我可以使用(x,y)来计算半径为r的球体的z值,但是我不确定该球体是否生活在世界空间或图像空间中,其含义是什么。也许我想得太过分了。

编辑时:是。您需要使用View矩阵将(x,y,z)值转换为世界空间。

#1 楼

假设您指的是根据鼠标移动旋转的相机:

实现它的一种方法是跟踪相机的位置及其在空间中的旋转。球形坐标恰好对此方便,因为您可以直接表示角度。由m_theta,m_phi和m_radius定义。通过更改这三个值,我们可以随意旋转和移动。但是,我们总是查看并旋转m_target。 m_target是球体的本地原点。但是,我们可以将这个原点自由移动到世界空间中的任何地方。

相机具有三个主要功能:

float m_theta;
float m_phi;
float m_radius;

float3 m_target;


最简单的形式是Rotate()和Zoom()。分别修改m_theta,m_phi和m_radius即可:

void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);


平移有点复杂。摄像机平移定义为分别将摄像机移动到当前摄像机视图的左/右和/或上/下。实现此目的最简单的方法是将当前的摄影机视图从球面坐标转换为笛卡尔坐标。这将为我们提供一个向上和向右的向量。

void Camera::Rotate(float dTheta, float dPhi) {
    m_theta += dTheta;
    m_phi += dPhi;
}

void Camera::Zoom(float distance) {
    m_radius -= distance;
}


因此,首先,我们将球面坐标系转换为笛卡尔坐标,以得到外观向量。接下来,我们将向量与世界上的向量做叉积,以获得正确的向量。这是直接指向摄像机视图右侧的向量。最后,我们进行另一个矢量叉积运算,以使摄像机向上移动向量。问:为什么总是在笛卡尔和球面之间进行转换(您还必须进行转换才能创建View矩阵)。

好问题。我也有这个问题,并试图专门使用笛卡尔。您最终会遇到旋转问题。由于浮点操作不完全精确,因此多次旋转最终会积累误差,这会慢慢对应于相机,并且会意外滚动。



所以,最后,我陷入了球坐标系。为了应对额外的计算,我最终缓存了视图矩阵,并且仅在摄像机移动时对其进行计算。

最后一步是使用此Camera类。只需在应用程序的MouseDown / Up / Scroll函数中调用相应的成员函数即可:平移/滚动

上面的代码是我为辅助项目camera.h和camera.cpp制作的摄像机系统的简化伪代码版本。相机尝试模仿Maya相机系统。该代码是免费和开源的,因此可以在您自己的项目中随意使用它。

评论


$ \ begingroup $
我想除以300只是给定鼠标位移时旋转灵敏度的一个参数?
$ \ endgroup $
– BRabbit27
15年8月12日,0:43

$ \ begingroup $
正确。当时与我的分辨率配合得很好。
$ \ endgroup $
–RichieSams
15年8月12日在1:02

#2 楼

如果您想看看现成的解决方案,我有一个C ++和C#中的THREE.JS TrackBall控件端口。

评论


$ \ begingroup $
我倾向于这样做。他可以从跟踪球内部的代码中学习。
$ \ endgroup $
–迈克尔四世
2015年9月8日在7:59

$ \ begingroup $
@MichaelIV不过,艾伦·沃尔夫(Alan Wolfe)有一点。您可以通过在答案本身中包含相关代码,使其自成体系,并保证将来有一天不出现链接失效,从而大大改善您的答案。
$ \ endgroup $
–马丁·恩德(Martin Ender)
2015年11月3日,8:45