Opengl ES2.0 android 學習02——glDrawArrays


// C function void glDrawArrays ( GLenum mode, GLint first, GLsizei count )

    public static native void glDrawArrays(
        int mode,
        int first,
        int count
    );

mode:可以有如下選項
public static final int GL_POINTS                                  = 0x0000;//點
public static final int GL_LINES = 0x0001;//線
public static final int GL_LINE_LOOP = 0x0002;//線段
public static final int GL_LINE_STRIP = 0x0003;
public static final int GL_TRIANGLES = 0x0004;
public static final int GL_TRIANGLE_STRIP = 0x0005;
public static final int GL_TRIANGLE_FAN = 0x0006;

first:從數組第幾個開始

count:繪制的點數。
 

下面逐一實驗這些mode 

一、GL_POINTS

package com.tian.studyopengles.points

import android.opengl.GLES20
import android.opengl.GLSurfaceView
import com.tian.studyopengles.utils.GL2Utils
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class OnePointsRender : GLSurfaceView.Renderer {
    private val V_SHADER_SOURCE = "" +
            "void main(){\n" +
            "gl_Position = vec4(0.0,0.0,0.0,1.0);\n" +
            "gl_PointSize = 10.0;\n" +
            "}"

    private val F_SHADER_SOURCE = "" +
            "void main(){\n" +
            "gl_FragColor = vec4(1.0,0.0,0.0,1.0);" +
            "}"

    private var mProgram: Int = -1
    override fun onDrawFrame(gl: GL10?) {
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
        GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1)
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
    }

    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)

        mProgram = GL2Utils.createProgram(V_SHADER_SOURCE, F_SHADER_SOURCE)

        GLES20.glUseProgram(mProgram)
    }

}

這是最簡單的,繪制一個固定的點。

如何繪制多個點?

package com.tian.studyopengles.points

import android.opengl.GLES20
import android.opengl.GLSurfaceView
import com.tian.studyopengles.utils.GL2Utils
import com.tian.studyopengles.utils.LogUtils
import java.nio.ByteBuffer
import java.nio.ByteOrder
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class MultiplePointsRender : GLSurfaceView.Renderer {
    private val V_SHADER_SOURCE = "" +
            "attribute vec4 a_Position;\n" +
            "void main(){\n" +
            "gl_Position = a_Position;\n" +
            "gl_PointSize = 20.0;\n" +
            "}"

    private val F_SHADER_SOURCE = "" +
            "void main(){\n" +
            "gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n" +
            "}"
    private val vertexPoints = floatArrayOf(
        0.0f, 0.0f,
        -0.5f, -0.5f,
        0.5f, 0.5f
    )
    private var mProgram: Int = -1

    override fun onDrawFrame(gl: GL10?) {
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
        GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 3)
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
    }

    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {

        mProgram = GL2Utils.createProgram(V_SHADER_SOURCE, F_SHADER_SOURCE)

        val buffer = ByteBuffer.allocateDirect(vertexPoints.size * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(vertexPoints)
            .position(0)

        val position = GLES20.glGetAttribLocation(mProgram, "a_Position")
        GLES20.glVertexAttribPointer(position, 2, GLES20.GL_FLOAT, false, 0, buffer)
        GLES20.glEnableVertexAttribArray(position)

        GLES20.glValidateProgram(mProgram)
        val statusArray = IntArray(1)
        GLES20.glGetProgramiv(mProgram, GLES20.GL_VALIDATE_STATUS, statusArray, 0)

        val statusInfo = GLES20.glGetProgramInfoLog(mProgram)
        LogUtils.i("status code == ${statusArray[0]},status info == $statusInfo")

        GLES20.glUseProgram(mProgram)
    }

}

注意的點:1、shader不要寫錯,代碼里面有工具方法,可以監測出是否出錯。

                  2、因為是平面繪制,只用了(x,y)表示坐標,shader里面定義的是vec4 表示四個向量,此次表示默認第三和第四是(0.0,1.0)。

           GLES20.glVertexAttribPointer(position, 2, GLES20.GL_FLOAT, false, 0, buffer)中的2,表示是幾個數據來表示一個頂點坐標。此處是(x,y)則所以是2
3、這三行,鐵三角,先定位、再賦值、最后激活。
        val position = GLES20.glGetAttribLocation(mProgram, "a_Position") GLES20.glVertexAttribPointer(position, 2, GLES20.GL_FLOAT, false, 0, buffer) GLES20.glEnableVertexAttribArray(position)

 

具體可以查看https://github.com/tianjisheng/OpenGL-ES-2.0-android-learning/tree/master/app/src/main/java/com/tian/studyopengles/points

 

二、線段

    2.1)、GLES20.GL_LINES

package com.tian.studyopengles.lines

import android.opengl.GLES20
import android.opengl.GLSurfaceView
import com.tian.studyopengles.utils.GL2Utils
import java.nio.ByteBuffer
import java.nio.ByteOrder
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class LineRender : GLSurfaceView.Renderer {
    private val V_SHADER_SOURCR = "" +
            "attribute vec4 a_Position;\n" +
            "void main(){;\n" +
            "gl_Position = a_Position;\n" +
            "gl_PointSize = 10.0;\n" +
            "}"

    private val F_SHADER_SOURCE = "" +
            "void main(){\n" +
            "gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n" +
            "}"

    private var mProgram: Int = -1

    private val vertexPoints = floatArrayOf(
        0.5f, 0.5f,
        -0.5f, -0.5f,
        0.1f,0.0f,
        0.5f,0.0f)

    override fun onDrawFrame(gl: GL10?) {
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
        GLES20.glDrawArrays(GLES20.GL_LINE_STRIP, 0, 4)
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
    }

    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
         mProgram = GL2Utils.createProgram(V_SHADER_SOURCR,F_SHADER_SOURCE)

        var buffer = ByteBuffer.allocateDirect(vertexPoints.size * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(vertexPoints)
            .position(0)
        var position = GLES20.glGetAttribLocation(mProgram,"a_Position")
        GLES20.glVertexAttribPointer(position,2,GLES20.GL_FLOAT,false,0,buffer)
        GLES20.glEnableVertexAttribArray(position)

        GL2Utils.validateProgram(mProgram)

        GLES20.glUseProgram(mProgram)
    }

}

很簡單,兩個點確定一個線段。數組中v0和v1構成一條線段,v2和v3構成線段,不是共用一個點

   2.2)、GLES20.GL_LINE_LOOP

   loop顧名思義是一個環。v0和v1,一條線段,v1和v2一條線段,v2和v3一條線段,v3和v0一條線段。每個點使用兩次,收尾連接。只要大於等於三個點,就必然是一個封閉的圖形。

2.3)、GLES20.GL_LINE_STRIP

和GLES20.GL_LINE_LOOP相比,就少了收尾相連這條線段,不再是封閉的圖像。

https://github.com/tianjisheng/OpenGL-ES-2.0-android-learning/tree/master/app/src/main/java/com/tian/studyopengles/lines

三、三角形

3.1)、GLES20.GL_TRIANGLES

三個點,構成一個三角形,v0,v1,v2構成一個,v3,v4,v5表示第二個,很好理解

 
         
package com.tian.studyopengles.triangle

import android.opengl.GLES20
import android.opengl.GLSurfaceView
import com.tian.studyopengles.utils.GL2Utils
import java.nio.ByteBuffer
import java.nio.ByteOrder
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class TriangleRender : GLSurfaceView.Renderer {
private val V_SHADER_SOURCE = "" +
"attribute vec4 a_Position;\n" +
"void main(){\n" +
"gl_Position = a_Position;\n" +
"gl_PointSize = 10.0;\n" +//設為10.0,便於查看
"}"
private val F_SHADER_SOURCR = "" +
"void main(){\n" +
"gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n" +
"}"

private var mProgram: Int = -1

private val vertexPoints = floatArrayOf(
0.0f, 0.0f,
0.5f, 0.0f,
0.5f, 0.3f,

-0.1f, 0.0f,
-0.5f, 0.0f,
-0.5f, -0.3f
)

override fun onDrawFrame(gl: GL10?) {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6)
}

override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
GLES20.glViewport(0, 0, width, height)
}

override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
mProgram = GL2Utils.createProgram(V_SHADER_SOURCE, F_SHADER_SOURCR)

val buffer = ByteBuffer.allocateDirect(vertexPoints.size * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexPoints)
.position(0)

var position = GLES20.glGetAttribLocation(mProgram, "a_Position")
GLES20.glEnableVertexAttribArray(position)
GLES20.glVertexAttribPointer(position, 2, GLES20.GL_FLOAT, false, 0, buffer)

GL2Utils.validateProgram(mProgram)

GLES20.glUseProgram(mProgram)

}

}
 

 

3.2)、GLES20.GL_TRIANGLE_FAN

 直接把3.1中GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6)換成GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6)看下效果,得到如下圖:

,查資料,這個方法,是以第一個點為公共頂點。v0,v1,v2構成一個三角形,v0,v2,v3構成一個三角形,v0,v3,v4構成一個三角形,v0,v4,v5構成一個三角形

為了更直觀,調整頂點坐標。

private val vertexPoints = floatArrayOf(
        0.0f, 0.0f,
        0.5f, 0.0f,
        0.4f, 0.1f,

        0.3f, 0.15f,
        0.2f, 0.175f,
        0.1f, 0.18f
    )

得到下面圖像。

3.3)GLES20.GL_TRIANGLE_STRIP

還是使用原先的坐標,換成GLES20.GL_TRIANGLE_STRIP 直接變成下面圖形。

private val vertexPoints = floatArrayOf(
        0.0f, 0.0f,
        0.5f, 0.0f,
        0.5f, 0.3f,

        -0.1f, 0.0f,
        -0.5f, 0.0f,
        -0.5f, -0.3f
    )

 

結合線段中的理解,是不是就是兩個三角形共用頂點意思,沒有全部三角形共用v0的效果了?

為了驗證,調整頂點坐標。

private val vertexPoints = floatArrayOf(
0.0f, 0.0f,
0.25f, 0.25f,
0.25f, -0.25f,

0.5f, 0.0f
)
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)這個個地方改成四個點

驗證,的確如上面分析一樣。

詳情,可見https://github.com/tianjisheng/OpenGL-ES-2.0-android-learning/tree/master/app/src/main/java/com/tian/studyopengles/triangle

 

總結

    線段:

GL_LINES ,兩個頂點確定一個線段
GL_LINE_STRIP:除了收尾兩個頂點,其余的點,都會使用兩次,得到的是全部連在一起的線段

GL_LINE_LOOP:是所有頂點都使用兩次,到達尾部的時候,會連接起點,形成一個封閉的圖形

三角形:

GL_TRIANGLES:三個頂點,確定一個三角形

GL_TRIANGLE_STRIP:除了開始和最后的三角形,中間的三角形,都會共用兩個頂點。

GL_TRIANGLE_FAN:也是共用兩個頂點,但是有一個更特殊的點,是全部三角形,都會共用。

后面兩種完全可以使用增加一些頂點,實現同一效果。該參數,完全是方便繪制特定圖形,進行封裝的。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM