這是一篇科普性質的技術文章,最終目標是實現圈狀效果。在實現的過程中對需要理解的兩個概念Roughness和Anisotropy進行了本質性的剖析。希望對各位有幫助
內容不少,而且越往後越有一定的難度,量力而行。
本文中使用的技術是建立在李航(hang li 懸掛鯉)之前的一篇技術剖析的基礎之上,感謝偉大的李航。
這篇文章無私地公開了《驚奇隊長》中使用的技術,為此我去電影院認真觀摩了這部電影,然而並沒有觀察出明顯的圈狀劃痕現象。
在比較早之前,我個人就研究過這個效果的做法,很多朋友都還有印象。
為什麼這次又會拿出這個問題重新來聊,是因為李航公佈的做法和我之前研究的做法有某種程度上的本質區別。
之前我推送的方法是用凹凸去模擬劃痕,思維是很物理的方式:現實生活中會產生凹槽的地方,我就用凹凸貼圖做出凹下去的效果,以此復現現實中的物理效果。
而李航的方式本質上是用roughness——反射的粗糙度——來驅動的。
這兩種做法在實現層面上有根本的不同。
這種思維很不物理,很不直觀,很程序員,所以一直沒見人這麼想過這麼做過,(也許大公司內部早這麼做了,但我們不知道)。
而我單獨另寫一篇文章再來談這個問題,並不是對他文章內容的搬運或者複述。而是詳盡地解釋背後所涉及的原理,以及討論了另一個關鍵的核心點:繞過flowmap的生成,直接製作anisotropy rotation 貼圖,實現目標效果。
這樣整個流程會更簡單輕便,並且我使用Substance Designer這款程序紋理軟體去生成anisotropy rotation貼圖,這樣可以獲得程序紋理 「強大的隨機性,快速生成變種,幾乎無限的自定義特性」 等等屬性加持,創造出更多可能性。
Roughness的本質
凹凸強算粗糙度的效率問題
各向異性(anisotropy)產生的本質
flowmap轉aniRotationMap
繞過flowmap直接製作aniRotationMap的原理
在Substance Designer中的簡單實現方法
遺留問題解決,為什麼要轉90度?
換個快的渲染器,我說要有紅移(Redshift)
總結
接前言。為什麼說李航介紹的這這個思維很程序員呢,這就要說到roughness這個參數了。
世界上本沒有粗糙度,用的人多了也就有了粗糙度 —— 魯迅。
通過魯迅先生的這句警示名言,我們能夠窺探到很多問題。可能有很多朋友這個時候感受到了三觀的動搖,因為之前看過的很多文章了裏都說,粗糙度表徵物體反射的粗糙和銳利程度,是決定質感很重要的一個屬性。怎麼在魯迅先生的嘴裡,這個屬性就沒有了呢?
作為長期訂閱我公眾號的優秀各位來說,一定都是有著強烈的求知慾望,不可能滿足於表象的概念。這裡,我們就要探討roughness的本質。
我們首先思考,為什麼物體的反射會有清晰與模糊的區別呢?——因為微觀結構。有的物體微觀結構整齊,反射就清晰;有的物體微觀結構凹凸不平,體現在宏觀上的反射就模糊。
關鍵詞來了,凹凸不平。這個詞讓你聯想到什麼CG屬性?對,就是bump。
這裡不賣關子了, Roughness == Bump。
你可能不相信,這裡擺證據。
我在maya裏做了兩個球,
左球用roughness控制反射粗糙度的變化。
右球用的是一張whiteNoise貼圖貼到bump裡面,通過控制bump的強度來實現的粗糙度變化(roughness值恆定為0,你可以理解成材質球上這個參數被摳掉,沒有了)。
這張whiteNoise從Substance designer軟體中生成。
在maya中這張whiteNoise做了100次uv重複,以確保紋理足夠密集,接近所謂的微觀結構。
同時很重要的事情是關閉圖片本身的過濾(filter),以確保紋理在渲染時由於過小而被模糊掉(這樣會喪失原本的微觀結構,無法實現本文中所做的測試效果)
以Redshift渲染器為例:
這樣一對比大家就會發現,縱使右球沒有使用roughness參數,但是最終效果看起來非常接近於正常調節roughness參數帶來的變化效果。我覺得這張GIF圖已經能非常優秀地證明魯迅先生的觀點了。
我們再來複讀一次。
世界上本沒有粗糙度,凹凸太慢了也就有了粗糙度——魯迅
咦,等等,怎麼感覺有哪裡不對?
如果按照上文論述的觀點,那我們根本就不需要roughness參數了。反射越粗糙的東西,我們就給一個凹凸強度越高的紋理就解決了。
理論上說這個說法很正確,而且也非常物理、符合人的現實生活經驗。但這種用凹凸強行做出粗糙度的做法,有一個專業的詞可以去形容他,玩渲染的各位應該很熟悉了——brute force
道理是相通的。這種做法跟你渲GI的時候,用brute force的演算法一個意思,可能你表達的微觀結構非常準確,但是渲染速度卻極慢。
maxAA = 4
maxAA = 117
maxAA = 1024
maxAA = 8192
從這套圖就能看出來,用roughness參數調節反射粗糙度的時候,很低的採樣就已經沒有什麼噪點了。但是用bump來控制的話,需要非常高的採樣纔能有效減少噪點。而且就算把採樣給到系統可接受的最大值8192(圖片都是使用Redshift渲染器渲染,rs的sample單位為samples相當於單位為subdivs的數值的平方,此處的8192samples相當於subdivs的90左右;另外,使用maxAA來提高質量而不是使用lighting samples是因為這裡裏產生噪點的原因不是燈光採樣不夠,而是貼圖極為細密必須發射超級多的cameraAA去採樣,掃盲科普),依然會看到明顯噪點。
也就是說這個思路只是理論正確,但在生產和工業流程中是大錯特錯。
於是便引入了roughness這個參數來解決以上討論的問題。
在CG世界裡不管多麼物理正確的渲染器也都只是在模擬,是對微觀物理表面的的宏觀總結。——懸掛鯉
親們,相信您現在對這句至理名言又有了更深刻的體會。
另外,我之所以花很多時間精力嘗試學習和提升這個方法,很大一部分原因也是出於效率考慮。雖然用之前的bump或者normal的方法也能做出圈狀劃痕,但那個渲染效率著實是非常差勁的。
跟本文現在剖析的方法比差太多了。
為什麼物體的反射會產生各項異性?前文已經做好了足夠的鋪墊,前戲這麼足了,這次的學習肯定不會痛。
我們都已經接受了,粗糙度的本質是因為微觀表面的凹凸,那麼各向異性的產生,肯定也繞不開微觀表面的凹凸問題。
一般的微觀表面,因為其凹凸的隨機性,表現出來的高光擴散是四面八方均勻的。我們之前用一張whiteNoise就模擬出來了這種效果,大家再看看這張圖感受一下,物體的微觀表面凹凸就是如此,隨機且均勻(這不是二維碼哦,別掃,沒用的)。
但也有一些物體的表面,是另外一種形態。比如:
這種微觀表面有極其強烈的規律與方向性,一旦有這種結構,物體的宏觀反射就會出現各向異性的現象。
這種微觀結構,就是產生各向異性的本質。
我還是使用同樣的brute force做法,在渲染器中復現一下這個過程。
左邊的材質球是隻調節了anisotropy數值,從0到1的變化。(每個渲染器可能不一樣,比如arnold需要配合roughness值的調節,光調節anisotropy參數沒用,這裡只講原理,就不展開細節了)
右邊的材質球用的是剛剛在Substance designer中使用anisotropic_noise節點生成的一張凹凸圖。
同樣重複300倍以後插入bump強行製造反射模糊,動畫依然是k的凹凸強度。這一次,是帶有各項異性的反射模糊!
再截個圖給大家看一下,這張凹凸貼圖貼在模型上到底是什麼樣的。
(anisotropy rotation map 太長了,我把它縮短成aniRotationMap,標題是這個意思)
以上,我們已經理解了,roughness的本質就是凹凸。那麼終於要開始我們這一期的主題了——用roughness來還原圈狀劃痕的凹凸效果。
核心技術在懸掛鯉的這篇文章中都有詳細描述 ,想看後面的內容一定至少要搞明白這篇文章裏的內容。
文中使用了一張他自己繪製的flowmap圖片,用這張圖經過一系列的節點轉換,最終插入anisotropy rotation通道,讓各向異性的高光產生旋轉來實現目的。
實際上flowmap的本質是平面坐標的位置,xy的數值放在紅綠兩個通道之中記錄。而轉換成anisotropy rotation貼圖,則是通過某個點的位置,算出一個角度,用這個角度來控制旋轉。
核心就是使用一個叫做atan2的函數(有些工具裏有這個,比如arnold 和substance designer,有些工具沒有,比如vray和redshift)
我在嘗試使用非arnold渲染器渲染這個效果的時候,就因為缺乏數學工具而無法實現flowmap到anisotropy rotation map的轉換。於是嘗試了使用Substance Designer作為中間軟體進行轉換。
他的原圖是這樣的(都有簽名了,我隨便轉應該無所謂了吧)
以下為SD中的pixel process中節點截圖。我大概做了標註。主要作用是將flowmap轉換成anisotropy rotation map。點大圖應該是可以看清楚字的。
轉換的結果是這樣,已經能看出來黑白劃痕了(並且有一部分劃痕是負值,所以整圖看起來很黑):
最後用這張SD中生成的anisotropy rotation map直接使用,也可以渲染出我們想要的效果
由於flowmap沒有那麼直觀,並且在有些渲染器(vray、redshift)中不能直接使用。我開始嘗試直接製作anisotropy rotation map。
使用的工具當然是程序紋理霸王——substance designer。
首先我們要明確目標,知道要實現的貼圖效果到底是如何,然後再想製作方案。現在我們就來分析懸掛鯉製作的已經被驗證可行的貼圖到底有什麼特點。
我們將之前在SD裏的pixel process節點重新梳理一下,不使用-0.25 而是加0.5 ,這樣做可以使最後輸出的圖片亮度完全處於[0,1]的範圍之內,以便於我們觀察圖片特點(這個操作唯一的意義就是為了好觀察)。
現在圖片看起來是這樣,亮了很多。所有的亮度都在[0,1]之間。
這個時候我們使用SD中的一個叫做histogram select的節點來觀察圖片,這樣可以看到圖片中不同亮度的劃痕到底是怎麼分佈的。
下圖是亮度從0-1 把原圖掃了一遍的效果。
這下我們可以發現這張圖的兩個特點:
這樣的特性為什麼就能塑造出圈狀劃痕呢? 這跟我們材質球上的屬性有關。
材質球上有一個anisotropy rotation屬性,專門控制各項異性高光旋轉方向的。這個屬性的輸入區間為[0,1],數值與角度有個這樣的對應關係:
0 : 0°
0.25 : 90°
0.5 : 180°
0.75 : 270°
1.00 : 360°
中間是線性差值,大家應該很容易就理解這個參數了。
下圖是anisotropy rotation 從0變到1的效果,高光整整地轉了360度:
所以其實我們只要做出符合這兩個特點的劃痕圖就能達成目的:
用圖表示大概這樣(rotate 0 = rotate 1)
知道原理和目標以後,我們就要想辦法實現了。
這篇我只想簡單講講思路,因為會使用SD軟體的朋友應該在極少數。如果要詳細寫的話,另外開一篇才比較合適。
不過如果你喫透了上面的思路的話,理論上用ps都可以做,只不過相對麻煩很多而已。
節點圖比較簡單
主要是使用tile sampler來做散佈;shape節點就是個方形,壓得很扁做劃痕元素。一個高斯noise讓散佈產生隨機。
這個gaussian noise 要同時控制劃痕的旋轉和亮度,最後造成的效果就是:gaussian noise越黑的地方旋轉角度越小,劃痕亮度同時也越低;反之亦反。
最後生成的aniRotation貼圖效果,SD自然是無縫的。
再用histgram select節點檢查一下效果,因為我們用的是黑底,所以亮度選擇為0的時候,畫面大面積被選中,這個沒關係。整體效果看上去跟我們預期的是一樣的:
因為這是一個最簡單的實現,我的劃痕沒做花哨的東西,就是直的。我自己測的製作方法比這個複雜很多。不過用的核心原理就是上面介紹的這些內容了。
我們把剛在SD中做好的貼圖放到渲染器中嘗試渲染,其實還是會出現好幾個說起來都挺嚴重的問題。我們一個一個來解決吧。
首先,如果直接把這個圖插入anisotropy rotation通道,把別的所有參數都調正確,用arnold渲染器直接渲染,結果還是會非常奇怪。
為什麼會這樣呢?其實前文一直有一個較大的疑惑我留在那裡沒有解釋,就是在flowmap轉aniRotation map的過程中,前面的步驟都可以很容易理解了;最後一個操作 -0.25,代表的意思現在大家也應該領悟了,就是旋轉90度角。
但是,為什麼要進行這樣的旋轉操作呢??????
我建了一個簡單的場景說明這個問題。圖中是一排圓柱一字排開,圓柱在圖中是橫向的,而他們的高光方向卻是豎向的,兩者相互垂直。 其實這個圖也是對各向異性本質的簡略展示。
這個圖說明瞭一個問題,各向異性高光拉伸的方向,和凹槽本身的結構方向,是垂直的。
當我們有橫向凹槽的時候,我們想要的高光形態應該是豎直的。圖中黑線代表凹槽,白線代表高光。
而我們使用的aniRotate貼圖,如果顏色為純黑色代表的是什麼效果?對,默認不旋轉的橫向高光。而看我們之前的製作過程,橫向的凹槽一直是黑色的。所以,這個高光方向跟凹槽一個方向啊!!
所以我們要把高光旋轉90度!
在arnold中對貼圖的亮度+0.25(或者減也一樣)。
ok!!
在arnold中我們已經製作出了標杆效果,但是無法忍受緩慢的渲染速度,我們嘗試在一些GPU渲染器中也重現這個技術。本文中主要剖析Redshift渲染器中的問題。
因為Rs的各向異性旋轉方向和arnold是相反的,所以在完成上面同樣的操作以後,還要做一個反轉操作。
雖然劃痕都有了,但是出來的結果也還是很奇怪:
後來我研究李航的文件發現,他輸出了一個mask來解決這個問題。將原來做好的劃痕貼圖轉換成mask,只要有劃痕的地方現在都是純白。把這個mask壓在圖片的alpha通道裡帶出去。
然後在渲染器裏,把mask輸出到anisotropy屬性上去,這樣,只有有劃痕的地方纔有各項異性,沒有劃痕的地方都只是普通高光。
其中我加了一個remapHSV節點稍微調整一下劃痕區域的各向異性強度,屬於效果調整節點了,這個看個人口味去調。
有了mask以後你可以分開細調很多參數。
調整完之後,效果就很ok了。
李航發的那篇技術文章對我最近的影響算是比較大的。雖然解決的問題看起來是個比較偏門,一年都不一定做得上一次的問題。
但其實最有意義的並不是這個問題本身的被解決,而是解決方案之後蘊含的思想。
縱使我好多年前早就明白了Roughness Anisotropy這些東西背後的本質,但依然還是對他們的特性掌握得不夠深入透徹;像文中講的方法,以前其實好像在Mental ray的幫助文檔裏都看到過,但當時是不理解,不相信能做出好效果,更沒有去嘗試的。
這次學會了這個技術,又給我打開了一扇大門。我覺得用Roughness配合Anisotropy確實在很大程度上能模擬和取代bump或者normal的效果。這樣會讓渲染效率提高很多,甚至原來可能由於參數突破上限而無法實現的效果,現在也都有可能去做了。
並且我覺得自然界中應該有很多很多反射現象都是具有某種程度的各向異性的。這個就要看藝術家處理的時候,到底把百分之多少的結構做在凹凸裏,百分之多少的結構做在Roughness裏,只要Roughness有,那麼或多或少會體現出各項異性的現象,只是程度上有所差異。
而我們之前的製作流程裏,對各向異性都只在特別明顯的某些材質上才會使用。這可能是材質真實度缺失的其中一個環節吧。
之前看grant warwick的教程,發現他已經注意到了這個問題,並且已經嘗試在使用aniRotationMap了。只不過我覺得他處理的方法還比較粗糙,算不上對,只是保證有了這方面的變化。
後面我想看看能不能做出一些普適性的東西,比如直接根據bump + roughness貼圖,計算出aniRotation貼圖。
感覺這是一個非常有意義,也相當有挑戰性的方向。