Проектирование системы частиц с использованием Three. js и Shader - PullRequest
0 голосов
/ 15 февраля 2020

Я очень новичок в этом сообществе. Поскольку я задаю вопрос, если есть что-то, что я утверждаю, что это неправильно, пожалуйста, исправьте меня.

Теперь, к вопросу, я проектирую систему частиц, используя библиотеку Three. js, особенно я использую THREE.Geometry () и управляйте вершиной, используя шейдер. Я хочу, чтобы движение моей частицы было ограничено внутри прямоугольника, что означает, что когда частица пересекает грань бокса, ее новая позиция будет на противоположной стороне этой грани.

Вот как я подхожу к вершине шейдер:

uniform float elapsedTime;

        void main() {
            gl_PointSize = 3.2;
            vec3 pos = position;

            pos.y -= elapsedTime*2.1;

            if( pos.y < -100.0) {
                pos.y = 100.0;
            }



            gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0 );
        }

ellapsedTime отправляется из javascript анимации l oop через униформу. И позиция y каждой вершины будет обновляться в соответствии с временем. В качестве теста я хочу, чтобы если частица была ниже нижней плоскости (y = -100), она переместится в верхнюю плоскость. Это был мой план. И вот результат, после того как все они достигнут дна:

Начало падения

Start to fall

После достижения дна

After reach the bottom

Итак, что мне здесь не хватает?

Ответы [ 2 ]

1 голос
/ 16 февраля 2020

Вы можете достичь этого, используя функцию mod:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 300);
var renderer = new THREE.WebGLRenderer({
  antialis: true
});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

var gridTop = new THREE.GridHelper(200, 10);
gridTop.position.y = 100;
var gridBottom = new THREE.GridHelper(200, 10);
gridBottom.position.y = -100;
scene.add(gridTop, gridBottom);

var pts = [];
for (let i = 0; i < 1000; i++) {
  pts.push(new THREE.Vector3(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).multiplyScalar(100));
}
var geom = new THREE.BufferGeometry().setFromPoints(pts);
var mat = new THREE.PointsMaterial({
  size: 2,
  color: "aqua"
});
var uniforms = {
  time: {
    value: 0
  },
  highY: {
    value: 100
  },
  lowY: {
    value: -100
  }
}
mat.onBeforeCompile = shader => {
  shader.uniforms.time = uniforms.time;
  shader.uniforms.highY = uniforms.highY;
  shader.uniforms.lowY = uniforms.lowY;
  console.log(shader.vertexShader);
  shader.vertexShader = `
    uniform float time;
    uniform float highY;
    uniform float lowY;
  ` + shader.vertexShader;
  shader.vertexShader = shader.vertexShader.replace(
    `#include <begin_vertex>`,
    `#include <begin_vertex>
      
      float totalY = highY - lowY;
      transformed.y = highY - mod(highY - (transformed.y - time * 20.), totalY);
    `
  );
}
var points = new THREE.Points(geom, mat);
scene.add(points);

var clock = new THREE.Clock();

renderer.setAnimationLoop(() => {
  uniforms.time.value = clock.getElapsedTime();
  renderer.render(scene, camera);
});
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
0 голосов
/ 15 февраля 2020

Нельзя изменить состояние в шейдере. вывод только для вершинных шейдеров gl_Position (для генерации точек / линий / треугольников) и изменений, которые передаются фрагментному шейдеру. Единственный вывод фрагментированного шейдера - gl_FragColor (в общем). Поэтому попытка изменить pos.y ничего не даст. В тот момент, когда шейдер выходит из вашего изменения, он забывается.

Для вашего кода частицы, хотя вы могли бы сделать положение повторяющейся функцией времени

       const float duration = 5.0;
       float t = fract(elapsedTime / duration);
       pos.y = mix(-100.0, 100.0, t);

Если предположить, что elapsedTime будет в секундах, то pos.y изменится с go с -100 до 100 более 5 секунд и повторите.

Обратите внимание, что в этом случае все частицы упадут одновременно. Вы можете добавить атрибут, чтобы дать им разные смещения времени, или вы могли бы выстроить их положение в свою формулу. В связи с этим вы можете найти эту статью полезной.

Вы также можете сделать движение частиц в JavaScript как в этом примере и в этом Обновление позиций в Geometry (или, лучше, BufferGeometry)

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

...