three.js使用Instanced Draw+Frustum Cull+LOD来渲染大场景(开源)
大家好,本文使用three.js实现了渲染大场景,在移动端也有较好的性能,并给出了代码,分析了关键点,感谢大家~
关键词:three.js、Instanced Draw、大场景、LOD、Frustum Cull、优化、Web3D、WebGL、开源
代码:Github
我正在承接Web3D数字孪生项目,具体介绍可看承接各种Web3D业务
加QQ群交流:106047770
需求描述
数字孪生项目通常需要渲染超大场景,比如智慧城市就需要渲染一片城市区域,甚至整个城市
渲染大场景所需要的技术点包括:
- Instanced Draw
一个Draw Call批量渲染物体,物体可以有不同的Transform、Color - Frustum Cull
剔除视椎体外的物体 - Occlusion Cull
剔除被遮挡的物体(WebGL1不支持) - LOD
根据物体到相机的距离,显示不同Level的物体。越远的越粗糙,越近的越细致 - GPU Driven Pipeline
把前几个优化都放到GPU中来做,并且物体可以有更多差异(需要WebGPU) - Space Partition
使用Octree、BVH、BSP等加速结构来划分场景,在Cull、碰撞检测、Ray Picking等操作时查询加速结构而不是遍历所有物体,从而提高性能 - Multi Thread Render
开一个渲染线程来渲染 - AssetBundle、Stream Load
划分为多个场景包,动态、流式加载
本文使用Instanced Draw+Frustum Cull+LOD来渲染大场景,最终实现效果演示:

场景总三角面数是千万级,总物体数量是1万(PC端)/5000(移动端)
动态物体数量是800(PC端)/400(移动端)
其中,树使用了Instanced Draw+LOD,白色立方体使用了Instanced Draw
可以把相机拉进、拉远,可看到不同Level的树
移动相机,可看到红框内的Triangles在变化(大概在几十万到几百万),这是Frustum Cull后的三角面数
在5年前的中配手机上,FPS可达15左右
下面开始实现各个关键点,给出实现的思路:
Instanced Draw
比如要将克隆的1000个Mesh改为Instanced的,则保留它们作为source,并创建一个InstancedMesh,count设为1000,写入1000个Mesh的世界矩阵;然后隐藏source,显示InstancedMesh
之所以保留source,是因为可以用它们来做碰撞检测、Ray Picking等单个Mesh的操作
值得注意的是物体可能是多材质的Object3D(如树),所以要将其中的每个Mesh拆分到一组Instanced Draw中。举例来说,如果树有个3个材质(即3个子Mesh),则需要创建3个InstancedMesh,然后将所有树的第一个材质的Mesh对应到第一个InstancedMesh中,其余的以此类推
Frustum Cull

如上图所示,实现Instanced Draw+Frustum Cull的原理是将要剔除的物体移到InstancedMesh的instanceMatrix的最后,并将count减1
值得注意的是要将three.js默认的对单个Object3D的frustum cull关闭(即将source的frustumCulled设为false)
另外,我们直接遍历所有的待剔除物体来进行Fustum Cull检测,没有使用Octree等加速结构
相关的讨论请参考:
Linear search vs Octree (Frustum cull)
LOD

如上图所示,假设车有3个Level的LOD层级,我们希望离相机越远,显示越高的Level(Geometry、Material越简单)
我们需要创建3个InstanceMesh,分别对应不同的Level,如下图所示:

参考资料
InstancedMesh2 - Easy handling and frustum culling
What is a more straightforward way to do instance culling?
Linear search vs Octree (Frustum cull)
LOD with Instancing and Multi-Material Meshes
Three.js InstancedMesh performance optimizations - DevLog 10
three.js使用Instanced Draw+Frustum Cull+LOD来渲染大场景(开源)的更多相关文章
- arcgis for js学习之Draw类
arcgis for js学习之Draw类 <!DOCTYPE html> <html> <head> <meta http-equiv="Cont ...
- AeroGear.js 1.2.0 发布,手机Web应用脚手架 - 开源中国社区
AeroGear.js 1.2.0 发布,手机Web应用脚手架 - 开源中国社区 AeroGear.js 1.2.0 发布,手机Web应用脚手架
- three.js引擎基础知识—摄像机、场景及渲染器
一.three.js采用右手坐标系: x轴正方向向右,y轴正方向向上,z轴由屏幕从里向外,如下图右: 二.3D编程三要素:场景.渲染器.摄像机 1.场景:创建的物品和模型都需放入场景中 threejs ...
- 关于Unity中LOD和渲染队列----渲染通道通用指令(一)
每个shader里面有很多的subshader,如果所以的subshader都不执行的话就,就执行fallback.每个subshader都可以设置一个LOD,整个shader也有一个LOD. 系统就 ...
- Vue.js 2.0源码解析之前端渲染篇
一.前言 Vue.js框架是目前比较火的MVVM框架之一,简单易上手的学习曲线,友好的官方文档,配套的构建工具,让Vue.js在2016大放异彩,大有赶超React之势.前不久Vue.js 2.0正式 ...
- Vue.js 源码分析(三) 基础篇 模板渲染 el、emplate、render属性详解
Vue有三个属性和模板有关,官网上是这样解释的: el ;提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标 template ;一个字符串模板作为 Vue 实例的标识使用.模板将会 ...
- three.js 源代码凝视(十六)Math/Frustum.js
商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 - 本博客专注于 敏捷开发 ...
- three.js 入门详解(一)
1. 概述 1.1 什么是WebGL? WebGL是在浏览器中实现三维效果的一套规范 想要使用WebGL原生的API来写3D效果的话,很吃力.three.js是WebGL的一个开源框架,它省去了很多麻 ...
- js css3实现钟表效果
原理: 利用transform-origin改变旋转的圆心,实现秒数和分钟数的刻度线,利用transfrom translate实现钟表小时刻度的显示 html: <div class=&quo ...
- 解决js动态改变dom元素属性后页面及时渲染问题
今天实现一个进度条加载过程,dom结构其实就是两个div <div class="pbar"> <div class="ui-widget-header ...
随机推荐
- 摆脱鼠标系列 - vscode vim - 自动切换到英文 - im-select
为什么 摆脱鼠标系列 - vscode vim - 自动切换到英文 - im-select 省得每次都得按 shfit 下载软件 https://gitee.com/pengchenggang/im- ...
- 22_播放器之使用SDL显示YUV视频
简介 使用SDL实现简单的YUV播放器. 这里还需要使用到像素格式和计算图片大小,这两个我们直接使用ffmpeg来实现,因此需要使用ffmpeg的libavutil/avutil.h和libavuti ...
- Redis无法向磁盘写入RBD数据
2020-12-09 11:52:25|21965|ERROR|storage/DRedisAsyncCallback.cpp:394[cbIncrby]Cmd 'INCRBY' failed, ke ...
- Linux下配置node环境与failed to create symbolic link ‘/usr/bin/utserver’: File exists跟Error: Cannot find module '/root/node-v10.16.3-linux-x64/install'解决方法
NodeJS下载地址(官网) https://nodejs.org/en/download/ 下载下来后是个tar,xz压缩包 通过xftp将压缩包上传到Linux服务器上 如我放在root目录下 使 ...
- WC-Write Combining 合并写技术
WC-Write Combining 合并写技术 为了提高写效率: CPU在写入L1时,同时用WC写入L2 实验代码: public class WriteCombining { private st ...
- css实现多余文字隐藏,用省略号代替
.txt{ overflow: hidden; //溢出内容隐藏 white-space: nowrap; //强制文本在一行内显示 text-overflow: ellipsis; //当对象内文本 ...
- nuxt环境目录结构
- Spring Cloud项目搭建版本选择
1.查看spring cloud的版本 https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4 ...
- Scala 模式匹配拓展
1 package chapter08 2 3 object Test03_MatchTupleExtend { 4 def main(args: Array[String]): Unit = { 5 ...
- Scala 传名参数和传值参数
1 package com.atguigu.chapter04 2 3 object ControlAbstraction { 4 def main(args: Array[String]): Uni ...