如何在 fragmentShader 中以 three.js 的形式保留值?

How do I retain values in fragmentShader in three.js?

提问人:haru 提问时间:10/21/2023 更新时间:10/21/2023 访问量:45

问:

我想使用three.js ShaderMaterial将粒子动画应用于纹理。

粒子动画的细节

1:仅首次出现 fragmentShader 的行为 1_1:为每个像素分配一个随机坐标值 (参考:https://thebookofshaders.com/10/?lan=jp)

统一 int 标志;标志在三个.js渲染器中递增 1(初始值为 -1)

浮点随机(vec2 st) {

返回 fract( sin( dot(st.xy, vec2(12.9898, 78.233)) ) * 43758.5453123 );

}

如果(标志 == 0) {

vec2 移动 = 随机 (UV);

}

1_2:将 uv 坐标值分配给变量以保存纹理的原始坐标值

变化的 vec2 vUV;

vec2 uv = vUv;

如果(标志 == 0) {

VEC2 原点 = UV;

}

2:第二次后 fragmentShader 的行为 将每个粒子从 1_1 中分配的随机坐标值收敛到 1_2 中保留的原始坐标值

计算公式如下 (参考:https://www.youtube.com/watch?v=vAJEHf92tV0&list=WL&index=54&t=3934s)

float ease = 0.01;

move.x += (origin.x - move.x) * ease;

move.y += (origin.y - move.y) * ease;

但是,在上述 fragmentShader 的第二次之后, 在 main 函数之前声明它并使作用域全局不起作用,因为在声明变量时会重置该值。

我想知道如何在对 fragmentShader 的第二次和后续调用中引用 move 和 origin 的值。具体来说,我想知道如何保留这些值。先谢谢你。

-源代码-

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>nier three.js use case</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.157.0/three.min.js"></script>

  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
  </style>
</head>

<body>
  <div id="renderer"></div>

  <script>
    function init() {
      const scene = new THREE.Scene();

      const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000);
      camera.position.z = 10;

      const renderer = new THREE.WebGLRenderer();
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setClearColor(0x4a1c1c);

      const loader = new THREE.TextureLoader();
      const texture = loader.load('./image.png');

      const vertexShader = `
        varying vec2 vUv;
        varying vec3 pos;
        void main() {
          vUv = uv;
          pos = position;
          gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
      `;

      const fragmentShader = `
        uniform sampler2D texture_;
        varying vec2 vUv;
        varying vec3 pos;

        uniform float time;
        uniform vec2 resolution;
        uniform int flag;

        float random(vec2 st) {
            return fract( sin( dot(st.xy, vec2(12.9898, 78.233)) ) * 43758.5453123 );
        }
       

        void main() {
          vec2 uv = vUv;
          float ease = 0.01;
          vec4 color;
          vec2 st = gl_FragCoord.xy / resolution.xy;

          vec2 origin = vec2(0, 0);
          vec2 move = vec2(0, 0);

          if (flag == 0) {
            origin = uv;
            move = vec2(random(st), random(st));
          } 
          else {
            move.x += (origin.x - move.x) * ease;
            move.y += (origin.y - move.y) * ease;
          }

          color = texture(texture_, move);
          gl_FragColor = color;
        }
      `;


      const geometry = new THREE.PlaneGeometry(25, 15);

      const material = new THREE.ShaderMaterial({
        uniforms: {
          texture_: { value: texture },
          time: { value: 0.0 },
          flag: { value: -1 },
          resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
        },
        vertexShader: vertexShader,
        fragmentShader: fragmentShader,
      });

      const mesh = new THREE.Mesh(geometry, material);
      mesh.position.set(-2, 0, 0);
      scene.add(mesh);

      document.getElementById('renderer').appendChild(renderer.domElement);


      render();

      function render() {
        requestAnimationFrame(render);
        material.uniforms.time.value += 0.01;
        material.uniforms.flag.value += 1;

        renderer.render(scene, camera);

      }
    }

    window.onload = init;
  </script>
</body>

</html>
三个 .js GLSL 纹理片段 着色器

评论

0赞 Community 10/23/2023
请修剪您的代码,以便更轻松地找到您的问题。请遵循这些准则,以创建最小的可重现示例

答: 暂无答案