在计算机图形学中GPGPU需要用到的OpenGL概念

在计算机图形学中,纹理映射是实现复杂表面效果的高效方法,即以较小的计算量就可以实现较为逼真的模芯效果。在gpgpu中,纹理映射也是一个至关重要的概念。由图形api实现经典gpgpu的原理可以总结为:用纹理映射实现的科学计算(computation by texturing)。
1、纹理映射的概念
在渲染对象过程中,最简单的方式是给各个对象表面显式地涂上各种颜色。但这样颜色会非常单一。同时,让设计者手动地给每个像素定义不同颜色显然也不可能。于是,纹理映射就成为一个生成较高质量三维表面地高效地这种方案。
纹理映射的原理:首先,由应用程序生成顶点组成的三维模型。然后这些顶点被网格化或三角化,变成若干相连的平面。这是,可以选择使用一些预定好的二维位图,在定义好模型后,将这些位图贴在对象表面。这个过程称为纹理映射。映射,也就指的是通过空间中的顶点坐标与纹理坐标之间的函数关系,用纹理图为顶点赋值。
2、几何图元
几何图元是组成人们熟知地三维模型地基本元素,如点、直线、三角形等,通常由一个顶点列表组成。为了标志顶点列表地起始和终止位置,需要使用函数glbegin()和glend()。glbegin()地形参是一个几何图元对象地名称。
glbegin(gl_polygon); //gl_polygon 是多边形图元地标识。这里表示一个边长为2的二维正方形 glvertex2f(-1.-, -1.0); glvertex2f(-1.0, 1.0); glvertex2f(1.0, 1.0); glvertext2f(1.0, -1.0); glend();
常用opengl几何图元类型
几何图元类型 注释
gl_points   单个顶点集  
gl_lines    多组双顶点线段  
gl_polygon   单个简单填充凸多边形  
gl_triangles   多组独立填充三角形  
gl_quads   多组独立填充四边形  
gl_line_strip   不闭合折线  
gl_line_loop   闭合折线  
gl_triangle_strip   线性连续填充三角形串  
gl_triangle_fan   扇形连续填充三角形串  
gl_quad_strip   连续填充四边形串  
同时如果我们给同一个图元不同顶点指定了不同颜色,opengl默认对策是对图元进行平滑着色,即根据顶点颜色对其他部分线性插值。纹理坐标也是每个顶点的属性,可以使用函数gltexcoor()指定。
几何图元可以分为填充图元和非填充图元两类。直线是非填充图元,其不具备“内部”。二维多边形是一种填充图元,其“内部”可以定义。opengl中,填充图元有三种方式,即顶点方式、边线方式和填充方式。顶点方式是用顶点组成的点集来绘制;边线方式是仅绘制多边形的边线,其“内部”没有定义。填充方式是对多边形进行填充,此时边线在填充时也是内部的一部分。
3、位图与流水线
位图是另一种基本图元,也称为离散图元。它是一个由向量组成的矩阵。向量的元素数就是位图的通道数,比如彩色位图通常是rgb,或者加入透明通道为rgba。
与几何图元一样,位图也是图形应用程序可以生成的数据形式。同样会进入图像流水线。但是,位图已经是可以存储在帧缓存里的二维离散图元,它不用流经顶点处理单元,而是从另一条并行的流水线流入,在片段处理阶段和流过顶点处理单元的数据汇合。
opengl对像素的读写,具体有三种操作:
把像素块从帧缓存读到住存储器中,对应opengl函数是glreadpixels()
把像素块从主存储器写入光栅化器中,对应opengl函数是gldrawpixels()
把像素块从帧缓存复制到光栅化器中,对应opengl函数是glcopypixels()
基本流程如图:
注意,像素块在opengl中的存储方式可能和在主存储器中的不同,如像素中各分量的排列顺序。如果想要将像素块从帧缓存的一部分转移到另一部分,就需要先读出像素,然后在另一处写入。可以使用glreadpixels和gldrawpixels,但频繁在主机与设备间传输数据过于低效,推荐使用glcopypixels。
4、纹理图
可以将纹理图看成一张颜色查找表,根据每个顶点的纹理坐标可以从纹理图上查到该顶点的颜色。通常纹理图和帧缓存中的位图一样,都是由离散的像素构成。为了区分,我们将纹理图上的一个像素称为纹理元。事实上,由于纹理坐标都是经过插值和采样计算得到的,所以在纹理图中查找颜色并不是连三的。而是根据相邻纹理元的颜色插值或最近邻得到的。因此可以将纹理图看成连续的数组,它的二维坐标都是在实数域内得到定义的。
opengl中默认的纹理图都是边长为1的正方形。这样避免了使用明确坐标,用户就可以在不必知道纹理图尺寸的情况下使用纹理。但对gpgpu编程却产生了不便。如,需要知道一个长度为512的数组的第100个元素,用c语言查找只需要使用下标99即可,但opengl需要使用100.0/512.0=0.1953125.
opengl中设置纹理图的函数为glteximage2d(),一个指定4个分量、每个分量为1个字节的二维纹理图:
#define nimagewidth 64 #define nimageheight 64 static glubyte ubimage[nimageheight][nimagewidth][4]; //填充数组 glenable(gl_texture_2d); glteximage2d(gl_texture_2d,0,gl_rgba,nimagewidth,nimageheigght,0,gl_rgba,gl_unsigned_byte, ubimage);
当不需要对整幅纹理图进行操作时,可以使用函数gltexsubimage2d()来定义一幅子纹理图。
当使用glteximage2d时,opengl就会在显卡上分配一块纹理缓存,把纹理图从内存转移到纹理缓存中。如果已经调用过glteximage2d,更新纹理图最好使用gltexsubimage2d,这样就不用在显卡上重新分配存储空间,如果改动较小也不用将整个纹理图传输到显卡上,以提高效率。这也是gpgpu的典型做法。
5、纹理坐标
将纹理图映射到三维表面是通过为每个顶点定义纹理坐标实现的。与顶点坐标一样,是一个四维向量[s,t,r,q].除第一个分量外(使用时,用户至少需要使用一维纹理坐标,因而s一定由用户设定),其他分量的默认值为:t=0,r=0,q=1。设置纹理坐标函数为gltexcoord()。
6、纹理参数
在纹理映射前,还需要对一些参数进行设置。
1. 越界取值:当指定的纹理坐标值大于实际的取值范围时,即超出纹理图的边界时,gl_texture_wrap系列参数用来指定这种情况下,opengl采取的措施。总的来说,opengl一般有两种策略。一种是用钳位算法(clamp)将坐标值限制在某个区间内,即大于该范围的取值就钳定在区间上限,小于时就钳定在区间下限。另一种时在边界以外重复边界内的取值。
2. 放大/缩小纹理图
7、映射参数
此外,还需要确定映射过程中纹理图与表面的相互作用,即处理与表面已有颜色的相互关系。通过gltexenv进行。
8、纹理对象
如果用户同时使用多块纹理,则频繁使用glteximage来加载过于低效。opengl提供了纹理对象来管理纹理,这样多块纹理可以在纹理缓存中并存。纹理缓存不足时,opengl会按照优先级管理纹理,使加载纹理次数尽可能少。
首先,需要调用glgentextures()来建立一个纹理对象。其会返回n个有效的整数纹理标识符。这些整数被保存在texturenames数组中。这些返回的纹理表示符都是目前opengl未被占用的,不一定是连续的整数。0是opengl预留的纹理标识符,不会被分配。分配到的纹理对象的标识符,只表示该标识符有效,而纹理暂时还是无效的。使用前,用户需要将它与某种类型的纹理绑定起来glbindtexture()。同时相关程序结束后,可以使用gldeletetextures()删除。
9、纹理单元
纹理单元与多重纹理映射息息相关。在图形任务中,有时需要将多块纹理映射到同一表面,映射的结果是多重纹理融合的效果。opengl使用纹理单元来管理多重纹理映射中使用的不同纹理图。一个纹理单元就是一个独立的纹理,除了纹理图本身外,它还保存了纹理坐标和纹理参数等一切使用该纹理需要的信息。同一纹理图也可以被多个纹理单元使用。
多重纹理映射时,可以使用opengl常量gl_texturei来选择使用哪个纹理单元,其中i是0到31的整数。

魅蓝E2什么时候发布?全新外观截击红米系列,魅蓝新机E2细节曝光
车载显示屏的自动背光调节
5G常用术语和缩略语
【圣诞特辑】2018年的存储圈是什么样?
如何A2B技术和数字麦克风在新兴汽车应用中实现卓越性能
在计算机图形学中GPGPU需要用到的OpenGL概念
带低音增强的立体声前置放大器电路 (Stereo Pream
北斗三号卫星导航定位系统即将建成 目前仅差2颗GEO卫星
5G和无人机的搭配怎样
AI与供应链碰撞,会产生怎样的火花?
Eyeronman震动马甲:让盲人通过触觉“看”到世界
汽车集中计算平台的软件演进
电池材料之石墨
RTX 4090的实际运行频率和3DMark跑分?
将LCD显示器读数读入单片机的接口电路
了解一下实际Space Station的PFD值
曝索尼PS5将在3月份开启预购 标配版售价499美元
安路科技科创板IPO申请已于4月30日获得受理
一文纵览全球36个AI会议:机器学习十年发展回顾
如何利用3D点编码提升PETRV1/V2及StreamPETR性能