Как добиться этого эффекта шейдера движения размытия? - PullRequest
0 голосов
/ 04 декабря 2018

Я попытался создать эффект снега, как показано на нижней странице этой ссылки http://blog.edankwan.com/post/my-first-christmas-experiment. Все остальное работает нормально, но просто не могу заставить эффект размытия движения работать.Есть идеи?

текстурный спрайт, используемый для достижения эффекта размытия при движении

enter image description here

вот код:

(function(global) {

  var img = 'https://i.imgur.com/hlmsgWA.png'

  var renderer, scene, camera
  var w = 800, h = 320
  var uniforms
  
  var geometry
  var texture, material
  var gui
  var conf = {
    amount: 200,
    speed: 0.5,
    time: 0
  }

  var obj = {
    init: function() {
      renderer = new THREE.WebGLRenderer({
        antialias: true
      })
      renderer.setPixelRatio(window.devicePixelRatio)
      renderer.setSize(w, h)
      camera = new THREE.Camera
      scene = new THREE.Scene()

      geometry = new THREE.BufferGeometry()

      var positions = []
      
      for(var i = 0, l = conf.amount; i < l; i++) {
        positions[i * 3] = Math.random() * 800 - 400
        positions[i * 3 + 1] = i
        positions[i * 3 + 2] = Math.random() * 800
      }
      geometry.addAttribute('position', new THREE.Float32BufferAttribute(positions, 3))

      var vs = document.getElementById('vertexShader').textContent
      var fs = document.getElementById('fragmentShader').textContent

      uniforms = {
        u_amount: {
          type: 'f',
          value: conf.amount
        },
        u_speed: {
          type: 'f',
          value: conf.speed
        },
        u_time: {
          type: 'f',
          value: conf.time
        },
        u_resolution: {
          type: 'vec2',
          value: new THREE.Vector2(w, h)
        },
        u_texture : {
          value: new THREE.TextureLoader().load(img)
        }
      }
      material = new THREE.ShaderMaterial({
        uniforms: uniforms,
        vertexShader: vs,
        fragmentShader: fs,
        transparent: true
      })

      var points = new THREE.Points(geometry, material)
      scene.add(points)

      document.body.appendChild(renderer.domElement)
      this.render()
      this.createGui()
  
    },

    createGui: function() {
      gui = new dat.GUI()
      gui.add(conf, 'speed', -1, 1)
    },

    render: function() {
      requestAnimationFrame(this.render.bind(this))
      uniforms.u_time.value += conf.speed * 0.003
      renderer.render(scene, camera)
    }

  }

  obj.init()

})(window)
<script id="vertexShader" type="x-shader/x-vertex">
    precision highp float;
    vec3 getPosOffset(float ratio, float thershold) {
      return vec3(
        cos((ratio * 80.0 + 10.0) * thershold) * 20.0 * thershold,
        (sin((ratio * 90.0 + 30.0) * thershold) + 1.0) * 5.0 * thershold + mix(500.0, -500.0, ratio / thershold),
        sin((ratio * 70.0 + 20.0) * thershold) * 20.0 * thershold
      );
    }

    uniform vec2 u_resolution;
    uniform float u_amount;
    uniform float u_speed;
    uniform float u_time;
    varying float v_alpha;
    varying float v_rotation;
    varying float v_index;
    void main() {
      float indexRatio = position.y / u_amount;
      float thershold = 0.7 + indexRatio * 0.3;
      float ratio = mod(u_time - indexRatio * 3.0, thershold);
      float prevRatio = mod(u_time - u_speed - indexRatio * 3.0, thershold);
      vec3 offsetPos = getPosOffset(ratio, thershold);
      vec3 prevOffsetPos = getPosOffset(prevRatio, thershold);
      vec3 pos = position;
      pos += offsetPos;

      float perspective = (2000.0 - pos.z) / 2000.0;
      pos.x *= perspective;
      pos.y *= perspective;

      float delta = length(offsetPos.xy - prevOffsetPos.xy);
      float maxDelta = 2.7;
      v_index = floor(pow(clamp(delta, 0.0, maxDelta) / maxDelta, 5.0) * 15.99);  
      v_rotation = atan((offsetPos.x - prevOffsetPos.x) / (offsetPos.y - prevOffsetPos.y));

      pos.x *= 2.0 / u_resolution.x;
      pos.y *= 2.0 / u_resolution.y;
      pos.z = 0.0;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
      gl_PointSize = 24.0 * perspective;
      v_alpha = perspective;
    }
  </script>
  <script id="fragmentShader" type="x-shader/x-fragment">
  
    uniform sampler2D u_texture;
    varying float v_rotation;
    varying float v_index;
    varying float v_alpha;
    void main() {
      vec2 coord =  gl_PointCoord.xy;
      coord = vec2(
        clamp(cos(v_rotation) * (coord.x - 0.5) + sin(v_rotation) * (coord.y - 0.5) + 0.5, 0.0, 1.0),
        clamp(cos(v_rotation) * (coord.y - 0.5) - sin(v_rotation) * (coord.x - 0.5) + 0.5, 0.0, 1.0)
      );
      float index = floor(v_index + 0.5);
      coord.y = - coord.y + 4.0;
      coord.x += (index - floor(index / 4.0) * 4.0);
      coord.y -= floor(index / 4.0);
      coord *= 0.25;
      vec4 color = texture2D(u_texture, coord);
      color.a *= v_alpha;
      gl_FragColor = color;
    }
  </script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.3/dat.gui.js"></script>

http://blog.edankwan.com/post/my-first-christmas-experiment.

1 Ответ

0 голосов
/ 05 декабря 2018

В фрагменте кода вы обрабатываете переменную speed по-разному в цикле обновления и в вершинном шейдере.

  1. Обновление: uniforms.u_time.value += conf.speed * 0.003
  2. Использование шейдера: float prevRatio = mod(u_time - u_speed - indexRatio * 3.0, thershold);

Вы получите желаемый результат, если вы измените u_speed на u_speed * 0.003 в коде шейдера (или лучше переместите это умножение на определение в javascript).

Быстрый способ отладки таких вещей- передайте свои значения для вывода цвета и проверьте, соответствует ли это ожидаемому.

==================

Если кто-то хочетсделать хвосты с неплоской кривизной - вы можете хранить последние N точек каждой траектории частицы.Затем вы можете полностью вычислить геометрию сетки следов на ЦП и передать ее в графический процессор.

Или другим способом: вы можете загрузить все пути в один объект Uniform Buffer и найти нужную точку для извлечения с помощью pointId и uvхвостовой вершины сетки.

...