内容:


1 基本概念

Frustum(视锥体),focal point(视点或观察者位置),field of vision(视野)

目前看起来只能理解个大概,深入理解推导过程不太现实,后面积累足够再理解。


opengles GLSL 版本 opengles2_二维

(参考)



2 矩阵变换的过程与目的

上面基本概念都是用来进行矩阵变换使用的,上图描绘的是透视投影。个人理解,可以从结果来看,结果就是从我们的人眼看到手机屏幕的内容,就和上图从相机视角看过去一样,而尽管手机屏幕是个二维的面,但实际在屏幕中展现的是一个三维的物体,之所以能够让人觉得它是三维的(实际还是个二维的图形),主要还是因为它的绘制方式是仿照的真实三维世界,仿制的方式就是通过投影,而这说白了也就是对人眼的欺骗。

如何欺骗?在三维世界中,存在远近的物体,越近就越大,越远就越小,而且越近的物体越能占满眼睛的视角,越远的物体越趋近于视角中心那个点。将一个物体仿制到手机屏幕里也是一样,把屏幕想象成x与y的坐标系,屏幕中心点为(0,0),x轴与y轴把屏幕划分为4个象限,中心点右边和上边为正,中心点左边和下边为负,而z轴就从屏幕朝外的方向延伸出来。那么一个三维物体通过投影在屏幕上,就是将一个物体中多个三维坐标位置转换到屏幕中二维坐标位置的过程。

其转换方式就是通过一个个矩阵与顶点坐标相乘得到实际在屏幕上应该展现的坐标位置。


比如资料中关于这几句话的意义:

@Override public void onSurfaceChanged(GL10 gl, int width, int height) {
    glViewport(0, 0, width, height);
    MatrixHelper.perspectiveM(projectionMatrix, 45, (float) width / (float) height, 1f, 10f);

    setIdentityM(modelMatrix, 0);

    translateM(modelMatrix, 0, 0f, 0f, -2.5f);
    rotateM(modelMatrix, 0, -60f, 1f, 0f, 0f);

    final float[] temp = new float[16];
    multiplyMM(temp, 0, projectionMatrix, 0, modelMatrix, 0);
    System.arraycopy(temp, 0, projectionMatrix, 0, temp.length);
  }



perspectiveM方法就是创建一个投影矩阵,其作用就是为了改变vertex shader中的gl_position为三维坐标位置。它的构建有公式:


opengles GLSL 版本 opengles2_二维_02

构建代码:

public static void perspectiveM(float[] m, float yFovInDegrees, float aspect, float n, float f) {
    final float angleInRadians = (float) (yFovInDegrees * Math.PI / 180.0);

    final float a = (float) (1.0 / Math.tan(angleInRadians / 2.0));
    m[0] = a / aspect;
    m[1] = 0f;
    m[2] = 0f;
    m[3] = 0f;

    m[4] = 0f;
    m[5] = a;
    m[6] = 0f;
    m[7] = 0f;

    m[8] = 0f;
    m[9] = 0f;
    m[10] = -((f + n) / (f - n));
    m[11] = -1f;

    m[12] = 0f;
    m[13] = 0f;
    m[14] = -((2f * f * n) / (f - n));
    m[15] = 0f;
  }



比如计算视距,就是从相机处到第一个面的距离,是通过视角在y轴的角度运用三角函数计算得到这个距离。为何要这样构建目前还不清楚,但这样拿到的透视矩阵可以当做是一个工具,用它来乘以顶点上的一个点就可以得到透视在屏幕上的点。

而代码后面创建modelMatrix这个矩阵也是如此,先将其变成单位矩阵,然后往屏幕里面移动2.5个单位,再沿着x轴朝里旋转60度,最后两者相乘拿到的结果。

最后:

uniform mat4 u_Matrix;

attribute vec4 a_Position;
attribute vec4 a_Color;

varying vec4 v_Color;

void main()
{
    v_Color = a_Color;
    gl_Position = u_Matrix * a_Position;
    gl_PointSize = 10.0;
}



可以看到得到的矩阵被传进shader与最初的顶点坐标相乘。而实际上就是在最初顶点坐标的基础上对它进行了一系列的变换得到最终值。其意义就是将这个物体所有二维平面的点通过一系列的矩阵操作变换成三维坐标。目前对矩阵的操作的选择和构建还有不少疑问。