OpenGL ES for Android 绘制立方体

时间:2022-07-24
本文章向大家介绍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
            )

效果图如下:

我们仅仅看到一个矩形,并没有看到立方体啊?实际上我们已经绘制立方体了,只不过其他面被前面的面挡住了导致我们看不到其他面,如何才能看到其他面呢?这时候需要使用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)

效果如下:

我们发现立方体穿透了,出现这样的效果是因为没有开启深度检测,在绘制前清除深度缓存并开启深度检测,代码如下:

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

效果如下:

我们将立方体旋转45度,这样就可以看到立方体的侧面了,将模型矩阵旋转45度代码如下:

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

效果如下: