Three JS Tutorial – Three Particle Morphing Text


Rengga Dev – Particle morphing text with Three.js.

// Options
const particleCount = 6000;
        
const particleSize = .3;

const defaultAnimationSpeed = 1,
        morphAnimationSpeed = 18,
      	color = '#FFFFFF';

// Triggers
const triggers = document.getElementsByTagName('span')

// Renderer
var renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

// Ensure Full Screen on Resize
function fullScreen () {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

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

window.addEventListener('resize', fullScreen, false)

// Scene
var scene = new THREE.Scene();

// Camera and position
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );

camera.position.y = -45;
camera.position.z = 45;

// Lighting
var light = new THREE.AmbientLight( 0xFFFFFF, 1 );
scene.add( light );

// Orbit Controls
var controls = new THREE.OrbitControls( camera );
controls.update();

// Particle Vars
var particles = new THREE.Geometry();

var texts = [];

var pMaterial = new THREE.PointCloudMaterial({
            size: particleSize,
});

// Texts
var loader = new THREE.FontLoader();
var typeface = 'https://dl.dropboxusercontent.com/s/bkqic142ik0zjed/swiss_black_cond.json?';

loader.load( typeface, ( font ) => {
    Array.from(triggers).forEach((trigger, idx) => {
        
        texts[idx] = {};
        
        texts[idx].geometry = new THREE.TextGeometry( trigger.textContent, {
            font: font,
            size: window.innerWidth * 0.02,
            height: 4,
            curveSegments: 10,
        });
        
        THREE.GeometryUtils.center( texts[idx].geometry )
            

        texts[idx].particles = new THREE.Geometry();

        texts[idx].points = THREE.GeometryUtils.randomPointsInGeometry(texts[idx].geometry, particleCount);

        createVertices(texts[idx].particles, texts[idx].points)

        enableTrigger(trigger, idx);
        
    });
});

// Particles
for (var p = 0; p < particleCount; p++) {
    var vertex = new THREE.Vector3();
            vertex.x = 0;
            vertex.y = 0;
            vertex.z = 0;

    particles.vertices.push(vertex);
}

function createVertices (emptyArray, points) {
    for (var p = 0; p < particleCount; p++) {
        var vertex = new THREE.Vector3();
                vertex.x = points[p]['x'];
                vertex.y = points[p]['y'];
                vertex.z = points[p]['z'];

        emptyArray.vertices.push(vertex);
    }
}

function enableTrigger(trigger, idx){
    
    
    trigger.setAttribute('data-disabled', false);
    
    trigger.addEventListener('click', () => {
        morphTo(texts[idx].particles, trigger.dataset.color);
    })
    
    if (idx == 0) {
        morphTo(texts[idx].particles, trigger.dataset.color);
    }
}

var particleSystem = new THREE.PointCloud(
    particles,
    pMaterial
);

particleSystem.sortParticles = true;

// Add the particles to the scene
scene.add(particleSystem);

// Animate
const normalSpeed = (defaultAnimationSpeed/100),
            fullSpeed = (morphAnimationSpeed/100)

let animationVars = {
    speed: normalSpeed,
    color: color,
    rotation: -45
}


function animate() {
    
    particleSystem.rotation.y += animationVars.speed;
    particles.verticesNeedUpdate = true; 
    
    camera.position.z = animationVars.rotation;
    camera.position.y = animationVars.rotation;
    camera.lookAt( scene.position );
    
    particleSystem.material.color = new THREE.Color( animationVars.color );
    
    window.requestAnimationFrame( animate );
    renderer.render( scene, camera );
}

animate();

function morphTo (newParticles, color = '#FFFFFF') {
    
    TweenMax.to(animationVars, .1, {
        ease: Power4.easeIn, 
        speed: fullSpeed, 
        onComplete: slowDown
    });
    
    TweenMax.to(animationVars, 2, {
        ease: Linear.easeNone, 
        color: color
    });
    
    
    // particleSystem.material.color.setHex(color);
    
    for (var i = 0; i < particles.vertices.length; i++){
        TweenMax.to(particles.vertices[i], 2, {
            ease: Elastic.easeOut.config( 0.1, .3), 
            x: newParticles.vertices[i].x,
            y: newParticles.vertices[i].y, 
            z: newParticles.vertices[i].z
        })
    }
    
    console.log(animationVars.rotation)
    
    TweenMax.to(animationVars, 2, {
        ease: Elastic.easeOut.config( 0.1, .3), 
        rotation: animationVars.rotation == 45 ? -45 : 45,
    })
}
function slowDown () {
    TweenMax.to(animationVars, 0.3, {ease:
Power2.easeOut, speed: normalSpeed, delay: 0.2});
}

 

Nandemo Webtools

Leave a Reply