以前、 Three.js で EffectComposer の UnrealBloomPass を試しました。
今回は、EffectComposer の GlitchPass を試してみました。
ソースコード
app/src/page.tsx
'use client'; import { useEffect, useRef } from 'react'; import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'; import { GlitchPass } from 'three/examples/jsm/postprocessing/GlitchPass'; import { useOrbitControls } from '@/hooks/useOrbitControls'; import { useEffectComposer } from '@/hooks/useEffectComposer'; import { useResize } from '@/hooks/useResize'; import { useThree } from '@/hooks/useThree'; export default function GlitchPassPage() { const canvasRef = useRef<HTMLCanvasElement>(null); const { windowWidth, windowHeight } = useResize(); const { THREE, renderer, camera, scene } = useThree(canvasRef.current); const effectComposer = useEffectComposer(renderer); const orbitControls = useOrbitControls(camera, canvasRef.current); useEffect(() => { if (!renderer || !camera || !effectComposer || !orbitControls) { return; } camera.position.set(4, 4, 8); camera.lookAt(new THREE.Vector3(0, 0, 0)); const cube = new THREE.Mesh( new THREE.BoxGeometry(1, 1, 1), new THREE.MeshNormalMaterial() ); scene.add(cube); renderer.setClearColor(0x000000, 1); const light = new THREE.DirectionalLight(0xFFFFFF); light.position.set(1, 1, 1); scene.add(light) effectComposer.addPass( new RenderPass(scene, camera) ); effectComposer.addPass(new GlitchPass()); renderer.setAnimationLoop(() => { orbitControls.update(); effectComposer.render(); }); }, [renderer, camera, scene, effectComposer, orbitControls]); useEffect(() => { if (!renderer || !camera || !effectComposer) { return; } renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(windowWidth, windowHeight); effectComposer.setSize(windowWidth, windowHeight); camera.aspect = windowWidth / windowHeight; camera.updateProjectionMatrix(); }, [renderer, camera, effectComposer, windowWidth, windowHeight]); return ( <canvas ref={ canvasRef } /> ); }
src/hooks/useOrbitControls.tsx
import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; export function useOrbitControls(camera: THREE.PerspectiveCamera | undefined, canvas: HTMLCanvasElement | null) { if (!camera || !canvas) { return; } const orbitControls = new OrbitControls(camera, canvas); return orbitControls; }
src/hooks/useEffectComposer.tsx
import * as THREE from 'three'; import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'; export function useEffectComposer( renderer: THREE.WebGLRenderer | undefined ) { if (!renderer) { return; } const effectComposer = new EffectComposer(renderer); return effectComposer; }
src/hooks/useResize.tsx
import { useEffect, useState } from 'react'; export function useResize() { const [ windowWidth, setWindowWidth ] = useState(0); const [ windowHeight, setWindowHeight ] = useState(0); useEffect(() => { window.removeEventListener('resize', handleResize); window.addEventListener('resize', handleResize, { passive: true }); handleResize(); return () => { window.removeEventListener('resize', handleResize); } }, []); function handleResize() { setWindowWidth(window.innerWidth); setWindowHeight(window.innerHeight); } return { windowWidth, windowHeight }; }
src/hooks/useThree.tsx
import { useEffect, useState } from 'react'; import * as THREE from 'three' export function useThree(canvas: HTMLCanvasElement | null) { const [ renderer, setRenderer ] = useState<THREE.WebGLRenderer>(); const [ camera, setCamera ] = useState<THREE.PerspectiveCamera>(); const [ scene ] = useState<THREE.Scene>(new THREE.Scene); useEffect(() => { if (!canvas) { return; } setRenderer(new THREE.WebGLRenderer({ canvas, antialias: true, alpha: true })); }, [canvas]); useEffect(() => { if (!renderer) { return; } setCamera(new THREE.PerspectiveCamera()); }, [renderer]); return { THREE, renderer, camera, scene }; }
基本的には、
effectComposer.addPass(new GlitchPass());
で、グリッチが掛かります。
ソースコードを見ると、GlitchPassのコンストラクタは引数(dt_size)をとります。
dt_size = 1
dt_size = 100
1と100ではこれぐらい違いが出ます。(デフォルトは64)
グリッチがかかる周期とかも制御できると嬉しいのですが、お手軽な反面自由度は低いです。