在计算机图形学中,纹理映射是实现复杂表面效果的高效方法,即以较小的计算量就可以实现较为逼真的模芯效果。在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对像素的读写,具体有三种操作:

1.把像素块从帧缓存读到住存储器中,对应OpenGL函数是glReadPixels()

2.把像素块从主存储器写入光栅化器中,对应OpenGL函数是glDrawPixels()

3.把像素块从帧缓存复制到光栅化器中,对应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的整数。

GPGPU基础(二):GPGPU需要用到的OpenGL概念相关推荐

  1. 蓝鸥Unity开发基础二——课时20 接口

    蓝鸥Unity开发基础二--课时20 接口 一.接口 使用interface关键字定义接口 接口定义一组成员单不直接实现它们 二.实现接口 实现接口的任何类都必须实现其所有的成员方法 接口不能直接实例 ...

  2. shell基础二十篇 一些笔记

    shell基础二十篇 转自 http://bbs.chinaunix.net/thread-452942-1-1.html 研讨:Bash 内建命令 read (read命令更具体的说明见博客收藏的一 ...

  3. Bootstrap基础二十七 多媒体对象(Media Object)

    Bootstrap<基础二十七> 多媒体对象(Media Object) 原文:Bootstrap<基础二十七> 多媒体对象(Media Object) Bootstrap 中 ...

  4. Web开发(一)·期末不挂之第三章·HTML基础二(html实现表格和表单)

    HTML基础二 一. 表格✪✪✪ 二.表单 插入表单 输入标签✪✪ 多行文本域 下拉菜单 三.其他 label标签 内联框架 一. 表格✪✪✪ 插入表格: < table>< /ta ...

  5. shell基础二:查找技巧,find及xargs的使用

    2019独角兽企业重金招聘Python工程师标准>>> 使用find时,只要把想要的操作写在一个文件里,就可以用exec来配合find查找,很方便的 (在有些操作系统中只允许- e ...

  6. 自考计算机软件基础交作业,全国2009年7月自考计算机软件基础(二)试题及答案...

    全国2009年7月自考计算机软件基础(二)试题及答案 课程代码:02365 一.单项选择题(本大题共20小题,每小题1分,共20分) 1.下列选项中属于事务处理软件的是( A ) A.工资管理软件 B ...

  7. python路由编程_Python Django基础二之URL路由系统

    MVC和MTV框架 MVC Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的.松耦合的方式连接在一起,模型负责业务 ...

  8. [GO语言基础] 二.编译运行、语法规范、注释转义及API标准库知识普及

    作为网络安全初学者,会遇到采用Go语言开发的恶意样本.因此从今天开始从零讲解Golang编程语言,一方面是督促自己不断前行且学习新知识:另一方面是分享与读者,希望大家一起进步.前文介绍了什么是GO语言 ...

  9. MariaDB基础(二)

    MariaDB基础(二) 介绍关于MariaDB的如下知识点: 1. 查询缓存 2. 索引 3. EXPLAIN 1.查询缓存: 1)什么是缓存? 缓存就是数据交换的缓冲区,即Cache,存放在内存中 ...

最新文章

  1. java mybatis向mysql数据库插入中文出现乱码
  2. jenkins插件findbugs+pmd+checkstyle结合sonar与maven(java环境代码质量和代码规范管理)...
  3. axis使用wsdl生成客户端
  4. 记录解决nginx的access.log持续变大问题
  5. The Trip On Abandoned Railway(线段树+树状数组)
  6. eap aka_使用API​​密钥(aka身份验证令牌)部署到Maven Central
  7. Qtopia-2.2.0启动脚本
  8. chitubox micromake L3+ 切片软件配置对应关系
  9. 第5关:类与对象练习------Java面向对象 - 类与对象
  10. 从命令行读入一个字符串,表示一个年份,输出该年的世界杯冠军是哪支球队。如果该 年没有举办世界杯,则输出:没有举办世界杯。...
  11. 国外android大神博客,Android手机浏览器(国外篇)横向对比评测
  12. duilib库combo box提供输入字符模糊查询
  13. 跳转到新页面并清除当前页面的history记录
  14. html5怎么设置路由器,无线路由器
  15. 华为服务器批量修改bmc地址,华为服务器批量修改bmc地址
  16. 《编译原理》(三)词法分析
  17. mysql 与sqlserver对比?哪个更好用?
  18. form的onsubmit验证
  19. 年轻人才是短视频直播的营销未来
  20. 高清正射影像如何装入手机使用?

热门文章

  1. python人力成本数据测算_人力成本分析计算公式大全
  2. Forge 发布倒计时三天:陈天写下他加入 ArcBlock 一周年的感慨 | ArcBlock 博客
  3. Json-server简单实现mock数据
  4. linux查看是否开启审计功能,linux审计功能auditd
  5. 【ubuntu16.04 LTS】ping百度通,但浏览器打不开百度网页
  6. python 使用豆瓣镜像下载安装工具包
  7. Tita绩效宝:通过组织透明度提高绩效
  8. 高情商的王维注解了低政商孟浩然的后半生
  9. linux之ps命令--进程快照
  10. 2019暑期集训收获感悟