贴图
XML文件
- <?xml version="1.0" encoding="utf-8"?>
- <com.example.myapplication.MyGLSurfaceView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
复制代码 自界说GLSurfaceView代码
- class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs) {
- private var mRenderer = MyGLRenderer(context)
- init {
- // 设置 OpenGL ES 3.0 版本
- setEGLContextClientVersion(3)
- setRenderer(mRenderer)
- // 设置渲染模式, 仅在需要重新绘制时才进行渲染,以节省资源
- renderMode = RENDERMODE_WHEN_DIRTY
- }
- }
复制代码 自界说GLSurfaceView.Renderer代码
- class MyGLRenderer(private val mContext : Context) : GLSurfaceView.Renderer {
- private var mDrawData: DrawData? = null
- override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
- // 当 Surface 创建时调用, 进行 OpenGL ES 环境的初始化操作, 设置清屏颜色为青蓝色 (Red=0, Green=0.5, Blue=0.5, Alpha=1)
- GLES30.glClearColor(0.0f, 0.5f, 0.5f, 1.0f)
- mDrawData = DrawData().apply {
- initVertexBuffer()
- initShader()
- loadTexture(mContext, R.drawable.bitmap_shader)
- }
- }
- override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
- // 当 Surface 尺寸发生变化时调用,例如设备的屏幕方向发生改变, 设置视口为新的尺寸,视口是指渲染区域的大小
- GLES30.glViewport(0, 0, width, height)
- mDrawData?.computeMVPMatrix(width.toFloat(), height.toFloat())
- }
- override fun onDrawFrame(gl: GL10?) {
- // 每一帧绘制时调用, 清除颜色缓冲区
- GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
- mDrawData?.drawSomething()
- }
- }
复制代码 GLSurfaceView.Renderer必要的绘制数据
- class DrawData {
- private var mProgram : Int = -1
- private var NO_OFFSET = 0
- private val VERTEX_POS_DATA_SIZE = 3
- private val TEXTURE_POS_DATA_SIZE = 2
- // 纹理ID
- private var mTextureID = IntArray(1)
- // VBO IDs
- private var mVertexVBO = 0
- private var mTexCoordVBO = 0
- // 最终变化矩阵
- private val mMVPMatrix = FloatArray(16)
- // 投影矩阵
- private val mProjectionMatrix = FloatArray(16)
- // 相机矩阵
- private val mViewMatrix = FloatArray(16)
- private var mViewPortRatio = 1f
- // 1. 准备顶点坐标,分配直接内存
- // OpenGL ES坐标系:原点在中心,X轴向右为正,Y轴向上为正,Z轴向外为正
- val vertex = floatArrayOf(
- -1.0f, 1.0f, 0.0f, // 左上
- -1.0f, -1.0f, 0.0f, // 左下
- 1.0f, 1.0f, 0.0f, // 右上
- 1.0f, -1.0f, 0.0f, // 右下
- )
- val vertexBuffer = ByteBuffer.allocateDirect(vertex.size * 4)
- .order(ByteOrder.nativeOrder())
- .asFloatBuffer()
- // 2. 准备纹理坐标,分配直接内存
- // 纹理坐标系:原点在左下角,X轴向右为正,Y轴向上为正
- val textureCoords = floatArrayOf(
- 0.0f, 1.0f, // 左上
- 0.0f, 0.0f, // 左下
- 1.0f, 1.0f, // 右上
- 1.0f, 0.0f, // 右下
- )
- val textureBuffer = ByteBuffer.allocateDirect(textureCoords.size * 4)
- .order(ByteOrder.nativeOrder())
- .asFloatBuffer()
- // 3. 创建顶点缓冲区对象
- fun initVertexBuffer(){
- // 初始化顶点坐标缓冲区
- vertexBuffer.put(vertex)
- vertexBuffer.position(NO_OFFSET)
- // 初始化纹理坐标缓冲区
- textureBuffer.put(textureCoords)
- textureBuffer.position(NO_OFFSET)
- // 创建两个VBO,一个用于顶点坐标,一个用于纹理坐标
- val vbo = IntArray(2)
- GLES30.glGenBuffers(vbo.size, vbo, NO_OFFSET) // 生成一个缓冲区对象ID,并存储在数组 vbo 中,存放位置为0
- // 绑定顶点缓冲区
- GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0])
- GLES30.glBufferData(
- GLES30.GL_ARRAY_BUFFER,
- vertex.size * 4, // 数据总字节数 = 顶点数 * Float占4字节
- vertexBuffer,
- GLES30.GL_STATIC_DRAW
- )
- // 绑定纹理缓冲区
- GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[1])
- GLES30.glBufferData(
- GLES30.GL_ARRAY_BUFFER,
- textureCoords.size * 4, // 数据总字节数 = 顶点数 * Float占4字节
- textureBuffer,
- GLES30.GL_STATIC_DRAW
- )
- mVertexVBO = vbo[0]
- mTexCoordVBO = vbo[1]
- }
- // 4. 初始化着色器程序
- fun initShader() {
- val vertexShaderCode = """#version 300 es
- in vec4 aPosition; // 顶点坐标
- uniform mat4 uMVPMatrix; // 变换矩阵
- in vec2 aTexCoord; // 纹理坐标
- out vec2 vTexCoord;
- void main() {
- // 输出顶点坐标和纹理坐标到片段着色器
- gl_Position = uMVPMatrix * aPosition;
- vTexCoord = aTexCoord;
- }""".trimIndent() // 顶点着色器代码
- val fragmentShaderCode = """#version 300 es
- precision mediump float; // 定义float 精度为 mediump
- out vec4 fragColor; // 输出片段颜色
- in vec2 vTexCoord; // 接收顶点着色器传递过来的纹理坐标
- uniform sampler2D uTexture; // 纹理取样器
- void main() {
- // 使用内置函数texture, 根据纹理坐标和取样器sampler2D计算片段颜色
- fragColor = texture(uTexture, vTexCoord);
- }""".trimIndent()
- // 加载顶点着色器和片段着色器, 并创建着色器程序
- val vertexShader = LoadShaderUtil.loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode)
- val fragmentShader = LoadShaderUtil.loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode)
- mProgram = GLES30.glCreateProgram()
- GLES30.glAttachShader(mProgram, vertexShader)
- GLES30.glAttachShader(mProgram, fragmentShader)
- GLES30.glLinkProgram(mProgram)
- GLES30.glUseProgram(mProgram)
- }
- // 5. 加载纹理
- fun loadTexture(context: Context, resourceId: Int) {
- // 生成纹理
- GLES30.glGenTextures(mTextureID.size, mTextureID, NO_OFFSET)
- // 绑定纹理
- GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureID[0])
- // 设置纹理参数
- GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR) // 纹理缩小时使用线性插值
- GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR) // 纹理放大时使用线性插值
- GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE) // 纹理坐标超出范围时,超出部分使用最边缘像素进行填充
- GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE) // 纹理坐标超出范围时,超出部分使用最边缘像素进行填充
- // 加载图片
- val options = BitmapFactory.Options().apply {
- inScaled = false // 不进行缩放
- }
- val bitmap = BitmapFactory.decodeResource(context.resources, resourceId, options)
- // 将图片数据加载到纹理中
- GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, NO_OFFSET, bitmap, NO_OFFSET)
- // 释放资源
- bitmap.recycle()
- // 解绑纹理
- GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, NO_OFFSET)
- }
- // 6. 计算变换矩阵
- fun computeMVPMatrix(width: Float, height: Float) {
- // 正交投影矩阵
- takeIf { width > height }?.let {
- mViewPortRatio = width / height
- Matrix.orthoM(
- mProjectionMatrix, // 正交投影矩阵
- NO_OFFSET, // 偏移量
- -mViewPortRatio, // 近平面的坐标系左边界
- mViewPortRatio, // 近平面的坐标系右边界
- -1f, // 近平面的坐标系的下边界
- 1f, // 近平面坐标系的上边界
- 0f, // 近平面距离相机距离
- 1f // 远平面距离相机距离
- )
- } ?: run {
- mViewPortRatio = height / width
- Matrix.orthoM(
- mProjectionMatrix, // 正交投影矩阵
- NO_OFFSET, // 偏移量
- -1f, // 近平面坐标系左边界
- 1f, // 近平面坐标系右边界
- -mViewPortRatio, // 近平面坐标系下边界
- mViewPortRatio, // 近平面坐标系上边界
- 0f, // 近平面距离相机距离
- 1f // 远平面距离相机距离
- )
- }
- // 设置相机矩阵
- // 相机位置(0f, 0f, 1f)
- // 物体位置(0f, 0f, 0f)
- // 相机方向(0f, 1f, 0f)
- Matrix.setLookAtM(
- mViewMatrix, // 相机矩阵
- NO_OFFSET, // 偏移量
- 0f, // 相机位置x
- 0f, // 相机位置y
- 1f, // 相机位置z
- 0f, // 物体位置x
- 0f, // 物体位置y
- 0f, // 物体位置z
- 0f, // 相机上方向x
- 1f, // 相机上方向y
- 0f // 相机上方向z
- )
- // 最终变化矩阵
- Matrix.multiplyMM(
- mMVPMatrix, // 最终变化矩阵
- NO_OFFSET, // 偏移量
- mProjectionMatrix, // 投影矩阵
- NO_OFFSET, // 投影矩阵偏移量
- mViewMatrix, // 相机矩阵
- NO_OFFSET // 相机矩阵偏移量
- )
- // 纹理坐标系为(0, 0), (1, 0), (1, 1), (0, 1)的正方形逆时针坐标系,从Bitmap生成纹理,即像素拷贝到纹理坐标系
- // 变换矩阵需要加上一个y方向的翻转, x方向和z方向不改变
- Matrix.scaleM(
- mMVPMatrix,
- NO_OFFSET,
- 1f,
- -1f,
- 1f,
- )
- val matrixHandler = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix")
- GLES30.glUniformMatrix4fv(matrixHandler, 1, false, mMVPMatrix, NO_OFFSET)
- }
- // 7. 使用着色器程序绘制图形
- fun drawSomething(){
- // 激活纹理编号
- GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
- GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureID[0])
- // 激活纹理取样器
- val textureSampleHandle = GLES30.glGetUniformLocation(mProgram, "uTexture")
- GLES30.glUniform1i(textureSampleHandle, NO_OFFSET)
- // 激活变换矩阵
- val matrixHandle = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix")
- GLES30.glUniformMatrix4fv(matrixHandle, 1, false, mMVPMatrix, NO_OFFSET)
- // 输入顶点数据
- val positionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition")
- GLES30.glEnableVertexAttribArray(positionHandle)
- GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVertexVBO)
- GLES30.glVertexAttribPointer(positionHandle, VERTEX_POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, NO_OFFSET)
- // 绑定纹理数据
- val textureHandle = GLES30.glGetAttribLocation(mProgram, "aTexCoord")
- GLES30.glEnableVertexAttribArray(textureHandle)
- GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mTexCoordVBO)
- GLES30.glVertexAttribPointer(textureHandle, TEXTURE_POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, NO_OFFSET)
- // 绘制纹理
- GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)
- // 解绑顶点数据
- GLES30.glDisableVertexAttribArray(positionHandle)
- // 解绑纹理数据
- GLES30.glDisableVertexAttribArray(textureHandle)
- }
- }
- object LoadShaderUtil{
- // 创建着色器对象
- fun loadShader(type: Int, source: String): Int {
- val shader = GLES30.glCreateShader(type)
- GLES30.glShaderSource(shader, source)
- GLES30.glCompileShader(shader)
- return shader
- }
- }
复制代码 效果图
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |