从零开始学习OpenGL ES之五 – 材质

  • 作者: iPhoneGeek 爱疯极客
  • 09-Jan-10
  • iPhone Development
  • 浏览次数: 411
  • |  评论 ↓
Tweet
Share

在 上一篇文章,我们讨论了光效的设定以及光效的各种属性。我们还讨论了光的三要素:散射光, 环境光高光。如果你还不是完全清楚,那么我们来复习一下,在定义材质时大量的用到这些要素。
作为本文的起点,我们使用了此文中球体绘制 的项目文件。我们不再使用二十面体而是转向球体是因为球体是展示光和材质不同要素之间相互作用的最佳形状。

颜色是什么

这可能是对小学美术课的复习。为什么现实世界会有颜色?是什么造成的?
我们看得见的光被称为 光的可见频谱 。根据不同的波长我们可以感知到不同的颜色。在可见光谱的一端是低波长高频率的紫色和蓝色,而在另一端是低频高波长的橘色和红色:
电磁波在这个范围之外,因此不是“可见光”,尽管这只是人工的区分方法,它们的唯一不同在频率和波长,在于人眼的感知。尽管有各种方法感知各种电磁波的能力,但从OpenGL的角度出发,我们只关心可见光谱。
“白色光”包括等量的所有波长。换言之,白光之所以是白色的是因为它包括了所有(或至少大部分)可见光的频率。如果你曾经做过棱镜试验,那么你可能看过如下效果:
棱镜反射白光,各种波长被分离出来。这就是彩虹产生的原理。
如果你看到一个物体呈蓝色,那么实际上是该物体吸收了大部分可见光谱低频部分。它吸收了红,橘,黄和绿光。根据蓝色的不同色度,它还可能吸收一些紫色和蓝色。
但大部分蓝色的波长都被反射到你的眼睛。因为一些可见光被吸收了,由于它不再包括可见光谱中的所有波长所以反射到你眼中的光不再是白色。
简单吧?让我们看看这些是怎样运用在OpenGL的。

OpenGL 材质

我们通过定义材质的反射光来定义OpenGL ES中的材质,正如现实世界中一样。如果一个材质定义为反射红光,那么在正常的白光下,它将显示红色。
在OpenGL中 (至少在使用光滑着色处理和光效时),材质是没有颜色的。OpenGL具有分别定义材质是怎样反射OpenGL光效三要素(环境,散射和高光)的能力。另外,它还具有指定材质 自发光(emissive) 属性的能力,关于这点我们稍后再讨论。

指定材质

要在OpenGL创建一个材质,我们需要一次或多次调用 glMaterialf() 或者 glMaterialfv()。类似于上一篇文章中光效的定义,由于各属性或元素需要分别通过这些调用了指定,所以我们通常必须多次调用这些函数以完全定义材质。所有未定义的元素或属性默认值为0,或者以颜色来说为黑色。
传递给 glMaterialf() 或者 glMaterialfv() 的第一个参数总是用于指定是否材质影响多边形的前,后或两者的GL_ENUM。实际上除了为了与OpenGL兼容,第一个参数在OpenGL ES中没有什么意义,因为只有一个有效的选项: GL_FRONT_AND_BACK,它简单地表示材质适用于任何绘制的多边形。如果你还记得第一部分,那么你应该知道三角形的正面和背面是由winding(顶点的绘制次序)决定的。默认情况下,只有三角形的正面被绘制出来,但是有可能让OpenGL也绘制背面,或甚至只绘制背面,常规 OpenGL 允许你通过传递GL_FRONT,GL_BACK, 或者 GL_FRONT_AND_BACK来为正面和背面指定不同的材质。但是OpenGL ES仅支持GL_FRONT_AND_BACK。
glMaterialf() 或 glMaterialfv()的第二个参数是指示正在设定材质的哪个元素或属性的 GL_ENUM。它们像传递给glLightfv()的值一样,比如GL_AMBIENT ,另外还有些新的值我们稍后再谈。
最终值是 GL_FLOAT或包括了实际属性或元素的GL_FLOAT数组的指针。
材质的最重要元素是环境光和散射光,因为它们决定了材质是怎样反射大量光线的。我们今天使用的项目代码定义了正如太阳光或白炽灯产生的白色,它具有 平均分布的各种波长和颜色的光。如果光不是白色,球体看上去会有不同的外观。例如,反射至红色材质的蓝光将产生紫色阴影。简单起见,我们只使用白色光。当 然,你可以随意改变光的颜色进行试验看看光和材质是怎样交互作用的。大部分时候,它们在OpenGL ES中的表示与现实生活中完全一样。
下面是项目在添加材质前运行时的样子:
如你所见,它具有一些环境光和更为显著的散射光。

环境光和散射光

当讨论OpenGL的材质时,我们需要同时讨论环境光和散射光,这是因为这两个元素是一起工作从而决定物体被感知的颜色的。记住,散射光处于本文第 一个图片中球体的顶部(亮×××),环境光则是下方的暗×××。材质怎样反射这两个元素决定了物体被感知的颜色。上图的效果可以通过不止一种方法获得。同样 地,×××球以同样比例反射环境光和散射光,但是场景中具有较少的环境光。
大约 90% 或更多的情况下,将材质的环境光和散射光参数设定成一样。这样做,使它们成为决定物体阴影和外观的因素。实际上,有一种方法通过一个调用glMaterialfv()同时设定材质环境光和散射光。下面是定义材质为蓝色的示例:
    GLfloat ambientAndDiffuse[] = {0.0, 0.1, 0.9, 1.0};    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, ambientAndDiffuse);
正如 glColor4f(), 设置材质指示随后所有物体绘制的方式直到另一个材质被指定。如果将上叙代码放置于我们的绘制代码之前,那么运行时你将看到球体变为蓝色。由于环境光没有散射光强,其下方只是稍暗。
有时你希望更多地控制并希望分别设定材质对环境光和散射光的反射方式。例如,下例中,材质从环境光反射蓝色,从散射光反射红色:
    GLfloat ambient[] = {0.0, 0.1, 0.9, 1.0};    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);GLfloat diffuse[] = {0.9, 0.0, 0.1, 1.0};    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
运行结果:
在此情况下,它看上去像我们投射了有色光到球体上,实际上却不是这样。原因是我们反射了与环境光不一样的定向光线。
大部分情况下,如果你希望产生彩色光的效果,你只需创建彩色光线然后使用GL_AMBIENT_AND_DIFFUSE来指定材质颜色。但是有时却希望分别设置它们产生特殊效果或在不引起创建额外光线开销的情况下假造一个分离的彩色点光源。记住:你每增加一个光源,也就增加了每秒钟的运算量,所以有时候欺骗并不完全是一件坏事。

高光和光泽

你还可以单独设置场景中高光元素的反射方式,从而控制高光“热点”的亮度。一个叫 GL_SHININESS的参数与材质的高光元素一起定义了高光热点的大小。如果你设定了材质的 GL_SPECULAR 值,你还应该定义其反光度。反光度越高,高光反射越小,所以默认值 0.0 几乎完全淹没了散射光,因此看上去很糟糕。
让我们回到蓝色球体,增加高光热点:
    GLfloat ambientAndDiffuse[] = {0.0, 0.1, 0.9, 1.0};    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, ambientAndDiffuse);GLfloat specular[] = {0.3, 0.3, 0.3, 1.0};    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 25.0);
我们使用了一个较暗的白色作为球体的高光值。这个值看上去有些小,但就是这么小的值也能产生显著的效果。光线高光元素的值与材质的高光元素相乘所产生的光集中在材质反光度指定的区域。下面是上叙代码产生的结果:
现在,球体上有一个小的区域具有更强的反射光。我们可以通过增强光或光的高光元素,或者通过增加材质的反光度使这个点更亮。我们还可以通过调整反光度改变高光的大小。材质反光度越高,高光越集中。例如,如果我们将反光度从25.0 改为 50.0,我们将得到一个更小的热点,它使得球体显得更具有光泽。
但是,有一点要小心。本文之所以改为使用球体的部分原因以及为什么球体使用较高的顶点数目的原因是高光在一个低面数的物体上看上去实在糟糕。注意一下,如果我减少球体的顶点数会发生什么:
低面片
高光使三角形边缘突出,高光通常在我们的游戏中经常使用的低面片的物体上表现不佳。在常规OpenGL中,有一个称为 着色器(shader) 的机制可以用来为低面片物体产生较为理想的结果,但目前iPhone上的OpenGL ES并不支持此功能(译者注:iPhone 3GS支持OpenGL ES 2.0,有shader功能。但有一个问题就是OpenGL ES 1.1与OpenGL ES 2.0并不完全兼容)在游戏中如果你想使低面片物体漂亮的唯一方法就是完全摒弃高光元素而使用纹理映射,这将在下一篇文章中谈到。

自发光

还剩最后一个材质的重要属性,它称为自发光元素。通过设定自发光元素,使得材质看上去会发射我们指定的颜色。它并不是真正在发光。例如,其周边物体 并不会被发射的光线影响。如果你希望一个物体像灯泡一样发光照亮其他物体,由于在OpenGL ES中只有光源会发光(听上去像废话),你需要将自发光元素和与物体同一位置处的实际光源结合起来。但是自发光元素可以使物体漂亮地发光。
例如,我们可以为蓝色球体添加绿色的光泽:
    GLfloat emission[] = {0.0, 0.4, 0.0, 1.0};    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emission);
结果如下:
自发光元素影响整个材质,因此 GL_EMISSION的值将与落入物体指定区域的任何类型的光相叠加。请注意,甚至上图中的高光部分也成了一点蓝-绿色而不是纯白色。在高光点处其效果是很微小的,但在只有环境光被反射的底部效果更为明显。它实际影响整个物体。
原文见:OpenGL ES From the Ground Up, Part 5: Living in a Material World

转载于:https://blog.51cto.com/mkhgg/656329

从零开始学习OpenGL ES之五 – 材质相关推荐

  1. [转载]从零开始学习OpenGL ES之八 – 交叉存取顶点数据

    Technote 2230提出了很多用OpenGL ES来提升iphone程序性能的建议.我们现在远远不能深刻理解OpenGL ES所以你需要学习以下内容.不信?是真的,试试看,我等着你的读后感. 好 ...

  2. [转载]从零开始学习OpenGL ES之三 – 透视

    现在你已经知道OpenGL是怎样绘图的了,让我们回头谈谈一个很重要的概念:OpenGL视口(viewport). 许多人对3D编程还很陌生,那些使用过像Maya, Blender, 或 Lightwa ...

  3. 从显示一张图片开始学习OpenGL ES

    前言 网上很多介绍OpenGL ES的文章,但由于OpenGL ES内容太多,所以这些文章难免过于臃肿杂乱,很难抓住重点,对于初学者来说最后还是云里雾里.很多人(包括笔者本人)开始深入了解OpenGL ...

  4. 学习OpenGL ES之透明和混合

    获取示例代码 本文主要讲解OpenGL ES对于透明颜色的处理,在例子中我绘制了三个平面,分别赋予绿色半透明纹理,红色半透明纹理,和不透明纹理. 首先为这三张图生成纹理. - (void)genTex ...

  5. 学习OpenGL ES之绘制圆柱体

    获取示例代码 本文将要介绍如何使用代码绘制一个圆柱体,通过绘制圆柱体可以更好的掌握法线,UV,TriangleFan,TriangleStrip等相关知识.在绘制之前,先进行一些准备工作. GLGeo ...

  6. 学习OpenGL ES之教你制作迷雾

    获取示例代码 前言 本文将为大家介绍一种常见的3D技术-雾(fog).雾可以让你看不清远处的物体,除了模拟真实环境中的雾效果以外,还可以用来遮挡修饰远处细节精度比较低的模型,让它们看起来没那么粗糙.本 ...

  7. 【我的OpenGL学习进阶之旅】解决关于在OpenGL ES开发中GLSurfaceView调用了onPause和onResume方法,然后息屏亮屏之后GLSurfaceView黑屏的问题

    目录 一.问题描述 二.分析问题 2.1 排查onPause和onResume方法 2.2 注释掉onPause和onResume方法 2.3 GLSurfaceView 关于Activity生命周期 ...

  8. OpenGL ES EGL TLS(线程局部存储) G3D

    1. 什么是EGL EGL是用来管理绘图表面的(Drawing surfaces),并且提供了如下的机制 (1) 与本地窗口系统进行通信 (2) 查找绘图表面可用的类型和配置信息 (3) 创建绘图表面 ...

  9. 笔谈OpenGL ES(一)

    现在图形类.视频类app越来越多,学习OpenGL ES是很有必要的,作为程序员是有必要做技术积累的.现在做播放器开发的工作,正好也涉及这块,那就好好学一学. CSDN上有套教程不错,OpenGL E ...

最新文章

  1. Qt5开发及实例学习之标准颜色对话框类QColorDialog:选择某种颜色
  2. systemd常见使用总结
  3. Windows7中启动Mysql服务时提示:拒绝访问的一种解决方式
  4. UE4材质:只在石头缝中刷草
  5. Java集合入门总结
  6. EditText 显示明文和密码
  7. 华为鸿蒙系统不卡,华为鸿蒙系统,到底能不能取代安卓?网友:细节决定成败...
  8. JAVA两类比较器的区别(Comparable,Comparator)
  9. 在单元测试和TDD中指定时间的重要性
  10. luogu P3244 [HNOI2015]落忆枫音
  11. 【Kafka】消息超过最大值限制max.request.size
  12. xss攻击和csrf攻击
  13. 空间正交基的定义_正交向量与子空间
  14. 2014中国高校SAS数据分析大赛拉开帷幕
  15. 4.1 模拟低通滤波器设计
  16. [王垠系列]什么是语义学
  17. 简述BSD协议和GPL协议的区别
  18. Arduino学习笔记
  19. Android Contact分析(二):实战篇之读取联系人,模糊查询,通过汉字返回拼音
  20. 中大型公司的开发流程

热门文章

  1. WPF 自定义控件的坑(蠢的:自定义控件内容不显示)
  2. C#_List转换成DataTable
  3. 有备无患的Linux操作系统备份方法
  4. 计算机可执行指令吧,电脑“开始-运行”的常用命令及用法!很有用!
  5. c语言程序的多文件组织,C代码多文件的组织
  6. php 取多级分类,php – 获取所有类别(多级)
  7. 为什么分类对象越多训练时间越长?
  8. 输入对5层网络迭代次数的影响
  9. 计算特征数据matlab代码,科学网—MATLAB特征提取代码 - 蒋样明的博文
  10. 芬兰计算机研究生申请表,芬兰的研究生申请技巧