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学习篇八:纹理 的相关文章

  • glutPostRedisplay 不在循环内工作

    我试图让一个人在 y 轴上跳跃 所以我使用 2 秒的循环 第一秒它应该向下移动并弯曲膝盖 第二秒它应该向上移动 然后在起始位置完成 现在我刚刚开始让这个人在第一秒内跪下并弯曲膝盖 我还没有编写动画的其余部分 问题是 glutPostRedi
  • QOpenGLFunctions 缺少重要的 OpenGL 函数

    QOpenGLFunctions 似乎缺少重要的函数 例如 glInvalidateFramebuffer 和 glMapBuffer 据我了解 QOpenGLFunctions 加载桌面 OpenGL 函数和 ES 函数的交集 如果是这样
  • 使用 Qt 在 xoverlay 之上绘制

    我希望在使用 Xoverlay 渲染的视频流之上绘制一些 UI 我正在使用 gstreamer 播放视频并使用 xoverlay 在 xvimagesink 上渲染它 我的小部件继承自 QGLWidget 我希望使用 QPainter 绘制
  • lwjgl 3 , glUniformMatrix4 导致 jre 崩溃

    我正在使用 lwjgl 3 并学习现代 opengl 3 我想将统一矩阵发送到顶点着色器 以便我可以应用转换 我尝试过 但程序因此错误而崩溃 A fatal error has been detected by the Java Runti
  • lnk1104:无法打开“LIBC.lib”链接

    使用 GLee 将着色器写入我的 OpenGL 项目并编译后 我收到了错误LNK1104 cannot open file LIBC lib 我尝试按照其他人的建议添加它并忽略它 但没有解决问题 有没有其他方法可以解决我错过的这个问题 以下
  • Eclipse 标记 OpenGL 函数无法解析

    我尝试在 Eclipse C C 中使用一些 OpenGL 函数 一些 标准 函数如 GlClear 可以被 eclipse 识别 而其他函数如 glBindBuffer 和 glEnableVertexAttribArray 则不能 它们
  • SDL 鼠标位置调整大小后裁剪

    我在 SDL 中的鼠标位置上遇到了一些奇怪的行为 如果我将窗口大小调整得更大 则任一鼠标事件的 x y 位置似乎都限制为原始窗口的宽度和高度 如果我缺少一些函数调用来告诉 SDL 鼠标区域的大小已增加 应用程序的相关部分 void Resi
  • 使用 C# 截取任何外部应用程序的屏幕截图

    我们有一个 C WPF 应用程序 我们想要在其中截取我们启动的任意应用程序的屏幕截图 即 我们可以引用我们启动的进程 应用程序可能已最小化或位于其他窗口后面 但我们仍然只需要单个应用程序的图像 而不是重叠像素 我知道使用 BitBlt 或的
  • 如果我用opengl绘图的话SDL Renderer就没用了吗?

    我正在学习 SDL2 但我也在使用使用 OpenGL 调用的 imgui 库 从我在网上各种博客上读到的内容来看 我无法轻松混合 SDL2 渲染器和 opengl 调用 我要么使用其中之一 要么使用另一个 我读过的大多数教程都使用渲染器 所
  • 将四元数旋转转换为旋转矩阵?

    基本上 给定一个四元数 qx qy qz qw 我如何将其转换为OpenGL旋转矩阵 我也对哪个矩阵行是 向上 向右 向前 等感兴趣 我有一个四元数的相机旋转 我需要在向量中 以下代码基于四元数 qw qx qy qz 其中顺序基于 Boo
  • 在 Linux 上运行我自己的程序的权限被拒绝? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有Ubuntu 9 4 我已经构建了程序 一些基本的 OpenGL 该程序只是制作一个旋转的正方形 然后运行它并 sh blabla p
  • OpenGL:仅获取模板缓冲区而没有深度缓冲区?

    我想获取一个模板缓冲区 但如果可能的话 不要承受附加深度缓冲区的开销 因为我不会使用它 我发现的大多数资源表明 虽然模板缓冲区是可选的 例如 排除它以利于获得更高的深度缓冲区精度 但我还没有看到任何请求并成功获取仅 8 位模板缓冲区的代码
  • 使用 GLSL 直接在着色器中从位置计算平移矩阵

    我正在开发 C OpengL 程序以及 GLSL 顶点和片段着色器 我正在创建同一对象的多个实例 我只需要改变实例之间的对象位置 这是我所做的 我正在使用一个统一变量 它是一个变换矩阵数组 每个矩阵代表一个对象实例 MVP 也是一个变换矩阵
  • gldrawarrays 不绘制任何东西

    我正在尝试用 VBO 绘制一个三角形 我在窗口上没有看到任何像素 我也没有看到任何 GL ERROR 这是我尝试运行的代码 include
  • 即使手动设置显示环境变量后,WSL Ubuntu 也会显示“错误:无法打开显示”

    我在 WSL Ubuntu 上使用 g 我使用 git 克隆了 GLFW 存储库 使用了ccmake命令配置并生成二进制文件 然后使用make在 build 目录中最终创建 a文件 我安装了所有OpenGL相关的库 usr ld 我不记得我
  • 如何在 Visual Studio 2012 中安装 GLUT 和 OpenGL?

    我今天刚安装了Visual Studio 2012 我想知道如何在该平台上安装GLUT和OpenGL OpenGL 应该已经存在 可能会缺少 Freeglut GLUT GLUT 现在已经非常过时并且没有得到积极的支持 所以你当然应该使用
  • 不明确的 OpenGL 默认相机位置

    在我的Opengl程序中 在我应用透视投影矩阵之前 每当我绘制一些对象时 我都会在世界坐标系的原点处绘制它 但是几乎所有Opengl教程都指出相机 我的投影视图 位于原点朝向正 z 轴 这取决于您稍后如何处理投影矩阵中的 z 值 但是如果这
  • 在windows + opengl中选择图形设备

    我知道如何使用 openGL 打开窗口 使用 Win32 或其他工具包 但是当系统有2块显卡时 如何选择要渲染的图形设备 我的编程语言是 C 我专注于 Windows 但任何示例都将受到欢迎 编辑 也许更好地解释我的问题是个好主意 以便添加
  • 纹理映射 C++ OpenGL

    我已经阅读了相关内容 包括 Nehe 和此处的解决方案 但我找不到具体的答案 我正在尝试加载一张名为stars jpg 的照片 我想通过使用 uv 坐标映射它来使其成为场景的背景 方法是 glBegin GL QUADS glTexCoor
  • 如何在 GLSL 1.3 和 OpenGL 2.1 中使用位运算

    我正在尝试编写一个使用许多位操作的着色器 事实上 从 glsl 1 30 开始就支持它们 但我只使用 OpenGL 2 1 有没有办法在我的 OpenGL 版本中使用位运算 所有 SM3 兼容 OpenGL 2 1 硬件支持limited整

随机推荐

  • 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图形渲染最基本的操作之一