我正在尝试通过this website的说明实施拣选光线。
现在我基本上只希望能够点击地面命令我的小人物走向这一点。 由于我的地平面是平坦的,非旋转和非平移的,当y到达0时,我必须找到我的拾取光线的x和z坐标。
到目前为止,这是我提出的:
//some constants
float HEIGHT = 768.f;
float LENGTH = 1024.f;
float fovy = 45.f;
float nearClip = 0.1f;
//mouse position on screen
float x = MouseX;
float y = HEIGHT - MouseY;
//GetView() returns the viewing direction, not the lookAt point.
glm::vec3 view = cam->GetView();
glm::normalize(view);
glm::vec3 h = glm::cross(view, glm::vec3(0,1,0) ); //cameraUp
glm::normalize(h);
glm::vec3 v = glm::cross(h, view);
glm::normalize(v);
// convert fovy to radians
float rad = fovy * 3.14 / 180.f;
float vLength = tan(rad/2) * nearClip; //nearClippingPlaneDistance
float hLength = vLength * (LENGTH/HEIGHT);
v *= vLength;
h *= hLength;
// translate mouse coordinates so that the origin lies in the center
// of the view port
x -= LENGTH / 2.f;
y -= HEIGHT / 2.f;
// scale mouse coordinates so that half the view port width and height
// becomes 1
x /= (LENGTH/2.f);
y /= (HEIGHT/2.f);
glm::vec3 cameraPos = cam->GetPosition();
// linear combination to compute intersection of picking ray with
// view port plane
glm::vec3 pos = cameraPos + (view*nearClip) + (h*x) + (v*y);
// compute direction of picking ray by subtracting intersection point
// with camera position
glm::vec3 dir = pos - cameraPos;
//Get intersection between ray and the ground plane
pos -= (dir * (pos.y/dir.y));
此时我希望pos
成为我的采光射线撞击地平面的点。
然而,当我尝试它时,我得到这样的东西:
(未记录鼠标光标)
很难看到,因为地面没有纹理,但相机是倾斜的,就像大多数RTS游戏一样。
根据我的计算,我在Blender中对远程人类进行建模的可怜尝试标志着交叉点的发生点。
所以似乎view
和dir
之间的转换搞砸了,我的光线最终指向错误的方向。
计算出的位置与实际位置之间的差距越大,我越远离屏幕中心移动。
我发现了:
glm::perspective(45.f, 1.38f, 0.1f, 500.f)
(fovy,纵横比,fNear,fFar)。所以这就是我迷失的地方。为了获得准确的射线,我该怎么做?
PS:我知道有一些函数和库已经实现了,但我试图远离这些东西用于学习目的。
答案 0 :(得分:0)
这是使用深度缓冲信息执行光标到3D转换的工作代码:
glGetIntegerv(GL_VIEWPORT, @fViewport);
glGetDoublev(GL_PROJECTION_MATRIX, @fProjection);
glGetDoublev(GL_MODELVIEW_MATRIX, @fModelview);
//fViewport already contains viewport offsets
PosX := X;
PosY := ScreenY - Y; //In OpenGL Y axis is inverted and starts from bottom
glReadPixels(PosX, PosY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, @vz);
gluUnProject(PosX, PosY, vz, fModelview, fProjection, fViewport, @wx, @wy, @wz);
XYZ.X := wx;
XYZ.Y := wy;
XYZ.Z := wz;
如果你只测试光线/平面交叉点,那么这是没有DepthBuffer的第二部分:
gluUnProject(PosX, PosY, 0, fModelview, fProjection, fViewport, @x1, @y1, @z1); //Near
gluUnProject(PosX, PosY, 1, fModelview, fProjection, fViewport, @x2, @y2, @z2); //Far
//No intersection
Result := False;
XYZ.X := 0;
XYZ.Y := 0;
XYZ.Z := aZ;
if z2 < z1 then
SwapFloat(z1, z2);
if (z1 <> z2) and InRange(aZ, z1, z2) then
begin
D := 1 - (aZ - z1) / (z2 - z1);
XYZ.X := Lerp(x1, x2, D);
XYZ.Y := Lerp(y1, y2, D);
Result := True;
end;
我发现它与你正在做的事情有很大不同,但也许这会更有意义。