当前位置: 首页 > news >正文

大白话react第十六章React 与 WebGL 结合的实战项目

大白话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 结合项目的性能,让应用运行得更加流畅。

相关文章:

大白话react第十六章React 与 WebGL 结合的实战项目

大白话react第十六章React 与 WebGL 结合的实战项目 1. 项目简介 React 是一个构建用户界面的强大库&#xff0c;而 WebGL 则允许我们在网页上实现高性能的 3D 图形渲染。将它们结合起来&#xff0c;我们可以创建出炫酷的 3D 网页应用&#xff0c;比如 3D 产品展示、虚拟场景…...

DeepSeek-R1:引领AI领域革新,MLA技术助力模型迁移

摘要 DeepSeek的MLA技术实现了大型机器学习模型的轻松迁移&#xff0c;其突破性产品DeepSeek-R1凭借显著降低的训练和推理成本&#xff0c;吸引了业界广泛关注。MLA技术的核心在于创新性的低秩压缩键值缓存架构&#xff0c;使得推理成本大幅减少&#xff0c;仅为同等性能大型模…...

Nginx:从入门到实战使用教程

全方位解析Nginx&#xff1a;从入门到实战使用教程 Nginx安装、配置详细教程 文章目录 全方位解析Nginx&#xff1a;从入门到实战使用教程导语一、Nginx简介二、Nginx安装与配置 1. 在CentOS系统上安装Nginx&#xff1a;2. 在Ubuntu系统上安装Nginx&#xff1a;3. Nginx配置文…...

SyntaxError: Unexpected token ‘xxx‘

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 &#x1f35a; 蓝桥云课签约作者、…...

GaussDB安全配置指南:从认证到防御的全方面防护

一、引言 随着企业数据规模的扩大和云端化进程加速&#xff0c;数据库安全性成为运维的核心挑战之一。GaussDB作为一款高性能分布式数据库&#xff0c;提供了丰富的安全功能。本文将从 ​认证机制、权限控制、数据加密、审计日志​ 等维度&#xff0c;系统性地讲解如何加固 Ga…...

[项目]基于FreeRTOS的STM32四轴飞行器: 四.LED控制

基于FreeRTOS的STM32四轴飞行器: 四.LED控制 一.配置Com层二.编写驱动 一.配置Com层 先在Com_Config.h中定义灯位置的枚举类型&#xff1a; 之后定义Led的结构体&#xff1a; 定义飞行器状态&#xff1a; 在Com_Config.c中初始化四个灯&#xff1a; 在Com_Config.h外部声明…...

Python——计算机网络

一.ip 1.ip的定义 IP是“Internet Protocol”的缩写&#xff0c;即“互联网协议”。它是用于计算机网络通信的基础协议之一&#xff0c;属于TCP/IP协议族中的网络层协议。IP协议的主要功能是负责将数据包从源主机传输到目标主机&#xff0c;并确保数据能够在复杂的网络环境中正…...

【并发编程】聊聊定时任务ScheduledThreadPool的实现原理和源码解析

ScheduledThreadPoolExecutor 是在线程池的基础上 拓展的定时功能的线程池&#xff0c;主要有四种方式&#xff0c;具体可以看代码&#xff0c; 这里主要描述下 scheduleAtFixedRate &#xff1a; 除了第一次执行的时间&#xff0c;后面任务执行的时间 为 time MAX(任务执行时…...

nginx-静态资源部署

目录 静态资源概述 静态资源配置指令 listen指令 server_name指令 精确匹配 ?编辑 ?编辑 使用通配符匹配 使用正则表达式匹配 匹配执行顺序 default_server属性 location指令 root指令 alias指令 root与alisa指令的区别 index指令 error_page指令 直接使用…...

WebGPT: 基于浏览器辅助的问答系统,结合人类反馈优化答案质量

【摘要】 本论文介绍了WebGPT,这是一种通过浏览器辅助问答系统来使用人类反馈进行训练和优化的模型。具体来说,该系统通过与基于文本的网络浏览环境互动,使模型能够搜索和导航网络,从而提高其回答长文本问题的能力。通过将任务设计为人类可以完成的任务,研究人员能够利用…...

C# 异步任务队列封装

在 C# 中&#xff0c;可以使用 Task 和 ConcurrentQueue 来构建一个 异步任务队列&#xff0c;确保任务按照 FIFO&#xff08;先进先出&#xff09;顺序执行&#xff0c;并支持并发安全。 设计方案 任务队列 (ConcurrentQueue<Func>) 存储异步任务&#xff08;每个任务都…...

安装并运行hadoop程序

1.在虚拟机上安装javaJDK &#xff08;1&#xff09;把javaJDK文件上传到服务器 在opt文件夹下新建一个software文件夹&#xff0c;将jdk拖入software &#xff08;2&#xff09;解压文件 在opt文件夹下新建一个module文件夹&#xff0c;确认上传成功之后&#xff0c;在softwa…...

第TR3周:Pytorch复现Transformer

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客 &#x1f356; 原作者&#xff1a;K同学啊 Transformer通过自注意力机制&#xff0c;改变了序列建模的方式&#xff0c;成为AI领域的基础架构 编码器&#xff1a;理解输入&#xff0c;提取上下文特征…...

51c视觉~3D~合集2

我自己的原文哦~ https://blog.51cto.com/whaosoft/13422809 #中科大统一内外参估计和3DGS训练 这下真的不用相机标定了&#xff1f; 同时优化相机的内外参和无序图像数据 在给定一组来自3D场景的图像及其相应的相机内参和外参的情况下&#xff0c;3D高斯喷溅&#xff…...

dify在腾讯云服务器上部署

Dify 是一个开源的 LLM 应用开发平台。提供从 Agent 构建到 AI workflow 编排、RAG 检索、模型管理等能力&#xff0c;轻松构建和运营生成式 AI 原生应用&#xff0c;比 LangChain 更易用。 首先到dify官方网站上有详细介绍 https://docs.dify.ai/zh-hans/getting-started/ins…...

Redis——缓存穿透、击穿、雪崩

缓存穿透 什么是缓存穿透 缓存穿透说简单点就是大量请求的 key 根本不存在于缓存中&#xff0c;导致请求直接到了数据库上&#xff0c;根本没有经过缓存这一层。举个例子&#xff1a;某个黑客故意制造我们缓存中不存在的 key 发起大量请求&#xff0c;导致大量请求落到数据库…...

Java 并发编程:synchronized 与 Lock 的区别

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 Java 并发编程&#xff1a;synchronized 与 Lock 的深度对比 在 Java 多线程编程中&#xff0c;同步机制是保证线程安全的核心手段。synchronized 关键字和 …...

12组复古暖色调旅行电影摄影照片调色Lightroom预设 12 Warm Vintage Film Lightroom Presets

使用这 12 种暖色复古胶片 Lightroom 预设来转换您的照片&#xff0c;旨在将经典胶片的永恒精髓带入您的数字编辑中。每个预设都经过精心制作&#xff0c;以唤起丰富的色彩、微妙的颗粒和怀旧的色调。 这些预设非常适合寻求复古魅力和现代精度融合的摄影师&#xff0c;将毫不费…...

WebSocket:实现实时通信的利器

在现代Web应用中&#xff0c;实时通信变得越来越重要。无论是聊天应用、在线游戏&#xff0c;还是实时数据推送&#xff0c;传统的HTTP请求-响应模式已经无法满足需求。WebSocket作为一种全双工通信协议&#xff0c;应运而生&#xff0c;成为实现实时通信的利器。本文将深入探讨…...

小谈java内存马

基础知识 &#xff08;代码功底不好&#xff0c;就找ai优化了一下&#xff09; Java内存马是一种利用Java虚拟机&#xff08;JVM&#xff09;动态特性&#xff08;如类加载机制、反射技术等&#xff09;在内存中注入恶意代码的攻击手段。它不需要在磁盘上写入文件&#xff0c…...

wordpress自定the_category的输出结构

通过WordPress的过滤器the_category来自定义输出内容。方法很简单&#xff0c;但是很实用。以下是一个示例代码&#xff1a; function custom_the_category($thelist, $separator , $parents ) {// 获取当前文章的所有分类$categories get_the_category();if (empty($categ…...

Flink深入浅出之01:应用场景、基本架构、部署模式

Flink 1️⃣ 一 、知识要点 &#x1f4d6; 1. Flink简介 Apache Flink — Stateful Computations over Data StreamsApache Flink 是一个分布式大数据处理引擎&#xff0c;可对有界数据流和无界数据流进行有状态的计算。Flink 能在所有常见集群环境中运行&#xff0c;并能以…...

react脚手架(creat-react-app)

安装 react脚手架 React官方提供的脚手架工程Create React App&#xff1a;https://github.com/facebook/create-react-app npm install create-react-app -g 全局安装 create-react-app my-react (my-react为项目名称&#xff0c;可以自定义) cd my-react 启动项目&#xff1a…...

TypeError: Cannot set properties of undefined (setting ‘xxx‘)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 &#x1f35a; 蓝桥云课签约作者、…...

使用Node.js从零搭建DeepSeek本地部署(Express框架、Ollama)

目录 1.安装Node.js和npm2.初始化项目3.安装Ollama4.下载DeepSeek模型5.创建Node.js服务器6.运行服务器7.Web UI对话-Chrome插件-Page Assist 1.安装Node.js和npm 首先确保我们机器上已经安装了Node.js和npm。如果未安装&#xff0c;可以通过以下链接下载并安装适合我们操作系…...

考网络安全工程师证要什么条件才能考?

在当今数字化时代&#xff0c;网络安全问题日益凸显&#xff0c;网络安全工程师成为了一个备受瞩目的职业。许多有志于投身这一行业的学子或职场人士&#xff0c;都希望通过考取网络安全工程师证书来提升自己的专业素养和竞争力。那么&#xff0c;考网络安全工程师证需要具备哪…...

【情境领导者】评估情境——准备度水平

本系列是看了《情境领导者》一书&#xff0c;结合自己工作的实践经验所做的学习笔记。 在文章【情境领导者】评估情境——什么是准备度-CSDN博客我们提到准备度是由能力和意愿两部分组成的。 准备度水平 而我们要怎么去评估准备度呢&#xff1f;准备度水平是指人们在每项工作中…...

一套企业级智能制造云MES系统源码, vue-element-plus-admin+springboot

MES应该是继ERP之后制造企业信息化最热门的管理软件&#xff0c;它适应产品个性化与敏捷化制造需求&#xff0c;满足生产过程精益管理而产生和发展起来的信息系统。 作为企业实现数字化与智能化的核心支撑技术与重要组成部分&#xff0c;MES在帮助制造企业走向数字化、智能化等…...

蓝桥杯备考:动态规划线性dp之传球游戏

按照动态规划的做题顺序 step1&#xff1a;定义状态表示 f[i][j] 表示 第i次传递给了第j号时一共有多少种方案 step2: 推到状压公式 step3:初始化 step4:最终结果实际上就是f[m][1] #include <iostream> #include <cstring> using namespace std;const int N …...

网络编程 day05

网络编程 day05 12. SQL 数据库概念常用数据库MySQL与SQLite的区别 SQL基础SQL语句使用基本语句的使用—命令行操作sqlite3系统命令sqlite命令 sqlite3编程—函数接口 13. setsockopt&#xff1a;设置套接字属性 12. SQL 数据库 概念 数据库是“按照数据结构来组织、存储和管理…...

Excel中COUNTIF用法解析

COUNTIF 是 Excel 中一个非常实用的函数&#xff0c;用于统计满足某个条件的单元格数量。它的基本语法如下&#xff1a; 基本语法 COUNTIF(范围, 条件) 范围&#xff1a;需要统计的单元格区域&#xff0c;例如 A1:A10 或整列 A:A。 条件&#xff1a;用于判断哪些单元格需要被…...

使用XShell连接RHEL9并配置yum阿里源

目录 1.先在终端查看本地IP 2.打开XShell进行连接 方法一&#xff1a; 方法二&#xff1a; 3.关闭防火墙及SElinux 4.更改主机名为node2 5.修改YUM源为阿里源&#xff08;将系统中国外的yum文件换成国内的阿里镜像文件&#xff09; 1.找到本机的yum配置文件 2.删除原有…...

FPGA时序约束的几种方法

一,时钟约束 时钟约束是最基本的一个约束,因为FPGA工具是不知道你要跑多高的频率的,你必要要告诉工具你要跑的时钟频率。时钟约束也就是经常看到的Fmax,因为Fmax是针对“最差劲路径”,也就是说,如果该“最差劲路径”得到好成绩,那些不是最差劲的路径的成绩当然比…...

C# 在Excel中插入和操作切片器-详解

目录 使用工具 C# 在Excel中插入切片器 插入切片器到透视表 插入切片器到表格 C# 在Excel中修改切片器 C# 删除Excel中的切片器 切片器&#xff08;Slicer&#xff09;是Excel中的一个强大工具&#xff0c;它提供了直观且交互式的方式来过滤数据。通过切片器&#xff0c;…...

新编大学应用英语综合教程3 U校园全套参考答案

获取全套答案&#xff1a; 链接&#xff1a;https://pan.quark.cn/s/abaa0338724e...

Kubernetes中的 iptables 规则介绍

#作者&#xff1a;邓伟 文章目录 一、Kubernetes 网络模型概述二、iptables 基础知识三、Kubernetes 中的 iptables 应用四、查看和调试 iptables 规则五、总结 在 Kubernetes 集群中&#xff0c;iptables 是一个核心组件&#xff0c; 用于实现服务发现和网络策略。iptables 通…...

操作系统 2.2-多进程总体实现

多个进程使用CPU的图像 如何使用CPU呢&#xff1f; 通过让程序执行起来来使用CPU。 如何充分利用CPU呢&#xff1f; 通过启动多个程序&#xff0c;交替执行来充分利用CPU。 启动了的程序就是进程&#xff0c;所以是多个进程推进 操作系统需要记录这些进程&#xff0c;并按照…...

基于SeaShips数据集的yolov8训练教程

之前已经试过在yolov3和faster-rcnn上训练SeaShips数据集&#xff0c;本次在yolov8上进行训练。 yolov8的训练有两种方式&#xff0c;一种是在mmdetection框架下下载mmyolo运行&#xff0c;另一种是直接采用ultralytics。本文两种方法都会介绍。 目录 一、mmyolo 1.1 创建环…...

【时间序列聚类】从数据中发现隐藏的模式

在大数据时代&#xff0c;时间序列数据无处不在。无论是股票市场的价格波动、天气的变化趋势&#xff0c;还是用户的点击行为&#xff0c;这些数据都随着时间推移而产生。然而&#xff0c;面对海量的时间序列数据&#xff0c;我们如何从中提取有价值的信息&#xff1f;答案之一…...

在线研讨会 | 加速游戏和AI应用,全面认识Imagination DXTP GPU

近日&#xff0c;Imagination宣布推出 Imagination DXTP GPU IP&#xff0c;该产品重新定义了智能手机和其他功耗受限设备的图形和计算加速。它专为高效的效率而设计&#xff0c;能够提供运行AI、游戏和用户界面体验所需的性能&#xff0c;确保这些体验可以全天候流畅且持续地运…...

百度SEO关键词布局从堆砌到场景化的转型指南

百度SEO关键词布局&#xff1a;从“堆砌”到“场景化”的转型指南 引言 在搜索引擎优化&#xff08;SEO&#xff09;领域&#xff0c;关键词布局一直是核心策略之一。然而&#xff0c;随着搜索引擎算法的不断升级和用户需求的多样化&#xff0c;传统的“关键词堆砌”策略已经…...

数据库基础练习1

目录 1.创建数据库和表 2.插入数据 创建一个数据库&#xff0c;在数据库种创建一张叫heros的表&#xff0c;在表中插入几个四大名著的角色&#xff1a; 1.创建数据库和表 #创建表 CREATE DATABASE db_test;#查看创建的数据库 show databases; #使用db_test数据库 USE db_te…...

UVC for USBCamera in Android

基于UVC 协议&#xff0c;完成USBCamera 开发 文章目录 一、目的&#xff1a;二、USBCamera 技术实现方案难点 三、误区&#xff1a;四、基础补充、资源参考架构图了解Camera相关专栏零散知识了解部分相机源码参考&#xff0c;学习API使用&#xff0c;梳理流程&#xff0c;偏应…...

C++学习之路,从0到精通的征途:入门基础

目录 一.C的第一个程序 二.命名空间 1.namespace的价值 2.命名空间的定义 3.命名空间使用 三.C的输入与输出 1.<iostream> 2.流 3.std(standard) 四.缺省参数 1.缺省参数的定义 2.全缺省/半缺省 3.声明与定义 ​五.函数重载 1.参数个数不同 2.参数类型不…...

RSA-OAEP填充方案与定时攻击防护

目录 RSA-OAEP填充方案与定时攻击防护一、前言二、RSA 与 OAEP 填充方案概述2.1 RSA 加密算法基础2.2 OAEP 填充方案的引入2.3 数学公式推导 三、定时攻击原理与防护策略3.1 定时攻击的基本原理3.2 防护定时攻击的策略 四、基于 Python 的 RSA-OAEP 与定时攻击防护实现五、完整…...

探索高性能AI识别和边缘计算 | NVIDIA Jetson Orin Nano 8GB 开发套件测评总结

# NVIDIA Jetson Orin Nano 8GB测评&#xff1a;当边缘计算遇上"性能暴徒"&#xff0c;树莓派看了想转行 引言&#xff1a;比咖啡机还小的"AI超算"&#xff0c;却让开发者集体沸腾 2025年的某个深夜&#xff0c;程序员老王盯着工位上巴掌大的NVIDIA Jets…...

Seata

Seata是一款开源的分布式事务解决方案&#xff0c;由阿里巴巴发起并维护&#xff0c;旨在帮助应用程序管理和协调分布式事务。以下是对Seata的详细介绍&#xff1a; 一、概述 Seata致力于提供高性能和简单易用的分布式事务服务&#xff0c;它为用户提供了AT、TCC、SAGA和XA等…...

STM32之Unix时间戳

时间戳按秒计时&#xff0c;可转换成年月日时分。32有符号存储时间戳&#xff0c;2的32次/2-1到2038年&#xff0c;STM32是2的32次方-1&#xff0c;到2106年溢出。所有时区共用一个时间戳秒计数器&#xff0c;在伦敦和北京都是0&#xff0c;不同经度加上小时即可。...

告别手动复制粘贴:可定时自动备份的实用软件解析

软件介绍 此前不少小伙伴都在找备份工具&#xff0c;其实复制文件用fastcopy就可以&#xff0c;但它需要手动操作。 今天介绍的简易备份工具则能实现定时备份。 这款软件有个小问题&#xff0c;当源目录和目标目录路径太长时&#xff0c;【立即备份】按钮可能会超出软件界面范…...

Django下防御Race Condition

目录 漏洞原因 环境搭建 复现 A.无锁无事务时的竞争攻击 B.无锁有事务时的竞争攻击 防御 A.悲观锁加事务防御 B.乐观锁加事务防御 总结 漏洞原因 Race Condition 发生在多个执行实体&#xff08;如线程、进程&#xff09;同时访问共享资源时&#xff0c;由于执行顺序…...