【Three.js】渲染模型卡顿的优化办法

这篇具有很好参考价值的文章主要介绍了【Three.js】渲染模型卡顿的优化办法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

事先说明

优化方法是根据chatGPT的回答下,我这里记录一下,有的方法进行了尝试,有的还没有。


1、模型面数过多导致渲染卡顿

可以通过减少面数来优化,也可以使用LOD技术(Level of Detail)在不同距离下使用不同的模型细节来优化。

使用LOD技术可以在不同距离下使用不同的模型细节来优化three.js渲染性能,下面是具体步骤:

  1. 创建多个模型,每个模型的面数和细节不同,这些模型应该是同一个对象的不同版本。

  2. 将这些模型按照从低到高的细节顺序添加到同一个LOD(Level of Detail)对象中,如下所示:

const lod = new THREE.LOD();
const lowDetailModel = ... // 低细节模型
const midDetailModel = ... // 中细节模型
const highDetailModel = ... // 高细节模型
lod.addLevel(lowDetailModel, 0); // 添加低细节模型,距离为0
lod.addLevel(midDetailModel, 100); // 添加中细节模型,距离为100
lod.addLevel(highDetailModel, 200); // 添加高细节模型,距离为200
  1. LOD对象添加到场景中。
scene.add(lod);
  1. 在渲染循环中,根据相机与LOD对象的距离,自动选择当前需要显示的模型细节等级。可以使用THREE.LOD对象的update方法来实现。
function render() {
  requestAnimationFrame(render);
  lod.update(camera);
  renderer.render(scene, camera);
}

2、材质贴图过大导致渲染卡顿

可以通过减小贴图尺寸压缩贴图格式,使用纹理集(Texture Atlas)等方式来优化。

使用纹理集(Texture Atlas)可以将多张小纹理图合并成一张大纹理图,从而减少渲染时的纹理切换次数,优化three.js渲染性能,下面是具体步骤:

  1. 创建一张大纹理图,并将多张小纹理图拼接在一起,这些小纹理图应该是同一对象的不同部分,如下所示:
const texture = new THREE.TextureLoader().load('atlas.png');
const material = new THREE.MeshBasicMaterial({ map: texture });
  1. 将每个物体的UV坐标映射到对应的小纹理图区域,需要根据小纹理图在大纹理图中的位置和大小计算出UV坐标,如下所示:
const geometry = new THREE.BoxGeometry(1, 1, 1);
const uvAttribute = geometry.attributes.uv;
for (let i = 0; i < uvAttribute.count; i++) {
  const u = uvAttribute.getX(i);
  const v = uvAttribute.getY(i);
  // 根据小纹理图在大纹理图中的位置和大小计算出UV坐标
  uvAttribute.setXY(i, u * smallTextureWidth / bigTextureWidth + smallTextureX / bigTextureWidth, v * smallTextureHeight / bigTextureHeight + smallTextureY / bigTextureHeight);
}
  1. 在渲染循环中,更新大纹理图的偏移和缩放值。
function render() {
  requestAnimationFrame(render);
  const time = Date.now() * 0.001;
  texture.offset.x = time * 0.1; // x方向偏移量
  texture.offset.y = time * 0.2; // y方向偏移量
  texture.repeat.set(2, 2); // 横向和纵向缩放值
  renderer.render(scene, camera);
}

3、着色器复杂度过高导致渲染卡顿

可以通过简化着色器,使用预编译的着色器,使用Instancing等方式来优化。

使用Instancing(实例化)可以将多个相同的物体复用同一个几何体和材质,并在渲染时进行一次性绘制,从而减少渲染调用次数,优化three.js渲染性能,下面是具体步骤:

  1. 创建一个几何体和材质,将它们分别作为多个物体的原型。
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
  1. 创建一个InstancedBufferGeometry对象,并将原型几何体的属性复制到它的属性中。
const instances = 10000; // 实例数量
const instancedGeometry = new THREE.InstancedBufferGeometry();
instancedGeometry.copy(geometry); // 复制几何体属性
const translations = new Float32Array(instances * 3); // 实例位置数组
for (let i = 0; i < instances; i++) {
  translations[i * 3] = Math.random() * 100 - 50;
  translations[i * 3 + 1] = Math.random() * 100 - 50;
  translations[i * 3 + 2] = Math.random() * 100 - 50;
}
instancedGeometry.setAttribute('translation', new THREE.InstancedBufferAttribute(translations, 3));
  1. 创建一个InstancedMesh对象,并将原型材质和实例化几何体作为它的参数。
const instancedMesh = new THREE.InstancedMesh(instancedGeometry, material, instances);
scene.add(instancedMesh);
  1. 在渲染循环中,更新实例化几何体的属性,即实例的位置、旋转和缩放等信息。
function render() {
  requestAnimationFrame(render);
  const time = Date.now() * 0.001;
  for (let i = 0; i < instances; i++) {
    const translation = instancedMesh.geometry.attributes.translation;
    translation.setXYZ(i, Math.sin(time + i * 0.5) * 5, Math.cos(time + i * 0.3) * 5, i * 0.1);
  }
  instancedMesh.geometry.attributes.translation.needsUpdate = true; // 更新实例位置属性
  renderer.render(scene, camera);
}

4、不合理的渲染方式导致渲染卡顿

可以通过使用合适的渲染方式,如WebGL2渲染,使用Web Worker等方式来优化。

Ⅰ、使用WebGL2可以在现代浏览器中利用新的图形处理能力,优化three.js渲染性能,下面是具体步骤:
① 在渲染器中启用WebGL2。

const renderer = new THREE.WebGLRenderer({ canvas: canvas, context: canvas.getContext('webgl2') });

② 使用WebGL2支持的新特性,如transform feedbackinstanced arrays等。
例如,以下代码演示了如何使用transform feedback来记录顶点位置的变化:

const transformFeedback = new THREE.WebGL2TransformFeedback();
const bufferGeometry = new THREE.BufferGeometry();
const positions = new Float32Array([0, 0, 0]);
bufferGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
const shader = new THREE.ShaderMaterial({
  vertexShader: `
    out vec3 transformedPosition;
    void main() {
      transformedPosition = position;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    void main() {
      gl_FragColor = vec4(1.0);
    }
  `,
  transformFeedback: {
    // 将顶点位置记录到transformedPosition变量中
    varyings: ['transformedPosition'],
    // 开启transform feedback
    enabled: true,
    // 设置bufferGeometry的位置属性为transform feedback的输出属性
    bufferGeometry: bufferGeometry
  }
});
const mesh = new THREE.Mesh(bufferGeometry, shader);
scene.add(mesh);
function render() {
  requestAnimationFrame(render);
  renderer.setRenderTarget(null);
  // 开始transform feedback
  transformFeedback.begin();
  renderer.render(scene, camera);
  // 结束transform feedback,并将变化后的顶点位置存储到bufferGeometry中
  transformFeedback.end();
  // 更新顶点位置
  positions.set(bufferGeometry.getAttribute('position').array);
  bufferGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  renderer.render(scene, camera);
}

---------------------------------------------------------------分隔线-----------------------------------------------------------------


Ⅱ、使用Web Worker可以将计算密集型的任务分离到另一个线程中,从而避免主线程被阻塞,优化three.js渲染性能,下面是具体步骤:

① 创建一个Web Worker,用于处理计算密集型的任务。

const worker = new Worker('worker.js');

② 在Web Worker中定义处理函数。

// worker.js
function process(data) {
  // 计算密集型的任务
  return result;
}
onmessage = function(event) {
  const result = process(event.data);
  postMessage(result);
};

③ 在主线程中将任务发送到Web Worker,并设置回调函数处理返回结果。

function render() {
  requestAnimationFrame(render);
  // 发送任务到Web Worker
  worker.postMessage(data);
  worker.onmessage = function(event) {
    const result = event.data;
    // 处理返回结果
  };
  renderer.render(scene, camera);
}

通过以上步骤,就可以使用Web Worker来将计算密集型的任务分离到另一个线程中,从而避免主线程被阻塞,优化three.js渲染性能。需要注意的是,Web Worker中无法直接访问主线程的DOM和three.js对象,需要通过消息传递来实现通信。


5、CPU和GPU资源不平衡导致渲染卡顿

可以通过分析性能监控,优化代码逻辑,使用requestAnimationFrame等方式来平衡CPU和GPU资源占用。

使用requestAnimationFrame可以让浏览器根据自身的渲染节奏调整动画的帧率,从而避免过度渲染,优化three.js渲染性能,下面是具体步骤:

  1. 将渲染函数作为requestAnimationFrame的回调函数。
function render() {
  // 渲染代码
  renderer.render(scene, camera);
  // 请求下一帧动画
  requestAnimationFrame(render);
}
  1. 在初始化时调用一次requestAnimationFrame,启动动画。
var animationId = requestAnimationFrame(render);
  1. 在动画结束时,记得停止requestAnimationFrame,以避免不必要的资源消耗。
function stop() {
  cancelAnimationFrame(animationId);
}

需要注意的是,使用requestAnimationFrame时需要避免在渲染循环中进行过多的计算,以免影响渲染性能。文章来源地址https://www.toymoban.com/news/detail-446357.html

到了这里,关于【Three.js】渲染模型卡顿的优化办法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Three.js初识:渲染立方体、3d字体、修改渲染背景颜色

    用场景对three.js进行渲染:场景、相机、渲染器 场景 透视摄影机 参数解析: fov: 视野角度(FOV)。视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)。 aspect: 长宽比(aspect ratio)。 也就是你用一个物体的宽除以它的高的值

    2024年02月07日
    浏览(32)
  • 基于Three.js的WebXR渲染入门

    我不会花太多时间讨论 Three.JS 渲染管道的工作原理,因为它在互联网上有详细记录(例如,此链接)。 我将在下图中列出基础知识,以便更容易理解各个部分的去向。 在我们深入了解 WebXR API 本身之前,您应该知道 WebXR 设备 API Polyfill 可通过两种主要方式帮助开发人员: 如

    2024年02月11日
    浏览(33)
  • 多个数据webSocket推送太快导致前端渲染卡顿问题优化

    作者代码写的不怎么样,谅解!主要思路就是把websocket接收到的数据用一个数组暂存起来,达到一定数量一起修改统一渲染,可根据项目数据推送数据的速度适当调解数组大小,然后再加了一个可能一段时间内都到不到数组达标渲染数量,就使用定时器直接做渲染,防止数据

    2024年02月12日
    浏览(34)
  • Three.js之相机、渲染器、光源、动画、性能监测

    第一个3D案例—透视投影相机 第一个3D案例—渲染器 … Canvas画布布局和全屏 透视投影相机PerspectiveCamera WebGL渲染器WebGLRenderer 辅助观察坐标系AxesHelper 漫反射网格材质MeshLambertMaterial 点光源PointLight 点光源辅助观察PointLightHelper 环境光AmbientLight 平行光DirectionalLight 平行光辅助观

    2024年02月13日
    浏览(33)
  • Three.js教程:WebGL渲染器设置(锯齿模糊)

    推荐:将 NSDT场景编辑器 加入你的3D工具链 其他系列工具: NSDT简石数字孪生 一般实际开发,threejs的WebGL渲染器需要进行一些通用的基础配置,本节课给大家简单介绍下,比如渲染模糊或锯齿问题。 渲染器锯齿属性 .antialias 设置渲染器锯齿属性 .antialias 的值可以直接在参数中

    2024年02月11日
    浏览(38)
  • Three.js之几何体、高光材质、渲染器设置、gui

    阵列立方体和相机适配体验 Threejs常见几何体简介 … gui.js库(可视化改变三维场景) 注:基于Three.js v0.155.0 长方体:BoxGeometry 球体:SphereGeometry 圆柱:CylinderGeometry 矩形平面:PlaneGeometry 圆形平面:CircleGeometry 高光网格材质:MeshPhongMaterial(shininess、specular) WebGL渲染器设置:

    2024年02月11日
    浏览(39)
  • 【Three.js基础】创建场景、渲染场景、创建轨道控制器(一)

    🐱 个人主页: 不叫猫先生 🙋‍♂️ 作者简介:前端领域新星创作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀! 💫系列专栏:vue3从入门到精通、TypeScript从入门到实践 📢 资料领取:前端进阶资料以及文中源码可以找我免费领取 🔥 前端

    2024年02月01日
    浏览(42)
  • three js模型旋转

    如何让立方体模型旋转到指定的面 父页面 效果:

    2024年02月15日
    浏览(29)
  • Three.js 三维模型(一)

    今天主要给搭建介绍下three.js的基本使用,本篇是基于笔者在16年给做的一个项目的demo版进行讲解的,笔者当时采用Html5和JS进行编写的。可能大家会问有没有vue、React 、angular版的。这些笔者后面有时间的时候一定会给大家介绍。 其实编程的本源在于提炼属于自己的哲学思想

    2024年02月16日
    浏览(25)
  • three.js添加3d模型

    three官方的几何体也就那么几个,想要生成各种各样的模型,其难度十分之大,这时引入外部模型也不失为一种选择。具体引入办法如下。 虽然名字为GLTFLoader,但实际上glb文件也是能加载的。 其中需要注意的是调节相机参数与相机位置,否则很有可能导致场景中看不见任何东

    2024年02月04日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包