1

我正在尝试使用标准轨迹球旋转围绕其原点旋转网格。每当我单击 3D 对象时,我都会从鼠标投射光线以找到交点。我测量该交点与 3D 对象原点的距离,以创建一个球体,该球体将用作该旋转中的“弧球”(直到释放鼠标)。我在每次旋转开始时这样做的原因是因为我希望单击的点保持在鼠标下方。对象旋转正确,只是旋转的幅度较小,因此单击的点不会保留在鼠标下方。以下示例尝试旋转立方体。我在纹理上绘制了一个黑色矩形来跟踪最初点击的点。这是该问题的视频:

http://youtu.be/x8rsqq1Qdfo

这是根据鼠标位置和点击时计算的球体半径(arcballRadius)获取轨迹球矢量的函数(我担心这个函数没有考虑立方体对象的位置,尽管它恰好是立方体对象位于 (0,0,z):

/**
* Get a normalized vector from the center of the virtual ball O to a
* point P on the virtual ball surface, such that P is aligned on
* screen's (X,Y) coordinates.  If (X,Y) is too far away from the
* sphere, return the nearest point on the virtual ball surface.
*/

glm::vec3 get_arcball_vector(double x, double y) {
glm::vec3 P = glm::vec3(x,y,0);
float OP_squared = P.x * P.x + P.y * P.y;
if (OP_squared <= arcballRadius*arcballRadius)
    P.z = sqrt(arcballRadius*arcballRadius - OP_squared);  // Pythagore
else
 {
   static int i;
   std::cout << i++ << "Nearest point" << std::endl;
   P = glm::normalize(P);  // nearest point
 }
 return P;
}

每当鼠标移动

//get two vectors, one for the previous point and one for the current point
glm::vec3 va = glm::normalize(get_arcball_vector(prevMousePos.x, prevMousePos.y)); //previous point
glm::vec3 vb = glm::normalize(get_arcball_vector(mousePos.x, mousePos.y));         //current point
float angle = acos(glm::dot(va, vb));  //angle between those two vectors based on dot product

//since these axes are in camera coordinates they must be converted before applied to the object
glm::vec3 axis_in_camera_coord = glm::cross(va, vb);   
glm::mat3 camera2object = glm::inverse(glm::mat3(viewMatrix) * glm::mat3(cube.modelMatrix));
glm::vec3 axis_in_object_coord = camera2object * axis_in_camera_coord;

//apply rotation to cube's matrix
cube.modelMatrix = glm::rotate(cube.modelMatrix, angle, axis_in_object_coord);

如何使单击的点保持在鼠标下方?

4

1 回答 1

2

将轨迹球半径设置为单击的点与对象中心之间的距离。换句话说,第一个点是立方体上的光线投射,随后的点将是一个以对象为中心并具有上述半径的假想球体上的光线投射。

PS:在 codereview.SE 上查看我的轨迹球旋转代码。它不会与 acos 和 axis-angle 混淆,只会标准化两次。

于 2014-12-11T08:09:24.557 回答