如何在 three.js 中实现这个 shadertoy?

How to implement this shadertoy in three.js?

https://www.shadertoy.com/view/4tfXzl

片段着色器有细微的变化:

  uniform sampler2D u_texture;
  uniform float u_time;

  float noise( in vec2 x ) {
    vec2 p = floor(x);
    vec2 f = fract(x);
    vec2 uv = p.xy + f.xy*f.xy*(3.0-2.0*f.xy);
    return texture( u_texture, (uv+118.4)/256.0, -100.0 ).x;
  }

  float fbm( vec2 x) {
    float h = 0.0;

    for (float i=1.0;i<10.0;i++) {
      h+=noise(x*pow(1.6, i))*0.9*pow(0.6, i);
    }

    return h;
  }

  float warp(vec2 p, float mm) {
    float m = 4.0;
    vec2 q = vec2(fbm(vec2(p)), fbm(p+vec2(5.12*u_time*0.01, 1.08)));

    vec2 r = vec2(fbm((p+q*m)+vec2(0.1, 4.741)), fbm((p+q*m)+vec2(1.952, 7.845))); 
    m /= mm;
    return fbm(p+r*m);
  }

  void main() {
    vec2 fragCoord = gl_FragCoord.xy;

    fragCoord+=vec2(u_time*100.0, 0.0);
    float col = warp(fragCoord*0.004, 12.0+fbm(fragCoord*0.005)*16.0);
    gl_FragColor = mix(vec4(0.2, 0.4, 1.0, 1.0), vec4(1.0), smoothstep(0.0, 1.0, col));
  }

然后我在three.js中创建简单平面并在tick函数中更新u_time,但结果只是蓝屏。我做错了什么?

试试看:

let camera, scene, renderer;

let uniforms;

init();
animate();

function init() {

  camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);

  scene = new THREE.Scene();

  const geometry = new THREE.PlaneGeometry(2, 2);

  uniforms = {
    u_time: {
      value: 1.0
    },
    u_texture: {
      value: new THREE.TextureLoader().load('https://i.imgur.com/BwLDhLB.png')
    }
  };

  const material = new THREE.ShaderMaterial({

    uniforms: uniforms,
    vertexShader: document.getElementById('vertexShader').textContent,
    fragmentShader: document.getElementById('fragmentShader').textContent

  });

  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  renderer = new THREE.WebGLRenderer();
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  window.addEventListener('resize', onWindowResize);

}

function onWindowResize() {

  renderer.setSize(window.innerWidth, window.innerHeight);

}

function animate() {

  requestAnimationFrame(animate);

  uniforms['u_time'].value = performance.now() / 1000;

  renderer.render(scene, camera);

}
body {
      margin: 0;
}
    <script src="https://cdn.jsdelivr.net/npm/three@0.130.1/build/three.min.js"></script>
    <script id="vertexShader" type="x-shader/x-vertex">

            void main() {

                gl_Position = vec4( position, 1.0 );

            }

        </script>

    <script id="fragmentShader" type="x-shader/x-fragment">

    uniform sampler2D u_texture;
  uniform float u_time;

  float noise( in vec2 x ) {
    vec2 p = floor(x);
    vec2 f = fract(x);
    vec2 uv = p.xy + f.xy*f.xy*(3.0-2.0*f.xy);
    return texture( u_texture, (uv+118.4)/256.0, -100.0 ).x;
  }

  float fbm( vec2 x) {
    float h = 0.0;

    for (float i=1.0;i<10.0;i++) {
      h+=noise(x*pow(1.6, i))*0.9*pow(0.6, i);
    }

    return h;
  }

  float warp(vec2 p, float mm) {
    float m = 4.0;
    vec2 q = vec2(fbm(vec2(p)), fbm(p+vec2(5.12*u_time*0.01, 1.08)));

    vec2 r = vec2(fbm((p+q*m)+vec2(0.1, 4.741)), fbm((p+q*m)+vec2(1.952, 7.845))); 
    m /= mm;
    return fbm(p+r*m);
  }

  void main() {
    vec2 fragCoord = gl_FragCoord.xy;

    fragCoord+=vec2(u_time*100.0, 0.0);
    float col = warp(fragCoord*0.004, 12.0+fbm(fragCoord*0.005)*16.0);
    gl_FragColor = mix(vec4(0.2, 0.4, 1.0, 1.0), vec4(1.0), smoothstep(0.0, 1.0, col));
  }

        </script>