Render Target
Khi chúng ta sử dụng React Three Fiber, chúng ta chỉ cần thêm một Canvas
component và đặt cảnh 3D của chúng ta vào bên trong và nó sẽ render lên màn hình.
Nếu bạn có một chút kinh nghiệm với Three.js, bạn biết rằng chúng ta cần tạo một WebGLRenderer
và sau đó gọi renderer.render(scene, camera)
để render cảnh của chúng ta lên màn hình.
May mắn thay, React Three Fiber làm tất cả điều này cho chúng ta một cách tự động, nhưng đối với các trường hợp sử dụng nâng cao hơn, việc hiểu cách nó hoạt động là rất quan trọng.
Vai trò của renderer là xử lý cảnh 3D để tạo ra hình ảnh 2D thực tế mà chúng ta thấy trên màn hình.
Theo mặc định, đầu ra của renderer được đặt cho Canvas
component và hiển thị trên màn hình, nhưng chúng ta cũng có thể xuất nó thành một texture (thông qua một WebGLRenderTarget
).
Bây giờ, điều này có thể hơi trừu tượng, hãy xem nó hoạt động thế nào trong thực tế và những cách sáng tạo mà chúng ta có thể sử dụng nó.
Camera An Ninh
Để hiểu cách Render Targets hoạt động và những gì chúng ta có thể làm với chúng, tôi đã chuẩn bị một cảnh 3D bao gồm:
- Một mô hình 3D phòng khách của Alex Safayan CC-BY thông qua Poly Pizza
- Một avatar Ready Player Me (giống như cái chúng ta sử dụng trong bài học portfolio) đang xem Spongebob Squarepants trên TV
- Một điều khiển từ xa 2D với nhiều nút bấm
Mục tiêu là tạo một hệ thống giám sát bằng cách render cảnh từ góc nhìn của một camera an ninh trên TV.
Kết xuất khung cảnh vào một texture
Để kết xuất khung cảnh hiện tại của chúng ta vào một texture, ta cần phải tạo một Render Target.
Nhờ vào thư viện Drei, chúng ta có thể dễ dàng tạo một Render Target với hook useFBO
:
// ... import { useFBO } from "@react-three/drei"; export const Experience = () => { const cornerRenderTarget = useFBO(); // ... };
Nếu bạn muốn biết cách tạo một Render Target từ đầu, bạn có thể xem mã nguồn của hook
useFBO
tại đây. Đó là một thói quen tốt để hiểu cách mọi thứ hoạt động bên dưới.
Bây giờ chúng ta đã có một Render Target, chúng ta cần chỉ định cho renderer của mình để kết xuất scene
bằng cách sử dụng camera
của chúng ta.
Tất cả các đối tượng đó có sẵn trong root state của ứng dụng React Three Fiber. Đây là đối tượng được trả về bởi hook useThree
.
Thuộc tính
gl
là renderer.
Nhưng, vì chúng ta muốn hiển thị những gì đang diễn ra theo thời gian thực trên TV, chúng ta sẽ thực hiện quá trình này ở mỗi frame bằng cách sử dụng hook useFrame
.
Hàm callback bao gồm root state nên chúng ta có thể truy cập các biến của mình trực tiếp từ đó:
// ... import { useFrame } from "@react-three/fiber"; export const Experience = () => { // ... useFrame(({ gl, camera, scene }) => { gl.setRenderTarget(cornerRenderTarget); gl.render(scene, camera); gl.setRenderTarget(null); }); // ... };
Những gì chúng ta đang làm ở đây là:
- Thiết lập Render Target như đầu ra của renderer
- Kết xuất
scene
bằngcamera
và vì đầu ra của renderer đã được thiết lập cho Render Target, nó sẽ kết xuất cảnh vào đó - Thiết lập đầu ra của renderer thành
null
để kết xuất cảnh lên canvas một lần nữa
Khi chúng ta đã có Render Target, chúng ta cần hiển thị nó trên TV. Hãy thêm một tham chiếu đến material hiện đang kết xuất video:
// ... import { useRef } from "react"; export const Experience = () => { // ... const tvMaterial = useRef(); // ... return ( <> {/* ... */} <group position-y={-0.5}> <group> <Sky /> <Avatar rotation-y={Math.PI} scale={0.45} position-z={0.34} /> <Gltf src="models/Room.glb" scale={0.3} rotation-y={-Math.PI / 2} /> <mesh position-x={0.055} position-y={0.48} position-z={-0.601}> <planeGeometry args={[0.63, 0.44]} /> <meshBasicMaterial ref={tvMaterial} /> </mesh> </group> </group> {/* ... */} </> ); };
Và sau đó, chúng ta có thể sử dụng hook useFrame
để cập nhật thuộc tính map
của material với Render Target của chúng ta:
// ... export const Experience = () => { // ... useFrame(({ gl, camera, scene }) => { // ... tvMaterial.current.map = cornerRenderTarget.texture; }); // ... };
Bây giờ, chúng ta có thể thấy góc nhìn từ camera an ninh trên TV nhưng màn hình TV trong góc nhìn từ camera an ninh thì trống.
Điều này là bởi vì khi chúng ta kết xuất cảnh vào Render Target, màn hình của chúng ta trống.
Hiệu ứng Inception
Để xem hình ảnh từ camera an ninh bên trong màn hình TV của màn hình TV 🤯, chúng ta cần:
- Tạo một render target khác (chúng ta sẽ đặt tên nó là
bufferRenderTarget
) - Render cảnh vào đó
- Gắn nó vào material của màn hình TV
- Render cảnh vào
corderRenderTarget
- Gắn nó vào material của TV
// ... export const Experience = () => { const bufferRenderTarget = useFBO(); // ... useFrame(({ gl, camera, scene }) => { gl.setRenderTarget(bufferRenderTarget); gl.render(scene, camera); tvMaterial.current.map = bufferRenderTarget.texture; gl.setRenderTarget(cornerRenderTarget); gl.render(scene, camera); gl.setRenderTarget(null); tvMaterial.current.map = cornerRenderTarget.texture; }); // ... };
Nó có thể nghe có vẻ đáng sợ nhưng thực ra rất đơn giản. Chỉ cần suy nghĩ về những gì đang diễn ra ở mỗi bước.
Bây giờ cảnh của chúng ta đã được render vô hạn bên trong màn hình TV!
Mặc dù đây là hiệu ứng thực nhất mà chúng ta có thể tạo ra, nhưng đó không phải là hiệu ứng sáng tạo nhất. Hãy loại bỏ hiệu ứng inception và hiển thị Spongebob Squarepants trên màn hình thay vì:
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.