① 什麼是投影面積,怎麼算
一、什麼是投影面積?
假設太陽正當頂時,此房屋落在地上的陰影外輪廓線包圍的面積就叫它的水平投影面積。其實一般情況下也就是構件的施工平面圖上的面積。
一般用於房屋建築上,用於建築面積計算。
二、如何計算投影面積?
成套房屋的套內建築面積由套內房屋使用面積,套內牆體面積,套內陽台建築面積三部分組成。
1、套內的使用面積:套內房屋使用面積為套內房屋使用空間的面積,以水平投影面積按以下規定計算:
a.套內房屋使用面積為套內卧室、起居室、過廳、過道、廚房、衛生間、廁所、儲藏室、壁櫥等空間面積的總和。
b.套內內部樓梯按自然層數的面積總和計入使用面積。
c.不包括含在結構面積內的套內內部煙囪、通風道、管道井均計入使用面積。 d.內牆面裝飾厚度計入使用面積。
2、套內牆體面積:套內牆體面積是套內使用空間周圍的維護或承重牆體或其他承重支撐體所佔的面積,其中各套之間的分隔牆和套與公共建築空間的分隔以及外牆(包括山牆)等共有牆,均按水平投影面積的一半計入套內牆體面積。套內自由牆體按水平投影面積全部計入套內牆體面積。
② 從條帶狀陰影談Unity Shadow
不知道你曾經在Unity中遇到過陰影異常沒有,比如近處馬賽克狀的陰影塊?亦或是脫離投影物體的「懸浮」陰影?還是稍遠處陰影的突然消失?多塊陰影互相疊加處顏色異常的亮度等等。我感覺最讓人無法直觀理解,也相對常見的一種陰影異常要數「條帶狀陰影」了。請允許我暫時如此稱呼它,因為這很形象。
要重現「條帶狀陰影」其實很簡單,我們甚至可以在不修改任何Unity默認設置的情況下獲得這種現象。做個實驗,新建一個Unity工程(2019),創建2個Quad對象,然後上下堆疊起來,設置頂層Quad的高度(Y軸世界坐標)為0.05,設置底層高度為0,調節一下主方向光,使之保持垂直朝向的姿勢,既Rotation: (90, 0, 0),一切OK的話大概能得到下圖所示的表現,看起來還不錯,姑且稱之為 現象<0> 。
我們保持光照和平面位置不變,接下來我們要調節2個重要參數,叫 bias 和 normal bias ,Unity在標准渲染管線模式下,將這2個參數暴露在了Light組件有關shadow的設置參數中;URP模式則可以在 Render Feature的設置欄中找到它們倆。總之找到並設置 bias = 0 , normal bias = 0 ,我們再看看有什麼變化:
簡單盤點下,在具有一定傾斜角度直接光照下,觀察兩塊相聚非常近的面片中,上方面板向下方面片的投影,我們會發現「條帶狀陰影」;在此基礎上,我們將 bias 和 normal bias 這兩個參數歸零,面片間投射的陰影恢復正常,但是面片上原本非陰影區域又出現了「條帶狀陰影」。
無論如何,在解讀之前,我們都應該明確這種現象是Unity在處理陰影效果時產生的,因為我們全程只調節了2個控制陰影顯示的參數而已。而對於Unity或者一般游戲引擎是如何渲染物體投影效果這一部分,考慮到網上相關內容的資料非常豐富,這里就不再詳細闡述了,凝練一下,可以把通用渲染邏輯整理為3個步驟,羅列如下:
步驟1略微展開一下,它涉及到將在光源位置放置攝像機,然後基於光源的視角生成深度圖,場景中光源的陰影區也就是光源位置攝影機看不到的地方。ShadowMap本質上是一張深度圖,它記錄了從該光源的位置出發,能看到的場景中,距離光源最近的表面的深度值。
上圖左側為深度圖。右側在相機位置繪制場景時,能夠看到場景中的點Va,其對應的ShadowMap中的位置為a,Va的深度不大於深度圖中a位置存儲的深度,因此Va不處於陰影
考慮到上述採用shadowmap技術渲染陰影的技術最早可以追述到1978年,人們已經對這項技術能給圖形渲染帶來的利與弊有了充分的認識。回到 現象<2> 來,在圖形學中描述這類現象自然也有其慣用的術語,叫做「Shadow Acne」或者「Self-Shadowing」。這兩個英文單詞,前者可以翻譯為「陰影粉刺」,後者則一般翻譯為「自陰影」,一個表形,一個表意,可以說描述得挺好,後續我們還會提到,如果有興趣了解更多細節,這里有一篇對各種陰影異常表現總結得很好的 技術博文 可以作為參考。
在有了一定的陰影紋理演算法基礎,以及對所使用數據結構有一定了解的前提下,我們不妨從復盤光照模型開始研究 現象<2> 的成因。
在PL上紅色斑點的右側標記了另一個黑色斑點,毫無疑問它也落在了可見區域中,而且由於光照是垂直向下的,光源到這個黑色斑點的最短距離和一旁的紅色斑點應當是一致的,數值上等於圖中紅色連線的長度,既{Depth}。
當傾斜光照,使之與物體平面(PL)成一定角度相交後,事情就變得有意思起來了。我們都知道,由於透視原理,攝像機近處的物體(PL)相較於遠處的物體(光源)會擠占更多的屏幕空間像素,而生成陰影紋理(ShadowMap)的光源空間也有類似的現象,只不過不是因為透視投影導致的(直接光照使用的是正交投影),而是由角度和解析度共同作用導致的:
現在考察上圖中黃色虛線填充的BCP三角形,在這塊區域內的物體(比如頂點P1),到光源處的最短距離必然小於圖中紅色實線表示的深度值{Depth};同樣的在黑色虛線填充的三角形PED中,所有點到光源的距離必然大於深度值{Depth}。根據光照投影演算法的定義,在BCP三角形中的點P1,轉換到光源空間後的深度值小於該處記錄的光源深度,所以P1不在陰影中,這顯然是期望的結果;然而另一側三角形PED中的P2卻在相同的演算法中被分配到了陰影中,這顯然是錯誤的結論。
通過前面的分析,我們看到,本該處於非陰影狀態的三個平面PL上的點 P1、P和P2,在一定光照角度外加一定的紋理解析度條件下,經過標准光照投影演算法處理後會得出錯誤的結論(三角形PED區域的投影結果),而且導致投影錯誤的原因也以作圖的方法進行的展示。為了能更直觀,更量化的反應問題,我們不妨對上述圖例作如下簡化():
在上圖中,黑色粗線表示場景中的平面,黃色粗線表示為光源所對應的近平面。該近平面會對應產生的ShadowMap。AB表示為這個近平面上對應ShadowMap上一個紋素的區域。假設近平面是一個規范尺寸的正方形,且邊長為FSize。對應的ShadowMap解析度被設置為SSize。那麼AB所對應的坐標尺寸通過如下計算可獲得: AB = FSize / SSize
我們希望通過某些方式,讓紋素AB對應區域在物體平面上的投影CD部分,能夠完整的處於圖中藍色虛線的左側。解決的方法也很樸素直觀,按道理只需將ShadowMap中存放的深度值稍微增大點即可,最好是大得剛剛好,恰巧確保CD段處於非陰影區域。
這是第一種修正,針對光線的方向進行偏移:
觀察線段(向量)GD,這是我們按照光線方向的最短平移距離,藍色虛線在平移後恰好位於線段CD的右側,從而確保了CD段在計算陰影深度時,其在光源空間的深度能夠小於ShadowMap采樣深度(既圖中的BD線段長度)。
求解GD:
除了沿著光線方向直接增加深度之外,還可以沿著法線方向作偏移,間接影響深度值,這就是我們接下來要研究的normal bias法線偏移。
法線偏移其實還分兩種實現方式,一種是在將物體頂點轉換到光源空間之前,先沿著法線正方向作移動,達到減小片元的深度,具體參考下圖:
另一種是在生成ShadowMap時,將物體的頂點沿著法線反方向進行偏移,從而變相得增大陰影的深度值,具體參考下圖:
先說第一種方式,它的作用機制不是直接修改陰影紋理的深度值,而是嘗試縮小物體在光源空間的深度,因此需要在片元著色器中實現。參考圖[normal 1],物體表面沿著自身法線方向移動了距離GM,獲得新的位置C'G。將原本CM段的區域整體提升到了藍色虛線的左側。我們知道C'G區域的深度取值必然小於等於F點的深度值EF,現在會被光源正常照亮了;至於點G右側的部分線段可以不用擔心,它們將會被相鄰的ShadowMap覆蓋和處理。
此處的α指的還是光線方向和法線方向形成的夾角。
對於第二種方式,理解起來會直觀一些,因為它直接作用於ShadowMap,修改(增加)紋素中的深度值。參考圖[normal 2],修正後藍色虛線向左下方偏移了距離FN, 從而確保CD段區域處於陰影深度線的左側,被正常照亮。至於偏移量MN的計算,需要分為2步:
其中α指光線方向與法線的夾角;φ指光源方向與法線的夾角。
Unity引入2個bias變數作為控制陰影深度參數的理由,我想至少有2層。其一是增加了靈活性,讓用戶可以依據場景本身的特質調整光源方向或者法線方向的深度,試想如果Unity只提供了normal bias作為參數,在某些極端情況下,過大的normal bias會導致物體投射的陰影與物體本體脫離的現象(Peter Panning)。
至於另一層理由,可以參考上圖,bias對於圖中的tanθ曲線,normal bias對於sinθ曲線,θ是光源平面與物體平面的夾角。當光線方向與物體表面越加趨向平行時,光源平面越加垂直於物體平面,θ角越接近90度(π/2),此時使用bias計算得出的修正距離也將隨著tan一起趨向無窮大(圖中斜向上藍色箭頭)。若此時引入sinθ,則可以平衡bias的影響,這是因為很樸素的道理:sin函數是有上界的(圖中藍色水平箭頭),我們可以在θ角小於45度(π/4)時優先使用bias的計算結果,而當θ角超過45度後,將計算偏移距離的權重倒向normal bias一邊。
也許有人會問,既然bias計算出的偏移會趨於無窮大,為何不只用normal bias呢?對此之前已經有了回答:我們需要避免Peter Panning現象。
Normal Bias的兩種移動方式,在實際效果上並不完全相同。採用在頂點著色器中改變ShadowMap深度值的方式,會在某些情況下導致Normal Bias失效。參考上圖,最左側為產生陰影的普通情況,由於整個單元內採用C點的深度進行比較,所以ED段會錯誤產生陰影。中間示意圖為頂點著色器增加 ShadowMap 深度的做法,在這種方法中,已知從C到D的深度差距記為d,光線和AB段的法線角度為θ,則最小的消除Shadow Acne的沿法線反方向的距離計算為:
在這種情況下,當θ趨向於90°(即光線與AD近乎平行時),最小的距離趨向於無窮大,Normal Bias就很難達到消除Acne的大小。右側示意圖為片元著色器移動片元位置的計算方法,在角度變化的情況下也不會出現最小距離趨近無窮大的情況。但在片元著色器上進行這部分計算,就比前一種方式要更多的計算量。
條帶狀的「亮暗」漸變,在Unity2019.4.13版本下,使用標注渲染管線,開啟軟陰影後截屏。
「粉刺」狀或者「銼刀」狀的暗斑,在Unity2019.4.13版本下,使用標注渲染管線,關閉軟陰影後截屏。
吐槽:曾經我也很好奇,為何自陰影的別名叫做 Shadow Acne(陰影粉刺),而不是更加常見的陰影條帶。直到我關閉了軟陰影並清空了bias修正後看到上圖。確實這才是二維格子狀紋理出問題後該有的表現,就像下圖這樣,每個獨立的紋素所對應的區域應當被分割成了正方形(正交投影),在二維平面上遇到一定角度的入射光,形成了上圖這種規則排列的「粉刺」狀暗斑。
進過了上面的分析,我們知道 現象<2> 的出現本質是由於標注陰影演算法的缺陷,導致物體自己產生的陰影紋理遮蔽了自己(部分),也就是所謂的「自陰影」。現在我們來看看 現象<1> 的成因,不妨先從2種現象在條件上的差異開始入手。
當場景中存在正常產生陰影的物體時(上圖藍色矩形表示障礙物),全局添加一個Bias,在上圖情況中解決了 Self Shadow 的問題,但是正常應該產生的陰影也被消除了。當Bias從小到大逐漸變化時,對一個正常產生陰影的物體來說,它的陰影表現為由靠近物體的一端開始,逐漸消失。這種現象有個專用術語,叫「漏光」(Light Bleeding)。
接下來,我們通過上圖復現文章開頭引入 現象<1> 的場景布局。還是傾斜入射,這次在物體平面(PL)的正下方多了一層新的平面(UD)。如果不對陰影深度進行修正(bias皆為0),那麼來自陰影紋理中像素A投射的等深線CD會與PL平面相交於點P,此時我們在PL上能看到自陰影效果,既圖中由點BCP包圍的黃色三角形以及由點PDH圍成的黑色三角形區域。當開啟bias後,等深線CD分別沿著光線方向和物體法線的反方向做了2次偏移(圖中紅色箭頭),並來帶了線段GI所在之處。當UD平面與PL平面距離足夠近時,線段GI將於UD平面相交於點P2,同時形成由點EGP2和IJP2圍成了2塊不同區域。此時我們說在平面UD上出現了「漏光」,既本來不該被照亮的區域(EP2)現在被錯誤的照亮了。
取消2個bias,有可能消除下層平面UD上投影異常效果。參考上圖線段CD所代表的陰影紋理等深平面,並沒有出現在平面UD上EJ段的右側(或者說與線段EJ沒有相交),可見這種情況下,UD上能正確顯示來自PL的投影。
還是在取消bias前提下,當我們進一步縮小2個平面之間的距離,可以再次復現異常,此時上下層平面可以近似認為是一個平面,下層平面UD會產生源自PL的自陰影。
現象<1> 成因可以說是Unity為了解決 現象<2> ,在引入bias後間接導致的。下面是我總結的一些有助於減緩 現象<1> 的辦法,和大家一起分享,當然問題的解決方案是開放的,如果大家有其他好方案,希望不要吝嗇得分享出來。
從 現象<1> 的成因分析,它只會出現在光照方向與物體表面成較小夾角時,我們可以通過合理的布置場景中會導致此類現象的物件位置,優化它們的迎光角度,從而避免出現透光現象。
如果我們對出現 現象<1> 的問題物體投影質量要求不高,完全可以取消該物體的投影選項(不參與陰影紋理的生成,但是可以被動接受陰影),然後使用結構相對簡單的投影代理來為該物體實際生成陰影。簡言之,我們解決不了問題,那就解決產生問題的物體就好。
如上圖中綠色箭頭,我們需要通過某種方法,在片原階段,將平面UD沿著其法線方向的反方向做一次小偏移,使之遠離被下壓過來的等深線段GI。這裡面有個難點,我們如何判斷一個像素需要做額外偏移?或者說我們該如何知道物體平面UD需要做額外偏移,而不是物體平面PL呢?一種最簡單的方法是把問題丟給CPU,在預處理階段對不同頂點進行標記,運行時帶入到GPU中參與計算。