所以基本上我用OpenGL制作了一个可以执行3D Ray Picking的程序。如果Camera View Direction Ray
触摸/交叉任何东西(不是空气),则会在交点/点处渲染一个紫色的小框。
如果光线与任何“红色框”相交,则与光线相交的光线将变为绿色。地面和墙壁根本不会改变颜色或纹理。
示例:
我现在进行3D射线拾取的方法是获取相机的视线方向光线,然后只计算交叉点。 我计算交叉点的函数不作为布尔值返回,它作为3D矢量返回(交集本身的坐标)
所以我想要实现的是计算 Picking Ray ,但是根据鼠标不锁定到屏幕时。
示例 - 所以在这里你可以看到紫色的盒子在十字准线上,但是如果我要解锁鼠标并移动它(在屏幕顶部,就像通常那样)并移动它到我绘制的绿色X标记的中心,然后我想计算从摄像机中心到屏幕顶部鼠标坐标的光线。
这应该是一个数学问题。这里只是我目前用来计算Ray(并尝试计算第二条射线)的一些简短列表
鼠标X& Y原点(0x0)位于窗口/框架的左下角。
Vector3D position = new Vector3D(
camera.x,
camera.y,
camera.z);
Vector3D direction = new Vector3D(
Math.cos(Math.toRadians(camera.pitch)) * -Math.sin(Math.toRadians(-camera.yaw)) * camera.far,
Math.cos(Math.toRadians(camera.pitch)) * cameara.far,
Math.cos(Math.toRadians(camera.pitch)) * -Math.sin(Math.toRadians(-camera.yaw)) * camera.far);
direction.normalize();
Ray3D ray = new Ray(position, direction);
这就是我计算主要拾取光线本身的方式(锁定鼠标的拾取光线)。我自己制作了这些课程,虽然它们应该有意义(Vector3D
,Ray3D
等),而normalize()
方法完全按照它的说法进行,使矢量规范化。
因此,当我尝试使用鼠标坐标进行计算时,我在调用direction.normalize();
之前插入了以下代码,因此在创建Vector3D direction
之后。
if (!Mouse.isGrabbed())
{
float mx = Mouse.getX() / (float) scene.width - 0.5f;
float my = Mouse.getY() / (float) scene.height - 0.5f;
mx *= camera.far;
my *= camera.far;
line.b.x += mx;
line.b.y += my;
line.b.z += mz;
}
当鼠标没有被锁定/抓住时,这给了我一个奇怪的结果。这是有道理的,因为我只是在乱搞并尝试一些在我脑海中首先出现的事情。
我猜我需要根据音高,偏航和滚动来转换鼠标坐标。虽然我不知道,但我会怎么做。
所以我希望有人可以帮助我实现这个目标和/或给我一些资源,这样我就能理解如何做我想做的事。
如果您需要更多相关信息,请写下评论,我会尽力而为。
我现在最终使用fen的方式,因为它比计算所有内容要简单得多!
FloatBuffer projection = BufferTools.createFloatBuffer(16);
FloatBuffer modelview = BufferTools.createFloatBuffer(16);
IntBuffer viewport = BufferTools.createIntBuffer(16);
glGetFloat(GL_PROJECTION_MATRIX, projection);
glGetFloat(GL_MODELVIEW_MATRIX, modelview);
glGetInteger(GL_VIEWPORT, viewport);
float win_x = Mouse.getX();
float win_y = Mouse.getY();
FloatBuffer position_near = BufferTools.createFloatBuffer(3);
FloatBuffer position_far = BufferTools.createFloatBuffer(3);
gluUnProject(win_x, win_y, 0f, modelview, projection, viewport, position_near);
gluUnProject(win_x, win_y, 1f, modelview, projection, viewport, position_far);
Ray3D ray = new Ray3D(
new Vector3D(
position_near.get(0),
position_near.get(1),
position_near.get(2)),
new Vector3D(
position_far.get(0),
position_far.get(1),
position_far.get(2)));
答案 0 :(得分:10)
这是我创建鼠标光线的代码:
double matModelView[16], matProjection[16];
int viewport[4];
// get matrix and viewport:
glGetDoublev( GL_MODELVIEW_MATRIX, matModelView );
glGetDoublev( GL_PROJECTION_MATRIX, matProjection );
glGetIntegerv( GL_VIEWPORT, viewport );
// window pos of mouse, Y is inverted on Windows
double winX = (double)mouseX;
double winY = viewport[3] - (double)mouseY;
// get point on the 'near' plane (third param is set to 0.0)
gluUnProject(winX, winY, 0.0, matModelView, matProjection,
viewport, m_start.x, &m_start.y, &m_start.z);
// get point on the 'far' plane (third param is set to 1.0)
gluUnProject(winX, winY, 1.0, matModelView, matProjection,
viewport, m_end.x, &m_end.y, &m_end.z);
// now you can create a ray from m_start to m_end
OpenGL 2.0,但希望你明白这一点。
答案 1 :(得分:3)
您需要做的就是从通过屏幕空间点(x,y)的相机原点拍摄光线。这里的问题是,从摄像机的原点到屏幕空间中的某个点,通常会发生许多变换(实际上是2个矩阵和一个视口映射)。另一个问题是,这会将所有内容抛到脑后,通常你会从世界空间位置开始,并在OpenGL管道中结束屏幕空间 - 你想要采取另一种方式:)
单独使用相机的方向无法解决此问题。您需要知道场景如何投影到您的观察平面上,因此需要投影矩阵。您还需要知道视口尺寸和相机的原点。如果您知道视口尺寸,投影矩阵和模型视图矩阵,则可以解决整个问题。
我建议你研究gluUnProject (...)
,它会做你需要的一切。快速搜索Google会产生这种情况,这看起来非常有用:http://myweb.lmu.edu/dondi/share/cg/unproject-explained.pdf