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

Three.js性能优化和实践建议

Three.js 是一个功能强大的 3D 引擎,当场景足够大的时候,就会出现卡顿的现象,首先要保证电脑的性能够用,然后看看下面方法,帮助你提高应用的运行效率。

1. 使用 stats.js 监视性能

在进行任何优化之前,首先要监视应用的性能。stats.js 是一个简单而有效的工具,可以帮助你实时监视帧率(FPS)、每帧渲染所需时间(MS)和内存使用情况(MB)。

安装和使用 stats.js

首先,通过 npm 安装 stats.js

npm install --save stats.js

然后,可以在 Three.js 项目中使用它:

import Stats from 'stats.js';
​
const stats = new Stats();
stats.showPanel(0); // 显示面板 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild(stats.dom);
​
const tick = () => {stats.begin();// 监视的代码放在这里stats.end();requestAnimationFrame(tick);
};
​
requestAnimationFrame(tick);

FPS:在最后一秒内渲染的帧数。数值越高越好。

MS:渲染一帧所需的毫秒数。数值越低越好。

MB:分配的内存大小(以兆字节为单位)。需要在 Chrome 中使用 --enable-precise-memory-info 启动。

CUSTOM:用户自定义面板支持。

2. 优化几何体和材质

复杂的几何体和高分辨率的材质会显著影响渲染性能。以下是一些优化建议:

降低几何体细节

使用 THREE.LOD(Level of Detail)类来根据摄像机距离动态切换几何体细节。

import * as THREE from 'three';
​
// 创建场景和相机
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 10;
​
// 创建渲染器
const renderer = new THREE.WebGLRenderer({antialias: true,powerPreference: 'high-performance'
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
​
// 创建不同细节级别的几何体
const highDetailGeometry = new THREE.BoxGeometry(1, 1, 1, 32, 32, 32);
const mediumDetailGeometry = new THREE.BoxGeometry(1, 1, 1, 16, 16, 16);
const lowDetailGeometry = new THREE.BoxGeometry(1, 1, 1, 8, 8, 8);
​
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
​
// 使用 LOD 动态切换几何体
const lod = new THREE.LOD();
lod.addLevel(new THREE.Mesh(highDetailGeometry, material), 0);
lod.addLevel(new THREE.Mesh(mediumDetailGeometry, material), 5);
lod.addLevel(new THREE.Mesh(lowDetailGeometry, material), 10);
scene.add(lod);
​
// 动画循环
const animate = function () {requestAnimationFrame(animate);
​// 旋转 LODlod.rotation.x += 0.01;lod.rotation.y += 0.01;
​// 更新摄像机位置camera.position.x = Math.sin(Date.now() * 0.001) * 20;camera.position.z = Math.cos(Date.now() * 0.001) * 20;camera.lookAt(scene.position);
​// 渲染场景和相机renderer.render(scene, camera);
};
​
animate();

使用压缩纹理

使用压缩纹理格式(如 DDS、KTX2)来减少内存占用和加载时间。这里以 KTX2 为例。

首先,安装 three/examples/jsm/loaders/KTX2Loader.jsBasisu 解码器,然后,在你的项目中使用 KTX2Loader 加载压缩纹理:

import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
import { MeshStandardMaterial } from 'three';
​
// 创建 KTX2Loader
const ktx2Loader = new KTX2Loader().setTranscoderPath('path/to/basisu/transcoder/') // 设置 Basisu 解码器路径.detectSupport(renderer);
​
// 加载 KTX2 压缩纹理
ktx2Loader.load('path/to/texture.ktx2', (texture) => {const material = new MeshStandardMaterial({ map: texture });
​const geometry = new THREE.BoxGeometry(1, 1, 1);const mesh = new THREE.Mesh(geometry, material);scene.add(mesh);
});

合并几何体

(1)使用Blender将模型合并一下

(2)将多个几何体合并为一个几何体,以减少绘制调用(draw call)的次数。使用将使用BufferGeometryUtils 合并几何体。

import { BufferGeometryUtils } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
​
// 创建多个几何体
const geometries = [];
for (let i = 0; i < 50; i++) {const geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
​geometry.translate((Math.random() - 0.5) * 10,(Math.random() - 0.5) * 10,(Math.random() - 0.5) * 10);
​geometries.push(geometry);
}
​
// 合并几何体
const mergedGeometry = BufferGeometryUtils.mergeBufferGeometries(geometries);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(mergedGeometry, material);
scene.add(mesh);
​
// 动画循环
const animate = function () {requestAnimationFrame(animate);
​// 旋转合并后的几何体mesh.rotation.x += 0.01;mesh.rotation.y += 0.01;
​// 渲染场景和相机renderer.render(scene, camera);
};
​
animate();

3. 优化灯光和阴影

灯光和阴影计算开销较大,特别是多光源和动态阴影。以下是一些优化建议:

  • 减少光源数量:尽量减少场景中的光源数量,选择性能开销较小的光源如 AmbientLight 和 DirectionalLight。
  • 优化阴影贴图:降低阴影贴图的分辨率,并限制阴影相机的视野范围,以减少计算开销。
  • // 优化阴影贴图
    directionalLight.shadow.mapSize.width = 1024; // 默认值是 512
    directionalLight.shadow.mapSize.height = 1024; // 默认值是 512
    ​
    // 限制阴影相机的视野范围
    directionalLight.shadow.camera.top = 3;
    directionalLight.shadow.camera.right = 6;
    directionalLight.shadow.camera.left = -6;
    directionalLight.shadow.camera.bottom = -3;
    directionalLight.shadow.camera.near = 0.1;
    directionalLight.shadow.camera.far = 10;
    ​
    // 可选:使用相机助手查看阴影相机的范围
    const cameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
    scene.add(cameraHelper);
    
  • 静态光照贴图:对于静态场景,可以预先计算光照和阴影,生成光照贴图。这里我们使用 Lightmap,一个 Three.js 的扩展,可以帮助实现静态光照贴图。

首先,安装 three-lightmap

npm install three-lightmap

然后,在你的项目中使用 three-lightmap 来生成静态光照贴图:

import { Lightmap } from 'three-lightmap';
​
// 创建静态光照贴图
const lightmap = new Lightmap(scene, renderer, {mapSize: 1024,samples: 4,bake: true,exposure: 0.7,softEdges: 0.01,aoOnly: false,aoStrength: 0.6
});
​
// 在几何体上启用静态光照贴图
cube.material.lightMap = lightmap.generate(cube.geometry);
plane.material.lightMap = lightmap.generate(plane.geometry);
​
// 运行一次性光照贴图烘焙过程
lightmap.bake();

4. 纹理贴图

纹理贴图非常消耗 GPU 内存,以下是一些优化建议:

  • 调整尺寸:调整纹理贴图的分辨率可以通过图像编辑工具(如 Photoshop、GIMP)或编程工具(如 Sharp for Node.js)来实现。在加载纹理时,可以使用 Three.js 内置的 THREE.TextureLoader 来加载已经调整好尺寸的纹理。

  • 使用正确格式:确保使用合适的文件格式(如 .jpg 或 .png)。可以使用在线工具如 TinyPNG 来压缩纹理文件,减小文件大小,同时保持较高的视觉质量。

  • 保持分辨率为 2 的幂次方:确保纹理尺寸为 2 的幂次方(如 256x256, 512x512,1024x1024) 如果纹理的尺寸不是 2 的幂次方,Three.js 会自动调整它们,但这会影响性能。

5. 使用对象池

在动画或游戏应用中,经常需要频繁创建和销毁对象。使用对象池可以有效减少内存分配和垃圾回收频繁的开销。

class ObjectPool {constructor(createFunc, size) {this.createFunc = createFunc;this.pool = [];for (let i = 0; i < size; i++) {this.pool.push(this.createFunc());}}
​get() {return this.pool.length ? this.pool.pop() : this.createFunc();}
​release(obj) {this.pool.push(obj);}
}

6. 渲染器优化

以下是一些针对渲染器的优化建议:

限制像素比:一些设备有非常高的像素比,但渲染的像素越多,消耗的性能越大。将渲染器的像素比限制为 2:

renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

配置偏好:指定 powerPreference 属性来提示用户代理适当的 GPU 配置:

const renderer = new THREE.WebGLRenderer({ powerPreference: 'high-performance' });

抗锯齿:只有在有明显锯齿且不会显著影响性能时才启用抗锯齿。

// 创建渲染器时启用抗锯齿
const renderer = new THREE.WebGLRenderer({canvas: document.querySelector('#canvas'),antialias: true, // 启用抗锯齿powerPreference: 'high-performance' // 提示浏览器选择高性能的 GPU
});

7. 相机优化

通过缩小相机的视野范围(FOV)以及调整相机的 near 和 far 属性,可以显著减少渲染的对象数量,从而提高渲染性能。下面是具体的实现代码和逻辑说明。

缩小相机的视野范围

通过减少相机的视野角度(FOV),可以让屏幕中显示的对象更少,从而减少需要渲染的三角形数量。

调整相机的近端面和远端面

调整相机的 near 和 far 属性,可以确保只渲染特定范围内的对象,避免渲染不必要的远距离对象。

// 调整相机的视野角度和近端面、远端面
const fov = 50; // 缩小视野角度(默认值通常为75)
const aspect = window.innerWidth / window.innerHeight;
const near = 1; // 将 near 属性从 0.1 增大到 1
const far = 50; // 将 far 属性从 100 缩小到 50
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 10;

8. 清除不必要的对象

当场景中不再需要某个对象时,及时清除它:

// 创建示例对象
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
​
// 在某个时刻移除对象
function removeObject(object) {// 移除对象scene.remove(object);// 释放几何体资源if (object.geometry) {object.geometry.dispose();}// 释放材质资源if (object.material) {if (Array.isArray(object.material)) {// 如果材质是数组,遍历并释放每个材质object.material.forEach((material) => {material.dispose();});} else {// 单一材质,直接释放object.material.dispose();}}// 释放纹理资源if (object.material.map) {object.material.map.dispose();}
}
// 在某个时刻调用函数移除对象
removeObject(cube);

9. 后期处理和着色器优化

限制后期处理通道

每个后期处理过程都会增加渲染负担,尽量减少不必要的后期处理步骤。

着色器优化

  • 指定精度:强制材质中着色器的精度:

const shaderMaterial = new THREE.ShaderMaterial({ precision: 'lowp' });
  • 保持代码简单:尽量保持着色器代码简单,避免复杂的逻辑和多层嵌套。

  • 使用贴图纹理:尽量使用纹理来代替复杂的计算,例如噪声生成。

  • 使用 defines:对于不会改变的值,使用 defines 而不是 uniform

const shaderMaterial = new THREE.ShaderMaterial({defines: { uDisplacementStrength: 1.5 },
});

性能优化任重而道远,有更好的方法可以分享出来呀。

相关文章:

Three.js性能优化和实践建议

Three.js 是一个功能强大的 3D 引擎&#xff0c;当场景足够大的时候&#xff0c;就会出现卡顿的现象&#xff0c;首先要保证电脑的性能够用&#xff0c;然后看看下面方法&#xff0c;帮助你提高应用的运行效率。 1. 使用 stats.js 监视性能 在进行任何优化之前&#xff0c;首…...

C#入门 023 什么是类(Class)

什么是“类” 是一种数据结构 是一种数据类型 代表现实世界中的“种类” 构造器和析构器 析构器 析构器&#xff08;Destructor&#xff09;是一种特殊的成员方法&#xff0c;用于在对象被垃圾回收器&#xff08;Garbage Collector, GC&#xff09;回收之前执行清理操作。…...

一篇Spring Boot 笔记

一、Spring Boot 简介 Spring Boot 是一个用于创建独立的、基于 Spring 的生产级应用程序的框架。它简化了 Spring 应用的初始搭建和开发过程&#xff0c;通过自动配置等功能&#xff0c;让开发者能够快速地构建应用&#xff0c;减少了大量的样板代码和复杂的配置。 二、核心特…...

一生一芯 预学习阶段 NEMU代码学习(2)

接上回&#xff1a;一生一芯 预学习阶段 NEMU代码学习&#xff08;1&#xff09; 上次说到这里 static int cmd_c(char *args) {cpu_exec(-1);return 0; } 当输入c时&#xff0c;会执行&#xff1a;cpu_exec(-1); void cpu_exec(uint64_t n) {g_print_step (n < MAX_IN…...

《手写Spring渐进式源码实践》实践笔记(第二十章 实现简单ORM框架)

文章目录 第二十章 简单ORM框架实现背景技术背景基本概念工作原理优点缺点常见的ORM框架 业务背景 目标设计实现代码结构类图实现步骤 测试事先准备属性配置文件测试用例(selectOne)测试结果测试用例(selectList)测试结果 总结 第二十章 简单ORM框架实现 背景 技术背景 ORM&…...

AI技术赋能电商行业:创新应用与未来展望

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《热点时事》 期待您的关注 引言 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;技术正逐步渗透到各行各业&a…...

windows 11编译安装ffmpeg(包含ffplay)

一、源码及安装包下载 1.1&#xff0c;ffmpeg源码包下载 下载地址&#xff1a;Download FFmpeg 1.2&#xff0c;mysys下载 下载地址&#xff1a;MSYS2 1.3&#xff0c;libx264源码包下载 下载地址&#xff1a;x264, the best H.264/AVC encoder - VideoLAN 二、软件安装 2.1&…...

系统启动时将自动加载环境变量,并后台启动 MinIO、Nacos 和 Redis 服务

服务器信息 服务器 IP&#xff1a;192.168.1.44服务器用户&#xff1a;changzhou用户密码&#xff1a;XXXXXXXX Nacos 数据库用户信息&#xff1a; 账号&#xff1a;cz_nacos密码&#xff1a;XXXXXXXX Nacos 内网地址&#xff1a;http://192.168.1.44:8848/nacos 账号&#x…...

[ACTF2020 新生赛]Upload 1--详细解析

信息收集 题目告诉我们是一道upload&#xff0c;也就是文件上传漏洞题目。 进入界面&#xff0c;是一个灯泡&#xff0c;将鼠标放在图标上就会出现文件上传的相应位置&#xff1a; 思路 文件上传漏洞&#xff0c;先看看有没有前端校验。 在js源码中找到了前端校验&#xff…...

power bi中的related函数解析

在Power BI中&#xff0c;RELATED函数是一种用于检索相关表中数据的函数。它用于在一个表中检索与当前行相关联的另一个表中的数据。 销售成本 [销售数量]*related(商品表[进价])...

目前区块链服务商备案支持的区块链技术类型

status"success"data1-name"比特币/Bitcoin/BTC"3-name"以太坊/Ethereum/ETH"875-name"超级账本/Hyperledger"5-name"柚子/EOS/EOS"6-name"恒星链/Stellar/XLM"1055-name"Quorum"7-name"莱特币/Li…...

CatBoost中的预测偏移和排序提升

在 CatBoost 中&#xff0c;预测偏移&#xff08;Prediction Shift&#xff09; 和 排序提升&#xff08;Ordered Boosting&#xff09; 是其关键概念和创新点。CatBoost 通过引入 排序提升 解决了梯度提升决策树&#xff08;GBDT&#xff09;算法中常见的 预测偏移问题&#x…...

python: postgreSQL using psycopg2 or psycopg

psycopg2 # encoding: utf-8 # 版权所有 2024 ©涂聚文有限公司 # 許可資訊查看&#xff1a;言語成了邀功的功臣&#xff0c;還需要行爲每日來值班嗎&#xff1f; # 描述&#xff1a; pip install --upgrade pip PostgreSQL database adapter for Python # pip install…...

从 MySQL 5.7 到 8.0:理解 GROUP BY 的新规则与实战优化20241112

&#x1f3af; 从 MySQL 5.7 到 8.0&#xff1a;理解 GROUP BY 的新规则与实战优化 &#x1f50e; 引言 随着 MySQL 的不断升级&#xff0c;从 5.7 到 8.0&#xff0c;不仅性能得到提升&#xff0c;其对 SQL 标准的严格执行也显著提高。GROUP BY 的行为变化就是一个典型例子。…...

npm完整发包流程(亲测可验证)

1. 准备工作 &#xff08;1&#xff09; 在npm官网上注册一个账号 &#xff08;2&#xff09; 注册成功之后&#xff0c;npm会发送一封邮件给你&#xff0c;点击邮件里面的链接&#xff0c;做确认关联操作&#xff08;必需&#xff09; 2. 创建自己的npm包 &#xff08;…...

学习threejs,使用JSON格式保存和加载模型

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE toJSON()方法 二、&a…...

中国首部《能源法》正式问世,它的亮点有哪些呢?

2024年11月8日&#xff0c;《中华人民共和国能源法》经十四届全国人大常委会第十二次会议审议通过&#xff0c;正式出台&#xff0c;将于明年1月1日起施行。 中国首部《能源法》正式问世&#xff0c;它的亮点有哪些呢&#xff1f; 一、填补立法空白&#xff0c;完善能源法律体…...

【外包】软件行业的原始形态,项目外包与独立开发者

【外包】互联网软件行业的原始形态&#xff0c;项目外包与独立开发者 本科期间写的一些东西&#xff0c;最近整理东西看到了&#xff0c;大致整理一下放出来&#xff0c;部分内容来自其他文章&#xff0c;均已引用。 文章目录 1、互联网软件行业的原始形态2、项目订单&#xff…...

工程数学线性代数(同济第七版)附册课后习题答案PDF

《线性代数附册 学习辅导与习题全解》是与同济大学数学科学学院编《工程数学 线性代数》第七版教材配套的教学辅导书&#xff0c;由同济大学作者团队根据教材内容和要求编写而成。本书在《工程数学 线性代数》第六版附册&#xff08;即辅导书&#xff09;的基础上修改而成。全书…...

【Ubuntu24.04】部署服务(基础)

目录 0 背景1 设置静态IP2 连接服务器3 部署服务3.1 安装JDK3.2 下载并安装MySQL8.43.2.1 从官网下载 APT Repository 配置文件3.2.2 安装 MySQL8.43.2.3 配置远程连接 3.3 下载并配置Redis3.4 上传jar包并部署应用3.5 开放端口 4 总结 0 背景 在成功安装了Ubuntu24.04操作系统…...

Linux符号使用记录

~ 账户 home 目录&#xff0c;如果是 root 账户就是 /root . 当前目录 .. 上层目录 | 管道符 & 后台工作&#xff0c;放在完整指令列的最后端&#xff0c;表示将该指令列放入后台中工作。 > 输出重定向&#xff0c;重新…...

初阶C++之C++入门基础

大家好&#xff01;欢迎来到C篇学习&#xff0c;这篇文章的内容不会很难&#xff0c;为c的引入&#xff0c;c的重点内容将在第二篇的文章中讲解&#xff0c;届时难度会陡然上升&#xff0c;请做好准备&#xff01; 我们先看网络上的一个梗&#xff1a;21天内⾃学精通C 好了&am…...

ODOO学习笔记(7):模块化架构(按需安装)

一、Odoo模块化架构概述 Odoo是一个功能强大的企业资源规划&#xff08;ERP&#xff09;系统&#xff0c;其模块化架构是它的核心优势之一。这种架构允许系统通过添加、移除或修改不同的模块来灵活地适应企业的各种业务需求。 核心模块与自定义模块&#xff1a; Odoo本身带有一…...

Java的dto,和多表的调用

1理论 需求是新增菜品eg&#xff1a;菜名:豆腐脑&#xff1b;口味&#xff1a;甜口&#xff0c;咸口&#xff0c; 菜单表&#xff1a;dish&#xff1b;口味表dish_flavor&#xff1b; 1dto:数据传输对象 新建一个dishDto对象有两个表里的属性 2用到两个表&#xff0c;dish,d…...

时序数据库TimescaleDB安装部署以及常见使用

文章目录 一、时序数据库二、TimescaleDB部署1、repository yum仓库配置2、yum在线安装3、插件配置4、TimescaleDB使用登录pg创建插件使用超表 一、时序数据库 什么是时序数据库&#xff1f;顾名思义&#xff0c;用于处理按照时间变化顺序的数据的数据库即为时序数据库&#x…...

MG算法(英文版)题解

翻译&#xff1a; 考虑一个加法流&#xff0c;其中一个特定项目出现 n^(1/2) 次&#xff0c;并且有 n - n^(1/2) - 1 个其他不同的项目&#xff0c;每个项目出现一次。在应用 Misra-Gries&#xff08;MG&#xff09;算法时&#xff0c;应该选择哪个 ε&#xff08;epsilon&…...

2-UML概念模型测试

1. (单选题, 1.0 分) UML中的关系不包括&#xff08;&#xff09;。 A. 抽象B. 实现C. 依赖D. 关联 我的答案:A正确答案: A 知识点&#xff1a; UML的构成 1.0分 2. (单选题, 1.0 分) 下列事物不属于UML结构事物的是&#xff08;&#xff09;。 A. 组件B. 类C. 节点D. 状…...

人工智能(AI)对于电商行业的变革和意义

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/402a907e12694df5a34f8f266385f3d2.png#pic_center> &#x1f393;作者简介&#xff1a;全栈领域优质创作者 &#x1f310;个人主页&#xff1a;百锦再新空间代码工作室 &#x1f4de;工作室&#xff1a;新空间代…...

智能病历xml提取

select * from (SELECT m.病人Id, m.主页Id, x.title, x.content.getclobval() 参考, x.content content --EXTRACTVALUE(x.Content, //zlxml//document//subdoc[antetypeid"3C38A8DAB01C473A9074A8EDD0B8553"]//utext) 主治医师, --EXTRACTVALUE(x.…...

RK3568平台开发系列讲解(GPIO篇)GPIO的sysfs调试手段

🚀返回专栏总目录 文章目录 一、内核配置二、GPIO sysfs节点介绍三、命令行控制GPIO3.1、sd导出GPIO3.2、设置GPIO方向3.3、GPIO输入电平读取3.4、GPIO输出电平设置四、Linux 应用控制GPIO4.1、控制输出4.2、输入检测4.3、使用 GPIO 中断沉淀、分享、成长,让自己和他人都能有…...