【问题标题】:3D Ray Picking use Mouse Coordinates when Mouse isn't locked鼠标未锁定时 3D 光线拾取使用鼠标坐标
【发布时间】:2013-08-17 04:04:26
【问题描述】:

所以基本上我已经使用 OpenGL 制作了一个可以执行 3D 光线拾取的程序。如果Camera View Direction Ray 接触/相交任何东西(不是空气),那么会在相交点处呈现一个紫色的小框。

如果射线与任何“红框”相交,则与射线相交的那一次将变为绿色。地面和墙壁完全不会改变颜色或纹理。

例子:

我目前进行 3D 光线拾取的方式是获取相机的视角方向光线,然后只计算交叉点。 我的计算交叉点的函数没有返回布尔值,它返回一个 3D 向量(交叉点本身的坐标)

问题

所以我想要实现的是计算Picking Ray,但是根据鼠标锁定到屏幕时。

示例 - 所以在这里你可以看到紫色框在十字准线处,但如果我解锁鼠标并移动它(在屏幕顶部,像往常一样)并将它移动到我绘制的绿色 X 标记的中心,然后我想计算从相机中心到屏幕顶部鼠标坐标的射线。

当前的测试和想法

这应该只是一个数学问题。这只是我目前用来计算光线(并尝试计算第二条光线)的简短列表

  • 相机 X、Y、Z
  • 相机俯仰偏航滚动(目前未使用滚动)
  • 相机近远(距离)
  • 相机视野
  • 相机视角
  • 鼠标 X、Y(在屏幕顶部)
  • 画面宽度、高度

鼠标 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);

这就是我计算主拾取射线本身(锁定鼠标的拾取射线)的方式。我自己制作了这些类,尽管它们应该有意义(Vector3DRay3D 等)并且 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

我现在最终使用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)));

【问题讨论】:

    标签: opengl vector 3d projection ray-picking


    【解决方案1】:

    这是我创建鼠标射线的代码:

    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,但希望你明白。

    一些链接Select + Mouse + OpenGL

    【讨论】:

    • 但我只想使用我在帖子和数学中指定的变量。那么你有更好的选择吗?
    • 我认为,正如 Andon M. Coleman 所写:您必须使用相机和投影变换来创建适当的光线。
    • 是的,我也这么认为,因为我想看看我是否可以使用他写的内容获得所需的结果。不过,如果您有更好的方法或更简单的答案,那也很好。
    • gluUnProject 的作用并没有什么神奇之处,它只是颠倒了投影的顺序。如果你想手动实现数学,你可以反转你的模型视图/投影矩阵(假设它们有逆矩阵),然后使用视口来映射坐标。顺便说一句,您在帖子中拥有所有正确的变量来构造这些矩阵,而无需从 GL 状态机查询它们。
    • @fen 我最终使用了你的方式,虽然你的样本有 1 个缺陷,而且我也不需要反转 winY,但无论如何谢谢!
    【解决方案2】:

    您需要做的就是从相机的原点射出一条穿过屏幕空间点 (x,y) 的光线。这里的问题是,要从相机的原点到屏幕空间中的某个点,通常会发生许多转换(实际上是 2 个矩阵和一个视口映射)。另一个问题是,这会把一切都抛在脑后,通常你从一个世界空间位置开始,然后在 OpenGL 管道中以屏幕空间结束——你想走另一条路:)

    仅凭相机的方向无法解决此问题。您需要知道场景如何投影到您的观察平面上,因此需要投影矩阵。您还需要知道视口尺寸和相机的原点。如果知道视口尺寸、投影矩阵和模型视图矩阵,就可以解决整个问题。

    我建议您查看gluUnProject (...),它可以满足您的一切需求。在 Google 上快速搜索得到了这个结果,这看起来很有帮助:http://myweb.lmu.edu/dondi/share/cg/unproject-explained.pdf

    【讨论】:

      猜你喜欢
      • 2014-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-11
      相关资源
      最近更新 更多