我正在用OpenGL做一个3D项目。拾取对象是我要担心的事情,但现在我不能让主要的事情工作。那就是用鼠标从我的相机投射光线。我已经挖掘了太多的例子,包括没有“取消投影”的光线投射,但它们给予我的结果几乎是一样的!它们几乎是工作的,现在我几乎被卡住了,不知道该怎么做。
考虑一下我最后选择的方法:
function CCamera.GetRay(x: Single; y: Single;) : TVector3;
var
mouseX: single;
mouseY: single;
invVP: TMatrix4;
screenPos: TVector4;
worldPos: TVector4;
worldPos3: TVector3;
dir: TVector3;
begin
// NDC
mouseX := x / (fViewportWidth * 0.5) - 1.0;
mouseY := y / (fViewportHeight * 0.5) - 1.0;
invVP := mView * mProjection;
// invVP.SetInversed; // Inversed doesn't even cast the ray close to where I want it cast at.
// mProjection * mView would also generate behavior that isn't close to what I want.
screenPos.Init(mouseX, -mouseY, 1.0, 1.0);
worldPos := invVP * screenPos;
worldPos3.Init(worldPos.X, worldPos.Y, worldPos.Z);
dir := worldPos3.Normalize();
Exit(dir);
end;
从字面上看。每一个。单个。例子都给了我同样的结果!这是我会坚持的一个。
然后,我将确定摄影机光线的结束位置,如下所示:
已更新代码:
procedure TOpenGLControl.OnMouseDown(Sender: TObject; Button:
TMouseButton; Shift: TShiftState; X: Integer; Y: Integer);
var
ray_start: TVector3;
ray_end: TVector3;
ray_dir: TVector3;
begin
ray_start := GetCamera.GetPosition(); // Position of the camera
ray_dir := GetCamera.GetRay(X, Y); // Pass 2D mouse coordinates
ray_end := ray_start + ray_dir * 50.0; // Max distance of 50 units
Invalidate();
end;
使用Neslib.FastMath作为数学函数和属性。所以,基本上,发生的事情是,我从世界的中心(三角形所在的地方)点击得越远,光线就越靠近中心。检查图像。
2条答案
按热度按时间p1tboqfb1#
不是一个 Delphi 编码器,但这里有一些来自BCB和VCL的见解(应该是相同的):
1.使用本地鼠标位置(
OnMouseMove
)1.将鼠标位置转换为OpenGL位置
注意鼠标
y
轴是在相反的方向OpenGL和(0,0)
是在屏幕的中心,而不是在左上角。和范围通常是<-1.0,+1.0>
从我所看到的,你不是反转y
,并有范围<0.0,1.0>
,如果我看到它的权利...如果你的表单中有面板,那么你也应该检查你的
glViewbox
设置,因为VCL有时会错误地计算ClientWidth/Height,你需要减去缺少的东西,比如- Panel1->Width;
...1.小心你的雷源
在透视图中,它必须从相机焦点开始。根据您的投影矩阵,它可能会移动
znear
(焦距)。如果不正确,这将造成更大的错误边缘的看法,所以我敢打赌,这是你的问题的原因。
1.注意深度缓冲区精度
您可以调整透视图,使
zfar/znear
与深度缓冲区精度相匹配。如果数量不足或无法使用,请使用linear depth buffer
看看这些:
pbossiut2#
解决方案!这是新的取消项目的方法。它是100%准确的。我设法把它全部放在一起。奇怪。