《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》——6.5节光照的每顶点计算与每片元计算...

本节书摘来自异步社区《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》一书中的第6章,第6.5节光照的每顶点计算与每片元计算,作者 吴亚峰,更多章节内容可以访问云栖社区“异步社区”公众号查看

6.5 光照的每顶点计算与每片元计算
OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例
细心的读者会发现,本章前面的案例都是在顶点着色器中进行光照计算的。这是由于在顶点着色器中对每个顶点进行光照计算后得到顶点的最终光照强度,再由管线插值后传入片元着色器以计算片元的颜色,这样一方面效率比较高;另一方面产生的光照效果也不错。

但由于这种计算方式插值的是基于顶点计算后的光照强度,因此在要求很高,希望有非常细腻光照效果的场合下就略显粗糙了。本节将介绍另一种光照计算方式,其首先将插值后的法向量数据传入片元着色器,然后在片元着色器中进行光照计算。这种新的方式也称为每片元光照,可以取得为更细腻的光照效果。

进行案例开发之前需要首先了解一下本节两个案例(Sample6_9和Sample6_10)的运行效果,具体情况如图6-21所示。


72fbbe8bc699882a123fe863e061b58255a2a81a

图6-21中左侧是每片元计算一次光照的案例Sample6_9的运行效果,右侧是每顶点计算一次光照的案例Sample6_10的运行效果。从两幅图的对比中可以看出,每片元执行一次光照使过渡更平滑,没有明显的边缘。另外,仅从图上观察可能区别还不是很明显,笔者建议读者用真机运行一下两个案例,将光源设置在不同的位置观察比较,区别会更明显。
了解了两个案例的运行效果后,就可以进行开发了。实际上这两个案例主要是将前面6.2.5小节中的案例Sample6_5复制并修改了部分代码而成的。其中Sample6_10仅修改了Java代码中切割球面的角度以及绘制球体的次数,没有本质变化,这里不再赘述,需要的读者请参考随书光盘中的源代码。

而案例Sample6_9除了也进行了Sample6_10的Java代码改动外,还大面积修改了顶点着色器与片元着色器,具体情况如下所列。

(1)首先介绍Sample6_9中修改后的顶点着色器,其具体代码如下。

1  uniform mat4 uMVPMatrix;            //总变换矩阵
2  attribute vec3 aPosition;           //顶点位置
3  attribute vec3 aNormal;            //法向量
4  varying vec3 vPosition;            //用于传递给片元着色器的顶点位置
5  varying vec3 vNormal;              //用于传递给片元着色器的法向量
6  void main(){ 
7    gl_Position = uMVPMatrix * vec4(aPosition,1);//根据总变换矩阵计算此次绘制此顶点位置 
8    vPosition = aPosition;             //将顶点的位置传给片元着色器
9    vNormal = aNormal;               //将法向量传给片元着色器
10  }

从上述代码中可以看出,顶点着色器比改动前简单多了,没有了计算光照的大量代码,同时增加了将法向量通过易变变量传入片元着色器的代码。
(2)介绍完顶点着色器后,接着就应该介绍改动后的片元着色器了,其具体代码如下。

1  precision mediump float;              //给出默认浮点精度
2  uniform float uR;                      //球的半径
3  uniform vec3 uLightLocation;       //光源位置
4  uniform mat4 uMMatrix;           //变换矩阵
5  uniform vec3 uCamera;           //摄像机位置
6  varying vec3 vPosition;          //接收从顶点着色器传递过来的顶点位置
7  varying vec3 vNormal;            //接收从顶点着色器传递过来的法向量
8  void pointLight(              //定位光光照计算的方法
9   in vec3 normal,             //法向量
10   inout vec4 ambient,          //环境光最终强度
11   inout vec4 diffuse,           //散射光最终强度
12   inout vec4 specular,          //镜面光最终强度
13   in vec3 lightLocation,         //光源位置
14   in vec4 lightAmbient,          //环境光强度
15   in vec4 lightDiffuse,          //散射光强度
16   in vec4 lightSpecular          //镜面光强度
17  ){
18   ambient=lightAmbient;          //直接得出环境光的最终强度 
19   vec3 normalTarget=vPosition+normal; //计算变换后的法向量
20   vec3 newNormal=(uMMatrix*vec4(normalTarget,1)).xyz-(uMMatrix*vec4(vPosition,1)).xyz;
21   newNormal=normalize(newNormal);    //对法向量规格化
22   //计算从表面点到摄像机的向量
23   vec3 eye= normalize(uCamera-(uMMatrix*vec4(vPosition,1)).xyz); 
24   //计算从表面点到光源位置的向量vp
25   vec3 vp= normalize(lightLocation-(uMMatrix*vec4(vPosition,1)).xyz); 
26   vp=normalize(vp);//格式化vp
27   vec3 halfVector=normalize(vp+eye);  //求视线与光线的半向量  
28   float shininess=50.0;          //粗糙度,越小越光滑
29   float nDotViewPosition=max(0.0,dot(newNormal,vp));//求法向量与vp的点积与0的最大值
30   diffuse=lightDiffuse*nDotViewPosition;        //计算散射光的最终强度
31   float nDotViewHalfVector=dot(newNormal,halfVector);  //法线与半向量的点积 
32   float powerFactor=max(0.0,pow(nDotViewHalfVector,shininess));//镜面反射光强度因子
33   specular=lightSpecular*powerFactor;        //计算镜面光的最终强度
34  }
35  void main() {
36    ……//此处省略了计算片元颜色值的代码,请读者自行查看随书光盘中的源代码  
37    vec4 ambient,diffuse,specular;  //用来接收3个通道最终强度的变量  
38    pointLight(normalize(vNormal),ambient,diffuse,specular,uLightLocation,                          //计算定位光各通道强度 
39    vec4(0.15,0.15,0.15,1.0),vec4(0.8,0.8,0.8,1.0),vec4(0.7,0.7,0.7,1.0));   
40    //综合3个通道光的最终强度及片元的颜色计算出最终片元的颜色并传递给管线
41    gl_FragColor=finalColor*ambient + finalColor*diffuse + finalColor*specular;
42  }

读者应该发现,上述片元着色器中的很多代码都是本章前面案例中多次出现过的,只不过前面的案例中都是在顶点着色器中出现,而这里挪到了片元着色器中。因此,每片元计算光照与每顶点计算光照算法并没有本质区别,只是代码执行的位置不同、效果与效率不同而已。实际开发中读者应该权衡速度、效果的要求,选用合适的计算策略。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/258987.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

毛笔笔锋算法IOS版

http://www.merowing.info/2012/04/drawing-smooth-lines-with-cocos2d-ios-inspired-by-paper/#.VUln2_mqpBe转载于:https://www.cnblogs.com/wangjinming/p/4481145.html

USE PDFCREATE TO CREATE A PDF FILE

来源:http://www.pdfforge.org/files/old_forum/1002.html a working sample with C & COM 2007-08-15 22:56:18 by eckart hi, here is a working sample of how to use PDFCreator in Visual C (after searching on internet for something similar I guess t…

python将一行作为字段_关于python:Django admin在同一行显示多个字段

我已经创建了一个模型,它将自动显示模型中的所有字段,并将其显示在管理页面上。 现在,我有一个问题,我希望在同一行中有两个字段,为此,我必须在modeladmin中指定字段集: 1 2 3 4 5fieldsets ( …

c++显式加载dll并使用DLL的类

转载自: http://blog.163.com/tianjunqiang666126/blog/static/8725911920121064573594/ 首先需要强调,当使用某个类时一般目的有二:实例化成对象或者继承它产生新类。对于前者,我们可以构造一个抽象类&a…

如何在Debian上安装配置ownCloud

如何在Debian上安装配置ownCloud 据其官方网站,ownCloud可以让你通过一个Web界面或者WebDAV访问你的文件。它还提供了一个平台,可以轻松地查看、编辑和同步您所有设备的通讯录、日历和书签。尽管ownCloud与广泛使用Dropbox非常相似,但主要区别…

jQuery相当于对 javascript二次开发,所以基于 jQuery实现的各种插件直接调用即可...

jQuery相当于对 javascript二次开发,所以基于 jQuery实现的各种插件直接调用即可转载于:https://www.cnblogs.com/npk19195global/p/4482363.html

[转]js判断url是否有效

本文转自:http://www.cnblogs.com/fumj/p/3490121.html 方法一:(仅适用于ie) function CheckStatus(url){XMLHTTP new ActiveXObject("Microsoft.XMLHTTP")XMLHTTP.open("HEAD",url,false)XMLHTTP.send()return XMLHTTP.status200}function Ne…

VS中lib和dll

转载: http://www.cnblogs.com/Yogurshine/archive/2013/06/14/3136025.html Lib文件 先来说一说lib文件,C中lib文件主要有两类,一种是静态的编译连接,叫做静态链接库,另一种是动态的编译链…

32位md5解密_冰蝎特征检测及报文解密

点击“蓝字”关注我们,不迷路~‍‍前言19年驻场于某金融单位。参加19年9月、11月两次攻防演练,负责攻防演练组织、技术支持和复盘。期间,多个攻击队伍使用冰蝎 webshell ,防守方监测时确实各 IDS 确实报出 webshell 连接&#xff…

使用extern C改善显式调用dll

extern "C"的简单解析 我们前面介绍了显式调用dll的方法,例如 http://www.cnblogs.com/laogao/archive/2012/12/07/2806528.html ,其中在GetProcAddress第二个参数的填写煞费苦心,我们需要比较麻烦…

《移动App测试的22条军规》—App测试综合案例分析23.13节测试微信App的流量和电量消耗...

本节书摘来自异步社区《移动App测试的22条军规》一书中的App测试综合案例分析,第23.13节测试微信App的流量和电量消耗,作者黄勇,更多章节内容可以访问云栖社区“异步社区”公众号查看。 23.13 测试微信App的流量和电量消耗关于微信App消耗流…

UVA 10269 Super Mario,最短路+动态规划

这个题目我昨晚看到的,没什么思路,因为马里奥有boot加速器,只要中间没有城堡,即可不耗时间和脚力,瞬间移动不超过L距离,遇见城堡就要停下来,当然不能该使用超过K次。。。我纠结了很久&#xff0…

python做数据可视化的代码_Python数据可视化正态分布简单分析及实现代码

Python说来简单也简单,但是也不简单,尤其是再跟高数结合起来的时候。。。 正态分布(Normaldistribution),也称“常态分布”,又名高斯分布(Gaussiandistribution),最早由A…

ACdream 1061(abs用法)

题目链接:http://acdream.info/problem?pid1061 主要是abs用法,看题目的数据 long long的最大值:9223372036854775807 long long的最小值:-9223372036854775808 unsigned long long的最大值:18446744073709551615 由题…

wpf window 不执行show 就不能load执行_Numpy反序列化命令执行漏洞分析(CVE-2019-6446)附0day...

1、介绍 NumPy 是 Python 机器学习库中之一,主要对于多为数组执行计算。NumPy 提供大量的 函数和操作,能够帮助程序员便利进行数值计算。在 NumPy 1.16.0 版本之前存在反序列化 命令执行漏洞,用户加载恶意的数据源造成命令执行。2、环境 软件…

使用Def文件导出dll

前面我们介绍了dll的生成,大多数是使用extern "C"__declspec(dllexport)函数名的方法导出dll。其实我们还有另一种方法来导出dll。 先介绍参考文献: 1.dll导出声明相关 2.VS2012中 C创建DLL图解 3.DLL中导出函数的两种方式(dllexport与.…

HDU 1003 Maxsum

题目大意&#xff1a;求出数列的最大子段和&#xff0c;并且说明是从第几项至第几项。 题解1&#xff1a;简单贪心。 #include <cstdio> #define rep(i,n) for(int i1;i<n;i) int main(){int t,l0;scanf("%d",&t);while(t--&&l){if(l!1)printf…

《JavaScript面向对象精要》——1.8 原始封装类型

本节书摘来自异步社区《JavaScript面向对象精要》一书中的第1章&#xff0c;第1.8节&#xff0c;作者&#xff1a;【美】Nicholas C. Zakas著&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看 1.8 原始封装类型 JavaScript中一个最让人困惑的部分可能就是原始…

XML语法学习

本文章集合两篇博文而写&#xff0c;两篇博文地址&#xff1a; XML学习总结(二)——XML入门&#xff1a; XML基础<第一篇> XML简介 XML是一种标记语言&#xff0c;用于描述数据&#xff0c;它提供一种标准化的方式来来表示文本数据。XML文档以.xml为后缀。需要彻底注…

FM实现F4帮助系列三:弹出框多筛选…

FM实现F4帮助系列三&#xff1a;弹出框多筛选条件的搜索帮助&#xff08;根据搜索帮助筛选字段&#xff09;函数&#xff1a;F4IF_GET_SHLP_DESCRF4IF_START_VALUE_REQUEST效果图&#xff1a;本例子代码&#xff1a;找到需要的帮助:*&------------------------------------…