《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.pswp.cn/news/258987.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/258987.shtml
英文地址,請注明出處:http://en.pswp.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;找到需要的幫助:*&------------------------------------…