; }"> ; }"> ; }">
export default function TestObj() {
	const meshRef = useRef();
	const geoRef = useRef();
	const shaderRef = useRef();
	const uniforms = useMemo( ()=>({lerp: {value: 0}}), [] );
	objectLogger.add("mesh", meshRef.current);
	objectLogger.add("geo", geoRef.current);
	objectLogger.add("mat", shaderRef.current);
	objectLogger.add("uniforms", uniforms);
	objectLogger.add("mat-uniform", shaderRef.current?.uniforms);

	return <mesh position-x={1} ref={meshRef}>
		<boxGeometry ref={geoRef}/>
		<shaderMaterial 
			vertexShader={vertexShader}
			fragmentShader={fragmentShader}
			uniforms={ uniforms }
			ref={shaderRef}
		/>
	</mesh>;
}

TestObj를 리렌더링하면, meshRef, geoRef, shaderRef는 동일한 값을 유지한다. 하지만 uniforms는 매번 다른 값을 가진다. useRef는 컴포넌트의 생명주기마다 동일한 값을 유지하지만(아무리 리렌더링이 일어나도 똑같은 값을 참조함), useMemo는 useEffect와 비슷하게 뒤에 있는 배열의 원소 값(즉 의존하는 값)이 변경될 때마다 함수를 호출해서 값을 반환한다. useMemo의 함수가 반환하는 객체가 매번 달라진다는 점을 주목해라.

export default function TestObj() {
	const [lerpTo, setLerpTo] = useState(0);
	const { lerpValue } = useSpring({lerpValue: lerpTo});

	const meshRef = useRef();
	const geoRef = useRef();
	const shaderRef = useRef();
	// const uniforms = useRef({lerp: {value: 0}});
	const uniforms = useMemo( ()=>({lerp: {value: 0}}), [] );
	const lerp = useMemo( ()=>lerpValue.to([0,1], [0,1]), [] );

	objectLogger.add("mesh", meshRef.current);
	objectLogger.add("geo", geoRef.current);
	objectLogger.add("mat", shaderRef.current);
	objectLogger.add("uniforms", uniforms);
	objectLogger.add("mat-uniform", shaderRef.current?.uniforms);
	objectLogger.add("uniforms-lerp", uniforms.lerp);

	function onClick() {
		setLerpTo( e=>+!e );
	}

	return <mesh position-x={1} onClick={onClick} ref={meshRef}>
		<boxGeometry ref={geoRef}/>
		<animated.shaderMaterial 
			vertexShader={vertexShader}
			fragmentShader={fragmentShader}
			uniforms={ uniforms}
			uniforms-lerp-value={ lerp }
			ref={shaderRef}
		/>
	</mesh>;
}

three.js의 셰이더 매터리얼은 최초로 생성된 uniforms 객체를 셰이더에 부착하고, uniforms 객체의 상태가 바뀔 때마다 셰이더에 uniforms의 값을 자동으로 넘겨준다. 그런데, 컴포넌트가 리렌더링되어서 useMemo가 호출되어 유니폼 객체가 새로 생성되고, shaderMaterial의 uniforms 프로퍼티를 덮어씌우면 three.js는 자동으로 프로퍼티에 새로 할당된 객체를 셰이더에 자동으로 할당해주지 않는다! 따라서 shaderMaterial의 uniforms는 열심히 바뀌고 있지만 이 객체는 실제 셰이더에 부착된 객체가 아니므로 셰이더는 uniforms의 값 변경을 감지하지 못한다.

해결방법은 간단하다. uniforms 객체를 useMemo가 아닌 useRef로 선언해서 컴포넌트의 생명주기마다 동일한 값을 유지시키는 것이다. 이러면 실제로 셰이더에 부착된 객체를 컴포넌트가 리렌더링해도 계속 참조할 수 있으므로 셰이더를 변경시킬 수 있다.