看板 GameDesign 關於我們 聯絡資訊
Shader Toy 上, 大部分都是用 Ray Marching 的演算法寫的。 https://www.shadertoy.com/ 不懂 Ray Marching 的話, 看那些 code 和看天書差不多。 [Ray Tracing] 3D電腦繪圖中,要決定一個 PIXEL 要畫甚麼顏色, 我們會模擬一道從假想的攝影機或眼睛射出的光, 通過了一個平面的銀幕,最後射中了某個物體。 射到物體後, 我們會知道光線觸擊了甚麼物體, 與那個點是在空間中的哪個位置。 所以一道光就是有一個位置與一個方向組成的。 Ray Tracing 要計算光線觸及點時, 是從光線起始位置, 朝著光線方向每次移動一小段距離, 然後計算新位置與空間中所有物件有無碰撞。 因為每次光線只移動一小段就要重新計算碰撞, 所以這是種效率很差的方法, 因此有了 Ray Marching。 [Ray Marching] 如果我們描述空間中的物件, 是用 “某一點 x 觸及到該物件的最小距離 (Distance to the Scene, 以下簡稱 DTS)” 來表示的話, 那我們每次從任一個點要移動光線時, 就可以不只移動一小段距離, 而是先計算出光線出發點與所有物件的 DTS, 然後移動其中最小的 DTS。 或是說 DTS 就是保證某個距離內, 光線絕對不會碰到任何東西的意思。 因為每次移動光線的距離變長許多, 所以在非極端的情況下, 效率比 Ray Tracing 好非常多。 舉例: 一個在 XZ 平面上,高度為 0 的無限寬廣的地板, 空間中任何一點 a 與該地板的最小距離一定是 a.y。 一個圓球,中心點在 0,0,0,半徑為 R, 空間中任何一點 a 與該圓球的最短距離是 length( a ) – R。 所以,空間中任何一點 a, 觸及該空間中所有物件的最小距離是: float DTS( vec3 a ) return min( a.y, length( a ) – R ); 所以假設我有一道光, 從 pos (10, 10, 10) 出發,方向是 dis( -1, -0.5, -1 ), 要計算那個光會擊中在哪個點的方法。 for i [0, MAX_STEP] // ds: 離光線出發點最近的物件距離 ds = DTS( pos ) // DS 太小表示撞到東西了 if ds < 0.00001 then break; // 光線可以安全的射 ds 這麼長而不用擔心碰到東西 pos = pos + ds * dir // 射了太遠都碰不到東西,就別在前進了 if length(pos – (10,10,10)) > 10000.0 then break; 每一個 PIXEL, 或是對每一個 shader 的 UV, 都可以用這樣算出觸碰的距離, 有了距離當然也能知道觸碰的位置 (pos + dir * ds)。 這種計算光線碰撞距離的方法, 就是 Ray Marching [NORMAL (法向量)] 知道距離,接下來要算顏色。 要算顏色,要知道場景燈光位置,還有觸碰點的法向量。 法向量就是一個物體中, 任一個點垂直於該平面的單位向量。 要如何計算 f(x) 中,某個點 x 的斜率? 斜率 = f( x + delta ) – f(x) / ( delta ) 用類似的方法就能算法向量了, 真正的算法在 shader toy 看一下就有了, 就五六行。 有了 normal,計算它與光源方向的角度, 角度越大越亮,越小越暗。 [Shadow (陰影)] 當我們有了一個光線觸及點 a,要如何知道該點有沒有影子呢? 一、計算從光源到該點的 DTS (應該說是光線碰撞距離啦) 二、計算從光源道該點的實際距離 三、如果 DTS < 實際距離, 表示光源在射向該點時,有撞到東西, 所以該點就應該是陰影。 有點無聊的東西, 但如果想抄 shader toy 到 game engine 用, 卻不懂這個的話,連想抄作業都抄不起來的。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 61.228.116.6 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/GameDesign/M.1646277345.A.055.html ※ 編輯: YoshiCasa (61.228.116.6 臺灣), 03/03/2022 11:31:44
nicetw20xx: 推,感謝解說 03/03 12:36
※ 編輯: YoshiCasa (61.228.116.6 臺灣), 03/03/2022 20:02:16
coolrobin: 未看先推,感謝分享 03/03 22:04
sargent: 推分享,但我不懂,為什麼要分那麼多次呢?真複雜 03/04 13:12
grezod: 推 03/06 09:52