본문 바로가기

3D Project/3D 인터랙티브 웹

[3D 인터랙티브 웹] 파티클 시스템/애니메이션 만들기 by Three.js

파티클 시스템 구축 -> 렌더링 최적화를 위해 파티클은 여러개의 3D 동그라미 모델링을 띄우는게 아니라 여러좌표에 동그라미 이미지를 띄우는 방식으로 파티클을 구축한다.

  • BufferGeometry - 정점의 개수와 좌표를 지정할 수 있음.
  • PointsMaterial - 모델링의 정점을 점으로 시각화 시켜주는 메터리얼, Three.js에서 파티클 전용으로 만들어 놓은 메터리얼

파티클 시스템 구현 순서

  1. 파티클이 생성될 위치 넣기 - Geometry 생성
  2. 파티클 Material 생성
  3. 파티클로 합성
//create Particle
//파티클 위치 입력하기
let positions = []; //모든 파티클의 위치값을 배열에 넣을것임

// positions.push(Math.random()*2 -1); //0~1 -> -1 ~ 1
for(let i=0; i<1000; i++){
    positions.push((Math.random()*2 -1)*30);  //x -> -30~30
    positions.push((Math.random()*2 -1)*30);  //y
    positions.push((Math.random()*2 -1)*30);  //z
}
const particlePosition = new THREE.BufferGeometry(); //Jacascript 데이터를 통해서 모델링을 해주는 class
particlePosition.setAttribute("position", new THREE.BufferAttribute(new Float32Array(positions),3))

// console.log(particlePosition)

const particleMaterial = new THREE.PointsMaterial(); //PointMaterial은 기본값으로 흰색 네모로 형성됨
const particle = new THREE.Points(particlePosition, particleMaterial)
scene.add(particle);

+particle 원형으로 바꾸기 -> image texture 적용

const particleMaterial = new THREE.PointsMaterial({
    size:0.5,
    map: new THREE.TextureLoader().load("/particle/circle.png"), //네모 위에 이미지 텍스처 입히기
    // color: new THREE.Color("yellow"),
    color: new THREE.Color("hsl(200,50%,50%)"),
    //동그라미 이미지 주변의 검정색 없애기
    transparent: true,
    blending: THREE.AdditiveBlending,
    depthWrite:false,
}); //PointMaterial은 기본값으로 흰색 네모로 형성됨
const particle = new THREE.Points(particlePosition, particleMaterial)
scene.add(particle);

function render() {
    requestAnimationFrame(render);
    controls.update();
    //02. move particles
    renderer.render(scene, camera);
}

 

구름 효과 적용하기 -> 파티클과 동일한 방식으로 적용

//create cloud particle - 구름 파티클
let cloudPositions = []; //모든 파티클의 위치값을 배열에 넣을것임

// positions.push(Math.random()*2 -1); //0~1 -> -1 ~ 1
for(let i=0; i<300; i++){
    cloudPositions.push((Math.random()*2 -1)*50);  //x -> -30~30
    cloudPositions.push((Math.random()*2 -1)*30);  //y
    cloudPositions.push((Math.random()*2 -1)*50);  //z
}

const cloudParticlePosition = new THREE.BufferGeometry(); //Jacascript 데이터를 통해서 모델링을 해주는 class
cloudParticlePosition.setAttribute(
    "position",
    new THREE.BufferAttribute(new Float32Array(cloudPositions),3)
);

// console.log(particlePosition)

const cloudParticleMaterial = new THREE.PointsMaterial({
    size:80,
    map: new THREE.TextureLoader().load("/particle/cloud.png"), //네모 위에 이미지 텍스처 입히기
    color: new THREE.Color("hsl(200,50%,50%)"),
    transparent: true,
    blending: THREE.AdditiveBlending,
    depthWrite:false,
    opacity: 0.08,
});
const cloudParticle = new THREE.Points(cloudParticlePosition,cloudParticleMaterial)
scene.add(cloudParticle);

 

파티클과 구름 애니메이션 적용

function render() {
    requestAnimationFrame(render);
    controls.update();
    //02. move particles
    particle.rotation.y += 0.001;
    cloudParticle.rotateY += 0.002;
    renderer.render(scene, camera);
}

 

파티클의 움직임을 무작위로 적용하기(둥실둥실 띄우는 방법) -> 파티클 애니메이션

let time = 0;
// console.log(particlePosition);

function render() {
    requestAnimationFrame(render);
    controls.update();
    //02. move particles
    // particle.rotation.y += 0.001;
    // cloudParticle.rotateY += 0.002;
    time += 0.002;
    for(let i=0; i<1000; i++){
        const yIndex = i*3 + 1;
        particlePosition.attributes.position.array[yIndex] =
            positions[yIndex] + 5 * Math.sin(i + time);
    }
    particlePosition.attributes.position.needsUpdate = true;
    renderer.render(scene, camera);
}

 

파티클 애니메이션 렌더링 결과