将屏幕坐标转换为 OpenGL 坐标
Convert screen coordinates to OpenGL coordinates
我正在为 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)
gluPerspective
在您的情况下可能有点不幸。这是由视野定义的 frustum
操作的便利。
根据您目前的设置,这一切都是可行的,但我建议您直接使用 frustum
,因为它更容易计算:
截锥体由边界参数(top
、bottom
、left
、right
)、near
和 far
定义。距离为 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 个骰子。
我正在为 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)
gluPerspective
在您的情况下可能有点不幸。这是由视野定义的 frustum
操作的便利。
根据您目前的设置,这一切都是可行的,但我建议您直接使用 frustum
,因为它更容易计算:
截锥体由边界参数(top
、bottom
、left
、right
)、near
和 far
定义。距离为 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 个骰子。