androidopengl-esbulletphysicsjbullet

Convert screen coordinates to OpenGL coordinates


I'm creating a Dice roller app for Android. Using Kotlin, OpenGL-ES and jBullet. I've implemented the dice. Now I need to create walls, because otherwise the dice will roll out of the screen.

Because screens can have different aspect ratios, I'm trying to determine the position for the walls with glUnProject, but I can't figure it out. The coordinates I receive are not correct.

    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)

Solution

  • The gluPerspective might be a bit unfortunate in your case. This is a convenience from the frustum operation being defined by the field of view.

    It is all doable from the setup you are having at the moment but I suggest you rather use frustum directly as it will be easier to compute:

    The frustum is defined by border parameters (top, bottom, left, right), near and far. The rectangle with border parameters with a distance of near will be exactly full-screen. So it is best to start with the board itself. If you define the board to be of size (viewWidth, viewHeight) and want a field of view fov=35 in width then the distance d to this object should be d*tan(35/2)=viewWidth/2 so d=viewWidth/(2*tan(35/2)) which is now a relatively large value. The distance d can now be used as far as I assume that you will be drawing nothing behind the board, but just to be sure rather user d*2. (Increasing the far will decrease the precision of depth buffer but nothing else). So now you can define near as something like 0.1 where then the scale of the object projection is scale=near/d and the border values are then original values multiplied by the scale:

    So having this setup you will se the rectangle of size (viewWidth, viewHeight) at a distance d as exactly full screen. So insert the d into the lookAt parameters and that should be all. The size of the dice may then be defined by the screen width so it appears similar on all devices. For instance using screenWidth/10 for dice size you will always be able to fit exactly 10 dices horizontally on the screen.