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

标签 javascript glsl webgl

<分区>

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

enter image description here

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

另请参阅:How to implement this rotating spiral in WebGL?

最佳答案

嗯,这很有趣。 :)

此处提供 WebGL 演示:http://boblycat.org/~knute/webgl/tunnel/

(编辑:不再可用,但我创建了一个 ShaderToy 版本:https://www.shadertoy.com/view/XdKfRD)

主要算法在片段着色器中。基本思想是 for 循环遍历黑色环/圆圈,从大到小,同时偏移中心以产生类似隧道的效果。

给定任何像素,我们可以检查该像素是否足够接近环以成为黑色像素的候选者。如果它在环外,请断开环以避免通过较大的环看到较小的环。

与前一个(外)圆的距离用于在圆环靠近时将图案“挤压”在一起,这有助于营造 3D 表面的错觉。

每个环的波浪图案当然是正弦曲线。像素的 Angular (与圆心相比)与统一的时间参数相结合,为每个圆环制作波浪图案动画。

最后,使用不同的参数和转换函数(如 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;
}

关于javascript - 如何在 WebGL 中实现这种类似隧道的动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5451376/

相关文章:

javascript - 访问 .json 文件导致银行假期访问被拒绝

javascript - 从保存的 Canvas 图像中找不到 SOI

c++ - GLSL 编译失败但没有错误信息

OpenGL - 如何访问深度缓冲区值? - 或 : gl_FragCoord. z 与纹理渲染深度

javascript - 在 Polymer 中加载数据后重新加载元素

javascript - 带有 html 的导航器无法使用 javascript

c++ - 从顶点着色器中修改着色器存储缓冲区对象

android - WebGL 会是适用于 Android 平台的良好代码原型(prototype)吗?

three.js - "uv"和其他 WebGL 变量的文档在哪里?

text - WebGL:文本渲染和混合问题