Intro.
최근에 재밌게 보고 있는 유투버 겸 개발자 (Yuri Artikuh) 스트리밍 영상들을 통해 이런 저런 기법들 배우는 게 많아서 영상 따라 공부하며 배운것들을 공유해보자고 한다.
영상에서 얻어간 것은 다음과 같다.
- 이미지를 어떻게 입자화 시킬 것인가?
- 입자들에 넣는 반짝이는 이펙트는 어떻게 구현한 것인가?
- 비디오와 Three.js 간 동기화 + 애니메이션 처리는 어떻게 할 것인가?
- 안보이는 입자 제거를 통해 gpu성능 최적화
1. 이미지를 어떻게 입자화 시키는가?
3가지 스텝으로 이루어진다.
먼저, geometry 와 material을 일반적인 Mesh에 연결시키는것이 아닌, Points 객체에 연결시킨다.
const geometry = new THREE.PlaneGeometry(480 * 1.77, 820 * 1.77, 480, 820);
const points = new THREE.Points(geometry, material);
다음으로, vertex shader에서 제공되는 gl_PointSize 값으로 입자의 크기를 조절할 수 있다.
gl_PointSize = 2.
마지막으로 fragment shader에서 텍스쳐를 추출해, 색상값으로 사용하면 텍스쳐를 입자화 시킬 수 있다.
vec4 tt = texture2D(t, vUv);
vec4 finalTexture = tt;
gl_FragColor = finalTexture;
2. 입자들에 넣는 반짝이는 이펙트는 어떻게 구현한 것인가?
이 이펙트에 이름이 있는 줄은 몰랐는데, Bloom 이펙트라고 한다.
Three.js에서 제공하는 BloomPath 후처리기를 이용하여 적용할 수 있다.
먼저 후처리 패스 형성을 위해 모듈들을 임포트 한다.
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
후처리 파이프라인 형성을 한다. 이 글에서는 사실상 bloomStrength값 컨트롤로 구현할 수 있기에, threshold, radius는 생략 가능하다.
const renderScene = new RenderPass(scene, camera);
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5,
0.4,
0.85
);
bloomPass.threshold = settings.bloomThreshold;
bloomPass.strength = settings.bloomStrength;
bloomPass.radius = settings.bloomRadius;
const composer = new EffectComposer(renderer);
composer.addPass(renderScene);
composer.addPass(bloomPass);
3. 비디오와 Three.js간 동기화를 어떻게 처리할 것인가?
동기화 후 각종 애니메이션을 구성하기 위해 gsap모듈을 사용하였다.
gsap모듈의 존재는 알고는 있었으나, 이번 공부를 통해 정말 그 효용성을 극히 체감할 수 있었다.
video 요소에 'ended' 이벤트 리스너를 달고, gsap모듈을 통해, 애니메이션 파이프라인을 구성한다.
const video = document.getElementById("video1");
video.addEventListener("ended", () => {
gsap.to(video, {
duration: 0.1,
opacity: 0,
});
gsap.to(material.uniforms.distortion, {
duration: 2,
value: 3,
ease: "power2.inOut",
});
gsap.to(bloomPass, {
duration: 2,
strength: 7,
ease: "power2.in",
});
gsap.to(material.uniforms.progress, {
duration: 1,
value: 1,
ease: "power2.in",
delay: 1.5,
});
gsap.to(material.uniforms.distortion, {
duration: 2,
value: 0,
delay: 2,
ease: "power2.inOut",
});
gsap.to(bloomPass, {
duration: 2,
strength: 0,
delay: 2,
ease: "power2.out",
onComplete: () => {
video.currentTime = 0;
video.play();
gsap.to(video, {
duration: 0.1,
opacity: 1,
});
},
});
여기서 텍스쳐 전환을 위해 progress라는 값을 추가하였다.
이 progress값이 텍스쳐간 전환을 위한 키인데, fragment shader에 이 값에 의존하여 각 텍스쳐를 mix했다.
vec4 tt = texture2D(t, vUv);
vec4 tt1 = texture2D(t1, vUv);
vec4 finalTexture = mix(tt, tt1, progress);
gl_FragColor = finalTexture;
4. 안보이는 입자 제거를 통해 gpu 최적화
인간의 눈이 그리 예민하지 않기에 보일랑 말랑 하는 입자들을 애당초 렌더링하지 않는다면 당연하지만 성능향상에 도움이 된다.
fragment shader에서 특정 임계값을 기준으로 discard 처리한다.
if(gl_FragColor.r < 0.1 && gl_FragColor.b < 0.1 && gl_FragColor.g < 0.1){
discard;
}
'Gen Art' 카테고리의 다른 글
[WebGL] - case study : The Avener (0) | 2024.07.15 |
---|---|
Shattering Text Animation 제작기 (2) | 2024.06.06 |
[Javascript] 폭죽 이펙트 (fireworks) (3) | 2023.05.29 |