云图三维 | Three.js 按需加载

云图三维 连接你·创造的世界 致力于打造国内第一家集查看、建模、装配和渲染于一体的“云端CAD”协作设计平台。

应读者的要求,希望我们成立一个专业的、面向成渝地区的前端开发人员的webgl、Threejs行业QQ交流群,便于大家讨论问题。群里有研究webgl、Threejs大佬哦,欢迎大家加入!——点击链接加入群聊【three.js/webgl重庆联盟群】:jq.qq.com/?_wv=1027&k…

按需加载

在three.js中,他们设置了一个 requestAnimationFrame循环或rAF 循环这样的东西

   function render() {
       ...
       requestAnimationFrame(render);
   }
   requestAnimationFrame(render);
复制代码

对于有动画效果的东西来说这是有道理的,但是对于没有动画效果的东西呢?在这种情况下,连续渲染会浪费设备电源,如果用户使用便携式设备,则会浪费用户的电池。

解决这个问题最明显的方法是在开始时渲染一次,然后仅在发生变化时才渲染。更改包括最终加载的纹理或模型、来自某些外部来源的数据、用户调整设置或相机提供其他相关输入。  

首先,我们将控制器添加进来,OrbitControls以便我们可以响应一些可以更改的内容。


   import * as THREE from './resources/three/r132/build/three.module.js';

   import {OrbitControls} from './resources/threejs/r132/examples/jsm/controls/OrbitControls.js';

复制代码

并设置它们


   const fov = 75;

   const aspect = 2; // 画布默认

   const near = 0.1;

   const far = 5;

   const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);

   camera.position.z = 2;

    

   const controls = new OrbitControls(camera, canvas);

   controls.target.set(0, 0, 0);

   controls.update();

复制代码

由于我们将不再为立方体设置动画,因此我们不再需要跟踪它们  


   makeInstance(geometry, 0x44aa88, 0);

   makeInstance(geometry, 0x8844aa, -2);

   makeInstance(geometry, 0xaa8844, 2);

复制代码

我们可以删除动画立方体的代码和调用 requestAnimationFrame  


function render() {

   if (resizeRendererToDisplaySize(renderer)) {

       const canvas = renderer.domElement;

       camera.aspect = canvas.clientWidth / canvas.clientHeight;

       camera.updateProjectionMatrix();
   }

   renderer.render(scene, camera);

}

复制代码

我们需要随时渲染OrbitControls更改相机设置。幸运的是,OrbitControls只要有change事情发生变化,就会调度一个事件。


   controls.addEventListener('change', render);

复制代码

我们还需要处理用户调整窗口大小的情况。这在之前是自动处理的,因为我们是连续渲染的,但现在我们不需要在窗口改变大小时渲染。


   window.addEventListener('resize', render);

复制代码

有了这个,我们得到了一些按需渲染的东西。如下图所示

image.png

查看实例

OrbitControls中可以选择添加一种惯性,使他们感觉不那么生硬。我们可以通过将enableDamping属性设置为 true来启用此功能。

   controls.enableDamping = true;
复制代码

随着enableDamping我们需要调用controls.update的渲染函数,以便在OrbitControls平滑移动时可以继续为我们提供新的相机设置。但是,这意味着我们不能在render中直接调用change事件,因为我们最终会陷入无限循环。控件将向我们发送一个change事件和renderrender将调用controls.updatecontrols.update将发送另一个change事件。

我们可以通过调用requestAnimationFrame来解决这个问题,render但是我们需要确保我们只在没有被请求的情况下才请求一个新的帧,我们可以通过保留一个变量来跟踪我们是否已经请求了一个帧。


   let renderRequested = false;

   function render() {

       renderRequested = false;
       if (resizeRendererToDisplaySize(renderer)) {

           const canvas = renderer.domElement;

           camera.aspect = canvas.clientWidth / canvas.clientHeight;

           camera.updateProjectionMatrix();

       }

       renderer.render(scene, camera);

   }

   render();

   function requestRenderIfNotRequested() {

       if (!renderRequested) {

           renderRequested = true;

           requestAnimationFrame(render);
       }
   }

   controls.addEventListener('change', requestRenderIfNotRequested);

复制代码

我们也可以使用requestRenderIfNotRequested来调整大小


   window.addEventListener('resize', requestRenderIfNotRequested);

复制代码

可能很难看出区别。尝试单击下面的示例并使用箭头键来回移动或拖动旋转。然后尝试单击上面的示例并执行相同的操作,您应该能够分辨出不同之处。当您按箭头键或拖动时,上方的会捕捉,下方的会滑动。

image.png

查看实例

我们还添加一个简单的 dat.GUI GUI 并使其更改按需呈现。


   import * as THREE from './resources/three/r132/build/three.module.js';

   import {OrbitControls} from './resources/threejs/r132/examples/jsm/controls/OrbitControls.js';

   import {GUI} from '../3rdparty/dat.gui.module.js';

复制代码

我们可以设置每个立方体的颜色和 x 比例。为了能够设置颜色,我们将使用ColorGUIHelper来创建。

首先我们需要创建一个GUI


   const gui = new GUI();

复制代码

然后对于每个多维数据集,我们将创建一个文件夹并添加 2 个控件,一个用于 material.color,另一个用于cube.scale.x


   function makeInstance(geometry, color, x) {

       const material = new THREE.MeshPhongMaterial({color});
       const cube = new THREE.Mesh(geometry, material);
       scene.add(cube);
       cube.position.x = x;
       const folder = gui.addFolder(`Cube${x}`);
       folder.addColor(new ColorGUIHelper(material, 'color'), 'value')
       .name('color')
       .onChange(requestRenderIfNotRequested);
       folder.add(cube.scale, 'x', .1, 1.5)
       .name('scale x')
       .onChange(requestRenderIfNotRequested);
       folder.open();
       return cube;
   }

复制代码

你可以看到上面的 dat.GUI 控件有一个onChange方法,当 GUI 改变一个值时,你可以传递一个回调来调用。在我们的例子中,我们只需要在requestRenderIfNotRequested中调用folder.open使文件夹开始扩展。

image.png

查看实例

我希望这能让你对如何让three.js 按需渲染而不是连续渲染有所了解。按需呈现three.js 的应用程序/页面不像大多数使用three.js 的页面那样常见,要么是游戏要么是3D 动画艺术,但可以更好地按需呈现的页面示例可以说是地图查看器、3d 编辑器、 3d 图形生成器、产品目录等...

翻译于:threejsfundamentals.org/threejs/les…

写在最后

本文介绍了Three.js按需加载相关的内容,希望对你有帮助。

本文发布自 云图三维大前端团队,文章未经授权禁止任何形式的转载。

猜你喜欢

转载自juejin.im/post/7019258580356300836