2011-03-27 86 views
7

如何在WebGL中像動畫一樣實現這個隧道?如何在WebGL中像動畫一樣實現這個隧道?

enter image description here

來源:http://dvdp.tumblr.com/

參見:How to implement this rotating spiral in WebGL?

+2

(看30秒後拋出了) – Blender 2011-03-27 18:39:28

+0

嘗試使用展示在牆上它的投影機;) – zproxy 2011-03-27 20:43:53

+2

雖然這有一個公認的答案,我們的社會是不是要用於爲您提供個人便利的代碼工廠。 – Kev 2011-11-08 12:39:19

回答

26

嗯,這很有趣。 :)

一個WebGL的演示,請訪問:http://boblycat.org/~knute/webgl/tunnel/

主要算法是在片段着色器。基本思想是for循環遍歷黑圈/圓圈,從大到小,同時偏移中心以產生隧道效應。

給定任何像素,我們可以檢查像素是否足夠接近環以成爲黑色像素的候選者。如果它在環之外,則打破環路以避免在較大的環上看到較小的環。

當環接近時,與前一個(外)圓的距離用於「擠壓」圖案,這有助於創建3D表面的幻覺。

每個環的波浪圖案當然是一條正弦曲線。像素的角度(與圓心相比)與均勻的時間參數相結合,爲每個環形的波浪圖案製作動畫。

最後,有很多實驗用不同的參數和轉換函數,例如pow()來獲得接近目標動畫的結果。這並不完美,但非常接近。

片段着色器代碼:

#ifdef GL_ES 
precision highp float; 
#endif 

const float PI = 3.14159265358979323846264; 
const float TWOPI = PI*2.0; 

const vec4 WHITE = vec4(1.0, 1.0, 1.0, 1.0); 
const vec4 BLACK = vec4(0.0, 0.0, 0.0, 1.0); 

const vec2 CENTER = vec2(0.0, 0.0); 

const int MAX_RINGS = 30; 
const float RING_DISTANCE = 0.05; 
const float WAVE_COUNT = 60.0; 
const float WAVE_DEPTH = 0.04; 

uniform float uTime; 
varying vec2 vPosition; 

void main(void) { 
    float rot = mod(uTime*0.0006, TWOPI); 
    float x = vPosition.x; 
    float y = vPosition.y; 

    bool black = false; 
    float prevRingDist = RING_DISTANCE; 
    for (int i = 0; i < MAX_RINGS; i++) { 
     vec2 center = vec2(0.0, 0.7 - RING_DISTANCE * float(i)*1.2); 
     float radius = 0.5 + RING_DISTANCE/(pow(float(i+5), 1.1)*0.006); 
     float dist = distance(center, vPosition); 
     dist = pow(dist, 0.3); 
     float ringDist = abs(dist-radius); 
     if (ringDist < RING_DISTANCE*prevRingDist*7.0) { 
      float angle = atan(y - center.y, x - center.x); 
      float thickness = 1.1 * abs(dist - radius)/prevRingDist; 
      float depthFactor = WAVE_DEPTH * sin((angle+rot*radius) * WAVE_COUNT); 
      if (dist > radius) { 
       black = (thickness < RING_DISTANCE * 5.0 - depthFactor * 2.0); 
      } 
      else { 
       black = (thickness < RING_DISTANCE * 5.0 + depthFactor); 
      } 
      break; 
     } 
     if (dist > radius) break; 
     prevRingDist = ringDist; 
    } 

    gl_FragColor = black ? BLACK : WHITE; 
} 
+0

看起來真棒!不錯的工作。 – Qcom 2011-04-05 23:13:03

+0

在我的低端系統上使用Firefox進行測試時:着色器鏈接錯誤:C:\ util \ firefox-3.7a5pre.en-US.win32 \ firefox \ memory(98,16):警告X3206:向量類型C的隱式截斷:\ util \ firefox-3.7a5pre.en-US.win32 \ firefox \ memory(33,5):錯誤X3511:無法展開循環,循環顯示不及時終止(17次迭代),請使用[ unroll(n)]屬性強制執行一個確切的更高數字 – zproxy 2011-04-08 05:45:52

+0

MAX_RINGS = 10:着色器鏈接錯誤:C:\ util \ firefox-3.7a5pre.en-US.win32 \ firefox \ memory(98,16):warning X3206:隱式截斷向量類型C:\ util \ firefox-3.7a5pre.en-US.win32 \ firefox \ memory(74,4):錯誤X5608:編譯着色器代碼使用太多算術指令槽(733)。最大。目標(ps_2_0)允許的值爲64.(1,1):錯誤X5609:編譯的着色器代碼使用太多的指令槽(733)。最大。目標(ps_2_0)允許的值爲96. – zproxy 2011-04-08 05:50:06