一.前言
我们将上一篇文章中写的应用程序再次运行起来,然后将屏幕横过来,我们会发现空气曲棍球的桌子被压扁了。这之所以会发生,是因为我们没有考虑屏幕的宽高比,直接将坐标传递给了OpenGL。在这片文章中,我们会弄清楚为什么桌子被压扁了,以及如何使用投影解决这个问题。
二.宽高比的问题
我们现在都知道一个事实:在OpenGL中,我们要渲染的一切物体,都要映射到x,y和z轴的[-1,1]范围内,这个范围内的坐标被称为归一化设备坐标,其独立于屏幕实际的形状和尺寸。不幸的是,由于它独立于实际的屏幕尺寸和形状,我们直接使用就会出现问题,例如横屏模式下桌子被压扁了。
我们现在假设设备的分辨率是1280×720,并且OpenGL占据整个屏幕,那么[-1,1]的范围对应1280像素的高,却只有720像素的宽,图像在x轴上就会显得扁平,同样的问题在y轴上也会发生。想要解决这个问题,我们需要调整坐标空间,以使它把屏幕形状考虑在内。我们可以把较小的范围固定在[-1,1]内,而按屏幕尺寸的比例调整较大的范围。举例来说,在竖屏模式下,可以把宽度限制在[-1,1]内,把高度限制在[-1280/720,1280/720]内。同理,在横屏模式下,可以将高度限制在[-1,1]中,而把高度限制在[-1280/720,1280/720]中。通过这个方法,无论是在竖屏还是横屏下,物体的形状都是一样的,我们所进行的操作就是正交投影。
三.定义正交投影
要定义正交投影,我们要借助Android的Matrix类,这个类有一个称为orthoM()的方法,它可以为我们生成一个正交投影,这个函数的定义如下:
public static void orthoM( float[] m, //目标数组,这个目标数组的长度至少16个元素,这样才能存储正交投影矩阵 int mOffset,//结果矩阵起始的偏移值 float left, //x轴的最小范围 float right, //x轴的最大范围 float bottom, //y轴的最小范围 float top,//y轴的最大范围 float near, //z轴的最小范围 float far//z轴的最大范围 )
当我们调用这个函数的时候,它会给我们生成一个4×4的矩阵,这个正交投影矩阵会把所有在左右之间,上下之间和远近之间的事物映射到归一化设备坐标中[-1,1]的范围中,在这个范围内的东西在屏幕上都是可见的。
四.加入正交投影
让我们加入正交投影,并修复那个被压扁的桌子。首先我们需要修改顶点着色器,在里面接收这个投影矩阵,代码修改如下:
#version 300 es layout(location=0) in vec4 a_Position; layout(location=0) uniform mat4 u_Matrix; layout(location=1) in vec4 a_Color; out vec4 v_Color; void main() { gl_Position=u_Matrix*a_Position; v_Color=a_Color; gl_PointSize=10.0; }
然后在MyRenderer类的顶部加入如下代码:private val projectionMatrix:FloatArray=FloatArray(16)//存储投影矩阵
接着再更新onSurfaceChanged()函数,在末尾加入如下代码:
//根据屏幕方向生成投影矩阵 val aspectRatio=if(width>height) width.toFloat()/height.toFloat() else height.toFloat()/width.toFloat() if(width>height){ Matrix.orthoM(projectionMatrix,0,-aspectRatio,aspectRatio,-1f,1f,-1f,1f) } else{ Matrix.orthoM(projectionMatrix,0,-1f,1f,-aspectRatio,aspectRatio,-1f,1f) }
最后,将生成的投影矩阵传入顶点着色器,在onDrawFrame()函数中的glClear()函数后加入如下代码即可:
//传入投影矩阵 glUniformMatrix4fv(0,1,false,projectionMatrix,0)
第一个参数指uniform变量的位置,第二个参数指矩阵的个数。
最后,我们可以修改下桌子的结构,让桌子更高点,这样看起来效果更好,只需要修改y值即可。更新后的结构如下:
val tableVertices=floatArrayOf( //Triangle fan 0f,0f,1f,1f,1f, -0.5f,-0.8f,0.7f,0.7f,0.7f, 0.5f,-0.8f,0.7f,0.7f,0.7f, 0.5f,0.8f,0.7f,0.7f,0.7f, -0.5f,0.8f,0.7f,0.7f,0.7f, -0.5f,-0.8f,0服务器托管网.7f,0.7f,0.7f, //Mid Line -0.5f,0f,1f,0f,0f, 0.5f,0f,1f,0f,0f, //Mallets 0f,-0.4f,0f,0f,1f, 服务器托管网 0f,0.4f,1f,0f,0f )
最后,可以运行程序了,看看效果是不是和我们期待的那样。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: Ray on ACK 实践探索之旅 – RayCluster 篇
作者:张杰、霍智鑫、行疾 什么是 Ray? Ray 是一个开源框架,专为构建可扩展的分布式应用程序而设计,旨在通过提供简单直观的 API,简化分布式计算的复杂性,让开发者能够便捷高效地编写并行和分布式 Python 应用程序。 Ray 的统一计算框架由三层组成…