Shader 转场

Starter pack

在本课中,我们将学习如何使用 shaders 创建转场效果。

我们将创建的第一个效果是屏幕转场效果:

我们可以完全控制转场效果,可以更改持续时间、缓动函数以及 shader 本身。

我们将创建的第二个效果是模型转场效果:

在淡出时,模型会溶解并且颜色渐变为白色,淡入时则相反。

启动包

以下是本课中使用的所有 3D 模型,由 Ergoni 提供并授权于 Creative Commons Attribution

启动包使用了以下软件包:

使用的两个字体是 KanitRubik Doodle Shadow,均来自 Google Fonts.

可以随意根据你的喜好调整任何组件。

您可以通过在右上角使用 Leva 控件来调整颜色。一旦找到满意的颜色,将 hidden 属性添加到 App.jsx 中的 Leva 组件:

// ...

function App() {
  // ...
  return (
    <>
      <Leva hidden />
      {/* ... */}
    </>
  );
}

// ...

屏幕过渡效果

让我们开始创建屏幕过渡效果。我们将制作一个名为 ScreenTransition 的组件来处理过渡效果。

components 文件夹中创建一个新文件,名为 ScreenTransition.jsx

export const ScreenTransition = ({ transition, color }) => {
  return (
    <mesh>
      <planeGeometry args={[2, 2]} />
      <meshBasicMaterial color={color} />
    </mesh>
  );
};

在这个组件中,我们创建了一个完整覆盖屏幕的彩色平面。我们将使用这个平面在屏幕之间进行过渡。

我们的组件接收两个 props:

  • transition:一个布尔值,用于判断组件是否应该显示过渡效果
  • color:过渡效果的主色

让我们将 ScreenTransition 组件添加到 App.jsx 中:

// ...
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;

目前,我们通过传递 true 强制显示过渡效果。稍后我们将添加控制过渡效果的逻辑。

根据您的喜好调整颜色。如果更改,请确保在 index.css 文件中更新颜色,以避免网站加载时颜色闪烁:

// ...

html {
  background-color: #a5b4fc;
}

场景中间的平面

平面在场景的中间。

全屏平面

我们希望我们的平面覆盖整个屏幕。我们可以使用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 来轻松覆盖整个屏幕,无论相机和平面之间的距离是多少。

Plane covering the entire screen

平面现在覆盖了整个屏幕。

转场逻辑

在创建我们的自定义 shader 之前,最后一件事是在 UI.jsx 中定义一个 transition 状态:

// ...
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

homemenu

<motion.button
  onClick={() => transitionToScreen("menu")}
  // ...
>

menuhome

<motion.button
onClick={() => transitionToScreen("home")}
// ...
>
Three.js logoReact logo

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
Unlock the Full Course – Just $85

One-time payment. Lifetime updates included.