1

I'm trying to animate the color transition for ShaderMaterial. I want to have 5 colors, and switch them every few seconds for a whole object (wave of particles).

Here is my JS code

var material = new THREE.ShaderMaterial( {
    uniforms: {
      color: { value: new THREE.Color('violet') },
    },
    vertexShader: document.getElementById( 'vertexshader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentshader' ).textContent
  });

And fragment shader part:

   uniform vec3 color;
   void main() {
      if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard; 
      gl_FragColor = vec4(color, 1.0 );
    }

I have just a little idea of how three.js works. Any suggestions highly appreciated! :)

All code is here: codepen.io/agrhff/pen/MWKEqQy

0

1 Answer 1

1

As an option, you can use setInterval():

body {
  background-color: black;
  overflow: hidden;
  margin: 0;
}
<script type="x-shader/x-vertex" id="vertexshader">

  attribute float scale;

  void main() {

    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );

    gl_PointSize = scale * ( 300.0 / - mvPosition.z );

    gl_Position = projectionMatrix * mvPosition;

  }

</script>

<script type="x-shader/x-fragment" id="fragmentshader">
  uniform vec3 color;
  void main() {


    if ( length( gl_PointCoord - 0.5 ) > 0.475 ) discard;

    gl_FragColor = vec4(color, 1.0 );

  }

</script>
<script type="module">
import * as THREE from 'https://threejs.org/build/three.module.js';

import Stats from 'https://threejs.org/examples/jsm/libs/stats.module.js';

var SEPARATION = 100, AMOUNTX = 150, AMOUNTY = 100;

var container, stats;
var camera, scene, renderer;

var particles, count = 0;

var mouseX = 0, mouseY = -500;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

var colors = [
  new THREE.Color(0xffff00),
  new THREE.Color(0xff00ff),
  new THREE.Color(0x00ffff),
  new THREE.Color(0xffffff),
  new THREE.Color(0x888888)
];
var colIdx = 0;

init();
animate();

function init() {

  container = document.createElement( 'div' );
  container.classList.add("mystyle");
  document.body.appendChild( container );

  camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
  camera.position.z = 1000;
  scene = new THREE.Scene();

  //

  var numParticles = AMOUNTX * AMOUNTY;

  var positions = new Float32Array( numParticles * 3 );
  var scales = new Float32Array( numParticles );
  
  var i = 0, j = 0;

  for ( var ix = 0; ix < AMOUNTX; ix ++ ) {

    for ( var iy = 0; iy < AMOUNTY; iy ++ ) {

      positions[ i ] = ix * SEPARATION - ( ( AMOUNTX * SEPARATION ) / 2 ); // x
      positions[ i + 1 ] = 0; // y
      positions[ i + 2 ] = iy * SEPARATION - ( ( AMOUNTY * SEPARATION ) / 2 ); // z

      scales[ j ] = 1;

      i += 3;
      j ++;

    }

  }
  
  var geometry = new THREE.BufferGeometry();
  geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
  geometry.setAttribute( 'scale', new THREE.BufferAttribute( scales, 1 ) );

  
  var material = new THREE.ShaderMaterial( {
    uniforms: {
      color: { value: new THREE.Color('violet') }
    },
    vertexShader: document.getElementById( 'vertexshader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentshader' ).textContent

  } );

  //

  particles = new THREE.Points( geometry, material);
  scene.add( particles );

  //

  renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
  renderer.setPixelRatio( window.devicePixelRatio );
  renderer.setSize( window.innerWidth, window.innerHeight );
  container.appendChild( renderer.domElement );
  stats = new Stats();
  container.appendChild( stats.dom );

  document.addEventListener( 'mousemove', onDocumentMouseMove, false );
  document.addEventListener( 'touchstart', onDocumentTouchStart, false );
  document.addEventListener( 'touchmove', onDocumentTouchMove, false );

  //

  window.addEventListener( 'resize', onWindowResize, false );
  
  // change the colours, one a second
  setInterval(function(){
    colIdx = (colIdx + 1) % 5;;
    material.uniforms.color.value.copy(colors[colIdx]);
  }, 1000);

}

function onWindowResize() {

  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

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

}

//

function onDocumentMouseMove( event ) {

  mouseX = event.clientX - windowHalfX;
  // mouseY = event.clientY - windowHalfY;

}

function onDocumentTouchStart( event ) {

  if ( event.touches.length === 1 ) {

    event.preventDefault();

    mouseX = event.touches[ 0 ].pageX - windowHalfX;
    // mouseY = event.touches[ 0 ].pageY - windowHalfY;

  }

}

function onDocumentTouchMove( event ) {

  if ( event.touches.length === 1 ) {

    event.preventDefault();

    mouseX = event.touches[ 0 ].pageX - windowHalfX;
    // mouseY = event.touches[ 0 ].pageY - windowHalfY;

  }

}

//

function animate() {

  requestAnimationFrame( animate );

  render();
  stats.update();

}

function render() {

  camera.position.x += ( mouseX - camera.position.x ) * .05;
  camera.position.y += ( - mouseY - camera.position.y );
  camera.lookAt( scene.position );

  var positions = particles.geometry.attributes.position.array;
  var scales = particles.geometry.attributes.scale.array;

  var i = 0, j = 0;

  for ( var ix = 0; ix < AMOUNTX; ix ++ ) {

    for ( var iy = 0; iy < AMOUNTY; iy ++ ) {

      positions[ i + 1 ] = ( Math.sin( ( ix + count ) * 0.3 ) * 50 ) +
        ( Math.sin( ( iy + count ) * 0.5 ) * 50 );

      scales[ j ] = ( Math.sin( ( ix + count ) * 0.3 ) + 1 ) * 8 +
        ( Math.sin( ( iy + count ) * 0.5 ) + 1 ) * 8;

      i += 3;
      j ++;

    }

  }

  particles.geometry.attributes.position.needsUpdate = true;
  particles.geometry.attributes.scale.needsUpdate = true;

  renderer.render( scene, camera );

  count += 0.1;

}
</script>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.