Javascript 如何在WebGL中实现这种类似隧道的动画?

Javascript 如何在WebGL中实现这种类似隧道的动画?,javascript,glsl,webgl,Javascript,Glsl,Webgl,如何在WebGL中实现这种类似隧道的动画 资料来源: 另请参见:嗯,这很有趣 此处提供了WebGL演示: (编辑:不再可用,但我创建了ShaderToy版本:) 主要算法在片段着色器中。基本思想是一个for循环,从大到小在黑环/圆上迭代,同时偏移中心以产生隧道式效果 给定任何像素,我们都可以检查该像素是否足够接近圆环,从而成为黑色像素的候选。如果它在环的外面,打破环以避免通过较大的环看到较小的环 环闭合时,与上一个(外)圆的距离用于将图案“挤压”在一起,这有助于创建3D曲面的错觉 每个环的波浪

如何在WebGL中实现这种类似隧道的动画

资料来源:

另请参见:

嗯,这很有趣

此处提供了WebGL演示:

(编辑:不再可用,但我创建了ShaderToy版本:)

主要算法在片段着色器中。基本思想是一个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;
}
\ifdef glu
高精度浮点;
#恩迪夫
常量浮点PI=3.14159265358979323846264;
常量浮点TWOPI=PI*2.0;
const vec4 WHITE=vec4(1.0,1.0,1.0,1.0);
常数vec4 BLACK=vec4(0.0,0.0,0.0,1.0);
常数vec2中心=vec2(0.0,0.0);
常数int MAX_环=30;
常数浮环距离=0.05;
恒浮波计数=60.0;
恒定浮波深度=0.04;
均匀浮动时间;
可变vec2位置;
真空总管(真空){
浮动rot=mod(uTime*0.0006,TWOPI);
float x=v位置.x;
浮动y=V位置y;
布尔黑=假;
float prevRingDist=环距离;
对于(int i=0;i半径){
黑色=(厚度<环距*5.0-深度系数*2.0);
}
否则{
黑色=(厚度<环距*5.0+深度系数);
}
打破
}
如果(距离>半径)中断;
prevRingDist=环度;
}
gl_FragColor=黑色?黑色:白色;
}

(观看30秒后呕吐)尝试使用投影仪在墙上显示;)虽然这是一个公认的答案,但我们的社区不会为了您的个人方便而提供代码工厂。在我的低端系统上测试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)]属性强制使用更高的数值,最大环数=10:着色器链接错误:C:\util\firefox-3.7a5pre.en US.win32\firefox\memory(98,16):警告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。在Galaxy S上它可以工作:)着色器可以被简化以使用更少的指令吗?也许着色器可以拆分为多个着色器以适合96的算术指令槽?除非>>同一类型的多个着色器对象可能无法连接到单个程序对象。我自己在一个旧的Eee上网本上发现了第一个错误,但还没有进一步研究它。但我的HTC Desire手机上的Firefox 4也可以使用,速度约为每秒半帧。:)