OpenGl ES 2.0 Learn For Android(一)世界是三角形的

OpenGl ES 2.0 Learn For Android(一)世界是三角形的

为什么说世界是三角形的呢?常规我们理解的世界——三维世界,由点线面构成。这是一个比较常规的认知。那么,理解opengl的世界的时候,也当然由这个逻辑去想象。但在实际绘制的时候,无限这种概念没法实际的在计算机里进行描述。所以opengl的世界,事实上由线段、和三角形来组成。为什么不是四边形呢?我想,可能是创始者的强迫症。希望设计是123的逻辑,不是124这种跳过3的逻辑。当然,我只是乱猜。

前一篇的内容在这里。
OpenGl ES 2.0 Learn For Android

1. 三角形的基础——顶点

即使是世界是三角形构成的。但三角形终究也是一个一个的点,所以,opengl也是从点开始。

讲到点,自然要讲到坐标系。opengl使用的是右手三维坐标系。


OpenGl ES 2.0 Learn For Android(一)世界是三角形的_第1张图片
坐标系

也就是说,我们拿着手机,正对着它。想象里面的绘制坐标的话,向右是X轴正方向,向上是Y轴正方向,向你面部的位置是Z轴正方向。而且,这个世界只能显示[-1,1]的内容(这里的话不一定对,有可能之后来修正)。那么我们现在先只看一个面,所以可以暂时忽略Z轴,理解成原点在手机屏幕正中央,向右是X轴正方向,向上是Y轴正方向。

OpenGL作为本地系统库是直接运行在硬件上的,在Android里,而我们的代码是运行在Dalvik(现在是ART)上,导致OpenGL无法去读取我们的数据,所以有两种方案解决上述问题:

  • 从Java调用本地代码(JNI)。
    一般我们调用GLES20包,就是在后台使用JNI。

  • 把内存从Java堆复制到本地堆。意思就是改变内存分配的方式,Java有个特殊的类集合,把Java数据复制到本地内存中。

    OpenGl ES 2.0 Learn For Android(一)世界是三角形的_第2张图片
    内存从Java堆复制到本地堆

    FloatBuffer使用方式可以参照下面博客:
    java中的float缓冲区FloatBuffer

对应代码使用:

private final FloatBuffer mVertexData;

private float[] mTrianglePoints = {-0.5f, -0.5f, 0.5f, -0.5f, 0f, 0.5f};

mVertexData = ByteBuffer
        .allocateDirect(mTrianglePoints.length * BYTES_PER_FLOAT)
        .order(ByteOrder.nativeOrder())
        .asFloatBuffer();
mVertexData.put(mTrianglePoints);

现在的话,我们知道有了点,但是怎么告诉opengl呢?

2. OpenGL:顶点着色器和片段着色器###

一般我们定义好物体的顶点,被读取到本地内存中,在绘制到屏幕的时候,需要通过管道进行传输,这类管道其实也成为着色器。

着色器:会告诉GPU如何处理绘制数据

在OpenGL中,总共有两种类型的着色器:
(1)顶点着色器(Vertex Shader)生成每个顶点的最终位置,针对每个顶点,它都会执行一次;一旦最终位置确定了,OpenGL就可以把这些可见顶点的集合组装成点、直线、以及三角形
(2)片段着色器(Fragment Shader)为组成的点、直线、三角形的每个片段生成最终的颜色,针对每个片段,都会执行一次;一个片段是一个小的、单一颜色的长方形区域,类似于计算机屏幕上的一个像素。

一旦最后颜色生成后,OpenGl就会把它们写到一块称为帧缓冲区(frame buffer)的内存块中,然后Android会把这块帧缓冲区显示到屏幕上。

在代码里,我们可以完成一个最简单的顶点着色器:

 private String mVertexShaderCode =
            "attribute vec4 a_Position;     \n" +
            "void main()                    \n" +
            "{                              \n" +
            "    gl_Position = a_Position;  \n" +
            "}   \n";

同样的,完成一个最简单的片段着色器:

private String mFragmentShaderCode =
            "precision mediump float; \n" +
            "uniform vec4 u_Color;          \n" +
            "void main()                    \n" +
            "{                              \n" +
            "    gl_FragColor = u_Color;    \n" +
            "}";

关于attributeuniform,可以参看这篇博客:OpenGL ES 三种类型修饰 uniform attribute varying
颜色是四维向量,很容易理解(R,G,B,A)。顶点我们之前说过是三维的,它这里是(X,Y,Z,W)。W是什么我们之后讲。

3. OpenGL ES的编译连接过程###

这里要讲到,GLES20的接口,都是先生成一个实例,拿到一个句柄,再对这个句柄指向的实例进行操作。熟悉C语言的应该会比较眼熟这个流程。java入行的会感到一点别扭。
1.shader的连接过程:
glCreateShader->glShaderSource->glCompileShader
2.program的生成过程:
glCreateProgram->glAttachShader->glLinkProgram
program是将一个顶点着色器和一个片段着色器链接在一起生成一个对象。没有片段着色器,OpenGL就不知道怎么绘制那些组成每个点、直线和三角形的片段;没有顶点着色器,OpenGL就不知道在哪里绘制这些片段。

//create vertex shader
int vertexShader = compileShader(GL_VERTEX_SHADER, mVertexShaderCode);
//create fragment shader
int fragmentShader = compileShader(GL_FRAGMENT_SHADER, mFragmentShaderCode);
//create program and link two shader
mShaderProgram = linkProgram(vertexShader,fragmentShader);
//use this program
glUseProgram(mShaderProgram);

4. OpenGL ES的赋值绘制过程###

program拿到后,就是对变量进行赋值绘制了。

        uColorLocation = glGetUniformLocation(mShaderProgram, "u_Color");

        aPositionLocation = glGetAttribLocation(mShaderProgram, "a_Position");

        // Bind our data, specified by the variable vertexData, to the vertex
        // attribute at location A_POSITION_LOCATION.
        mVertexData.position(0);
        glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT,
                false, 0,mVertexData);
        glEnableVertexAttribArray(aPositionLocation);

        glUniform4f(uColorLocation, 1.0f, 1.0f, 1.0f, 1.0f);

上面拿到了"u_Color""a_Position"对应的变量,并对"a_Position"也就是顶点变量进行了赋值了一个顶点数组,对"u_Color"赋值为白色。

在绘制的时候

    @Override
    public void onDrawFrame(GL10 glUnused) {
        glClear(GL_COLOR_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLES, 0, 3);
    }

这里是从顶点数组下标0开始,绘制3个顶点。glDrawArrays具体我就不介绍了。这里的参数有些不同,可以参看
https://www.khronos.org/registry/OpenGL-Refpages/es2.0/
下面是效果图。

OpenGl ES 2.0 Learn For Android(一)世界是三角形的_第3张图片
drawTriangle

demo地址:
https://github.com/YueZhiFengMing/LearnOpenGl/tree/master/SecondDrawTriangle

参考资料###

  1. java中的float缓冲区FloatBuffer
  2. OpenGL ES 三种类型修饰 uniform attribute varying
  3. https://www.khronos.org/registry/OpenGL-Refpages/es2.0/
  4. 《OpenGL ES应用开发实践指南:Android卷》

你可能感兴趣的:(OpenGl ES 2.0 Learn For Android(一)世界是三角形的)