我正在尝试使用标准的arcball旋转来围绕其原点旋转网格。每当我点击3D对象时,我都会从鼠标投射光线以找到交叉点。我测量该交点与3D对象原点的距离,以创建一个球体,该球体将用作该旋转中的“弧形球”(直到释放鼠标为止)。我在每次旋转开始时这样做的原因是因为我希望点击的点保持在鼠标下面。对象正确旋转,只是旋转的幅度较小,因此点击的点不会保留在鼠标下方。以下示例尝试旋转多维数据集。我在纹理上绘制一个黑色矩形以跟踪最初点击的点。以下是该问题的视频:
这是根据鼠标位置和点击计算的球体半径(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);
如何让点击的点保留在鼠标下?
答案 0 :(得分:2)
将弧形球半径设置为点击的点与对象中心之间的距离。换句话说,第一个点是立方体上的光线投射,随后的点将是以对象为中心并具有上述半径的假想球体上的光线投影。
P.S。:查看我的arcball rotation code on codereview.SE.它没有混乱acos和轴角度,只能标准化两次。