2019独角兽企业重金招聘Python工程师标准>>>

学习内容来源and参考

opengl es 3.0编程指南

https://www.jianshu.com/p/4d8d35288a0f

3D图形渲染最基本的操作之一是对一个表面进行纹理,纹理可以表现只从网格的几何形状中无法得到的附加细节。在opengl es3.0中的纹理有多种形式:2D纹理,2D纹理数组,3D纹理以及立方图纹理。

2D纹理

2D纹理是一个图像数据的二维数组。一个纹理单独数据元素称作“纹素”(Texel)。图像中的每个纹素根据基本格式和数据类型指定。如果用2D纹理渲染时,纹理坐标用作图像中的索引。2D纹理的纹理坐标用一对2D坐标(s,t)或者(u,v)来表示,这些坐标用于查找一个纹理贴图的规范化坐标。

纹理坐标如下所示:

纹理图像的左下坐标由(0.0,0.0)决定,右上角坐标由(1.0,1.0)指定。在[0.0,1.0]之外的坐标是允许的,在区间之外的纹理读取行为由纹理包装模式决定。

立方图纹理

立方图是由6个单独2D纹理面组成的纹理。对于立方图纹理贴图,一般使用环境贴图特效,即在物体上的倒影通过使用一个表示环境的立方图渲染。。通常,生成环境贴图所用的立方图通过在场景中央放置一个摄像机,从6个轴方向(+x,-x,+y,-y,+z,-z)捕捉场景图像并将结果保存在立方体的每个面上。

3D纹理

3D纹理可以看做2D纹理多个切片的一个数组,用一个三元坐标(s,t,r)访问,r坐标选择3D纹理需要采样的切片,(s,t)用来读取每个切片中的2D贴图。

2D纹理数组

2D纹理数组与3D纹理数组相似,但是用途不同,一般用来存储2D图像的动画。数组的每个切片标识纹理动画的一帧。坐标使用与3D纹理相同,都是使用(s,t,r)来表示,r坐标选择2D数组中需要采样的切片,(s,t)用来选取切片。

纹理对象和纹理加载

纹理对象是一个容器对象,保存所需要渲染的纹理数据,如图像数据,过滤模式以及包装模式。纹理对象使用一个无符号整数表示,该整数位纹理对象的句柄,生成纹理对象的函数如下:

void glGenTextures(GLsizei n,GLuint *textures);//native 实现// C function void glGenTextures ( GLsizei n, GLuint *textures )  java层代码
public static native void glGenTextures(int n,java.nio.IntBuffer textures);

Java代码中n表示生成纹理对象数量,textures为一个保存n个纹理对象id的无符号整数数组。创建时,glGenTextures方法生成的纹理对象是一个空的容器,用于加载纹理数据和参数。纹理对象在不使用时候可以通过调用glDeleteTextures(...)方法来删除。

一旦使用glGenTextures(...)来生成纹理对象id,应用程序就必须通过glBindTexture()绑定纹理对象进行操作。一旦绑定到一个特定的目标,纹理对象会一直绑定在此目标中直到删掉为止。在绑定完成后,需要去加载图像了,用于加载立方图纹理和2D的基本函数是glTexImage2D()。在opengl es3.0中可以使用多种代替方法指定2D纹理,包括不可变纹理(glTexStorage2D)以及glTexSubImage2D的结合。为了得到最佳性能,推荐使用不可变纹理。在Android中,系统帮我们封装了GLUtils来方便我们使用:

public static void texImage2D(int target, int level, Bitmap bitmap,int border);
//target为将纹理对象绑定到GL_TEXTURE_2D,GL_TEXTURE_3D,GL_TEXTURE_2D_ARRAY,GL_TEXTURE_CUBE_MAP的标识
//level为指定要加载mip的级别,第一个级别为0,后续的递增
//bitmap为需要加载的图像
//border在opengl es中忽略,传0即可

上述方法使用如下:


private void generateTexture(Bitmap bitmap) {int[] size = new int[1];GLES30.glGenTextures(size.length, size, 0);if (size[0] == 0) {Log.w(TAG, "创建纹理失败!");return;}int target = size[0];GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, target);GLUtils.texImage2D(target, 0, bitmap, 0);GLES30.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);GLES30.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);}

上述的glTexParameteri(..)方法将缩小和放大过滤模式设置为GL_NEAREST。这个对于纹理贴图来说是必须的,因为我们还没有为纹理加载完整的mip贴图链,因此,必须选择非mip贴图缩小过滤器。其他的模式还有GL_LINEAR,提供双线性非mip贴图过滤。

纹理过滤和mip贴图

纹理坐标用于生成一个2d索引,用来从纹理贴图中读取,当缩小和放大的过滤器设置为GL_NEAREST的时候,一个纹素将在提供的纹理坐标位置上读取,这个称为点采样或者最近采样。but,使用该方法采样可能会造成严重的视觉伪像,因为三角形在屏幕空间中变得较小,在不同像素间的差值,纹理坐标可能有很大的跳跃,从而造成从一个大的纹理涂重取得少量样本,造成锯齿伪像,并且可能造成巨大的性能损失。

上述的解决办法可以通过mip贴图来解决伪像的问题。其思路是构建一个mip贴图链,开始于原来指定的图像,后续的每个图像在每个维度上是前一个图像的一般,一直持续到最后到达链底部的1x1纹理。mip贴图级别可以变成生成(上述的level参数),一个mip级别中的每个像素通常根据上一级别中相同位置的4个像素的平均值计算。

纹理渲染时会发生两种过滤情况:缩小和放大。

  • 缩小的情况发生在屏幕投影的多边形小于纹理尺寸的时候。
  • 放大的情况发生在屏幕投影的多边形大于纹理尺寸的时候。

对于放大而言,mip贴图是不起作用的,因为我们总是从最大的可用级别进行采样。对于缩小来说,可以使用不同的采样方式。 过滤模式使用glTexParameteri(...)进行设置:

   public static native void glTexParameteri(int target,int pname,int param);
//纹理对象,GL_TEXTURE_2D,GL_TEXTURE_3D,GL_TEXTURE_2D_ARRAY,GL_TEXTURE_CUBE_MAP
//pname一般指定为GL_TEXTURE_MIN_FILTER(缩小),GL_TEXTURE_MAG_FILTER(放大)
//param为采用的过滤模式

过滤模式的采样过程如图所示:

GL_LINEAR

GL_NEAREST

  • GL_LINEAR:从最靠近纹理坐标中的纹理中获得一个双线性样本
  • GL_NEAREST:从最靠近纹理坐标中的纹理中获得一个单点样本

更加详细介绍关于过滤模式的区别可以查看这篇博客。

自动mip贴图生成

opengls es3.0中提供glGenerateMipmap()方法来自动生成mip贴图。

public static native void glGenerateMipmap(int target);
//之前生成的纹理对象,GL_TEXTURE_2D,GL_TEXTURE_3D,GL_TEXTURE_2D_ARRAY,GL_TEXTURE_CUBE_MAP

纹理包装模式

纹理包装模式用于指定纹理坐标超出[0.0,1.0]方位内所发生的行为。使用glTexParameter[i|f]v来进行设置:

public static native void glTexParameterfv(int target,int pname,java.nio.FloatBuffer params);// C function void glTexParameteri ( GLenum target, GLenum pname, GLint param )public static native void glTexParameteri(int target,int pname,int param);

这些模式可以为s,t,r坐标进行单独设置,GL_TEXTURE_WRAP_S设置s坐标的模式,GL_TEXTURE_WRAP_T设置t坐标的模式,GL_TEXTURE_WRAP_R设置r坐标的模式。

在opengl es中有三种模式可供使用:

  1. GL_REPEAT:对纹理的默认行为,重复纹理图像。
  2. GL_MIRRORED_REPEAT:和GL_REPEAT一样,但每次重复图片是镜像放置的。
  3. GL_CLAMP_TO_EDGE:纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。

代码demo

GLES30.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
GLES30.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

着色器中使用纹理

这里的demo不考虑图像拉伸的问题,旨在理清展示的逻辑

简单使用2D纹理展示一下效果,首先封装一个展示纹理的关键方法:

代码位于 https://github.com/JerryChan123/LearnOEL/tree/gl30 的[2D纹理普通贴图&&2D纹理立方体贴图]提交当中

   private Bitmap mBitmap;public int loadTexture(Context context, int resId) {int[] textureObjIds = new int[1];GLES30.glGenTextures(1, textureObjIds, 0);if (textureObjIds[0] == 0) {return 0;}BitmapFactory.Options options = new BitmapFactory.Options();options.inScaled = false;if (mBitmap == null) {mBitmap = BitmapFactory.decodeResource(context.getResources(), resId, options);if (mBitmap == null) {GLES30.glDeleteTextures(1, textureObjIds, 0);return 0;}}GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureObjIds[0]);//bindGLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, mBitmap, 0);GLES30.glGenerateMipmap(GLES30.GL_TEXTURE_2D);GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);//unbindreturn textureObjIds[0];}

在SurfaceView的onDraw()方法中进行绘制:

...int texCoord = GLES30.glGetAttribLocation(mProgram, "texCoord");GLES30.glEnableVertexAttribArray(texCoord);GLES30.glVertexAttribPointer(texCoord, 2, GLES30.GL_FLOAT, false, 0, textBuffer);int textureId = loadTexture(mContext, R.drawable.aa);GLES30.glActiveTexture(GLES30.GL_TEXTURE0);GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);int uTextureUnitLocation = GLES30.glGetUniformLocation(mProgram, "s_texture");GLES30.glUniform1i(uTextureUnitLocation, 0);
...

绘制出来图像如下所示:

附上次绘制立方体的纹理贴图效果:

代码地址:https://github.com/JerryChan123/LearnOEL/tree/gl30 提交信息为[add the texture for cube]

转载于:https://my.oschina.net/u/3863980/blog/1854342

opengl es3.0学习篇八:纹理相关推荐

  1. opengl es3.0学习篇七:使用opengl绘制一个立方体

    2019独角兽企业重金招聘Python工程师标准>>> 这里简单运用之前所学的知识来实现一个对应的立方体: public class MainActivity extends App ...

  2. OpenGL ES3 0实现简单粒子火焰效果

    通过粒子系统来实现火焰效果,基本思想是把一团火焰看成是由一颗颗有其生命期的粒子组成,粒子在不停的产生直至消亡从而产生升腾的火焰效果.通过生成每个粒子的坐标,每颗火焰粒子是一个矩形,而这个矩形由两个三角 ...

  3. Android使用NDK OpenGL ES3.0绘制一个三角形

    Android使用NDK  OpenGL ES3.0绘制一个三角形 [尊重原创,转载请注明出处]https://blog.csdn.net/guyuealian/article/details/820 ...

  4. Java学习篇八——break语句

    写在前面:本人是借助两本参考书自学的,其中部分例子和语句均是来自参考书.第一本:<Java 编程指南>,[美] Budi Kurniawan 著,闫斌 贺莲 译.第二本:<第一行代码 ...

  5. WF4.0 基础篇 (三十 完) 对学习WF的一点建议

    从09年10月份 NET4.0 Bata 2发布后,我就开始写[WF4.0 基础篇]这个系列,经历了5个多月终于在NET4.0正式发布前将这个系列完成了 这段时间与一些对WF4.0感兴趣的公司与开发人 ...

  6. OpenGL编程入门学习

    OpenGL编程入门学习  非常详细的教程,很适合初学者 本文转自:http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html === ...

  7. 初识 OpenGL ES2.0

    原文链接:Android OpenGLES2.0(一)--了解OpenGLES2.0 OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API ...

  8. OpenGL之入门学习

    第一个OpenGL程序 一个简单的OpenGL程序如下:(注意,如果需要编译并运行,需要正确安装GLUT,安装方法如上所述) #include <GL/glut.h> void myDis ...

  9. workflow4.0学习资料

    http://www.cnblogs.com/foundation/archive/2010/04/03/1703809.html 2篇说明: WF4 Bata 2 WF4.0 RC 对比 Beta2 ...

最新文章

  1. java B2B2C springmvc mybatis多租户电子商城系统-Spring Cloud Feign
  2. LocalResizeIMG前端HTML5本地压缩图片上传,兼容移动设备IOS,android
  3. apache 配置rewrite模块,URL中隐藏index.php
  4. tom大叔blog--------深入理解javascript系列-----------笔记
  5. 4.17杭州KubeMeet 开发者沙龙·云原生应用管理专场来啦!
  6. Win 11 真的要来了!微软宣布 Win10 将于 2025 年终止支持!
  7. FPGA初学者入门相关概念知识点
  8. 让 C#智能注释时允许换行
  9. 剑桥大学终身教授T.S.:7大机器学习算法与应用案例
  10. Linux信号实践(4) --可靠信号
  11. jsp中的四种对象作用域
  12. rocketMq概念介绍
  13. 网络中各层协议(7层)
  14. 基于ASP.NET AJAX的WebPart开发与部署
  15. android 经纬度距离计算器,经纬度距离角度计算软件|经纬度距离角度计算器(geography) v2.0免费版_星星软件园...
  16. 最新最全论文合集——基于机器学习/深度学习的睡眠信号分类
  17. 实用的bi报表工具--Smartbi报表软件
  18. 苹果cms怎么添加2019和2020年份筛选
  19. 简单好听的id_简单好听的贴吧id名字大全
  20. cJSON 使用详解

热门文章

  1. JAVA语法基础作业
  2. hdu 1316 斐波那契数
  3. 2011年计算机二级c++笔记:类的转换
  4. 如何在 Windows 2000 中安装 Microsoft 环回适配器
  5. 【bzoj4321】queue2 dp
  6. Mybatis笔记 – Po映射类型
  7. MetInfo 5.1 自动化getshell工具
  8. R语言:ggplot2精细化绘图——以实用商业化图表绘图为例
  9. 介绍Angular的注入服务
  10. 解析大型.NET ERP系统 20条数据库设计规范