Android OpenGL快速绘制多边形

OpenGL ES是OpenGL(Open Graphics Library)的精简子集,是以手持和嵌入式设备为目标的高级3D图形API,我们开始尝试在Android开发中通过OpenGL ES快速绘制形状

创建GLSurfaceView

GLSurfaceView就是OpenGL的视图容器

package com.kotlin.demo.gl

import android.content.Context
import android.opengl.GLSurfaceView
import android.util.AttributeSet

class MyGLSurfaceView(context: Context?,attrs: AttributeSet?) : GLSurfaceView(context,attrs) {
    val mRenderer:MyGLRenderer
    init {
        setEGLContextClientVersion(2)
        mRenderer = MyGLRenderer()
        setRenderer(mRenderer)
        // RENDERMODE_WHEN_DIRTY:surface在创建后调用一次, 或者在开发者主动调用MyGLSurfaceView的requestRender时才会调用GLSurfaceView.Renderer去绘制
        //RENDERMODE_CONTINUOUSLY:自动连续调用GLSurfaceView.Renderer去绘制,绘制时会执行GLSurfaceView.Renderer的onDrawFrame()方法;
        renderMode = RENDERMODE_WHEN_DIRTY
    }
}

定义绘制多边形

OpenGL使用FloatBuffer来管理顶点数据提高效率,所以需要将坐标系转换成FloatBuffer对象

package com.kotlin.demo.gl

import android.opengl.GLES20
import android.util.Log
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer

class ShapeGL(pointsList:ArrayList<FloatArray>,colorList:ArrayList<FloatArray>) {
    val TAG = "ShapeGL"
    val mPointsList = pointsList
    val mColorList = colorList
    var vertexBuffers = mutableListOf<FloatBuffer>()

    /**
     * 顶点着色器
     */
    private val vertexShaderCode =
        "attribute vec4 vPosition;" +
                "void main() {" +
                "  gl_Position = vPosition;" +
                "}"

    /**
     * 片段着色器
     */
    private val fragmentShaderCode =
        "precision mediump float;" +
                "uniform vec4 vColor;" +
                "void main() {" +
                "  gl_FragColor = vColor;" +
                "}"
    /**
     * 着色器程序ID引用
     */
    private var mProgram: Int

    init {
        for (points in mPointsList){
            var vertexBuffer: FloatBuffer = ByteBuffer.allocateDirect(points.size * 4)
                .order(ByteOrder.nativeOrder()).asFloatBuffer().apply {
                    // 把坐标添加到FloatBuffer
                    put(points)
                    // 设置buffer的位置为起始点0
                    position(0)
                }
            vertexBuffers.add(vertexBuffer)
        }
        // 编译顶点着色器和片段着色器
        val vertexShader: Int = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
        val fragmentShader: Int = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
        // glCreateProgram函数创建一个着色器程序,并返回新创建程序对象的ID引用
        mProgram = GLES20.glCreateProgram().also {
            // 把顶点着色器添加到程序对象
            GLES20.glAttachShader(it, vertexShader)
            // 把片段着色器添加到程序对象
            GLES20.glAttachShader(it, fragmentShader)
            // 连接并创建一个可执行的OpenGL ES程序对象
            GLES20.glLinkProgram(it)
        }
    }
    private fun loadShader(type: Int, shaderCode: String): Int {
        // glCreateShader函数创建一个顶点着色器或者片段着色器,并返回新创建着色器的ID引用
        val shader = GLES20.glCreateShader(type)
        // 把着色器和代码关联,然后编译着色器
        GLES20.glShaderSource(shader, shaderCode)
        GLES20.glCompileShader(shader)
        return shader
    }

    val COORDS_PER_VERTEX = 3
    private val vertexStride: Int = COORDS_PER_VERTEX * 4 // 4 bytes per vertex

    fun draw() {
        // 激活着色器程序,把程序添加到OpenGL ES环境
        GLES20.glUseProgram(mProgram)
        // 获取顶点着色器中的vPosition变量
        val position = GLES20.glGetAttribLocation(mProgram, "vPosition")
        // 允许操作顶点对象position
        GLES20.glEnableVertexAttribArray(position)
        // 将顶点数据传递给position指向的vPosition变量;将顶点属性与顶点缓冲对象关联
        for (i in 0 until vertexBuffers.size){
            GLES20.glVertexAttribPointer(
                position, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
                false, vertexStride, vertexBuffers[i])
            // 获取片段着色器中的vColor变量
            val colorHandle = GLES20.glGetUniformLocation(mProgram, "vColor")
            // 通过colorHandle设置绘制的颜色值
            GLES20.glUniform4fv(colorHandle, 1, mColorList[i], 0)
            // 绘制顶点数组;
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, mPointsList[i].size/ COORDS_PER_VERTEX)
        }
        // 操作完后,取消允许操作顶点对象position
        GLES20.glDisableVertexAttribArray(position)
    }
}

创建Renderer

Renderer负责实际的绘制工作,这里定义两个图形进行绘制,传入两组坐标和颜色

package com.kotlin.demo.gl

import android.opengl.GLES20
import android.opengl.GLES30
import android.opengl.GLSurfaceView
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class MyGLRenderer:GLSurfaceView.Renderer {
    private lateinit var shapeGL: ShapeGL
    var points = floatArrayOf(
        -0.5f, 0.3f, 0f,
        -0.7f, -0.2f, 0f,
        -0f, -0f, 0f,
        0.7f, -0.3f, 0f,
        0.9f, 0.2f, 0f,
    )
    val color = floatArrayOf(148.0f, 0.0f, 211f,1.0f)
    var points1 = floatArrayOf(
        -0.5f, 0.9f, 0f,
        -0.7f, 0.5f, 0f,
        0.7f, 0.6f, 0f
    )
    val color1 = floatArrayOf(0.0f, 0.0f, 255f,1.0f)
    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
        // 设置背景色
        GLES20.glClearColor(0.0f, 255.0f, 255.0f, 1.0f)
        shapeGL = ShapeGL(arrayListOf(points,points1), arrayListOf(color,color1))
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        // 上面提到OpenGL使用的是标准化设备坐标;
        GLES20.glViewport(0, 0, width, height)
    }

    override fun onDrawFrame(gl: GL10?) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
        shapeGL.draw()
    }
}

引用OpenGL

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.kotlin.demo">
    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
    <uses-permission android:name="android.permission.INTERNET" />

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.kotlin.GLActivity">

    <com.kotlin.demo.gl.MyGLSurfaceView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

效果

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用OpenGL绘制多边形,需要使用顶点数组来定义多边形的形状,并使用glDrawArrays或glDrawElements函数来渲染多边形。 下面是一个使用glDrawArrays函数绘制多边形的示例代码: ```c++ GLfloat vertices[] = { -0.5f, -0.5f, 0.0f, // 左下角顶点 0.5f, -0.5f, 0.0f, // 右下角顶点 0.0f, 0.5f, 0.0f // 顶部顶点 }; glGenVertexArrays(1, &vao); // 创建顶点数组对象 glGenBuffers(1, &vbo); // 创建顶点缓冲区对象 glBindVertexArray(vao); // 绑定顶点数组对象 glBindBuffer(GL_ARRAY_BUFFER, vbo); // 绑定顶点缓冲区对象 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将顶点数据复制到缓冲区 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); // 设置顶点属性指针 glEnableVertexAttribArray(0); // 启用顶点属性 glBindVertexArray(0); // 解绑顶点数组对象 ... glUseProgram(shaderProgram); // 使用着色器程序 glBindVertexArray(vao); // 绑定顶点数组对象 glDrawArrays(GL_TRIANGLES, 0, 3); // 绘制三角形 glBindVertexArray(0); // 解绑顶点数组对象 ``` 在上面的代码中,我们使用glGenVertexArrays和glGenBuffers函数创建了顶点数组对象和顶点缓冲区对象,并使用glBindVertexArray和glBindBuffer函数将它们绑定到OpenGL上下文中。然后,我们使用glBufferData函数将顶点数据复制到顶点缓冲区中,并使用glVertexAttribPointer和glEnableVertexAttribArray函数来设置顶点属性指针和启用顶点属性。最后,我们使用glDrawArrays函数绘制多边形。 注意,上面的代码使用了一个着色器程序来将顶点数据转换为屏幕上的像素。如果你还没有了解过OpenGL着色器编程,可以先学习一下。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值