opengl es3.0学习篇八:纹理

2023-11-10

OpenGL ESMIP

开发十年,就只剩下这套架构体系了! >>>   

学习内容来源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_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]);//bind
        GLES30.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);//unbind
        return 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]

© 著作权归作者所有

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

opengl es3.0学习篇八:纹理 的相关文章

  • 重新创建窗口而不破坏上下文

    这个问题是关于使用 OpenGL 的图形应用程序 当时我正在使用 GLFW 框架 但我考虑更改它 我的目标是让用户 尽可能 在全屏模式和窗口模式之间不断切换 此过程应该花费不到一秒的时间 并且可以在运行时发生 例如 看看游戏 我的世界 用户
  • wglCreateContextAttribsARB 函数崩溃

    我尝试写下代码 我有InitializeOGL 的代码 bool Ogl InitializeOGL bool vSync cout lt lt Init OpenGL lt
  • OpenGL 使用着色器将 NV12 转换为 RGB24

    我尝试编写一个应用程序来在 OpenGL 中显示 YUV 图像 我使用此代码片段在 C 中成功将 Y UV 转换为 RGB source https blog csdn net subfate article details 4730514
  • 渲染具有透明度的纹理时,OpenGL 不需要的像素

    我已经为这个问题苦苦挣扎了一段时间了 当我使用 OpenGL 渲染 2D 纹理 在无透明度和部分透明度之间的过渡上具有透明度值 时 我得到了一些烦人的灰色像素 我认为这是像素值插值的产物 关于如何改进这一点有什么想法吗 I m attach
  • Windows下使用GLEW使用OpenGL扩展

    我一直在 Windows 上使用 OpenGL 扩展痛苦的方式 https stackoverflow com questions 14413 using opengl extensions on windows GLEW 是更简单的方法吗
  • 为什么我的 CAOpenGLLayer 更新速度比之前的 NSOpenGLView 慢?

    我有一个在 Mac OS X 上渲染 OpenGL 内容的应用程序 最初它渲染到 NSOpenGLView 然后我将其更改为渲染到 CAOpenGLLayer 子类 当我这样做时 我看到了巨大的性能损失 帧速率减半 鼠标响应能力降低 卡顿
  • GLSL聚光投影体积

    在我的开源项目中 我使用 Qt3D 设置了延迟渲染管道 到目前为止一切顺利 但现在我想通过添加聚光灯投影量来继续前进 例如场景中好像有烟雾 像这样 我正在使用的片段着色器位于问题的末尾 我读过 对于每个片段 我应该从光位置进行光线行进并找到
  • 在 OpenGL 中实例化数百万个对象:提高每秒帧数

    我的最终目标是以 60 fps 渲染 100 万个不同尺寸和颜色的球体 我也希望能够在屏幕上移动相机 我已经修改了代码我正在学习的教程的这一页 http learnopengl com Advanced OpenGL Instancing尝
  • 如何在多采样纹理上渲染帧缓冲区对象?

    我目前有一个使用多个通道的渲染引擎 其中图像的各个部分在纹理上渲染 然后使用着色器进行组合 它有效 现在我想激活多重采样 我在这里读到 http www opengl org wiki Framebuffer Object Examples
  • 渲染到一个颜色通道而不影响其他通道

    使用 OpenGL 任何版本 如何通过一次仅影响一个颜色通道来渲染到帧缓冲区对象 例如 我的帧缓冲区对象具有 GL BGRA 布局 现在我想执行一些渲染命令 这些命令应该只改变红色通道 因此 如果片段用颜色 204 0 0 0 渲染并且像素
  • WGL:没有双缓冲 + 多重采样 = 失败?

    我通常使用创建像素格式wglChoosePixelFormatARB 与这些论点 除其他外 WGL DOUBLE BUFFER ARB GL TRUE WGL SAMPLE BUFFERS ARB GL TRUE WGL SAMPLES A
  • 为贝塞尔曲线中的每个点绘制切线

    我设法绘制了一条贝塞尔曲线 如下所示 glColor3f 0 1 0 glBegin GL LINE STRIP for int i 3 i lt nPt i 3 glColor3f 0 0 0 for float k 0 k lt NLI
  • Retina 显示屏中具有 QOpenGLWIdget 的 Qt MainWindow 显示错误大小

    我有一个 Qt 应用程序MainWindow 我嵌入一个QOpenGLWidget在里面 一切正常 直到我开始使用 Apple Retina 显示屏并在高 DPI 模式下运行我的应用程序 我的QOpenGLWidget只是它应该具有的大小的
  • 进行亚像素平移时,2D 纹理会扭曲

    我想知道一个理论推理为什么这是可能的 几何体的平移与纹理映射有何关系 我只能在进行子像素平移时注意到这种效果 如果通过整个像素平移 纹理看起来很好 我正在使用正交投影 GL CLAMP TO EDGE GL NEAREST 片段着色器是hi
  • 如何创建自己的 openGL 上下文并将其绑定到 GLCanvas?

    所以当我开始掌握java时 paint Graphics g 我继续创建自己的渲染方法 但我必须了解缓冲区策略以及如何 获取 图形 所以现在我在学习openGL 我必须掌握方法 Override public void display GL
  • 开启TK onRenderFrame和onUpdateFrame的区别?

    我目前正在使用 OpenTK 框架和 OpenGL 用 C 编写 Jump n Run 游戏 Open TK 提供预设功能 例如GameWindow Run or GameWindow onUpdateFrame onRenderFrame
  • glTranslatef 不在 glBegin .. glEnd 中工作

    我正在尝试并排绘制不同颜色的两个方块 我的问题是我无法让 glTranslatef 将第二个方块向右移动 第二个方块只是绘制在第一个方块上 void display void glClear GL COLOR BUFFER BIT glMa
  • OpenGL 新手: glutMouseFunc

    我试图在单击鼠标后更改球体位置 但在使用 glutMouseFunc 中的 x 和 y 时它不起作用 以下是代码 include stdafx h include
  • OpenGL/GLSL - 纹理过滤的实现

    我想在 GLSL 着色器中自己实现纹理过滤 min 和 magfilter 因为我想使用 image load and store 而不是采样器 而且我想以特殊方式处理未定义的像素 并且我正在寻找一篇文章或者这样讨论过滤过程 我记得如何从我
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半

随机推荐

  • 1、python调用java的jar包

    在python中调用jar包 最近的项目功能需要调用客户的java接口 在调用接口的时候需要使用配套的jar包生成一些参数 但是公司的项目是用django搭建的 经过无数血与泪的尝试 最终终于找到了合适的方法去调用 jpype包是一个Pyt
  • 解决dubbo问题:forbid consumer

    原文地址 http www jameswxx com e4 b8 ad e9 97 b4 e4 bb b6 e8 a7 a3 e5 86 b3dubbo e9 97 ae e9 a2 98 ef bc 9aforbid consumer 线
  • Win10环境python3.7安装dlib模块

    自己按照别人的博客安装了一下dlib 测试成功 在这里自己也稍微总结一下 博客原文 https blog csdn net zhang475546259 article details 84104368 1 安装VS201x 全称visua
  • 简单支付验证-SPV

    SPV的来源 在比特币整个生态圈里 大部分都是普通用户 即只有基本的比特币投资及消费支付需要的用户 他们可能没有矿机 没有高端配置的电脑 那么他们是否也要运行一个全节点程序呢 要知道 现在官方显示的结果 比特币所有区块数据目前在120G左右
  • webstorm等JetBrains全家桶搜索任何插件都无反应

    使用webstorm搜索任何插件都无反应 打开webstorm设置 搜索settings或者是System Settings 找到HTTP Proxy 设置AUTO detect proxy settings后 点击右下角的Apply应用后
  • vue 中provide的用法_Vue中使用provide和inject

    相信大家在工作中一定遇到过多层嵌套组件 而vue 的组件数据通信方式又有很多种 比如vuex dollar parent与 dollar children prop dollar emit与 dollar on dollar attrs与
  • 为什么需要对数值类型的特征做归一化?

    为什么需要对数值类型的特征做归一化 1 举例子 比如分析一个人的身高和体重对健康的影响 身高的单位是m 范围是1 6 1 8 体重的单位是kg 在50kg 100kg之间 分析出的结果自然会倾向于数值差异较大的体重特征 因此我们需要数值归一
  • 新版Spring Boot(10)- Spring Boot 整合数据持久层(1)

    1 整合JdbcTemplate Service Description TODO Author tzb Date 2021 8 22 10 23 Version 1 0 Service public class UserService A
  • 【Mysql】删除表记录,并限制条数

    删除表数据 好删 那如果要限制条数 如何删除呢 例如 有个表tag list 我要删除aid为6666的前100条数据 sql如下 删除表记录limit限制条数 delete from tag list where aid 6666 lim
  • JUC 六. 线程中断 与 LockSupport

    目录 一 基础理解 如何退出一个线程 volatile 与 AtomicBoolean 中断线程示例 Thread中自带的中断api示例 阻塞状态线程中断时异常解决 二 Thread中自带的中断底层分析 三 总结 一 基础理解 先了解几个问
  • 打印九九口诀表(pta练习题)

    下面是一个完整的下三角九九口诀表 本题要求对任意给定的一位正整数N 输出从1 1到N N的部分口诀表 输入格式 输入在一行中给出一个正整数N 1 N 9 输出格式 输出下三角N N部分口诀表 其中等号右边数字占4位 左对齐 include
  • AIDL原理和相关文件解析

    Binder概述 相信从事Android相关的研发人员 都对Binder有个或多或少的了解 相关技术博客也有一大推 我今天对Binder的学习过程进行一个记录 理论性的叙述会少一点 更多的是基于AS自动生成的AIDL文件进行代码分析 但读者
  • 【Java基础】使用Java 8的Stream API来简化Map集合的操作

    在 Java 8 中引入的 Stream API 是一种非常强大的函数式编程工具 可以帮助开发者更加方便地对集合进行操作和处理 而在 Map 集合中 Stream API 的使用也能够极大地简化代码 并提升程序效率和可读性 在本文中 我们将
  • 网络基础通过子网掩码 计算主机数网络范围

    192 168 11 16 27 主机的个数为32 27 5 2 5 32 32 2 30主机数为30 主机范围是0 31 63 95 必须是32的倍数 16在0 32之间 31是广播地址 网络号是192 168 11 0
  • 白话学习防火墙3 之防火墙工作模式(适用于IPS、IDS、WAF等其他安全设备)

    说白了 透明模式就是当交换机使 路由模式就是当路由使 混杂就是杂交物种 即当作路由使 又当作交换机使 透明模式 透明模式一般用于网络建设完 网络功能基本已经实现的情况下 用户需要加装防火墙以实现安全区域隔离的要求 早期也称之为桥模式 桥这个
  • jvm的内存模型之eden区

    浅谈java内存模型 不同的平台 内存模型是不一样的 但是jvm的内存模型规范是统一的 其实java的多线程并发问题最终都会反映在java的内存模型上 所谓线程安全无 非是要控制多个线程对某个资源的有序访问或修改 总结java的内存模型 要
  • 如何完成卷积神经网络有关的毕业设计

    前言 毕业设计对于每个学生而言都是一种十分痛苦的渡劫仪式 尤其是当你拿到的是完全陌生的毕业设计的时候 内心无疑有各种王尼玛从心中飘过 我在这里聊聊我在完成毕设的过程中得到的一些经验教训 因为我的毕业设计主题是卷积神经网络 所以在这里我的话题
  • 【云计算与数据中心规划】【期末复习题】【2022秋】

    文章目录 一 单选题 共7题 二 多选题 共15题 三 填空题 共7题 四 判断题 共5题 五 简答题 共7题 Reference 题量 41 满分 100 0 一 单选题 共7题 1 以下哪个虚拟机系统可以独立安装在计算机硬件之上 不需要
  • 什么是整洁的代码

    点击蓝色 五分钟学算法 关注我哟 加个 星标 天天中午 12 15 一起学算法 作者 xybaby 来源 https www cnblogs com xybaby p 11335829 html 写出整洁的代码 是每个程序员的追求 clea
  • opengl es3.0学习篇八:纹理

    OpenGL ESMIP 开发十年 就只剩下这套架构体系了 gt gt gt 学习内容来源and参考 opengl es 3 0编程指南 https www jianshu com p 4d8d35288a0f 3D图形渲染最基本的操作之一