Shader 전환
이 강의에서는 셰이더를 사용하여 전환 효과를 만드는 방법을 배워봅니다.
첫 번째로 만들 효과는 화면 전환 효과입니다:
전환 효과에 대한 완전한 제어가 가능하며, 지속 시간, 이징 함수 및 셰이더 자체를 변경할 수 있습니다.
두 번째로 만들 효과는 모델 전환 효과입니다:
모델이 사라질 때 흰색으로 녹아내리고 색상이 바뀌며, 반대의 경우도 마찬가지입니다.
시작 패키지
이 강의에서 사용할 모든 3D 모델은 Ergoni의 작품으로, Creative Commons Attribution에 따라 라이선스가 부여되었습니다:
시작 패키지에서 사용되는 패키지는 다음과 같습니다:
- 스타일링을 위한 Tailwind CSS
- 애니메이션을 위한 Framer Motion
- 컴포넌트 간의 상태 공유 관리를 위한 Jotai 라이브러리
사용된 폰트는 Google Fonts의 Kanit와 Rubik Doodle Shadow입니다.
컴포넌트는 자유롭게 조정하여 원하는 대로 설정하실 수 있습니다.
Leva 컨트롤을 오른쪽 상단에서 조작하여 색상을 조정할 수 있습니다. 원하는 색상을 찾았으면, App.jsx의 Leva 컴포넌트에 hidden 속성을 추가하세요:
// ... function App() { // ... return ( <> <Leva hidden /> {/* ... */} </> ); } // ...
화면 전환
화면 전환 효과를 만들면서 시작해 봅시다. 우리는 전환 효과를 처리할 ScreenTransition이라는 컴포넌트를 만들 것입니다.
components 폴더에 ScreenTransition.jsx라는 새 파일을 만듭니다:
export const ScreenTransition = ({ transition, color }) => { return ( <mesh> <planeGeometry args={[2, 2]} /> <meshBasicMaterial color={color} /> </mesh> ); };
이 컴포넌트에서는 화면 전체를 덮을 색상의 plane을 만들고 있습니다. 이 plane을 사용하여 화면 간 전환을 수행할 것입니다.
우리의 컴포넌트는 두 개의 props를 받습니다:
- transition: 컴포넌트가 전환 효과를 표시해야 하는지 여부를 결정하는 boolean 값
- color: 전환 효과의 주요 색상
App.jsx에 ScreenTransition 컴포넌트를 추가합시다:
// ... import { ScreenTransition } from "./components/ScreenTransition"; function App() { // ... return ( <> {/* ... */} <Canvas camera={{ position: [0, 1.8, 5], fov: 42 }}> <color attach="background" args={[backgroundColor]} /> <fog attach="fog" args={[backgroundColor, 5, 12]} /> <ScreenTransition transition color="#a5b4fc" /> <Suspense> <Experience /> </Suspense> </Canvas> </> ); } export default App;
현재는 transition prop에 true를 전달하여 전환 효과를 강제로 표시하도록 하고 있습니다. 나중에 전환 효과를 제어하는 로직을 추가할 것입니다.
색상을 원하는 대로 조정하세요. 색상을 변경하면, 웹 사이트가 로드될 때 색상이 깜빡이는 것을 방지하기 위해 index.css 파일의 색상도 업데이트하세요:
// ... html { background-color: #a5b4fc; }
plane가 장면의 정중앙에 위치해 있습니다.
전체 화면을 덮는 평면
우리의 평면이 화면 전체를 덮기를 원합니다. viewport 크기를 사용하여 카메라를 바라보게 만들 수 있지만, 우리는 또한 그것이 모든 것 위에 위치하기를 원합니다.
이를 달성하기 위해 Drei는 모든 것 위에 자식을 렌더링하는 Hud 컴포넌트를 제공합니다. Hud 컴포넌트에 고정 카메라를 추가하여 평면과 완벽하게 정렬되도록 할 수 있습니다:
import { Hud, OrthographicCamera } from "@react-three/drei"; export const ScreenTransition = ({ transition, color }) => { return ( <Hud> <OrthographicCamera makeDefault top={1} right={1} bottom={-1} left={-1} near={0} far={1} /> <mesh> <planeGeometry args={[2, 2]} /> <meshBasicMaterial color={color} /> </mesh> </Hud> ); };
OrthographicCamera를 사용하여 카메라와 평면 사이의 거리와 상관없이 쉽게 전체 화면을 덮을 수 있습니다.
평면이 이제 화면 전체를 덮고 있습니다.
전환 논리
커스텀 셰이더를 만들기 전에 마지막으로 UI.jsx
에서 전환 상태를 정의해 봅시다:
// ... import { atom } from "jotai"; export const transitionAtom = atom(true); // ...
웹사이트가 로드된 후 페이드 아웃 효과를 시작하기 위해 초기 값을 true로 설정합니다.
이 상태를 사용하여 전환 효과를 제어할 것입니다.
여전히 UI.jsx
에서 전환 효과의 지속 시간과 지연을 제어할 두 개의 상수를 정의하겠습니다:
// ... export const TRANSITION_DELAY = 0.8; export const TRANSITION_DURATION = 3.2; // ...
이제 setScreen
함수 호출을 전환 효과를 처리할 새로운 함수로 교체해 봅시다:
// ... import { useAtom } from "jotai"; import { useRef } from "react"; // ... export const UI = () => { // ... const [transition, setTransition] = useAtom(transitionAtom); const timeout = useRef(); // ... const transitionToScreen = (newScreen) => { setTransition(true); clearTimeout(timeout.current); timeout.current = setTimeout(() => { setScreen(newScreen); setTransition(false); }, TRANSITION_DURATION * 1000 + TRANSITION_DELAY * 1000); }; // ... };
직접 새로운 화면을 설정하는 대신, transition 상태를 true로 설정하고 setTimeout을 사용하여 전환 효과가 끝난 후 (전환 효과의 지속 시간과 지연의 합) 새로운 화면을 설정합니다.
이제 함수가 준비되었으니, UI
컴포넌트에서 setScreen
호출을 찾아 transitionToScreen
으로 교체하세요.
홈에서 메뉴로:
<motion.button onClick={() => transitionToScreen("menu")} // ... >
그리고 메뉴에서 홈으로:
<motion.button onClick={() => transitionToScreen("home")} // ... >
React Three Fiber: The Ultimate Guide to 3D Web Development
✨ You have reached the end of the preview ✨
Go to the next level with Three.js and React Three Fiber!
Get full access to this lesson and the complete course when you enroll:
- 🔓 Full lesson videos with no limits
- 💻 Access to the final source code
- 🎓 Course progress tracking & completion
- 💬 Invite to our private Discord community
One-time payment. Lifetime updates included.