OpenGL ES 纹理
- 纹理概念
- 纹理对象和纹理加载
- 应用纹理的例子
使用前面学过的技术已经可以利用OpenGL ES构建立体图形,并通过顶点着色器和片元着色器对其进行各种变化呢和光照等效果使得三维效果更加真实,实际上我看看到很多的3D游戏漂亮多了,那是因为有各种各样的漂亮的图像带给人很多视觉盛宴,这篇文章在前面的基础上,增加物体的表面贴图,使得物体更加好看。
纹理概念
纹理用来表示图像照片或者说一系列的数据,使用纹理可以使物体用用更多的细节。OpenGL ES 2.0 中有两种贴图:二维纹理和立方体纹理。
每个二维纹理都由许多小的纹理元素组成,类似与片元和像素,使用纹理最简单的方式就是直接从一个图像加载数据。在OpenGL中规定纹理图像的左下角由stst坐标(0.0,0.0)指定,右上角由stst坐标(1.0,1.0)指定,不过超过1.0的坐标也是允许的,在该区间之外的纹理在读取时的时候由纹理拉伸模式决定。
OpenGL ES 2.0不必是正方形,但是每个维度都应该是2的幂
在Android中使用的OpenGL ES的纹理坐标系跟官方的纹理坐标系统不一样,在Android中使用官方的纹理坐标系统,得到的结果是相反的,而是左上角是stst坐标(0.0,0.0)点,右下角是stst坐标(1.0,1.0)点。
二维纹理映射的原理
使用纹理就是在纹理图中进行采样,因此需要将选定的纹理坐标穿进顶点着色器,经过插值在片元着色器中从纹理图中的指定位置采样即可,纹理图的数据通过往片元插值器传递纹理单元指定的。
纹理对象和纹理加载
创建一个纹理对象,保存渲染所需的纹理数据,例如图像数据、过滤模式、包装模式。创建生成纹理对象的函数
public static native void glGenTextures(int n, // 指定要生成的纹理对象的数量int[] textures, // 保存纹理对象ID的数组int offset);
纹理对象在应用程序中不再使用时,需要删除。
public static native void glDeleteTextures(int n, // 指定要删除的纹理数量int[] textures, // 保存待删除的纹理ID的数组int offset);
纹理对象的 ID 必须是 glGenTextures 产生的,一旦生成纹理ID,就必须绑定纹理对象才能继续进行后续的操作。后续的操作将影响绑定的纹理对象。一旦纹理被绑定到一个特定的纹理目标,再删除之前就一直保持着绑定状态。
public static native void glBindTexture(int target, // 绑定纹理对象到目标 GL_TEXTURE_2D 或 GL_TEXTURE_CUBE_MAPint texture // 要绑定的纹理对象ID);
激活某个纹理单元
public static native void glActiveTexture(int texture // 要激活的纹理单元);
对这两个函数的理解:显卡中有N个纹理单元(GL_TEXTURE0,GL_TEXTURE1,GL_TEXTURE2…),每个纹理单元中保存着很多纹理目标(targetTexture1D,targetTexture2D,targetTexture3D,targetTextureCube…),OpenGL ES 2.0貌似只支持了targetTexture2D和targetTextureCube。
纹理单元TextureUnit的定义如下
struct TextureUnit
{GLuint targetTexture1D;GLuint targetTexture2D;GLuint targetTexture3D;GLuint targetTextureCube;...
};
glActiveTexture函数就是设置当前活动的纹理单元
TextureUnit textureUnits[GL_MAX_TEXTURE_IMAGE_UNITS]
GLuint currentTextureUnit = 0;
// ...
void glActiveTexture(GLenum textureUnit)
{currentTextureUnit = textureUnit - GL_TEXTURE0 ;
}
glBindTexture函数就是将纹理对象ID赋值给当前活动的纹理单元的对应的目标纹理。
void glBindTexture(GLenum textureTarget, GLuint textureObject)
{TextureUnit *texUnit = &textureUnits[currentTextureUnit];switch(textureTarget){case GL_TEXTURE_1D: texUnit->targetTexture1D = textureObject; break;case GL_TEXTURE_2D: texUnit->targetTexture2D = textureObject; break;case GL_TEXTURE_3D: texUnit->targetTexture3D = textureObject; break;case GL_TEXTURE_CUBEMAP: texUnit->targetTextureCube = textureObject; break;}
}
获取一副图片的纹理数据
public static void texImage2D(int target, // 常数GL_TEXTURE_2Dint level, // 表示多级分辨率的纹理图像的级数,若只有一种分辨率,则level设为0。Bitmap bitmap,int border // 边框,一般设为0 )
其他纹理选项的设置使用glTexParameterf系列函数
public static native void glTexParameterf(int target, int pname, // 设定的参数,可以是GL_TEXTURE_MAG_FILTER,GL_TEXTURE_MIN_FILTER,GL_TEXTURE_WRAP_S,GL_TEXTURE_WRAP_Tfloat param // 参数对应的值);
应用纹理的例子
对前面的立方体的每个面应用一张图片作为纹理贴图,效果图(这个纹理图是哪个老师来着?)
Rectangle.java
public class Rectangle {private FloatBuffer mVertexBuffer;private int mProgram;private int mPositionHandle;private int muMVPMatrixHandle;private int mColorHandle;private int muMMatrixHandle;private int muLightLocationHandle;private int mTextureCoordHandle;private int textureId;private int muTextureHandle;private Context mContext;public Rectangle(Context context) {this.mContext = context;initVetexData();}public void initVetexData() {float vertices[] = new float[] {// 顶点 颜色 纹理坐标//前面0, 0, 1, 1,1,1,0, 0.5f, 0.5f,1, 1, 1, 1,0,0,0, 1.0f, 0.0f,-1, 1, 1, 1,0,0,0, 0.0f, 0.0f,0, 0, 1, 1,1,1,0, 0.5f, 0.5f,-1, 1, 1, 1,0,0,0, 0.0f, 0.0f,-1,-1, 1, 1,0,0,0, 0.0f, 1.0f,0, 0, 1, 1,1,1,0, 0.5f, 0.5f,-1,-1, 1, 1,0,0,0, 0.0f, 1.0f,1,-1, 1, 1,0,0,0, 1.0f, 1.0f,0, 0, 1, 1,1,1,0, 0.5f, 0.5f,1,-1, 1, 1,0,0,0, 1.0f, 1.0f,1, 1, 1, 1,0,0,0, 1.0f, 0.0f,//后面0, 0,-1, 1,1,1,0, 0.5f, 0.5f,1, 1,-1, 1,0,0,0, 1.0f, 0.0f,1,-1,-1, 1,0,0,0, 0.0f, 0.0f,0, 0,-1, 1,1,1,0, 0.5f, 0.5f,1,-1,-1, 1,0,0,0, 0.0f, 0.0f,-1,-1,-1, 1,0,0,0, 0.0f, 1.0f,0, 0,-1, 1,1,1,0, 0.5f, 0.5f,-1,-1,-1, 1,0,0,0, 0.0f, 1.0f,-1, 1,-1, 1,0,0,0, 1.0f, 1.0f,0, 0,-1, 1,1,1,0, 0.5f, 0.5f,-1, 1,-1, 1,0,0,0, 1.0f, 1.0f,1, 1,-1, 1,0,0,0, 1.0f, 0.0f,//左面-1, 0, 0, 1,1,1,0, 0.5f, 0.5f,-1, 1, 1, 1,0,0,0, 1.0f, 0.0f,-1, 1,-1, 1,0,0,0, 0.0f, 0.0f,-1, 0, 0, 1,1,1,0, 0.5f, 0.5f,-1, 1,-1, 1,0,0,0, 0.0f, 0.0f,-1,-1,-1, 1,0,0,0, 0.0f, 1.0f,-1, 0, 0, 1,1,1,0, 0.5f, 0.5f,-1,-1,-1, 1,0,0,0, 0.0f, 1.0f,-1,-1, 1, 1,0,0,0, 1.0f, 1.0f,-1, 0, 0, 1,1,1,0, 0.5f, 0.5f,-1,-1, 1, 1,0,0,0, 1.0f, 1.0f,-1, 1, 1, 1,0,0,0, 1.0f, 0.0f,//右面1, 0, 0, 1,1,1,0, 0.5f, 0.5f,1, 1, 1, 1,0,0,0, 1.0f, 0.0f,1,-1, 1, 1,0,0,0, 0.0f, 0.0f,1, 0, 0, 1,1,1,0, 0.5f, 0.5f,1,-1, 1, 1,0,0,0, 0.0f, 0.0f,1,-1,-1, 1,0,0,0, 0.0f, 1.0f,1, 0, 0, 1,1,1,0, 0.5f, 0.5f,1,-1,-1, 1,0,0,0, 0.0f, 1.0f,1, 1,-1, 1,0,0,0, 1.0f, 1.0f,1, 0, 0, 1,1,1,0, 0.5f, 0.5f,1, 1,-1, 1,0,0,0, 1.0f, 1.0f,1, 1, 1, 1,0,0,0, 1.0f, 0.0f,//上面0, 1, 0, 1,1,1,0, 0.5f, 0.5f,1, 1, 1, 1,0,0,0, 1.0f, 0.0f,1, 1,-1, 1,0,0,0, 0.0f, 0.0f,0, 1, 0, 1,1,1,0, 0.5f, 0.5f,1, 1,-1, 1,0,0,0, 0.0f, 0.0f,-1, 1,-1, 1,0,0,0, 0.0f, 1.0f,0, 1, 0, 1,1,1,0, 0.5f, 0.5f,-1, 1,-1, 1,0,0,0, 0.0f, 1.0f,-1, 1, 1, 1,0,0,0, 1.0f, 1.0f,0, 1, 0, 1,1,1,0, 0.5f, 0.5f,-1, 1, 1, 1,0,0,0, 1.0f, 1.0f,1, 1, 1, 1,0,0,0, 1.0f, 0.0f,//下面0,-1, 0, 1,1,1,0, 0.5f, 0.5f,1,-1, 1, 1,0,0,0, 1.0f, 0.0f,-1,-1, 1, 1,0,0,0, 0.0f, 0.0f,0,-1, 0, 1,1,1,0, 0.5f, 0.5f,-1,-1, 1, 1,0,0,0, 0.0f, 0.0f,-1,-1,-1, 1,0,0,0, 0.0f, 1.0f,0,-1, 0, 1,1,1,0, 0.5f, 0.5f,-1,-1,-1, 1,0,0,0, 0.0f, 1.0f,1,-1,-1, 1,0,0,0, 1.0f, 1.0f,0,-1, 0, 1,1,1,0, 0.5f, 0.5f,1,-1,-1, 1,0,0,0, 1.0f, 1.0f,1,-1, 1, 1,0,0,0, 1.0f, 0.0f};ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);vbb.order(ByteOrder.nativeOrder());mVertexBuffer = vbb.asFloatBuffer();mVertexBuffer.put(vertices);mVertexBuffer.position(0);int vertexShader = loaderShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);int fragmentShader = loaderShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);mProgram = GLES20.glCreateProgram();GLES20.glAttachShader(mProgram, vertexShader);GLES20.glAttachShader(mProgram, fragmentShader);GLES20.glLinkProgram(mProgram);mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");mColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");mTextureCoordHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");muMMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMMatrix");muLightLocationHandle = GLES20.glGetUniformLocation(mProgram, "uLightLocation");muTextureHandle = GLES20.glGetUniformLocation(mProgram, "uTexture");initTexture();}// 初始化纹理public void initTexture() {int [] textures = new int[1];GLES20.glGenTextures(1, textures, 0);textureId = textures[0];// 激活纹理单元,默认激活的就是0号纹理单元//GLES20.glActiveTexture(GLES20.GL_TEXTURE0);// 将纹理对象ID绑定到当前活动的纹理单元0上的GL_TEXTURE_2D目标GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);// 后面对纹理的设置都是对绑定了的纹理所生效的//缩小采样使用最近点采样GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);//缩小采样使用最近点采样GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);//纹理包裹拉伸方式在st轴采用截取拉伸方式,这些设置指的是对坐标范围超过1的部分的限制GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.texture);GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);// 图片已经加载到了显存,可以回收bitmap.recycle();}public void draw() {GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 12*6);}public void setValue(float[] mvpMatrix, float[] mMatrix) {GLES20.glUseProgram(mProgram);mVertexBuffer.position(0);GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, (4+3+2) * 4, mVertexBuffer);mVertexBuffer.position(3);GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, (4+3+2) * 4, mVertexBuffer);mVertexBuffer.position(7);GLES20.glVertexAttribPointer(mTextureCoordHandle, 2, GLES20.GL_FLOAT, false, (4+3+2) * 4, mVertexBuffer);GLES20.glEnableVertexAttribArray(mPositionHandle);GLES20.glEnableVertexAttribArray(mColorHandle);GLES20.glEnableVertexAttribArray(mTextureCoordHandle);GLES20.glUniform3f(muLightLocationHandle, 0, 0, 20);GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mvpMatrix, 0);GLES20.glUniformMatrix4fv(muMMatrixHandle, 1, false, mMatrix, 0);// 将使用的纹理单元0传递给片元着色器GLES20.glUniform1i(muTextureHandle, 0);}private int loaderShader(int type, String shaderCode) {int shader = GLES20.glCreateShader(type);GLES20.glShaderSource(shader, shaderCode);GLES20.glCompileShader(shader);return shader;}private String vertexShaderCode = "uniform mat4 uMVPMatrix;"+ "attribute vec2 aTextureCoord;"+ "varying vec2 vTextureCoord;"+ "uniform mat4 uMMatrix;"+ "uniform vec3 uLightLocation;"+ "attribute vec4 aColor;"+ "varying vec4 vColor;" + "varying vec4 vDiffuse;"+ "attribute vec3 aPosition;"+ "void main(){" + "vec3 normalVectorOrigin = aPosition;"+ "vec3 normalVector = normalize((uMMatrix*vec4(normalVectorOrigin,1)).xyz);"+ "vec3 vectorLight = normalize(uLightLocation - (uMMatrix * vec4(aPosition,1)).xyz);"+ "float factor = max(0.0, dot(normalVector, vectorLight));"+ "vDiffuse = factor*vec4(1,1,1,1.0);"+ "gl_Position = uMVPMatrix * vec4(aPosition,1);"+ "vColor = aColor;"+ "vTextureCoord = aTextureCoord;" // 将纹理坐标传到片元着色器,得到更多的插值纹理坐标+ "}";private String fragmentShaderCode = "precision mediump float;"+ "uniform sampler2D uTexture;" // 这个uniform变量表示了纹理数据,从java中传过来的是所在的纹理单元编号+ "varying vec2 vTextureCoord;"+ "varying vec4 vColor;"+ "varying vec4 vDiffuse;"+ "void main(){"+ "gl_FragColor = (vColor*vDiffuse + vColor*vec4(0.6,0.6,0.6,1))*texture2D(uTexture, vTextureCoord);" // 在纹理的基础上还考虑到光照,texture2D函数用于纹理采样+ "}";
}
需要注意的还是传入的顶点的时候数组里面包含了顶点、颜色和纹理坐标,因此要用ByteBuffer的position方法定位。
代码下载
OpenGL ES 纹理相关推荐
- android opengl es 纹理 不同设备 白色,android – OpenGL ES 2.0纹理没有在某些设备上显示...
早上好,这是2个纹理非幂的典型例子. 由于多种原因,纹理在分辨率上需要2的幂,这是一个非常常见的错误,每个人都碰巧陷入这个陷阱:)我也是. 2个纹理的非功率在某些设备/ GPU上运行平稳的事实,仅仅取 ...
- OpenGL ES 纹理设置
纹理过滤 纹理采样 最近点采样 线性纹理采样 MIPMAP纹理 纹理过滤 纹理拉伸:重复拉伸和截取拉伸 用于指定纹理坐标超过(00.0,1.0)范围时所发生的行为,使用glTexParameterf函 ...
- opengl es纹理贴图效果实例
一.先准备好一张用来贴图的照片 二.纹理效果代码: gl.glEnable(GL10.GL_TEXTURE_2D);// 创建纹理gl.glGenTextures(1, textureids, 0); ...
- 一文详解 OpenGL ES 纹理颜色混合
在OpenGL中绘制的时候,有时候想使新画的颜色和已经有的颜色按照一定的方式进行混合.例如:想使物体拥有半透明的效果,或者绘制叠加光亮的效果,这时候就需要用到OpenGLES混合. 如上图所示,为石头 ...
- Android Studio OpenGL ES绘制三棱锥/四面体的多纹理贴图 每个面使用一张图片渲染
本文参考了王刚的<疯狂Android讲义(第3版)>P554-P559 要求:利用OpenGL ES绘制一个三棱锥,并对每个面进行纹理贴图,每个面使用不同的图片进行渲染. 环境:Andro ...
- OpenGL ES着色器语言之变量和数据类型
所有变量和函数在使用前必须声明.变量和函数名是标识符. 没有默认类型,所有变量和函数声明必须包含一个声明类型以及可选的修饰符.变量在声明的时候首先要标明类型,后边可以跟多个变量,之间用逗号隔开.很多情 ...
- OpenGL ES EGL 简介
目录 一.EGL 简介 二.EGL 跨平台之 ANGLE 1.ANGLE 支持跨平台 2.ANGLE 支持渲染器 3.ANGLE 下载地址 三.EGL 坐标系 四.EGL 绘图步骤 五.猜你喜欢 零基 ...
- android opengl分屏,OpenGL ES 分屏滤镜
想要绘制滤镜首先我们需要清楚如何绘制纹理,如果不了解的可以参考 OpenGL ES 纹理绘制. 这篇文章中绘制的图片是倒立的,我们需要将图片反转过来.方法很多,这里就简单介绍一种常用的方法,反转坐标系 ...
- OpenGL ES 名词解释(二)
目录 一.前言 二.坐标系 1.屏幕坐标系 2.纹理坐标系 3.顶点坐标系 4.图像坐标系 三.混合 四.变换矩阵 1.平移 2.旋转 3.缩放 4.矩阵组合顺序 五.投影矩阵 1.正交投影 2.透视 ...
最新文章
- Kali渗透测试——快速查找Metasploit的模块
- OPENCV打开图片进行边缘检测
- 进程和程序:编写shell——《Unix/Linux编程实践教程》读书笔记(第8章)
- vue 插入dom_vue内部复用问题以及虚拟dom的更新
- iframe嵌入页面白屏_Vue使用iframe嵌入第三方网页并修改标题
- 有状态的bean和无状态的bean的区别
- java ldap 父_java – DirContext:Active Directory Ldap请求:获取具有父组的用户组
- 使用canto+w3m实现在控制台上完美阅读RSS
- Windows网络编程 WSAstartup()详解
- pwm波如何控制电机代码_如何通过PLC控制伺服电机?
- Linq 语法的一系列问题,菜鸟求解。
- 创建动态的XML数据
- 龙门标局:注册地理标志证明商标有什么作用
- Windows11 微软拼音注册表方式添加小鹤双拼
- 检测图片篡改困难?快来试试这款黑科技
- C语言练习题——函数
- Vue-2-计算属性、侦听器、过滤器、样式绑定
- 短域名系统设计详解(全)
- 风投掘金可穿戴设备:大数据才是背后真金
- 6-7 制作电子书表单