(转)光照图的理论和实践
轉自:http://www.cnblogs.com/minggoddess/archive/2012/12/03/2800133.html
光照圖的理論和實踐
這是我翻譯的一篇文章,不知道哪年翻譯的,沒譯完。這幾天看見了,又拿出來接著翻譯。可是還有那么多,不知道那天能弄出來。所以我就先把翻譯的貼出來吧
原文鏈接http://www.flipcode.com/archives/Light_Mapping_Theory_and_Implementation.shtml
Light Mapping - Theory and Implementation
by?Keshav Channa?(21 July 2003)
?
說明
自從quake時代開始,程序員們廣泛的使用光照貼圖作為最接近現實光照的方法。(現在真正的實時逐像素光照正在緩慢替代光照圖)。
本文闡述了一個簡單但是快速的光照貼圖生成器。它是2001年在Dhruva Interactive(譯者注:印度游戲公司)的內部項目中使用。此算法不像輻射度算法那樣精確,但是仍然產生了有效的實用的結果。
此文對于那些還沒有在自己的引擎中使用光照貼圖,并且正在尋找相關資源的人有幫助。
總攬
?
此文解釋了為游戲或者其它圖形應用創建光照圖的過程。
目標
此文檔目標是解釋光照圖的產生過程。它描述了光照圖的光元(lumels--lumination elements) 的計算方法和像素顏色的產生。
然而,此文檔不包含任何最新的與當今顯卡適配的逐像素渲染技術。
假設
我們假設讀者熟知3D游戲編程技術和3D圖形的基本技術,尤其是光照,材質,3D幾何,多邊形,平面,紋理坐標等等。
當然,本文只解釋了光照圖的生成。并沒有解釋光照圖的紋理坐標的計算。如果你的網格里還沒用過光照圖的紋理坐標,這里有個簡單的方法來測試光照圖的產生。
點擊這里了解更多。
如果在你了解此文之前,你非常想知道基于光照技術的光照貼圖的結果,你可以點這里去demo部分。在demo那里你可以下載一個交互的演示程序。
光照基礎
你已經看到看起來非常接近現實環境的游戲(我是指,只是看起來合理)。這種效果的原因是它使用了光照。如果游戲沒有被“照亮”,它會看起來不真實。是光照讓玩家一遍一遍的看游戲。看看下面兩張圖的不同,是光照造成的:
圖1?
有光照圖照亮的世界。白色的菱形(右邊)代表光源
圖2
沒有光的世界
對比明顯,不是嗎?
現在你看到結果了,讓我們看下實際操作中(有關靜態世界)不同類型的光照
1.逐頂點照亮
o 基于光對頂點的影響,每個頂點計算一個顏色值。
o 顏色值在三角形內進行插值。
o 三角形、多邊形不能非常大,否則會產生毛刺。
o 為了顯示效果好些,多邊形需要被細分到合適的等級。
o 如果頂點數量增加,計算時間就會更長。因為是逐頂點計算的。
o 不會引起從顯存加載(光照貼圖需要)。
o 所有計算實時進行,因此實現實時光照是可行的。
o 影子錯誤。
o 得到非常好的照明效果。
2.逐像素光照(實時):此文所述的逐像素光照方法
并不包含現今如NVDIA GEForce 3/4 ,ATI Radeon 8500/9700 甚至更新的顯卡所能達到的效果。
o 基于光的影響,計算每個要被繪制的像素的顏色。
o 導致引擎的巨大加載。
o 實時渲染的游戲要使用是不現實的。
o 精確的陰影得以實現(很可能產生碰撞檢測的額外開銷)。
o 可以得到更為真實的光照效果,但是對于實時渲染來說太慢了。
3.逐像素光照(光照圖):
o 實時光照得以實現。
o 動態光照需要更多工作。
o 可以與逐頂點光照結合實現實時動態光照。
o 每一位的耗時的光照計算在預處理階段已經完成。
o 因此沒有運行時的開銷。
o 運行時,所以的計算(顏色計算)是由硬件完成,因此很快。
o 視覺顯示在光照方面的質量直接依賴光照圖紋理的大小。
o 這是我們用這么少的開銷所能達到的最接近的逐像素光照。
o 對每個三角形,先用一個漫反射貼圖,再把光照貼圖乘上去。
用光照圖進行逐像素光照
在本文剩下的部分我們要討論基于光照圖的光照。一個光照貼圖其實只是又一張紋理貼圖。光照貼圖和漫反射貼圖唯一的不同在于,漫反射貼圖裝的是顏色值就是顏色值,而光照貼圖的顏色值其實是光照值。是應用了這張貼圖的里相應的多邊形的光照值。其它都是一樣的。
o 光照貼圖用單獨的紋理坐標映射到一個三角形/多邊形上,這個紋理坐標被成為光照圖紋理坐標
o 光照圖的資源和漫反射圖的資源的加載方式相同。
o 漫反射貼圖的每個像素通常叫做texel,而光照圖的每個像素叫做lumel(光元)。我們都喜歡有意思的名字,不是嗎?
在鉆研光照圖的計算過程之前,讓我們先看下2D的紋理是怎樣映射到3D的三角形上的。
圖3
左邊的圖是一個2D的紋理(你隨便在什么圖形編輯工具里都能看見)是一個(N*N)的尺寸。圖中顯示的是規范化的維度。
右邊的是個3D的多邊形,正如你在游戲中會看到的那樣,假設背景消失。紋理坐標被每個頂點使用。正如你所見到的那樣,紋理以1:1的比率映射到多邊形上面。例如,整個紋理以1:1的比率映射在多邊形上。
現在考慮下面的圖表。圖表展現了一個映射或者粘貼在2D的紋理上的多邊形。這個多邊形只用了紋理的一部分。所以映射比率不是1:1。我們可以看到多邊形只包含了紋理的一部分。這個多邊形有紋理貼圖的一部分。因此,這個多邊形有越多的像素,它看起來就越好。(這是在3D的視角,假設相機距離多邊形距離適中。在這次討論中我們忽略MIPMAP)
圖四
讓我們仔細看下上面的圖并把光照圖考慮進去。漫反射貼圖,可能或者不能被多個多邊形共享。就是說漫反射貼圖上的一個像素可以屬于多個多邊形。而對光照圖來說,一個像素只能屬于一個多邊形。
光照圖里的每個像素在現實世界中有個與他所屬多邊形相關的對應位置。你必須非常清楚這一點。因為每個三角形的頂點有一個物理世界中的位置,所以這個三角形中的每個像素都有個物理世界中的位置。根據三角形的邊緣來算,這個位置是非常均勻的。
同樣,有個像素中心的定義。每當我們提及像素,它是指像素中心。像素不是一個點,而是一個盒子。可以比對下圖。
圖五
基于上面的標準,當我們需要一個像素的uv坐標時,計算方法如下:
x=(w+0.5)/Width
y=(h+0.5)/Height
上面的方程中,w和h是我們正在計算的像素的偏移。
Width是光照圖的寬。
Height是光照圖的高。
具體內容請看下圖。
圖六
現在,我試著用圖表解釋下我說的。請看下圖
圖七
在上面的圖表中,我假設性的描述了三角形和光照圖像素之間的關系。
在此圖中,
o 三角形由三條實線(邊)定義。
o 三角形的三個頂點是(0,0,0)(0,100,0)(100,0,0)
o 既然三個點的z值相同,我們就可以忽略計算過程中的z的部分。
o 每個在三角形內部(或者一小部分在外面)的盒子定義了唯一的(光照圖的)像素。
o 記住一個像素是個盒子(一個區域)不是一個點。
o 綠色盒子的意思是,像素基本在三角形內部,這樣光照圖的這個像素就是屬于這個三角形的。
o 粉色盒子意思是,像素的中心在三角形外部,因此光照圖的這個像素是不屬于這個三角形的。
o 每個屬于此三角形的像素中心都有一個編號。
o 這個三角形有15個像素。
o 我們接下來練習通過觀察三角形和像素的位置來確定大致的理論上的每個像素的世界坐標位置。
記住,我們正在做的是基于眼睛的測量。一點都不準確。
這個練習只是為了讓你理解頂點,光照圖紋理坐標和光照圖像素之間的關系。它會告訴你一個像素的世界坐標位置是什么意思。
看下面的那行,有5個像素并且每個像素的寬是x軸上的100個單位。
o 這意味著每個像素20個單位。
o 并且邊緣的位置只是在x范圍變化。所以Y和Z都是常量。
o 因此第一個像素的x值是20(不怎么準確)。
o 第一個像素點的位置是(20,0,0)
o 第二個位置是(40,0,0),第三個是(60,0,0),第四個是(80,0,0),第五個是(100,0,0)
同樣的,算一下別的像素的位置。
再次提醒,上面的計算是不準確的。上面的練習是為了讓你理解每個像素的世界坐標的意思。
從上面的圖表中,你可以分析出一個三角形有越多的(光照圖)像素,像素在世界坐標間的距離就越小,因此輸出結果就越平滑。試著指出這是為什么。
如果你仍然不能理解像素中心和世界坐標的概念,那么就再看一遍前面的文檔。如果不清楚請不要繼續。
這是用光照圖得到的一副圖片。
圖八
基于光照技術的簡單光照圖
現在讓我們看下光照映射技術的實際處理過程。完整的計算光照圖的過程被分成了三步。他們是:
o 1.計算/尋找光照圖紋理坐標。
o 2.為光照圖的每個像素計算世界坐標和法線。
o 3.計算每個像素最后的顏色。
a.計算/尋找光照圖紋理坐標:
這是非常重要和基礎的處理。它包含把每個多邊形安放到光照圖的對應區域里。這個話題可以變成一個很長的文章。因此,我們跳過這個話題繼續到下一步。
然而,如果你想得到解釋這個問題的鏈接,那么,在這篇文章的末尾有相關鏈接。
這是最重要的一個處理,因為它決定了使用這個紋理空間的效率。它可以被自動處理或者用3DMax或者Maya的編輯工具里手動進行。
o 創建一個空的立方體,很大的(空的,這樣就不需要碰撞檢測了)
o 設置漫反射和光照紋理坐標
o 更好的做法是,對立方體的立方體的所有表面用一個漫反射對六個不同的面(多邊形)用不同的光照圖。
o 這樣你就可以映射光照圖到立方體的多邊形用1:1的比率了。
o 在立方體的上面創建一個或者兩個光源。
o 用這個方案來測試你的光照圖生成。
o 下一步,為了測試影子的生成,你可以在立方體的下面的中心加一個盒子,添加碰撞檢測相關。
b.為光照圖的每個像素計算世界坐標和法線:
這是光照圖計算的預處理階段。如你所知,光照圖的每個像素可以映射一個世界坐標系中的位置。這正是為什么我們要計算的原因。只要世界的幾何結構和光照圖紋理的大小不變,此數據就是靜止的,也就是說,只需要計算一次并且可以被重用。
這就是實現方法。現在考慮一個和此圖差不多的三角形。為什么我們對于下圖的三角形的頂點坐標我們只有二維的內容將在下面的章節里解釋。
圖九
讓我們看一下我們都從這里知道了什么:
a. 我們知道了三角形的頂點(二維)。
b. 我們知道了所有三個頂點的(光照圖)紋理坐標。
這里我們需要計算的是:對于給定紋理坐標值(在二維三角形的邊緣或內部),取得二維三角形邊緣活著內部的二維坐標。我們不得不對屬于這個多邊形的光照圖的每個像素這么做。(記住,一個光照圖的像素屬于并且只能屬于一個三角形/多邊形)下面讓我們看看是怎么得出來的。
注意:下面的幾個章節中,我使用的某些公式,注釋并且引用與 鏈接 Chris Hecker 的文章 《投影紋理映射》。請查看上述鏈接以獲取更多內容。
圖十
一段支持光照貼圖的shader代碼:
Shader "Legacy Shaders/Lightmapped/Diffuse" { Properties {_Color ("Main Color", Color) = (1,1,1,1)_MainTex ("Base (RGB)", 2D) = "white" {}_LightMap ("Lightmap (RGB)", 2D) = "black" {} }SubShader {LOD 200Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Lambert struct Input {float2 uv_MainTex;float2 uv2_LightMap; }; sampler2D _MainTex; sampler2D _LightMap; fixed4 _Color; void surf (Input IN, inout SurfaceOutput o) {o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb * _Color;half4 lm = tex2D (_LightMap, IN.uv2_LightMap);o.Emission = lm.rgb*o.Albedo.rgb;o.Alpha = lm.a * _Color.a; } ENDCG } FallBack "Legacy Shaders/Lightmapped/VertexLit" }?
?
總結
以上是生活随笔為你收集整理的(转)光照图的理论和实践的全部內容,希望文章能夠幫你解決所遇到的問題。