沿表面法线定向物体

Orient object along surface normal

当用户单击表面时,我想在此位置放置一个对象并将其定向为垂直于表面法线。

用户单击后,我从缓冲区读取三个相邻像素的深度,将像素从屏幕坐标取消投影到对象 space,然后根据对象中的这些点计算表面法线 space:

glReadPixels(mouseX, mouseY, ..., &depthCenter);
pointCenter = gluUnProject(mouseX, mouseY, depthCenter, ...);

glReadPixels(mouseX, mouseY - 1, ..., &depthUp);
pointUp = gluUnProject(mouseX, mouseY - 1, depthUp, ...);

glReadPixels(mouseX - 1, mouseY, ..., &depthLeft);
pointLeft = gluUnProject(mouseX - 1, mouseY, depthLeft, ...);

centerUpVec = norm( pointCenter - pointUp );
centerLeftVec = norm( pointCenter - pointLeft );
normalVec = norm( centerUpVec.cross(centerLeftVec) );

我知道仅从三个像素计算法线是有问题的(例如在边缘处或三个点的深度差异很大),但对于我在平坦表面上的初始测试,这就足够了。

最后,为了沿着计算出的法向量定向对象,我从法向量和向上向量创建了一个旋转矩阵:

upVec = vec(0.0f, 1.0f, 0.0f);
xAxis = norm( upVec.cross(normalVec) );
yAxis = norm( normalVec.cross(xAxis) );

// set orientation of model matrix
modelMat(0,0) = xAxis(0);
modelMat(1,0) = yAxis(0);
modelMat(2,0) = normalVec(0);

modelMat(0,1) = xAxis(1);
modelMat(1,1) = yAxis(1);
modelMat(2,1) = normalVec(1);

modelMat(0,2) = xAxis(2);
modelMat(1,2) = yAxis(2);
modelMat(2,2) = normalVec(2);

// set position of model matrix by using the previously computed center-point
modelMat(0,3) = pointCenter(0);
modelMat(1,3) = pointCenter(1);
modelMat(2,3) = pointCenter(2);

出于测试目的,我在每次点击后将对象放置在平面上。这在大多数情况下效果很好,当我的相机朝下向上矢量时。

但是,一旦我旋转我的相机,放置的物体就会任意定向,我不明白为什么!

好的,我刚刚在我的代码中发现了一个与实际问题无关的小而愚蠢的错误。因此,上述问题中所述的方法是正确的。

为了避免一些陷阱,当然可以只使用数学库,例如 Eigen,来计算向上向量和表面法线之间的旋转:

upVec = Eigen::Vector3f(0.0f, 1.0f, 0.0f);
Eigen::Quaternion<float> rotationQuat;
rotationQuat.setFromTwoVectors(upVec, normalVec);