2015-09-10 97 views
2

我想我有一個愚蠢的例子,我正在執行一些保守的深度渲染(conservative rendering in CPU gems),但我堅持在最基本的級別:擴大三角。如何抵消webgl着色器中的二維三角形?

這裏是事務的狀態: http://nraynaud.github.io/webgcode/test_3D_conservative_rendering.html (黑色三角形是輸入,紅色點是放大的頂點,並且正方形代表與採樣網格)

我使用webgl的與你。 js,我將每個頂點的2個伴隨頂點作爲屬性發送,並且我試圖放大頂點着色器中的三角形。我可能處於最愚蠢的境地:我有一個正交相機,它的'up'是+ Y軸,視圖延伸到-Z(基本上我正在拍攝我的腳,屏幕的頂部是+ Y)。我不能(我認爲,投影幾何有點神祕)直接使用CPU寶石中的代碼,因爲它假設了一個透視相機(它計算通過三角形邊緣和觀察者眼點的平面,而在正常位置沒有眼點)。

這裏是我的嘗試:

 ' vec3 p1 = prevPoint, p2 = position, p3 = nextPoint;', 
     ' if (!isFrontFacing(p1.xy, p2.xy, p3.xy)) {vec3 temp = p1;p1 = p3; p3 = temp;}', 
     //move the vertex in 2D 
     ' vec2 e1 = p2.xy - p1.xy;', 
     ' vec2 e1Normal = normalize(vec2(e1.y, -e1.x));', 
     ' vec2 e1Translate = e1Normal * length(hPixelWorld);', 

     ' vec2 e2 = p3.xy - p2.xy;', 
     ' vec2 e2Normal = normalize(vec2(e2.y, -e2.x));', 
     ' vec2 e2Translate = e2Normal * length(hPixelWorld);', 

我想,這應該給我2個法線毗鄰P2(所考慮的頂點),都指向向內或向外三角形的,取決於2個邊我運氣。嗯,實際上,根據所考慮的頂點,我並不總是讓法線指向相同的方向(而不是一個缺點),並且我沒有解釋(我甚至試圖用isFrontFacing對頂點順序裝甲我的代碼() 在頂部)。

我嘗試了一些愚蠢的東西,比如計算法線方向的所有4種可能性,並選擇一個讓我離三角形質心最遠的點,但我認爲我甚至拙劣地實現了這一點,因爲有些點顯然不是最遠的離中心:

 ' vec3 possibilities[4];', 
     ' vec2 centroid = ((p1+p2+p3)/3.0).xy;', 
     ' possibilities[0] = translatePoint(p2.xy, +e1Translate, +e2Translate, e1, e2, centroid);', 
     ' possibilities[1] = translatePoint(p2.xy, -e1Translate, +e2Translate, e1, e2, centroid);', 
     ' possibilities[2] = translatePoint(p2.xy, -e1Translate, -e2Translate, e1, e2, centroid);', 
     ' possibilities[3] = translatePoint(p2.xy, +e1Translate, -e2Translate, e1, e2, centroid);', 
     ' vec3 currentBest = possibilities[0];', 
     ' if (possibilities[1].z >= currentBest.z)', 
     '  currentBest = possibilities[1];', 
     ' if (possibilities[2].z >= currentBest.z)', 
     '  currentBest = possibilities[2];', 
     ' if (possibilities[3].z >= currentBest.z)', 
     '  currentBest = possibilities[3];', 

     ' vec2 resultPoint2D = currentBest.xy;', 

這裏isFrontFacing:

 'bool isFrontFacing(vec2 p1, vec2 p2, vec2 p3) {', 
     ' float a = cross2d(p2-p1, p2-p3);', 
     ' return a > 0.0;', 
     '}', 

這裏是TranslatePoint將:

 // we are encoding the distance to centroid in z 
     'vec3 translatePoint(vec2 point, vec2 dir1, vec2 dir2, vec2 e1, vec2 e2, vec2 centroid) {', 
     ' vec2 e1TranslatedPoint = point + dir1;', 
     ' vec2 e2TranslatedPoint = point + dir2;', 
     //http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect 
     ' float u = cross2d(e2TranslatedPoint - e1TranslatedPoint, e2)/cross2d(e2, e1);', 
     ' vec2 result = e1TranslatedPoint + u * e1;', 
     ' float dist = length(result - centroid);', 
     ' return vec3(result, dist);', 
     '}', 

和cross2D:

 'float cross2d(vec2 v1, vec2 v2) {', 
     ' return v1.x * v2.y - v1.y * v2.x; ', 
     '}', 

這裏是完整的代碼: https://github.com/nraynaud/webgcode/blob/01550668fdedba5ab61e2fbf5ed9917ca06b5e75/test_3D_conservative_rendering.html

我們看到只有一個頂點在正確的方向移動,對2人,邊緣法線之一是錯誤。

好的,那麼當我們不是幾何白癡時,我們如何抵消一個三角形?

回答

1

我不認爲你需要真正的迭代通過正常方向的所有候選組合 - 因爲偏移是沿着當前頂點的角平分線,所以你知道實際方向已經從來自另外兩個三角形頂點的方向矢量p1p2

如果繪製出一個圖表,您會意識到距原始位置的偏移距離與兩個方向矢量之間角度的一半的正弦成比例。

float pixelSize = 10.0; // or whatever 

void main() { 
    vec3 a = normalize(position - prev); 
    vec3 b = normalize(position - next); 

    // we will offset along the vector `c` 
    vec3 c = normalize(a + b); 

    // a formula to calculate the sine of half an angle 
    float halfsine = sqrt((1.0 - dot(a, b))/2.0); 

    gl_Position = vec4(position + pixelSize * c/halfsine, 1); 
} 

這裏的一個餐巾圖:矢量AB是從其他頂點的歸一化方向。 pixel顯示偏移大小。小的直角三角形是一致的,因爲舊的和新的頂點位置與兩條邊線等距。

diagram

+0

非常非常感謝你。我現在對簡單感到有些慚愧,但至少我有一個工作代碼。我認爲我會堅持一個不變的偏移量(當每個邊緣選擇不同的偏移量時,有一種方法可以略微減少偏移量,但我認爲我不會管理它)。 – nraynaud