在OpenGL ES中绘制一张图片需要使用到纹理(texture),绘制纹理步骤如下:

编写shader

绘制纹理的shader需要顶点数据、纹理顶点数据和纹理。Vertex Shader代码如下:

attribute vec4 a_Position;
attribute vec2 a_TexCoordinate;
varying vec2 v_TexCoord;void main()
{v_TexCoord = a_TexCoordinate;gl_Position = a_Position;
}
  • a_Position:顶点数据。

  • a_TexCoordinate:纹理顶点数据。

  • v_TexCoord:varying类型,v_TexCoord是a_TexCoordinate的值,传递给Fragment Shader使用。

Fragment Shader代码如下:

precision mediump float;
uniform sampler2D u_Texture;
varying vec2 v_TexCoord;void main()
{gl_FragColor = texture2D(u_Texture, v_TexCoord);
}
  • u_Texture:纹理,其类型是sampler2D。

  • v_TexCoord:Vertex Shader传递过来的纹理顶点数据,texture2D是OpenGL ES内置函数,称之为采样器,获取纹理上指定位置的颜色值。

创建program并获取参数句柄

创建program的过程在《OpenGL ES for Android 环境搭建》中详细介绍,这里不在介绍,直接使用封装好的工具类,代码如下:

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

bitmap_vs.glsl和bitmap_fs.glsl是assets/glsl目录下文件,分别代表顶点shader和纹理shader。

AssetsUtils.readAssetsTxt为工具类,读取asset文件下的文件返回String类型,代码如下:

fun readAssetsTxt(context: Context, filePath: String): String {try {val inputStream = context.assets.open(filePath)val size = inputStream.available()val buffer = ByteArray(size)inputStream.read(buffer)inputStream.close()return String(buffer, Charset.forName("utf-8"))} catch (e: IOException) {e.printStackTrace()}return ""}

program的创建要在GLThread线程(所有的OpenGL ES的相关操作都要在GLThread线程中运行),在Renderer的onSurfaceCreated回调中创建,代码如下:

override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {createProgram()}

program创建完成后获取顶点数据(a_Position)、纹理顶点数据(a_TexCoordinate)、纹理(u_Texture)的句柄,代码如下:

override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {createProgram()//获取vPosition索引vPositionLoc = GLES20.glGetAttribLocation(mProgramHandle, "a_Position")texCoordLoc = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate")textureLoc = GLES20.glGetUniformLocation(mProgramHandle, "u_Texture")}

a_Poition、a_TexCoordinate、u_Texture对应Shader中的名称,mProgramHandle为program的句柄。

定义顶点数据

创建全屏的顶点数据代码如下:

      var vertexBuffer = GLTools.array2Buffer(floatArrayOf(-1.0f, 1.0f, 0.0f,  // top left-1.0f, -1.0f, 0.0f,  // bottom left1.0f, -1.0f, 0.0f,  // bottom right1.0f, 1.0f, 0.0f  // top right))

这里有4个点,每个点包含3个float数据,代表x,y,z。4个顶点的位置如下图:

OpenGL ES中绘制任何形状都是通过绘制多个三角形而组成,所以我们将这4个点分为2个三角形,分布为(V1,V2,V3)和(V1,V3,V4),因此定义三角形索引数组代码如下:

var index = shortArrayOf(0, 1, 2, 0, 2, 3)

将索引数组转为buffer,我们也将此方法封装在工具类里面,代码如下:

 fun array2Buffer(array: ShortArray): ShortBuffer {val bb = ByteBuffer.allocateDirect(array.size * 2)bb.order(ByteOrder.nativeOrder())var buffer = bb.asShortBuffer()buffer.put(array)buffer.position(0)return buffer}

调用方式代码如下:

val indexBuffer = GLTools.array2Buffer(index)

定义纹理顶点

纹理坐标系统如下图:

纹理坐标的原点是左上角,右下角是(1,1),将整张图片绘制的纹理顶点数据代码如下:

var texBuffer = GLTools.array2Buffer(floatArrayOf(0.0f, 0.0f,0.0f, 1.0f,1.0f, 1.0f,1.0f, 0.0f))

纹理坐标的顶点顺序不是随便定义的,要与定义的顶点数据一一对应,否则可能出现纹理错乱,对应顺序如下图:

如果将纹理顶点设置如下:

var texBuffer = GLTools.array2Buffer(floatArrayOf(0.0f, 1.0f,1.0f, 1.0f,1.0f, 0.0f,0.0f, 0.0f))

纹理将逆时针旋转90度,通过此方法可以旋转、镜像纹理,但我们一般不会使用此方法旋转、镜像纹理,可以通过OpenGL ES中著名的MVP矩阵进行此操作。

加载纹理

纹理的的来源是一张图片,将图片转为Bitmap,代码如下:

var bitmap =BitmapFactory.decodeResource(context.resources, R.drawable.bitmap)

创建2D纹理id,代码如下(此方法将封装在工具类中):

fun createTextureId(): Int {val textures = IntArray(1)GLES20.glGenTextures(1, textures, 0)glCheck("texture generate")GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0])glCheck("texture bind")GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_LINEAR.toFloat())GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR.toFloat())GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE)GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE)return textures[0]}
  • GLES20.glGenTextures(count,array,offset):生成纹理,参数说明如下:

  • count:生成纹理的个数。

  • array:生成纹理id存放的数组。

  • offset:存放纹理id数组的偏移。

  • GLES20.glGenTextures():生成1个纹理,textures[0]存放纹理id。

  • GLES20.glTexParameteri:纹理映射方式。

纹理创建成功后返回纹理id,将Bitmap传递给此纹理,代码如下:

import android.opengl.GLUtils
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0)

GLUtils是系统工具类,并不是我们自己写的工具类。

绘制纹理

override fun onDrawFrame(p0: GL10?) {GLES20.glUseProgram(mProgramHandle)//设置顶点数据vertexBuffer.position(0)GLES20.glEnableVertexAttribArray(vPositionLoc)GLES20.glVertexAttribPointer(vPositionLoc, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer)//设置纹理顶点数据texBuffer.position(0)GLES20.glEnableVertexAttribArray(texCoordLoc)GLES20.glVertexAttribPointer(texCoordLoc, 2, GLES20.GL_FLOAT, false, 0, texBuffer)//设置纹理GLES20.glActiveTexture(GLES20.GL_TEXTURE0)GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)GLES20.glUniform1i(textureLoc, 0)GLES20.glDrawElements(GLES20.GL_TRIANGLES, index.size, GLES20.GL_UNSIGNED_SHORT,indexBuffer)}
  • GLES20.glUseProgram():启用当前program,mProgramHandle是启用program的句柄。

  • 设置纹理,代码如下:

GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
GLES20.glUniform1i(textureLoc, 0)
  • GLES20.glActiveTexture:激活纹理,GLES20.GL_TEXTURE0表示激活0号纹理,也可以是GLES20.GL_TEXTURE1、GLES20.GL_TEXTURE2等。

  • GLES20.glBindTexture:将纹理绑定到GL_TEXTURE_2D类型。

  • GLES20.glUniform1i(textureLoc, 0):设置纹理,textureLoc是Fragment Shader中纹理句柄,后面的参数0和GLES20.GL_TEXTURE0是对应的,如果启用GLES20.GL_TEXTURE1,那么使用GLES20.glUniform1i(textureLoc, 1)。

  • GLES20.glDrawElements是真正的绘制,函数结构如下:

public static native void glDrawElements(int mode,int count,int type,java.nio.Buffer indices);

参数说明如下:

  • mode:绘制方式,GLES20.GL_TRIANGLES表示绘制三角形。

  • count:顶点的个数

  • type:索引(indices)数组中的元素类型,注意不是顶点的类型,值必须是GL_UNSIGNED_BYTE或者GL_UNSIGNED_SHORT。

  • indices:索引数组

到此绘制纹理就完成了。

更多相关阅读:

  • OpenGL ES for Android

  • OpenGL ES 环境搭建

OpenGL ES 绘制纹理相关推荐

  1. 2.x最终照着教程,成功使用OpenGL ES 绘制纹理贴图,添加了灰度图

    在之前成功绘制变色的几何图形之后,今天利用Openg ES的可编程管线绘制出第一张纹理. 学校时候不知道OpenGL的重要性,怕晦涩的语法.没有跟老师学习OpenGL的环境配置,现在仅仅能利用coco ...

  2. 2.x终于照着教程,成功使用OpenGL ES 绘制纹理贴图,增加了灰度图

    在之前成功绘制变色的几何图形之后,今天利用Openg ES的可编程管线绘制出第一张纹理.学校时候不知道OpenGL的重要性,怕晦涩的语法,没有跟老师学习OpenGL的环境配置,如今只能利用cocos2 ...

  3. Android Studio OpenGL ES绘制三棱锥/四面体的多纹理贴图 每个面使用一张图片渲染

    本文参考了王刚的<疯狂Android讲义(第3版)>P554-P559 要求:利用OpenGL ES绘制一个三棱锥,并对每个面进行纹理贴图,每个面使用不同的图片进行渲染. 环境:Andro ...

  4. 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)

    0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...

  5. 【Qt for Android】OpenGL ES 绘制彩色立方体

    Qt 内置对OpenGL ES的支持.选用Qt进行OpenGL ES的开发是很方便的,很多辅助类都已经具备.从Qt 5.0開始添加了一个QWindow类,该类既能够使用OpenGL绘制3D图形,也能够 ...

  6. 安卓学习笔记37:利用OpenGL ES绘制平面图形

    文章目录 零.学习目标 一.OpenGL概述 二.了解三维直角坐标系 三.案例演示 - 绘制三角形 (一)运行效果 (二)实现步骤 1.创建安卓应用[DrawTriangle] 2.建模:创建三角形类 ...

  7. OpenGL ES:绘制函数glDrawArrays 和 glDrawElements 的区别

    from:https://www.jianshu.com/p/4d02c2cd21ea 写文章注册登录 首页 下载App OpenGL ES:绘制函数glDrawArrays 和 glDrawElem ...

  8. Android 开发使用OpenGL ES绘制三棱锥并进行纹理贴图

    效果图: 直接上代码 MainActivity.java的代码 package com.zzu.shiyan3;import androidx.appcompat.app.AppCompatActiv ...

  9. OpenGL ES绘制3D纹理贴图

    最近看了<疯狂android讲义>的图形相关的内容,结合自己的理解,整理了一下. 下图是做出来的3D纹理贴图效果,手指在屏幕滑动时,图片可以随之转动. 要实现一个纹理贴图,很简单,大致需要 ...

  10. OpenGL ES 绘制图片

    流程 1.编写着色器(顶点着色器和片元着色器) 2.设置顶点.纹理坐标 3.加载着色器 4.创建纹理 5.渲染图片 OpenGL ES 中的顶点坐标与纹理坐标 绘制四边形 规定:图形环绕方向必须一致 ...

最新文章

  1. mysql 协议说明_MySQL认证协议_MySQL
  2. java怎么不安装到c盘的教程,帮您设置win10系统安装不了java的详细步骤
  3. 博客已从百度空间搬家到此
  4. 为什么借助开源学习是最有效的?
  5. LeetCode 1758. 生成交替二进制字符串的最少操作数(DP)
  6. windows配置java环境变量
  7. python毕业设计作品基于django框架 景区购票系统毕设成品(6)开题答辩PPT
  8. 怎么压缩图片文件大小?
  9. android支持wifi11ad,WiFi“千兆”必杀,802.11ax/802.11ad标准探秘
  10. 3d touch android,苹果3DTouch好用?安卓这个功能不比它差!
  11. php的implode函数的作用是,PHP函数implode介绍
  12. (转载)终极解密---房价,物价飞涨--分析得不错的文章
  13. 关于elementui的table主子表展示数据
  14. 如何拿到浏览器请求的所有url
  15. python 操作csv将符合条件的多行数据合并为一行
  16. 电信笔试C语言,电信的几个网络方面面试笔试题汇总
  17. 【转载】TCP/IP 之 大明王朝邮差
  18. SiteFactory 通用程序集中(PowerEasy.Common)的常用字符串处理函数
  19. Oracle KSL Latch 管理层 与 Latch管理(未看)
  20. idea 出现 Failure to find org.eclipse.m2e:lifecycle-mapping:pom:1.0.0 in http://maven.aliyun.com/

热门文章

  1. 如何对 Excel 中的数据使用 SQL 查询
  2. 云端卫士助力运营商实现DDoS安全业务的统一运营
  3. Siamese系列跟踪网络之SiamFC、SiamRPN、DaSiamRPN、SiamRPN++、SiamMask
  4. 前端内容安全策略(csp)
  5. 公民住宅权不可侵犯!为阻强拆致人重伤,属正当防卫
  6. 《网站推荐》音乐下载, 系统下载
  7. 计算机u盘病毒清除方式,终极:如何消除计算机上U盘的“文件夹.EXE病毒”?
  8. 登录注册判断+Mysql
  9. linux 压缩文件软件,Linux下最好用的解压缩软件unar
  10. CCF 202109-2 非零段划分(动态规划法,过了70%)