Animate particles with vertex shader

I’m trying to build floating particles with a vertex shader, but my particles won’t animate. I’m using React Three Fiber, but I recreated my setup with plain Three.js in this fiddle:

This is my vertex shader so far.

const sparkleMaterial = new THREE.ShaderMaterial({
  uniforms: { uTime: 0.0 },
    vertexShader: `
  varying vec3 vColor;
  uniform float uTime;
  attribute float size;
  void main() {
    vec4 modelPosition = modelMatrix * vec4(position, 1.0);
    modelPosition.y += sin(uTime + modelPosition.x * 100.0) * 0.2;
    modelPosition.z += cos(uTime + modelPosition.x * 100.0) * 0.2;
    modelPosition.x += cos(uTime + modelPosition.x * 100.0) * 0.2;

    vec4 viewPosition = viewMatrix * modelPosition;
    vec4 projectionPostion = projectionMatrix * viewPosition;
    gl_Position = projectionPostion;
    gl_PointSize = size * (100.0 / - viewPosition.z);
    vColor = color;
  }`,
  fragmentShader: `
    varying vec3 vColor;
    void main() {
      gl_FragColor = vec4( vColor, 1 );
    }
  `,

  blending: THREE.AdditiveBlending,
  depthTest: true,
  transparent: true,
  alphaTest: 0.5,
  vertexColors: true
});

Inside my component, I set it up like this

  let particleSystem = new THREE.Points(geometry, sparkleMaterial);
  const { scene } = useThree();
  scene.add(particleSystem);

  useFrame((state) => {
    if (particleSystem && particleSystem.material)
      particleSystem.material.uTime = state.clock.elapsedTime;
  });

I left the geometry part out, since the random distribution of the particles work. They show up just fine, but they won’t animate.

Does anybody know what I’m doing wrong?

I found the culprits:
A) The uniforms should be declared as:

uTime: {
    value: 0.0
  },

B) I forgot “.uniforms”

useFrame((state) => {
    sparkleMaterial.uniforms.uTime = state.clock.elapsedTime;
  });

Here’s a working Fiddle:

2 Likes