OpenGL ES -> GLSurfaceView纹理贴图

打印 上一主题 下一主题

主题 581|帖子 581|积分 1743

贴图


XML文件

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <com.example.myapplication.MyGLSurfaceView
  3.         xmlns:android="http://schemas.android.com/apk/res/android"
  4.     android:layout_width="match_parent"
  5.     android:layout_height="match_parent" />
复制代码
自界说GLSurfaceView代码

  1. class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs) {
  2.     private var mRenderer = MyGLRenderer(context)
  3.     init {
  4.         // 设置 OpenGL ES 3.0 版本
  5.         setEGLContextClientVersion(3)
  6.         setRenderer(mRenderer)
  7.         // 设置渲染模式, 仅在需要重新绘制时才进行渲染,以节省资源
  8.         renderMode = RENDERMODE_WHEN_DIRTY
  9.     }
  10. }
复制代码
自界说GLSurfaceView.Renderer代码

  1. class MyGLRenderer(private val mContext : Context) : GLSurfaceView.Renderer {
  2.     private var mDrawData: DrawData? = null
  3.     override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
  4.         // 当 Surface 创建时调用, 进行 OpenGL ES 环境的初始化操作, 设置清屏颜色为青蓝色 (Red=0, Green=0.5, Blue=0.5, Alpha=1)
  5.         GLES30.glClearColor(0.0f, 0.5f, 0.5f, 1.0f)
  6.         mDrawData = DrawData().apply {
  7.             initVertexBuffer()
  8.             initShader()
  9.             loadTexture(mContext, R.drawable.bitmap_shader)
  10.         }
  11.     }
  12.     override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
  13.         // 当 Surface 尺寸发生变化时调用,例如设备的屏幕方向发生改变, 设置视口为新的尺寸,视口是指渲染区域的大小
  14.         GLES30.glViewport(0, 0, width, height)
  15.         mDrawData?.computeMVPMatrix(width.toFloat(), height.toFloat())
  16.     }
  17.     override fun onDrawFrame(gl: GL10?) {
  18.         // 每一帧绘制时调用, 清除颜色缓冲区
  19.         GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
  20.         mDrawData?.drawSomething()
  21.     }
  22. }
复制代码
GLSurfaceView.Renderer必要的绘制数据

  1. class DrawData {
  2.     private var mProgram : Int = -1
  3.     private var NO_OFFSET = 0
  4.     private val VERTEX_POS_DATA_SIZE = 3
  5.     private val TEXTURE_POS_DATA_SIZE = 2
  6.     // 纹理ID
  7.     private var mTextureID = IntArray(1)
  8.     // VBO IDs
  9.     private var mVertexVBO = 0
  10.     private var mTexCoordVBO = 0
  11.     // 最终变化矩阵
  12.     private val mMVPMatrix = FloatArray(16)
  13.     // 投影矩阵
  14.     private val mProjectionMatrix = FloatArray(16)
  15.     // 相机矩阵
  16.     private val mViewMatrix = FloatArray(16)
  17.     private var mViewPortRatio = 1f
  18.     // 1. 准备顶点坐标,分配直接内存
  19.     // OpenGL ES坐标系:原点在中心,X轴向右为正,Y轴向上为正,Z轴向外为正
  20.     val vertex = floatArrayOf(
  21.         -1.0f,  1.0f, 0.0f, // 左上
  22.         -1.0f, -1.0f, 0.0f, // 左下
  23.         1.0f, 1.0f, 0.0f, // 右上
  24.         1.0f, -1.0f, 0.0f, // 右下
  25.     )
  26.     val vertexBuffer = ByteBuffer.allocateDirect(vertex.size * 4)
  27.         .order(ByteOrder.nativeOrder())
  28.         .asFloatBuffer()
  29.     // 2. 准备纹理坐标,分配直接内存
  30.     // 纹理坐标系:原点在左下角,X轴向右为正,Y轴向上为正
  31.     val textureCoords = floatArrayOf(
  32.         0.0f, 1.0f, // 左上
  33.         0.0f, 0.0f, // 左下
  34.         1.0f, 1.0f, // 右上
  35.         1.0f, 0.0f, // 右下
  36.     )
  37.     val textureBuffer = ByteBuffer.allocateDirect(textureCoords.size * 4)
  38.         .order(ByteOrder.nativeOrder())
  39.         .asFloatBuffer()
  40.     // 3. 创建顶点缓冲区对象
  41.     fun initVertexBuffer(){
  42.         // 初始化顶点坐标缓冲区
  43.         vertexBuffer.put(vertex)
  44.         vertexBuffer.position(NO_OFFSET)
  45.         // 初始化纹理坐标缓冲区
  46.         textureBuffer.put(textureCoords)
  47.         textureBuffer.position(NO_OFFSET)
  48.         // 创建两个VBO,一个用于顶点坐标,一个用于纹理坐标
  49.         val vbo = IntArray(2)
  50.         GLES30.glGenBuffers(vbo.size, vbo, NO_OFFSET) // 生成一个缓冲区对象ID,并存储在数组 vbo 中,存放位置为0
  51.         // 绑定顶点缓冲区
  52.         GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0])
  53.         GLES30.glBufferData(
  54.             GLES30.GL_ARRAY_BUFFER,
  55.             vertex.size * 4, // 数据总字节数 = 顶点数 * Float占4字节
  56.             vertexBuffer,
  57.             GLES30.GL_STATIC_DRAW
  58.         )
  59.         // 绑定纹理缓冲区
  60.         GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[1])
  61.         GLES30.glBufferData(
  62.             GLES30.GL_ARRAY_BUFFER,
  63.             textureCoords.size * 4, // 数据总字节数 = 顶点数 * Float占4字节
  64.             textureBuffer,
  65.             GLES30.GL_STATIC_DRAW
  66.         )
  67.         mVertexVBO = vbo[0]
  68.         mTexCoordVBO = vbo[1]
  69.     }
  70.     // 4. 初始化着色器程序
  71.     fun initShader()  {
  72.         val vertexShaderCode = """#version 300 es
  73.                 in vec4 aPosition; // 顶点坐标
  74.                 uniform mat4 uMVPMatrix; // 变换矩阵
  75.                 in vec2 aTexCoord; // 纹理坐标
  76.                 out vec2 vTexCoord;
  77.                 void main() {
  78.                     // 输出顶点坐标和纹理坐标到片段着色器
  79.                     gl_Position = uMVPMatrix * aPosition;
  80.                     vTexCoord = aTexCoord;
  81.                 }""".trimIndent()       // 顶点着色器代码
  82.         val fragmentShaderCode = """#version 300 es
  83.                 precision mediump float; // 定义float 精度为 mediump
  84.                 out vec4 fragColor; // 输出片段颜色
  85.                 in vec2 vTexCoord; // 接收顶点着色器传递过来的纹理坐标
  86.                 uniform sampler2D uTexture; // 纹理取样器
  87.                 void main() {
  88.                     // 使用内置函数texture, 根据纹理坐标和取样器sampler2D计算片段颜色
  89.                     fragColor = texture(uTexture, vTexCoord);
  90.                 }""".trimIndent()
  91.         // 加载顶点着色器和片段着色器, 并创建着色器程序
  92.         val vertexShader = LoadShaderUtil.loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode)
  93.         val fragmentShader = LoadShaderUtil.loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode)
  94.         mProgram = GLES30.glCreateProgram()
  95.         GLES30.glAttachShader(mProgram, vertexShader)
  96.         GLES30.glAttachShader(mProgram, fragmentShader)
  97.         GLES30.glLinkProgram(mProgram)
  98.         GLES30.glUseProgram(mProgram)
  99.     }
  100.     // 5. 加载纹理
  101.     fun loadTexture(context: Context, resourceId: Int) {
  102.         // 生成纹理
  103.         GLES30.glGenTextures(mTextureID.size, mTextureID, NO_OFFSET)
  104.         // 绑定纹理
  105.         GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureID[0])
  106.         // 设置纹理参数
  107.         GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR) // 纹理缩小时使用线性插值
  108.         GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR) // 纹理放大时使用线性插值
  109.         GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE) // 纹理坐标超出范围时,超出部分使用最边缘像素进行填充
  110.         GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE) // 纹理坐标超出范围时,超出部分使用最边缘像素进行填充
  111.         // 加载图片
  112.         val options = BitmapFactory.Options().apply {
  113.             inScaled = false // 不进行缩放
  114.         }
  115.         val bitmap = BitmapFactory.decodeResource(context.resources, resourceId, options)
  116.         // 将图片数据加载到纹理中
  117.         GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, NO_OFFSET, bitmap, NO_OFFSET)
  118.         // 释放资源
  119.         bitmap.recycle()
  120.         // 解绑纹理
  121.         GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, NO_OFFSET)
  122.     }
  123.     // 6. 计算变换矩阵
  124.     fun computeMVPMatrix(width: Float, height: Float) {
  125.         // 正交投影矩阵
  126.         takeIf { width > height }?.let {
  127.             mViewPortRatio = width / height
  128.             Matrix.orthoM(
  129.                 mProjectionMatrix, // 正交投影矩阵
  130.                 NO_OFFSET, // 偏移量
  131.                 -mViewPortRatio, // 近平面的坐标系左边界
  132.                 mViewPortRatio, // 近平面的坐标系右边界
  133.                 -1f, // 近平面的坐标系的下边界
  134.                 1f, // 近平面坐标系的上边界
  135.                 0f, // 近平面距离相机距离
  136.                 1f // 远平面距离相机距离
  137.             )
  138.         } ?: run {
  139.             mViewPortRatio = height / width
  140.             Matrix.orthoM(
  141.                 mProjectionMatrix, // 正交投影矩阵
  142.                 NO_OFFSET, // 偏移量
  143.                 -1f, // 近平面坐标系左边界
  144.                 1f, // 近平面坐标系右边界
  145.                 -mViewPortRatio, // 近平面坐标系下边界
  146.                 mViewPortRatio, // 近平面坐标系上边界
  147.                 0f, // 近平面距离相机距离
  148.                 1f // 远平面距离相机距离
  149.             )
  150.         }
  151.         // 设置相机矩阵
  152.         // 相机位置(0f, 0f, 1f)
  153.         // 物体位置(0f, 0f, 0f)
  154.         // 相机方向(0f, 1f, 0f)
  155.         Matrix.setLookAtM(
  156.             mViewMatrix, // 相机矩阵
  157.             NO_OFFSET, // 偏移量
  158.             0f, // 相机位置x
  159.             0f, // 相机位置y
  160.             1f, // 相机位置z
  161.             0f, // 物体位置x
  162.             0f, // 物体位置y
  163.             0f, // 物体位置z
  164.             0f, // 相机上方向x
  165.             1f, // 相机上方向y
  166.             0f // 相机上方向z
  167.         )
  168.         // 最终变化矩阵
  169.         Matrix.multiplyMM(
  170.             mMVPMatrix, // 最终变化矩阵
  171.             NO_OFFSET, // 偏移量
  172.             mProjectionMatrix, // 投影矩阵
  173.             NO_OFFSET, // 投影矩阵偏移量
  174.             mViewMatrix, // 相机矩阵
  175.             NO_OFFSET // 相机矩阵偏移量
  176.         )
  177.         // 纹理坐标系为(0, 0), (1, 0), (1, 1), (0, 1)的正方形逆时针坐标系,从Bitmap生成纹理,即像素拷贝到纹理坐标系
  178.         // 变换矩阵需要加上一个y方向的翻转, x方向和z方向不改变
  179.         Matrix.scaleM(
  180.             mMVPMatrix,
  181.             NO_OFFSET,
  182.             1f,
  183.             -1f,
  184.             1f,
  185.         )
  186.         val matrixHandler = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix")
  187.         GLES30.glUniformMatrix4fv(matrixHandler, 1, false, mMVPMatrix, NO_OFFSET)
  188.     }
  189.     // 7. 使用着色器程序绘制图形
  190.     fun drawSomething(){
  191.         // 激活纹理编号
  192.         GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
  193.         GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureID[0])
  194.         // 激活纹理取样器
  195.         val textureSampleHandle = GLES30.glGetUniformLocation(mProgram, "uTexture")
  196.         GLES30.glUniform1i(textureSampleHandle, NO_OFFSET)
  197.         // 激活变换矩阵
  198.         val matrixHandle = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix")
  199.         GLES30.glUniformMatrix4fv(matrixHandle, 1, false, mMVPMatrix, NO_OFFSET)
  200.         // 输入顶点数据
  201.         val positionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition")
  202.         GLES30.glEnableVertexAttribArray(positionHandle)
  203.         GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVertexVBO)
  204.         GLES30.glVertexAttribPointer(positionHandle, VERTEX_POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, NO_OFFSET)
  205.         // 绑定纹理数据
  206.         val textureHandle = GLES30.glGetAttribLocation(mProgram, "aTexCoord")
  207.         GLES30.glEnableVertexAttribArray(textureHandle)
  208.         GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mTexCoordVBO)
  209.         GLES30.glVertexAttribPointer(textureHandle, TEXTURE_POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, NO_OFFSET)
  210.         // 绘制纹理
  211.         GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, NO_OFFSET, vertex.size  / VERTEX_POS_DATA_SIZE)
  212.         // 解绑顶点数据
  213.         GLES30.glDisableVertexAttribArray(positionHandle)
  214.         // 解绑纹理数据
  215.         GLES30.glDisableVertexAttribArray(textureHandle)
  216.     }
  217. }
  218. object LoadShaderUtil{
  219.     // 创建着色器对象
  220.     fun loadShader(type: Int, source: String): Int {
  221.         val shader = GLES30.glCreateShader(type)
  222.         GLES30.glShaderSource(shader, source)
  223.         GLES30.glCompileShader(shader)
  224.         return shader
  225.     }
  226. }
复制代码
效果图



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

梦应逍遥

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表