2016-02-10 70 views
3

我一直在尋找,並試圖瞭解下面的代碼位GLSL立方體簽名距離字段的實現說明?

float sdBox(vec3 p, vec3 b) 
{ 
    vec3 d = abs(p) - b; 
    return min(max(d.x,max(d.y,d.z)),0.0) + 
     length(max(d,0.0)); 
} 

我明白length(d)處理SDF情況下點是關閉的「角落」(即中d所有部件正面),並且max(d.x, d.y, d.z)在所有其他情況下給我們適當的距離。我不明白的是,如果不使用if語句來檢查d組件的符號,這兩個組合是如何組合的。

當所有d組件都是積極的,返回表達式可以減少到length(d)的,因爲這樣min/max將評估 - 當所有d組件是否定的,我們得到max(d.x, d.y, d.z)。但我該如何理解中間情況呢? d的組件有混合跡象的那些?

我一直在試圖將其繪製出來無濟於事。如果有人能夠用幾何/數學術語向我解釋這一點,我會非常感激。謝謝。

回答

0

我想通了一段時間以前,廣泛在博客中寫到這裏一下:http://fabricecastel.github.io/blog/2016-02-11/main.html

下面是摘錄(見全文後更全面的解釋):

考慮四點,A,B,C和D.讓我們粗略地減少距離函數來嘗試去除最小/最大函數以瞭解它們的效果(因爲這是令人費解的關於這個函數的)。下面的符號有點草率,我用方括號來表示2D矢量。

// 2D version of the function 
d(p) = min(max(p.x, p.y), 0) 
     + length(max(p, 0)) 

--- 

d(A) = min(max(-1, -1), 0) 
     + length(max([-1, -1], 0)) 

d(A) = -1 + length[0, 0] 

--- 

d(B) = min(max(1, 1), 0) 
     + length(max([1, 1], 0)) 

d(B) = 0 + length[1, 1] 

好的,到目前爲止沒有什麼特別的。當A位於正方形內部時,我們基本上得到了基於平面/線的第一個距離函數,當B位於第一個距離函數不準確的區域時,它被歸零並得到第二個距離函數(長度)。訣竅在於C和D的另外兩種情況。讓我們來解決它們。

d(C) = min(max(-1, 1), 0) 
     + length(max([-1, 1], 0)) 

d(C) = 0 + length[0, 1] 

--- 

d(D) = min(max(1, -1), 0) 
     + length(max([-1, 1], 0)) 

d(D) = 0 + length[1, 0] 

如果你回頭看上面的圖表,你會注意到C'和D'。這些點分別具有座標[0,1]和[1,0]。這種方法使用兩個距離場在軸上相交的事實 - D和D'與正方形距離相同。

如果我們將矢量的所有負向分量零點並取其長度,我們將得到點與正方形之間的正確距離(僅適用於正方形以外的點)。這是max(d,0.0)所做的;一個組件式的最大操作。只要向量具有至少一個正分量,min(max(d.x,d.y),0.0)將解析爲0,只留下等式的第二部分。如果點在方格內,我們想返回方程的第一部分(因爲它表示我們的第一個距離函數)。如果載體的所有成分都是陰性,很容易看到我們的狀況會得到滿足。

這種理解應該在您將頭圍繞它時無縫地變回到3D。你可能會也可能不需要親手繪製幾張圖來真正「獲取」它 - 我知道我做過了,如果你對我的解釋不滿意,會鼓勵你這樣做。

這個工作落實到我們自己的代碼,我們得到這樣的:

float distanceToNearestSurface(vec3 p){ 
    float s = 1.0; 
    vec3 d = abs(p) - vec3(s); 
    return min(max(d.x, max(d.y,d.z)), 0.0) 
     + length(max(d,0.0)); 
} 

有你有它。