Chuyển cảnh bằng Shader

Starter pack

Trong bài học này, chúng ta sẽ học cách tạo chuyển cảnh bằng cách sử dụng shaders.

Hiệu ứng đầu tiên chúng ta sẽ tạo là hiệu ứng chuyển cảnh màn hình:

Chúng ta có thể hoàn toàn kiểm soát hiệu ứng chuyển cảnh, thay đổi thời lượng, hàm easing, và chính shader đó.

Hiệu ứng thứ hai chúng ta sẽ tạo là hiệu ứng chuyển cảnh cho mô hình:

Khi mô hình mờ dần, nó sẽ bị tan rã và màu sắc dần chuyển sang trắng, điều ngược lại xảy ra khi nó xuất hiện.

Gói khởi động

Dưới đây là tất cả các mô hình 3D mà chúng ta sẽ sử dụng trong bài học này của Ergoni và được cấp phép theo Creative Commons Attribution:

Gói khởi động sử dụng các thư viện sau:

Hai phông chữ được sử dụng là KanitRubik Doodle Shadow, cả hai đều từ Google Fonts.

Hãy thoải mái điều chỉnh bất kỳ thành phần nào theo ý thích của bạn.

Bạn có thể điều chỉnh màu sắc bằng cách thử nghiệm với các điều khiển Leva ở góc trên bên phải. Khi bạn tìm thấy màu sắc ưa thích, hãy thêm thuộc tính hidden vào thành phần Leva trong App.jsx:

// ...

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

// ...

Chuyển đổi màn hình

Hãy bắt đầu bằng cách tạo hiệu ứng chuyển đổi màn hình của chúng ta. Chúng ta sẽ tạo một component gọi là ScreenTransition để xử lý hiệu ứng chuyển đổi.

Hãy tạo một file mới gọi là ScreenTransition.jsx trong thư mục components:

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

Trong component này, chúng ta đang tạo một plane với một màu sắc sẽ bao phủ toàn bộ màn hình. Chúng ta sẽ sử dụng plane này để chuyển đổi giữa các màn hình.

Component của chúng ta nhận hai props:

  • transition: một boolean để biết liệu component có nên hiển thị hiệu ứng chuyển đổi không
  • color: màu chủ đạo của hiệu ứng chuyển đổi

Hãy thêm component ScreenTransition vào 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;

Hiện tại chúng ta đang bắt buộc hiển thị hiệu ứng chuyển đổi bằng cách truyền true cho prop transition. Chúng ta sẽ thêm logic để kiểm soát hiệu ứng chuyển đổi sau.

Điều chỉnh màu sắc theo ý thích của bạn. Nếu bạn thay đổi nó, hãy chắc chắn cập nhật màu sắc trong file index.css để tránh một nhấp nháy màu khi website tải:

// ...

html {
  background-color: #a5b4fc;
}

Plane nằm giữa cảnh

Plane nằm giữa cảnh.

Toàn màn hình

Chúng ta muốn mặt phẳng của mình bao phủ toàn bộ màn hình. Chúng ta có thể sử dụng kích thước viewport và làm cho nó hướng về phía camera, nhưng chúng ta cũng muốn nó nằm trên cùng mọi thứ.

Để đạt được điều này, Drei cung cấp một thành phần Hud sẽ render các phần tử con của nó trên tất cả mọi thứ. Chúng ta có thể thêm một camera cố định vào thành phần Hud để đảm bảo nó hoàn toàn thẳng hàng với mặt phẳng của chúng ta:

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>
  );
};

Chúng ta sử dụng OrthographicCamera để dễ dàng bao phủ toàn bộ màn hình dù khoảng cách giữa camera và mặt phẳng là bao nhiêu.

Mặt phẳng bao phủ toàn bộ màn hình

Mặt phẳng hiện tại đang che phủ toàn bộ màn hình.

Logic chuyển tiếp

Trước khi chúng ta tạo shader tùy chỉnh của mình, hãy định nghĩa một trạng thái transition trong UI.jsx:

// ...
import { atom } from "jotai";

export const transitionAtom = atom(true);
// ...

Chúng ta đặt giá trị ban đầu là true để bắt đầu với hiệu ứng mờ dần đi sau khi trang web tải xong.

Chúng ta sẽ sử dụng trạng thái này để kiểm soát hiệu ứng chuyển tiếp.

Vẫn trong UI.jsx, chúng ta sẽ định nghĩa hai hằng số để kiểm soát thời gian và độ trễ của hiệu ứng chuyển tiếp:

// ...
export const TRANSITION_DELAY = 0.8;
export const TRANSITION_DURATION = 3.2;
// ...

Bây giờ hãy thay thế lời gọi hàm setScreen bằng một lời gọi mới sẽ xử lý hiệu ứng chuyển tiếp:

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

Thay vì đặt màn hình mới trực tiếp, chúng ta đặt trạng thái transitiontrue và sử dụng setTimeout để đặt màn hình mới sau khi hiệu ứng chuyển tiếp hoàn tất (thời lượng của hiệu ứng chuyển tiếp cộng với độ trễ).

Bây giờ hàm của chúng ta đã sẵn sàng, tìm các lời gọi setScreen trong thành phần UI và thay thế chúng bằng transitionToScreen.

Từ home đến menu:

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

Và từ menu về home:

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