【问题标题】:Convert screen coordinates to OpenGL coordinates将屏幕坐标转换为 OpenGL 坐标
【发布时间】:2016-06-08 10:01:02
【问题描述】:

我正在为 Android 创建一个骰子滚轮应用。使用 Kotlin、OpenGL-ES 和 jBullet。 我已经实现了骰子。 现在我需要创建墙,否则骰子会滚出屏幕。

因为屏幕可以有不同的纵横比,我试图用glUnProject 确定墙壁的位置,但我无法弄清楚。 我收到的坐标不正确。

    gl.glViewport(0,0,width,height)    //Reset The Current Viewport
    gl.glMatrixMode(GL10.GL_PROJECTION)    //Select The Projection Matrix
    gl.glLoadIdentity()                    //Reset The Projection Matrix

    //Calculate The Aspect Ratio Of The Window
    GLU.gluPerspective(gl, 35.0f, width.toFloat() / height.toFloat(), 0.1f, 100.0f)

    GLU.gluLookAt(gl,
           0.0f, 30.0f,  0.0f, //Pos
           0.0f,  0.0f,  0.0f, //Look at
           0.0f,  0.0f,  1.0f  //Up
    );

    gl.glMatrixMode(GL10.GL_MODELVIEW)    //Select The Modelview Matrix
    gl.glLoadIdentity()                    //Reset The Modelview Matrix

    // Get matrices
    gl.glGetFloatv(GL11.GL_PROJECTION_MATRIX, glProjectionMatrix,0)
    gl.glGetFloatv(GL11.GL_MODELVIEW_MATRIX, glModelMatrix,0)
    gl.glGetIntegerv(GL11.GL_VIEWPORT, glViewPort,0)

    // Allocate matrices
    var modelMatrix = glModelMatrix
    var projMatrix  = glProjectionMatrix
    var view = glViewPort

    // Pre allocate wall positions
    var wallDown = FloatArray(4)

    // The needed point
    var wallDownP = Vector3f(view[2].toFloat(), view[3].toFloat(), 0.2888888f)

    GLU.gluUnProject(wallDownP.x, wallDownP.y, wallDownP.z, modelMatrix, 0, projMatrix, 0, view, 0, wallDown, 0)

【问题讨论】:

  • 你从哪里得到 0.2888888f 的?
  • 如果你想要墙壁,为什么要将视口划分为 2?您所说的墙可能是指相机视图的侧面?

标签: android opengl-es bulletphysics jbullet


【解决方案1】:

gluPerspective 在您的情况下可能有点不幸。这是由视野定义的frustum 操作带来的便利。

根据您目前的设置,这一切都是可行的,但我建议您直接使用frustum,因为它更容易计算:

截锥体由边框参数(topbottomleftright)、nearfar 定义。距离为near 的边框参数的矩形将完全全屏。所以最好从董事会本身开始。如果您将板的大小定义为(viewWidth, viewHeight) 并希望在宽度上具有fov=35 的视野,那么d 到该对象的距离应该是d*tan(35/2)=viewWidth/2 所以d=viewWidth/(2*tan(35/2)) 现在是一个相对较大的值。距离d 现在可以用作far,因为我假设你不会在棋盘后面画任何东西,但只是为了确定用户d*2。 (增加far 会降低深度缓冲区的精度,但仅此而已)。所以现在您可以将near 定义为0.1 之类的东西,其中对象投影的比例为scale=near/d,然后边框值是原始值乘以比例:

  • left = -screenWidth/2*scale
  • right = screenWidth/2*scale
  • top = screenHeight/2*scale
  • bottom = -screenHeight/2*scale

因此,通过此设置,您将在距离 d 处将大小为 (viewWidth, viewHeight) 的矩形设置为完全全屏。因此,将d 插入lookAt 参数中就可以了。然后可以通过屏幕宽度定义骰子的大小,因此它在所有设备上看起来都相似。例如,使用screenWidth/10 作为骰子大小,您将始终能够在屏幕上水平放置恰好 10 个骰子。

【讨论】: