我有自己的unproject
功能,用于执行屏幕点的反向投影。代码如下(用OpenTK编写):
public static Vector3 UnProject(Point screenLocation, float depth)
{
int[] viewport = GetViewport();
Vector4 pos = new Vector4();
// Map x and y from window coordinates, map to range -1 to 1
pos.X = (screenLocation.X - viewport[0]) / (float)viewport[2] * 2.0f - 1.0f;
pos.Y = 1 - (screenLocation.Y - viewport[1]) / (float)viewport[3] * 2.0f;
pos.Z = depth * 2.0f - 1.0f;
pos.W = 1.0f;
Vector4 pos2 = Vector4.Transform(pos, Matrix4.Invert(GetModelViewMatrix() * GetProjectionMatrix()));
Vector3 pos_out = new Vector3(pos2.X, pos2.Y, pos2.Z);
return pos_out / pos2.W;
}
基本上,您可以为我的功能提供所需的非投影深度,它将为您提供屏幕点的相应世界坐标。假设这个工作正常(我肯定认为它确实如此),我在将屏幕点转换为世界坐标时遇到了问题。这个非投影适用于选择:我将我的unproject
函数调用两次(一次深度= 0,另一次深度= 1)将屏幕点转换为光线。我执行光线/三角形交叉以确定哪个物体与光线相交,并基于我执行拾取(这非常准确)。
对于另一个操作(让我们称之为操作X),我只需要知道屏幕点的世界坐标(假设鼠标光标在屏幕上的对象上)。为此,我使用glReadPixel
函数获取光标下的深度。问题是我觉得通过读取深度缓冲区获得的Z值有点偏。如果我计算与光线投射的交点,我会得到准确的结果,但这对于操作X来说是不可行的,因为每次触发MouseMoved
时都需要执行操作X.
为了证明缺乏准确性,以下是我获得的两个数字:
glReadPixel + Unprojection产生(0.886105343709181,0.12422376198582,0.998496665566841)作为光标下的世界坐标。
光线投射+交叉点产生(0.885407337013061,0.124174778008613,1)作为光标下的世界坐标。
对于操作X,Z值中的0.0015误差太大(因为它对小数字非常敏感)。
我应该知道glReadPixels
有什么问题吗?是否发生这种情况是因为glReadPixels
只能读取float
值?
答案 0 :(得分:1)
我不认为glReadPixels
应该归咎于此。我认为Z缓冲区精度是个问题。默认情况下,您通常具有24位定点深度缓冲区。如果您使用32位浮点深度缓冲区,可能会有所帮助,但您可能需要一个FBO。