矩阵运算的顺序
调用Matrix.translateM时,执行的是
Mvm * Ntran
其中 Mvm 是ModelView矩阵,维度4X4,形式如下:
Ntran 是平移矩阵
对照着图,就不难理解Matrix.translateM方法执行的源代码列了。我们再执行Matrix.rotateM,结果是
Mvm * Ntran* Nrotate
这样得到的结果 Mresult 再与初始顶点坐标矩阵Mv相乘(左乘)就是
Mv' = Mresult * Mv
= Mvm * Ntran* Nrotate * Mv
= Mvm * Ntran* (Nrotate * Mv)
所以实际结果是先旋转再平移,与代码写的顺序相反。
坐标系Tip
因为OpenGL中的视图坐标(观察者或者照相机的视角对应的坐标系)和笛卡尔坐标系都是右手坐标系统,而归一化设备坐标系对应的是左手坐标系统,为了对应起来,投影矩阵的Z值会有个负号。
这样比如 Matrix.perspectiveM方法中的near far分别为1f, 10f。那么最后可见的Z值范围是 -1f~-10f。而默认的情况下Z值为0,所以为了让图形可见,需要执行类似
Matrix.translateM(mModelMatrix, 0, 0.1f, 0f, -2.5f);
的代码来移动Z值到范围内。
三维图形学,为什么使用四维矩阵?
- 为了能通过矩阵乘法实现平移变换
- 为了区别点和向量.第四维如果是1,表示一个点,如果是0,表示一个向量
坐标系旋转
使用的是视图坐标系(Z坐标箭头向外),并且遵循右手定则:
右手手掌张开,除大拇指的四指向掌心握住,大拇指向所旋转的轴的正方向,四指旋转的方向就是正方向。
比如
Matrix.rotateM(mModelMatrix, 0, 30f, 0f, 0f, 1f);
就相当于图形逆时针转了30度。
纹理单元与纹理目标
显卡中有N个纹理单元(具体数目依赖你的显卡能力),
每个纹理单元(GL_TEXTURE0、GL_TEXTURE1等)都有GL_TEXTURE_1D、GL_TEXTURE_2D等纬度。
openGL ES中只有GL_TEXTURE_2D。
当执行以下代码
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId1);
作用是将当前纹理单元0(GL_TEXTURE0)的GL_TEXTURE_2D绑定为纹理textureId,即赋值操作,当前纹理单元的GL_TEXTURE_2D成为了textureId1的别名。
比如之后的
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
就相当于是对textureId1的操作。如果要解绑的话,调用
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
但要掌握好时机,比如画完纹理再解绑。
假设我的操作都在纹理单元0执行,那么以下代码没有任何副作用,因为是在纹理单元1执行,并且最后重新切换到了纹理单元0:
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);