大白话react第十六章React 与 WebGL 结合的实战项目
1. 项目简介
React 是一个构建用户界面的强大库,而 WebGL 则允许我们在网页上实现高性能的 3D 图形渲染。将它们结合起来,我们可以创建出炫酷的 3D 网页应用,比如 3D 产品展示、虚拟场景游览等。接下来,我们会详细介绍如何搭建这样一个项目。
2. 项目搭建
首先,我们需要创建一个新的 React 项目,然后安装相关的 WebGL 库。这里我们使用 three.js
,它是一个流行的 WebGL 抽象库,能让我们更方便地创建 3D 场景。
bash
# 创建一个新的 React 项目
npx create-react-app react-webgl-project
cd react-webgl-project
# 安装 three.js 库
npm install three
3. 创建 3D 场景组件
在 React 中,我们将创建一个组件来渲染 3D 场景。以下是一个简单的示例:
jsx
// 引入 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
组件中使用它。
jsx
// 引入 React 库
import React from 'react';
// 引入我们之前创建的 ThreeScene 组件
import ThreeScene from './ThreeScene';
// 定义 App 组件
const App = () => {
return (
<div>
{/* 使用 ThreeScene 组件 */}
<ThreeScene />
</div>
);
};
export default App;
5. 优化与扩展
为了让项目更完善,我们可以做一些优化和扩展,比如处理窗口大小变化、添加交互功能等。
jsx
// 引入 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。
bash
# 创建一个新的 React 项目
npx create-react-app react-webgl-project
cd react-webgl-project
# 安装 three.js 库
npm install three
3. 创建 React 组件与 WebGL 交互
下面是一个简单的示例,展示了如何在 React 组件里使用 WebGL 渲染一个旋转的立方体。
jsx
// 引入 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
组件里使用它。
jsx
// 引入 React 库
import React from 'react';
// 引入我们刚刚创建的 WebGLScene 组件
import WebGLScene from './WebGLScene';
// 定义 App 组件
const App = () => {
return (
<div>
{/* 使用 WebGLScene 组件,这样就能在页面上看到 WebGL 渲染的 3D 场景了 */}
<WebGLScene />
</div>
);
};
export default App;
5. 处理交互
在实际项目中,我们可能需要处理用户的交互,比如点击、拖动等。下面是一个简单的示例,实现点击立方体改变颜色的功能。
jsx
// 引入 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;
// 更新状态变量 cubeColor
setCubeColor(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 游戏、虚拟展览这些都不在话下。
- 代码示例:
jsx
// 引入 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 效果。
- 代码示例:
jsx
// 引入 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 交互效果。
- 代码示例:
jsx
// 引入 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 场景,渲染循环也可能会产生不必要的绘制,我们要合理控制渲染时机。
jsx
// 引入 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 场景
- 减少几何体的复杂度:复杂的几何体需要更多的计算资源来渲染。可以简化模型,比如用简单的形状代替复杂的模型。
- 合并几何体:如果场景中有多个相似的几何体,可以把它们合并成一个,减少绘制调用的次数。
jsx
// 引入 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. 合理使用纹理
- 压缩纹理:大尺寸的纹理会占用大量内存,使用图像编辑工具对纹理进行压缩,在不影响视觉效果的前提下减小文件大小。
- 按需加载纹理:只有当需要显示某个纹理时才加载它,避免一次性加载过多纹理。
jsx
// 引入 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 的负担。
- 暂停不必要的渲染:当场景不可见或者用户没有交互时,暂停渲染循环。
jsx
// 引入 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 结合项目的性能,让应用运行得更加流畅。