2011-03-27 15 views
7

¿Cómo implementar este túnel como animación en WebGL?¿Cómo implementar este túnel como animación en WebGL?

enter image description here

Fuente: http://dvdp.tumblr.com/

Ver también: How to implement this rotating spiral in WebGL?

+2

(vomita después de ver durante 30 segundos) – Blender

+0

intentar usar un proyector de mostrarlo en la pared;) – zproxy

+2

Si bien esto tiene una respuesta aceptada, nuestra comunidad no es estar utilizado para proporcionar una fábrica de códigos para su conveniencia personal. – Kev

Respuesta

26

Bueno, esto fue divertido. :)

Un WebGL demo está disponible aquí: http://boblycat.org/~knute/webgl/tunnel/

El algoritmo principal se encuentra en el fragment shader. La idea básica es un bucle for que itera sobre los anillos/círculos negros, de grandes a pequeños, también compensando el centro para producir un efecto tipo túnel.

Dado cualquier píxel, podemos verificar si el píxel está lo suficientemente cerca del anillo como para ser candidato a un píxel negro o no. Si está fuera del anillo, rompa el ciclo para evitar ver anillos más pequeños a través de los más grandes.

La distancia desde el círculo anterior (exterior) se utiliza para "apretar" el patrón cuando los anillos están cerca, esto ayuda a crear la ilusión de una superficie 3D.

El patrón ondulado de cada anillo es, por supuesto, una curva sinusoidal. El ángulo del píxel (en comparación con el centro del círculo) se combina con un parámetro de tiempo uniforme para animar el patrón ondulado para cada anillo.

Y, por último, hubo mucha experimentación con diferentes parámetros y funciones de transformación como pow() para obtener el resultado cerca de la animación objetivo. No es perfecto, pero está bastante cerca.

El código fragmento shader:

#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

¡Se ve increíble! Buen trabajo. – Qcom

+0

Al probar con Firefox en mi sistema de gama baja: Error de enlace de sombreado: C: \ util \ firefox-3.7a5pre.en-US.win32 \ firefox \ memory (98,16): advertencia X3206: truncamiento implícito del vector tipo C : \ util \ firefox-3.7a5pre.en-US.win32 \ firefox \ memory (33,5): error X3511: no se puede desenrollar el bucle, el bucle no parece terminar de manera oportuna (17 iteraciones), utilice [ desenrollar (n)] atributo para forzar un número más alto exacto – zproxy

+0

Con MAX_RINGS = 10: Error de enlace de sombreado: C: \ util \ firefox-3.7a5pre.en-US.win32 \ firefox \ memory (98,16): advertencia X3206: truncamiento implícito del vector tipo C: \ util \ firefox-3.7a5pre.en-US.win32 \ firefox \ memory (74,4): error X5608: el código del sombreador compilado usa demasiadas ranuras de instrucción aritmética (733). Max. permitido por el objetivo (ps_2_0) es 64. (1,1): error X5609: el código de sombreador compilado usa demasiadas ranuras de instrucción (733). Max. permitido por el objetivo (ps_2_0) es 96. – zproxy