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)
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:
left = -screenWidth/2*scale
right = screenWidth/2*scale
top = screenHeight/2*scale
bottom = -screenHeight/2*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.