天天看點

OpenGL ES for Android 繪制立方體

一個

有态度

的程式員

OpenGL ES for Android 繪制立方體

立方體有6個面,8個頂點,是以繪制立方體其實就是繪制6個面。

頂點shader:

attribute vec4 a_Position;
attribute vec4 a_color;
varying vec4 v_color;
void main()
{
    v_color = a_color;
    gl_Position = a_Position;
}           

複制

a_Position為頂點資料,a_color為頂點顔色資料,v_color為varying變量,傳遞給我片段shader使用。

片段shader:

precision mediump float;
uniform vec4 u_color;
varying vec4 v_color;
void main()
{
    gl_FragColor = v_color;
}
           

複制

建立program:

private fun createProgram() {
            var vertexCode =
                AssetsUtils.readAssetsTxt(
                    context = context,
                    filePath = "glsl/cube_vs.glsl"
                )
            var fragmentCode =
                AssetsUtils.readAssetsTxt(
                    context = context,
                    filePath = "glsl/cube_fs.glsl"
                )
            mProgramHandle = GLTools.createAndLinkProgram(vertexCode, fragmentCode)
        }           

複制

cube_vs.cube_fs.glsl分别表示頂點shader和片段shader的檔案,存放于assets/glsl目錄下,readAssetsTxt為讀取assets目錄下檔案的公用方法。

擷取參數句柄

vPositionLoc = GLES20.glGetAttribLocation(mProgramHandle, "a_Position")
mColorLoc = GLES20.glGetAttribLocation(mProgramHandle, "a_color")           

複制

初始化頂點資料

private val r: Float = 0.5f
        //頂點坐标
        var vertexBuffer = GLTools.array2Buffer(
            floatArrayOf(
                -r, r, r,//0
                -r, -r, r,//1
                r, -r, r,//2
                r, r, r,//3
                r, -r, -r,//4
                r, r, -r,//5
                -r, -r, -r,//6
                -r, r, -r//7
            )
        )           

複制

初始化索引資料

var mIndices = shortArrayOf(
            0, 1, 2, 0, 2, 3,
            3, 2, 4, 3, 4, 5,
            5, 4, 6, 5, 6, 7,
            7, 6, 1, 7, 1, 0,
            7, 0, 3, 7, 3, 5,
            6, 1, 2, 6, 2, 4
        )
val mIndicesBuffer = GLTools.array2Buffer(mIndices)
           

複制

初始化顔色資料

var colorBuffer = GLTools.array2Buffer(
            floatArrayOf(
                1f,1f,0f,1f,
                1f,1f,0f,1f,
                1f,1f,0f,1f,
                1f,1f,0f,1f,
                1f,0f,0f,1f,
                1f,0f,0f,1f,
                1f,0f,0f,1f,
                1f,0f,0f,1f
            )
        )           

複制

繪制

GLES20.glUseProgram(mProgramHandle)
            //設定頂點資料
            vertexBuffer.position(0)
            GLES20.glEnableVertexAttribArray(vPositionLoc)
            GLES20.glVertexAttribPointer(vPositionLoc, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer)
            //設定顔色資料
            colorBuffer.position(0)
            GLES20.glEnableVertexAttribArray(mColorLoc)
            GLES20.glVertexAttribPointer(mColorLoc, 3, GLES20.GL_FLOAT, false, 0, colorBuffer)
            GLES20.glDrawElements(
                GLES20.GL_TRIANGLES,
                mIndices.size,
                GLES20.GL_UNSIGNED_SHORT,
                mIndicesBuffer
            )           

複制

效果圖如下:

OpenGL ES for Android 繪制立方體

我們僅僅看到一個矩形,并沒有看到立方體啊?實際上我們已經繪制立方體了,隻不過其他面被前面的面擋住了導緻我們看不到其他面,如何才能看到其他面呢?這時候需要使用mvp矩陣。

修改頂點shader如下

attribute vec4 a_Position;
attribute vec4 a_color;
uniform mat4 mvpMatrix;
varying vec4 v_color;
void main()
{
    v_color = a_color;
    gl_Position = mvpMatrix * a_Position;
}           

複制

添加了mvpMatrix矩陣。

擷取mvpMatrix矩陣句柄

mvpMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle,"mvpMatrix")           

複制

設定mvp矩陣

override fun onSurfaceChanged(p0: GL10?, width: Int, height: Int) {
            GLES20.glViewport(0, 0, width, height)
            var modelMatrix = FloatArray(16)
            Matrix.setIdentityM(modelMatrix, 0)
            var viewMatrix = FloatArray(16)
            Matrix.setIdentityM(viewMatrix, 0)
            Matrix.setLookAtM(viewMatrix, 0,
                0F, 5F, 10F,
                0F, 0F, 0F,
                0F, 1F, 0F)
            var projectionMatrix = FloatArray(16)
            Matrix.setIdentityM(projectionMatrix, 0)
            val ratio = width.toFloat() / height
            //設定透視投影
            Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 20f)
            var mTempMvMatrix = FloatArray(16)
            Matrix.setIdentityM(mTempMvMatrix, 0)
            Matrix.multiplyMM(mTempMvMatrix, 0, viewMatrix, 0, modelMatrix, 0)
            Matrix.multiplyMM(mMvpMatrix, 0, projectionMatrix, 0, mTempMvMatrix, 0)
        }           

複制

在onSurfaceChanged中設定矩陣,繪制的時候設定矩陣資料:

GLES20.glUniformMatrix4fv(mvpMatrixLoc, 1, false, mMvpMatrix, 0)           

複制

效果如下:

OpenGL ES for Android 繪制立方體

我們發現立方體穿透了,出現這樣的效果是因為沒有開啟深層檢測,在繪制前清除深度緩存并開啟深層檢測,代碼如下:

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT)
GLES20.glEnable(GLES20.GL_DEPTH_TEST)           

複制

效果如下:

OpenGL ES for Android 繪制立方體

我們将立方體旋轉45度,這樣就可以看到立方體的側面了,将模型矩陣旋轉45度代碼如下:

var modelMatrix = FloatArray(16)
Matrix.setIdentityM(modelMatrix, 0)
Matrix.rotateM(modelMatrix,0,45F,0F,1F,0F)
           

複制

效果如下:

OpenGL ES for Android 繪制立方體