由于设备使用的归一化坐标系与像素无关,范围在三个方向上都是-1~1,所以直接硬编码绘制图元的时候可能会因为设备像素问题产生横向或是竖向被压缩(扭曲)。
书中的解决方法是将操作放在一个虚拟坐标空间中,就是我们设计顶点数值的时候假象自己就是在虚拟坐标空间中进行的,至于如何映射到设备上,可以不必考虑。
正交投影是一种将一个空间区域投影到一个二维平面上的方法(投影就是把高维降到地位的过程),这里所说的这个空间区域是一个无论多远去看物体的大小都不会变得一个三维空间中的区域,超过这个区域的部分不能被看到。
使用正交投影矩阵的目的是将我们操作的虚拟坐标空间映射到设备屏幕上,构造好了之后在顶点着色器代码中给顶点位置赋值的之前都乘上这个正交投影矩阵就可以直接转化坐标了。
由于设备使用的是左手坐标系,但是在opengl绘制的时候使用默认是右手坐标系,因此在正交矩阵的设定中,需要把近/远的定义颠倒,
final float aspectRatio = width > height ? (float)width/(float)height : (float)height/(float)width; if(width > height){ orthoM(projectionMatrix,0,-aPositionLocation,aspectRatio,-1f,1f,-1f,1f); }else{ orthoM(projectionMatrix,0,-1f,1f,-aspectRatio,aspectRatio,-1f,1f); }
这就是在onSurfaceChanged中通过设备分辨率进行设置的,那个orthoM的方法是Android提供的构建正交矩阵的一个方法,会把结果保存在projectionMatrix(float[16])中
此时在顶点着色器中加入一个矩阵:
uniform mat4 u_Matrix; attribute vec4 a_Position; void main() { gl_Position = u_Matrix * a_Position; }
然后再绘制之前加入绑定数据的方法:
@Override public void onDrawFrame(GL10 gl) { glClear(GL_COLOR_BUFFER_BIT); glUniformMatrix4fv(uMatrixLocation,1,false,projectionMatrix,0); glUniform4f(uColorLocation,1.0f,1.0f,0.0f,1.0f); glDrawArrays(GL_TRIANGLE_STRIP,0,8); glUniform4f(uColorLocation,0.0f,1.0f,1.0f,1.0f); glDrawArrays(GL_TRIANGLE_STRIP,8,8); }
这是一个绘制立方体程序,一开始绘制的时候显示这样:
加入矩阵之后是这样:
实际上这个正方形应当是这样放置的(懒得画了,在虚幻上截个图来看):
下一步就是研究矩阵变换作用到这个空间上了,看看能不能做一个自动旋转的立方体。
时间: 2024-10-12 10:12:44