大白話react第十六章React 與 WebGL 結合的實戰項目
1. 項目簡介
React 是一個構建用戶界面的強大庫,而 WebGL 則允許我們在網頁上實現高性能的 3D 圖形渲染。將它們結合起來,我們可以創建出炫酷的 3D 網頁應用,比如 3D 產品展示、虛擬場景游覽等。接下來,我們會詳細介紹如何搭建這樣一個項目。
2. 項目搭建
首先,我們需要創建一個新的 React 項目,然后安裝相關的 WebGL 庫。這里我們使用 three.js
,它是一個流行的 WebGL 抽象庫,能讓我們更方便地創建 3D 場景。
# 創建一個新的 React 項目
npx create-react-app react-webgl-project
cd react-webgl-project# 安裝 three.js 庫
npm install three
3. 創建 3D 場景組件
在 React 中,我們將創建一個組件來渲染 3D 場景。以下是一個簡單的示例:
// 引入 React 庫
import React, { useRef, useEffect } from'react';
// 引入 three.js 庫
import * as THREE from 'three';// 定義一個名為 ThreeScene 的 React 組件
const ThreeScene = () => {// 使用 useRef 創建一個 ref 對象,用于引用 DOM 元素const sceneRef = useRef();useEffect(() => {// 創建一個新的場景const scene = new THREE.Scene();// 創建一個透視相機,設置視角、寬高比、近裁剪面和遠裁剪面const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);// 將相機沿 z 軸向后移動 5 個單位camera.position.z = 5;// 創建一個 WebGL 渲染器const renderer = new THREE.WebGLRenderer();// 設置渲染器的大小為窗口的寬度和高度renderer.setSize(window.innerWidth, window.innerHeight);// 將渲染器的 DOM 元素添加到我們之前創建的 ref 對應的 DOM 元素中sceneRef.current.appendChild(renderer.domElement);// 創建一個立方體幾何體const geometry = new THREE.BoxGeometry();// 創建一個基本材質,顏色為藍色const material = new THREE.MeshBasicMaterial({ color: 0x0000ff });// 創建一個網格對象,將幾何體和材質組合在一起const cube = new THREE.Mesh(geometry, material);// 將立方體添加到場景中scene.add(cube);// 定義一個渲染函數,用于更新場景const animate = () => {// 請求瀏覽器在下一次重繪之前調用 animate 函數,實現動畫循環requestAnimationFrame(animate);// 讓立方體繞 x 軸和 y 軸旋轉cube.rotation.x += 0.01;cube.rotation.y += 0.01;// 使用渲染器渲染場景和相機renderer.render(scene, camera);};// 調用 animate 函數開始動畫animate();// 組件卸載時的清理函數return () => {// 移除渲染器的 DOM 元素sceneRef.current.removeChild(renderer.domElement);};}, []);return (// 創建一個 div 元素,用于容納 3D 場景,使用 ref 關聯到 sceneRef<div ref={sceneRef} />);
};export default ThreeScene;
4. 在 App 組件中使用 3D 場景組件
現在我們已經有了一個 3D 場景組件,接下來我們要在 App
組件中使用它。
// 引入 React 庫
import React from 'react';
// 引入我們之前創建的 ThreeScene 組件
import ThreeScene from './ThreeScene';// 定義 App 組件
const App = () => {return (<div>{/* 使用 ThreeScene 組件 */}<ThreeScene /></div>);
};export default App;
5. 優化與擴展
為了讓項目更完善,我們可以做一些優化和擴展,比如處理窗口大小變化、添加交互功能等。
// 引入 React 庫
import React, { useRef, useEffect } from'react';
// 引入 three.js 庫
import * as THREE from 'three';// 定義一個名為 ThreeScene 的 React 組件
const ThreeScene = () => {// 使用 useRef 創建一個 ref 對象,用于引用 DOM 元素const sceneRef = useRef();// 定義相機和渲染器的變量let camera;let renderer;useEffect(() => {// 創建一個新的場景const scene = new THREE.Scene();// 創建一個透視相機,設置視角、寬高比、近裁剪面和遠裁剪面camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);// 將相機沿 z 軸向后移動 5 個單位camera.position.z = 5;// 創建一個 WebGL 渲染器renderer = new THREE.WebGLRenderer();// 設置渲染器的大小為窗口的寬度和高度renderer.setSize(window.innerWidth, window.innerHeight);// 將渲染器的 DOM 元素添加到我們之前創建的 ref 對應的 DOM 元素中sceneRef.current.appendChild(renderer.domElement);// 創建一個立方體幾何體const geometry = new THREE.BoxGeometry();// 創建一個基本材質,顏色為藍色const material = new THREE.MeshBasicMaterial({ color: 0x0000ff });// 創建一個網格對象,將幾何體和材質組合在一起const cube = new THREE.Mesh(geometry, material);// 將立方體添加到場景中scene.add(cube);// 定義一個渲染函數,用于更新場景const animate = () => {// 請求瀏覽器在下一次重繪之前調用 animate 函數,實現動畫循環requestAnimationFrame(animate);// 讓立方體繞 x 軸和 y 軸旋轉cube.rotation.x += 0.01;cube.rotation.y += 0.01;// 使用渲染器渲染場景和相機renderer.render(scene, camera);};// 調用 animate 函數開始動畫animate();// 處理窗口大小變化的函數const handleResize = () => {// 更新相機的寬高比camera.aspect = window.innerWidth / window.innerHeight;// 更新相機的投影矩陣camera.updateProjectionMatrix();// 更新渲染器的大小renderer.setSize(window.innerWidth, window.innerHeight);};// 監聽窗口大小變化事件,調用 handleResize 函數window.addEventListener('resize', handleResize);// 組件卸載時的清理函數return () => {// 移除渲染器的 DOM 元素sceneRef.current.removeChild(renderer.domElement);// 移除窗口大小變化事件的監聽window.removeEventListener('resize', handleResize);};}, []);return (// 創建一個 div 元素,用于容納 3D 場景,使用 ref 關聯到 sceneRef<div ref={sceneRef} />);
};export default ThreeScene;
6. 總結
通過以上步驟,我們成功地將 React 和 WebGL 結合起來,創建了一個簡單的 3D 場景。在實際項目中,我們可以進一步擴展這個項目,比如添加更多的 3D 模型、光照效果、交互功能等,讓項目更加豐富和有趣。
在實戰項目中,如何使用React與WebGL進行交互?
1. 理解 React 與 WebGL 交互的基本思路
React 是用來構建用戶界面的,而 WebGL 能在網頁上實現 3D 圖形渲染。把它們結合起來,就是想用 React 來管理界面和交互邏輯,同時用 WebGL 來渲染 3D 場景。就好比 React 是指揮官,告訴 WebGL 什么時候該做什么,WebGL 則是干活的工人,負責把 3D 效果呈現出來。
2. 項目準備
首先得創建一個 React 項目,然后安裝 three.js
這個 WebGL 庫,它能讓我們更輕松地操作 WebGL。
# 創建一個新的 React 項目
npx create-react-app react-webgl-project
cd react-webgl-project# 安裝 three.js 庫
npm install three
3. 創建 React 組件與 WebGL 交互
下面是一個簡單的示例,展示了如何在 React 組件里使用 WebGL 渲染一個旋轉的立方體。
// 引入 React 相關的庫,useRef 用于引用 DOM 元素,useEffect 用于處理副作用
import React, { useRef, useEffect } from'react';
// 引入 three.js 庫,它是一個強大的 WebGL 抽象庫
import * as THREE from 'three';// 定義一個名為 WebGLScene 的 React 組件
const WebGLScene = () => {// 創建一個 ref 對象,用于引用 DOM 元素,之后會把 WebGL 渲染的內容放到這個元素里const sceneRef = useRef();useEffect(() => {// 創建一個新的 THREE 場景,這就像是一個舞臺,3D 物體都會放在這個舞臺上const scene = new THREE.Scene();// 創建一個透視相機,就像我們的眼睛,決定了我們從什么角度看 3D 場景// 75 是視角,window.innerWidth / window.innerHeight 是寬高比,0.1 和 1000 分別是近裁剪面和遠裁剪面const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);// 把相機往后移 5 個單位,這樣就能看到場景里的物體了camera.position.z = 5;// 創建一個 WebGL 渲染器,它負責把 3D 場景渲染成我們能看到的圖像const renderer = new THREE.WebGLRenderer();// 設置渲染器的大小為瀏覽器窗口的大小renderer.setSize(window.innerWidth, window.innerHeight);// 把渲染器生成的 DOM 元素添加到之前創建的 ref 對應的 DOM 元素中sceneRef.current.appendChild(renderer.domElement);// 創建一個立方體的幾何體,也就是立方體的形狀const geometry = new THREE.BoxGeometry();// 創建一個基本材質,給立方體一個藍色的外觀const material = new THREE.MeshBasicMaterial({ color: 0x0000ff });// 把幾何體和材質組合成一個網格對象,這就是我們要渲染的立方體const cube = new THREE.Mesh(geometry, material);// 把立方體添加到場景中scene.add(cube);// 定義一個動畫函數,用于更新場景并渲染const animate = () => {// 請求瀏覽器在下一次重繪之前調用 animate 函數,形成動畫循環requestAnimationFrame(animate);// 讓立方體繞 x 軸和 y 軸旋轉,這樣就能看到它在動了cube.rotation.x += 0.01;cube.rotation.y += 0.01;// 使用渲染器渲染場景和相機所看到的內容renderer.render(scene, camera);};// 調用動畫函數,開始動畫animate();// 組件卸載時的清理函數return () => {// 移除渲染器的 DOM 元素,避免內存泄漏sceneRef.current.removeChild(renderer.domElement);};}, []);return (// 創建一個 div 元素,用 ref 關聯到之前創建的 ref 對象,用于容納 WebGL 渲染的內容<div ref={sceneRef} />);
};export default WebGLScene;
4. 在 App 組件中使用 WebGL 組件
創建好 WebGL 組件后,要在 App
組件里使用它。
// 引入 React 庫
import React from 'react';
// 引入我們剛剛創建的 WebGLScene 組件
import WebGLScene from './WebGLScene';// 定義 App 組件
const App = () => {return (<div>{/* 使用 WebGLScene 組件,這樣就能在頁面上看到 WebGL 渲染的 3D 場景了 */}<WebGLScene /></div>);
};export default App;
5. 處理交互
在實際項目中,我們可能需要處理用戶的交互,比如點擊、拖動等。下面是一個簡單的示例,實現點擊立方體改變顏色的功能。
// 引入 React 相關的庫,useRef 用于引用 DOM 元素,useEffect 用于處理副作用,useState 用于管理狀態
import React, { useRef, useEffect, useState } from'react';
import * as THREE from 'three';
// 引入 three.js 的射線投射器,用于檢測點擊事件
import { Raycaster, Vector2 } from 'three';const WebGLScene = () => {const sceneRef = useRef();// 定義一個狀態變量,用于存儲立方體的顏色const [cubeColor, setCubeColor] = useState(0x0000ff);useEffect(() => {const scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);camera.position.z = 5;const renderer = new THREE.WebGLRenderer();renderer.setSize(window.innerWidth, window.innerHeight);sceneRef.current.appendChild(renderer.domElement);// 創建一個立方體的幾何體const geometry = new THREE.BoxGeometry();// 使用狀態變量 cubeColor 來設置立方體的顏色const material = new THREE.MeshBasicMaterial({ color: cubeColor });const cube = new THREE.Mesh(geometry, material);scene.add(cube);// 創建一個射線投射器,用于檢測點擊事件const raycaster = new Raycaster();// 創建一個二維向量,用于存儲鼠標的位置const mouse = new Vector2();// 處理鼠標點擊事件的函數const handleClick = (event) => {// 計算鼠標在標準化設備坐標中的位置mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;// 使用射線投射器從相機位置沿著鼠標方向發射一條射線raycaster.setFromCamera(mouse, camera);// 檢測射線與場景中的物體是否相交const intersects = raycaster.intersectObjects(scene.children);// 如果射線與立方體相交if (intersects.length > 0 && intersects[0].object === cube) {// 隨機生成一個新的顏色const newColor = Math.random() * 0xffffff;// 更新狀態變量 cubeColorsetCubeColor(newColor);// 更新立方體的材質顏色cube.material.color.set(newColor);}};// 監聽鼠標點擊事件window.addEventListener('click', handleClick);const animate = () => {requestAnimationFrame(animate);cube.rotation.x += 0.01;cube.rotation.y += 0.01;renderer.render(scene, camera);};animate();return () => {sceneRef.current.removeChild(renderer.domElement);// 移除鼠標點擊事件的監聽,避免內存泄漏window.removeEventListener('click', handleClick);};}, [cubeColor]);return (<div ref={sceneRef} />);
};export default WebGLScene;
總結
通過以上步驟,我們就實現了 React 與 WebGL 的交互。先是創建了一個基本的 3D 場景,然后在 React 組件里管理這個場景,最后還實現了簡單的交互功能。在實際項目中,你可以根據需求進一步擴展,比如添加更多的 3D 模型、復雜的光照效果等。
除了three.js,還有哪些WebGL庫可以與React結合使用?
除了 three.js,能和 React 結合用的 WebGL 庫
在做網頁的 3D 效果時,除了大家常用的 three.js,還有不少其他的 WebGL 庫能和 React 搭配,下面就來詳細說說這些庫。
1. Babylon.js
- 白話解釋:Babylon.js 就像是一個功能強大的 3D 游戲開發小工具包,它能讓你輕松地在網頁上創建出復雜又炫酷的 3D 場景,像做 3D 游戲、虛擬展覽這些都不在話下。
- 代碼示例:
// 引入 React 相關的庫
import React, { useRef, useEffect } from'react';
// 引入 Babylon.js 庫
import * as BABYLON from 'babylonjs';// 創建一個名為 BabylonScene 的 React 組件
const BabylonScene = () => {// 創建一個 ref 對象,用來關聯后續的 DOM 元素const canvasRef = useRef(null);useEffect(() => {// 獲取 ref 對應的 DOM 元素,這里是畫布const canvas = canvasRef.current;// 創建一個 Babylon.js 的引擎,基于這個畫布const engine = new BABYLON.Engine(canvas, true);// 創建一個新的 3D 場景const scene = new BABYLON.Scene(engine);// 創建一個相機,讓用戶可以觀察場景const camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 2, 2, BABYLON.Vector3.Zero(), scene);// 讓相機可以被鼠標控制camera.attachControl(canvas, true);// 創建一個光源,照亮場景const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);// 創建一個球體,作為場景中的物體const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 1 }, scene);// 定義一個渲染循環函數const renderLoop = () => {// 渲染場景scene.render();};// 啟動渲染循環engine.runRenderLoop(renderLoop);// 監聽窗口大小變化,調整畫布大小window.addEventListener('resize', () => {engine.resize();});// 組件卸載時的清理操作return () => {// 停止渲染循環engine.stopRenderLoop(renderLoop);// 釋放引擎資源engine.dispose();};}, []);return (// 創建一個畫布元素,使用 ref 關聯到 canvasRef<canvas ref={canvasRef} style={{ width: '100%', height: '500px' }} />);
};export default BabylonScene;
2. PlayCanvas
- 白話解釋:PlayCanvas 就像是一個在線的 3D 創作平臺,它有自己的可視化編輯器,就算你不太懂代碼,也能做出好看的 3D 項目。而且它和 React 結合后,能讓你的網頁有很棒的 3D 效果。
- 代碼示例:
// 引入 React 相關的庫
import React, { useRef, useEffect } from'react';
// 引入 PlayCanvas 庫
import * as pc from 'playcanvas';// 創建一個名為 PlayCanvasScene 的 React 組件
const PlayCanvasScene = () => {// 創建一個 ref 對象,用來關聯后續的 DOM 元素const containerRef = useRef(null);useEffect(() => {// 獲取 ref 對應的 DOM 元素,作為容器const container = containerRef.current;// 創建一個 PlayCanvas 的應用實例const app = new pc.Application(container, {graphicsDeviceOptions: {alpha: true}});// 設置應用的分辨率和填充模式app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);app.setCanvasResolution(pc.RESOLUTION_AUTO);// 啟用統計信息顯示app.start();// 創建一個實體,作為相機const camera = new pc.Entity('camera');// 給相機添加相機組件camera.addComponent('camera', {clearColor: new pc.Color(0.1, 0.1, 0.1)});// 設置相機的位置camera.setPosition(0, 0, 3);// 將相機添加到場景中app.root.addChild(camera);// 創建一個實體,作為立方體const cube = new pc.Entity('cube');// 給立方體添加模型組件cube.addComponent('model', {type:'box'});// 將立方體添加到場景中app.root.addChild(cube);// 定義一個更新函數,用于更新場景const update = () => {// 讓立方體繞 y 軸旋轉cube.rotate(0, 1, 0);};// 監聽應用的更新事件,調用 update 函數app.on('update', update);// 組件卸載時的清理操作return () => {// 停止應用app.stop();// 移除應用的 DOM 元素container.innerHTML = '';};}, []);return (// 創建一個 div 元素,作為容器,使用 ref 關聯到 containerRef<div ref={containerRef} style={{ width: '100%', height: '500px' }} />);
};export default PlayCanvasScene;
3. PixiJS
- 白話解釋:PixiJS 主要是用來做 2D 圖形和動畫的,但它也支持 WebGL 加速,能讓 2D 畫面又快又好看。和 React 結合后,能在網頁上做出超棒的 2D 交互效果。
- 代碼示例:
// 引入 React 相關的庫
import React, { useRef, useEffect } from'react';
// 引入 PixiJS 庫
import * as PIXI from 'pixi.js';// 創建一個名為 PixiScene 的 React 組件
const PixiScene = () => {// 創建一個 ref 對象,用來關聯后續的 DOM 元素const appRef = useRef(null);useEffect(() => {// 創建一個 PixiJS 的應用實例const app = new PIXI.Application({width: 800,height: 600,backgroundColor: 0x1099bb});// 獲取 ref 對應的 DOM 元素,將應用的視圖添加進去appRef.current.appendChild(app.view);// 創建一個圓形圖形const circle = new PIXI.Graphics();circle.beginFill(0xFF0000);circle.drawCircle(0, 0, 50);circle.endFill();// 設置圓形的位置circle.x = 400;circle.y = 300;// 將圓形添加到舞臺上app.stage.addChild(circle);// 定義一個動畫函數,用于更新圓形的位置const animate = () => {// 讓圓形在 x 軸上移動circle.x += 1;if (circle.x > 800) {circle.x = 0;}// 請求下一幀動畫requestAnimationFrame(animate);};// 啟動動畫animate();// 組件卸載時的清理操作return () => {// 銷毀應用app.destroy(true);// 移除應用的視圖appRef.current.removeChild(app.view);};}, []);return (// 創建一個 div 元素,作為容器,使用 ref 關聯到 appRef<div ref={appRef} />);
};export default PixiScene;
這些庫各有各的特點,你可以根據項目的需求來選擇合適的庫和 React 結合使用,做出更酷炫的網頁效果。
如何優化React與WebGL結合的項目性能?
如何優化 React 與 WebGL 結合的項目性能
1. 減少不必要的渲染
在 React 里,組件可能會因為各種原因頻繁重新渲染,這會影響性能。我們可以用 React.memo
來避免組件的不必要渲染。對于 WebGL 場景,渲染循環也可能會產生不必要的繪制,我們要合理控制渲染時機。
// 引入 React 相關的庫,包括 React.memo 和 useEffect
import React, { memo, useEffect, useRef } from'react';
// 引入 three.js 庫,這里以 three.js 為例,其他 WebGL 庫思路類似
import * as THREE from 'three';// 使用 React.memo 包裹組件,只有當 props 改變時才重新渲染
const OptimizedWebGLComponent = memo((props) => {// 創建一個 ref 來引用 DOM 元素,后續用于掛載 WebGL 渲染器const containerRef = useRef(null);useEffect(() => {// 創建一個新的 THREE 場景const scene = new THREE.Scene();// 創建一個透視相機,設置視角、寬高比、近裁剪面和遠裁剪面const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);// 創建一個 WebGL 渲染器const renderer = new THREE.WebGLRenderer();// 設置渲染器的大小為窗口的寬度和高度renderer.setSize(window.innerWidth, window.innerHeight);// 將渲染器的 DOM 元素添加到我們之前創建的 ref 對應的 DOM 元素中containerRef.current.appendChild(renderer.domElement);// 創建一個立方體幾何體const geometry = new THREE.BoxGeometry();// 創建一個基本材質,顏色為藍色const material = new THREE.MeshBasicMaterial({ color: 0x0000ff });// 創建一個網格對象,將幾何體和材質組合在一起const cube = new THREE.Mesh(geometry, material);// 將立方體添加到場景中scene.add(cube);// 將相機沿 z 軸向后移動 5 個單位camera.position.z = 5;// 定義一個渲染函數const animate = () => {// 請求瀏覽器在下一次重繪之前調用 animate 函數,實現動畫循環requestAnimationFrame(animate);// 讓立方體繞 x 軸和 y 軸旋轉cube.rotation.x += 0.01;cube.rotation.y += 0.01;// 使用渲染器渲染場景和相機renderer.render(scene, camera);};// 調用 animate 函數開始動畫animate();// 組件卸載時的清理函數return () => {// 移除渲染器的 DOM 元素containerRef.current.removeChild(renderer.domElement);};}, []);return (// 創建一個 div 元素,用于容納 WebGL 場景,使用 ref 關聯到 containerRef<div ref={containerRef} />);
});export default OptimizedWebGLComponent;
2. 優化 WebGL 場景
- 減少幾何體的復雜度:復雜的幾何體需要更多的計算資源來渲染。可以簡化模型,比如用簡單的形狀代替復雜的模型。
- 合并幾何體:如果場景中有多個相似的幾何體,可以把它們合并成一個,減少繪制調用的次數。
// 引入 React 相關的庫,包括 useEffect 和 useRef
import React, { useEffect, useRef } from'react';
import * as THREE from 'three';const OptimizedGeometryComponent = () => {const containerRef = useRef(null);useEffect(() => {const scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);const renderer = new THREE.WebGLRenderer();renderer.setSize(window.innerWidth, window.innerHeight);containerRef.current.appendChild(renderer.domElement);// 創建一個簡單的平面幾何體,相比復雜模型更節省資源const geometry = new THREE.PlaneGeometry(5, 5);const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });const plane = new THREE.Mesh(geometry, material);scene.add(plane);camera.position.z = 5;const animate = () => {requestAnimationFrame(animate);renderer.render(scene, camera);};animate();return () => {containerRef.current.removeChild(renderer.domElement);};}, []);return (<div ref={containerRef} />);
};export default OptimizedGeometryComponent;
3. 合理使用紋理
- 壓縮紋理:大尺寸的紋理會占用大量內存,使用圖像編輯工具對紋理進行壓縮,在不影響視覺效果的前提下減小文件大小。
- 按需加載紋理:只有當需要顯示某個紋理時才加載它,避免一次性加載過多紋理。
// 引入 React 相關的庫,包括 useEffect 和 useRef
import React, { useEffect, useRef } from'react';
import * as THREE from 'three';const TextureOptimizedComponent = () => {const containerRef = useRef(null);useEffect(() => {const scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);const renderer = new THREE.WebGLRenderer();renderer.setSize(window.innerWidth, window.innerHeight);containerRef.current.appendChild(renderer.domElement);// 創建一個紋理加載器const textureLoader = new THREE.TextureLoader();// 加載一個壓縮后的紋理圖片textureLoader.load('compressed_texture.jpg', (texture) => {const geometry = new THREE.BoxGeometry();// 使用加載的紋理創建材質const material = new THREE.MeshBasicMaterial({ map: texture });const cube = new THREE.Mesh(geometry, material);scene.add(cube);});camera.position.z = 5;const animate = () => {requestAnimationFrame(animate);renderer.render(scene, camera);};animate();return () => {containerRef.current.removeChild(renderer.domElement);};}, []);return (<div ref={containerRef} />);
};export default TextureOptimizedComponent;
4. 管理渲染循環
- 控制幀率:不需要一直以最高幀率渲染,可以根據實際需求降低幀率,減少 CPU 和 GPU 的負擔。
- 暫停不必要的渲染:當場景不可見或者用戶沒有交互時,暫停渲染循環。
// 引入 React 相關的庫,包括 useEffect、useRef 和 useState
import React, { useEffect, useRef, useState } from'react';
import * as THREE from 'three';const RenderLoopOptimizedComponent = () => {const containerRef = useRef(null);// 使用 useState 來控制是否渲染const [isRendering, setIsRendering] = useState(true);useEffect(() => {const scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);const renderer = new THREE.WebGLRenderer();renderer.setSize(window.innerWidth, window.innerHeight);containerRef.current.appendChild(renderer.domElement);const geometry = new THREE.BoxGeometry();const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });const cube = new THREE.Mesh(geometry, material);scene.add(cube);camera.position.z = 5;// 定義一個渲染函數const animate = () => {if (isRendering) {// 請求瀏覽器在下一次重繪之前調用 animate 函數,實現動畫循環requestAnimationFrame(animate);cube.rotation.x += 0.01;cube.rotation.y += 0.01;renderer.render(scene, camera);}};animate();return () => {containerRef.current.removeChild(renderer.domElement);};}, [isRendering]);return (<div><div ref={containerRef} />{/* 添加一個按鈕來控制是否渲染 */}<button onClick={() => setIsRendering(!isRendering)}>{isRendering? '暫停渲染' : '開始渲染'}</button></div>);
};export default RenderLoopOptimizedComponent;
通過以上這些方法,我們可以顯著提升 React 與 WebGL 結合項目的性能,讓應用運行得更加流暢。