Vue3 + Three.js + gltf-pipeline大型园区场景渲染与3D业务

在非使用unity作为3D渲染方案的前提下,对与目前web开发者比较友好的除了canvas场景需要的2D babylon.jsfabric.js, Three.js是目前针对于jsWeb用户最直接且比较友好的3D引擎方案了。
准备工作:
1.明确需要用的场景方案都有那些,模型需要的加载器是什么
2.模型的场景大小已经相关的交互业务
3.场景的工作环境(浏览器及硬件要求)
step1:
以.glb模型为例

import * as THREE from "three";
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader";
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";

以上就是一个场景绘制需要的基本3个要素
模型压缩
由于建模工程师因为场景规模的原因模型在建立时过多了使用了面,导致整个模型的体积很大,一个校区或者大园区为例,建筑加环境要素及周边地形都整体的模型体积已经达到了100M+,这个时候就需要我们在开发前就考虑模型的压缩问题了
DRACO压缩算法

npm install -g gltf-pipeline
--input, -i                   Path to the glTF or glb file.[string] [required]
--output, -o                  Output path of the glTF or glb file. Separate   
                               resources will be saved to the same directory.  
                                                                       [string]
--binary, -b                  Convert the input glTF to glb.                                      //将输入的glTF转换为glb
                                                     [boolean] [default: false]
--json, -j                    Convert the input glb to glTF.                                      //将输入的glb转换为glTF
                                                     [boolean] [default: false]
--separate, -s                Write separate buffers, shaders, and textures                       //编写单独的缓冲区、着色器和纹理而不是把它们嵌入到glTF中
                               instead of embedding them in the glTF.          
                                                     [boolean] [default: false]
--separateTextures, -t        Write out separate textures only.                                   //只写出单独的纹理
                                                     [boolean] [default: false]
--stats                       Print statistics to console for output glTF                         //将统计信息打印到控制台以输出glTF文件
                               file.                 [boolean] [default: false]     
--keepUnusedElements          Keep unused materials, nodes and meshes.                            //保留未使用的材质、节点和网格
                                                      [boolean] [default: false]
--draco.compressMeshes, -d    Compress the meshes using Draco. Adds the                            //使用Draco压缩网格。添加KHR_draco_mesh_压缩扩展
                                KHR_draco_mesh_compression extension.
                                                      [boolean] [default: false]
--draco.compressionLevel      Draco compression level [0-10], most is 10,                           //Draco压缩级别[0-10],大多数是10,最小值为0。值为0将会连续应用 编码并保留face顺序。
                                least is 0. A value of 0 will apply sequential
                                encoding and preserve face order.
                                                           [number] [default: 7]   
--draco.quantizePositionBits  Quantization bits for position attribute when                        //位置坐标属性的量化位使用Draco压缩。
                                using Draco compression.  [number] [default: 11]

--draco.quantizeNormalBits    Quantization bits for normal attribute when                           //法线属性的量化位使用Draco压缩
                                using Draco compression.   [number] [default: 8]

--draco.quantizeTexcoordBits  Quantization bits for texture coordinate                               //纹理坐标的量化位属性。
                                attribute when using Draco compression.
                                                          [number] [default: 10]

--draco.quantizeColorBits     Quantization bits for color attribute when using                        //使用时颜色属性的量化位德拉科压缩
                                Draco compression.         [number] [default: 8]

--draco.quantizeGenericBits   Quantization bits for skinning attribute (joint                        //蒙皮属性(关节的量化位索引和关节权重)ad自定义属性使用Draco压缩时。
                                indices and joint weights) ad custom attributes
                                when using Draco compression. [number] [default: 8]

--draco.uncompressedFallback  Adds uncompressed fallback versions of the                            //添加未压缩的回退版本压缩网格
                                compressed meshes.    [boolean] [default: false]

  --draco.unifiedQuantization   Quantize positions of all primitives using the            //统一定义的量化网格所有基本体的边界框。 如果这个选项未设置,对每个应用量化原始的可能会导致差距出现在不同图元之间。
                                same quantization grid defined by the unified
                                bounding box of all primitives. If this option
                                is not set, quantization is applied on each
                                primitive separately which can result in gaps
                                appearing between different primitives.
                                                      [boolean] [default: false]

在这里插入图片描述
gltf-pipeline的参数有很多这里我们只需要提炼出一个满足我们需要的就够了

gltf-pipeline -i .\public\tep\23.glb -o .\public\tep\23-main.glb  -d --draco.compressionLevel 9 --draco.quantizePositionBits 10 --draco.quantizeColorBits 10
-i .\public\cascl\caa4.glb   //输入路径

-o .\public\cascl\caa4-main.glb  //输出路径及名称

-d --draco.compressionLevel 10 //压缩等级

--draco.quantizePositionBits 20  //量化  0 标识无损压缩 

需要注意的是安装好之后是不可以直接运行的我们需要一个three.js为我们提供的基本依赖draco_decoder.js 这个文件一般就放在node_module/three/examples/js/libs/draco目录下cpoy出来与模型文件一起放在public文件夹下即可

完成上述这些准备工作之后我们开始渲染我们的第一个大园区场景,因为我们使用了压缩算法所以我们需要额外再引入一个解压加载器,并将我们copy出来的draco_decoder.js文件与我们压缩好的模型都放在public下

import {DRACOLoader} from "three/examples/jsm/loaders/DRACOLoader"

step2
初始一个加载模型的方法

export const initMod=(id,filePath,fun)=>{
   container=document.getElementById(id);
   scene = new THREE.Scene();
   camera = new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 0.1, 1000);
   renderer = new THREE.WebGLRenderer({ antialias: true,alpha: true });
  renderer.setSize(container.clientWidth, container.clientHeight);
  container.appendChild(renderer.domElement);
  renderer.setClearColor('#6fc0ec', 1.0);
  renderer.outputEncoding = THREE.sRGBEncoding;
  const loader = new GLTFLoader();
  let dracoLoader = new DRACOLoader();
  dracoLoader.setDecoderPath("/cascl/"); // 设置public下的解码路径,注意最后面的/
  dracoLoader.setDecoderConfig({ type: "js" });
  dracoLoader.preload();
  loader.setDRACOLoader(dracoLoader);
  loader.load(
    filePath,
    gltf => {
      // 将模型放到中间
      const box = new THREE.Box3().setFromObject(gltf.scene);
      const size = box.getSize(new THREE.Vector3()).length();
      const center = box.getCenter(new THREE.Vector3());
      gltf.scene.position.x -= center.x;
      gltf.scene.position.y -= center.y;
      gltf.scene.position.z -= center.z;
      camera.near = size / 100;
      camera.far = size * 100;
      camera.updateProjectionMatrix();
      camera.position.copy(center);
      camera.position.x += size / 2;
      camera.position.y += size / 2;
      camera.position.z += size / 2;
      camera.lookAt(center);
      scene.add(gltf.scene);
       console.log('---加载的模型',gltf.scene)
      const ambient = new THREE.AmbientLight(0xffffff, 0.4);
      scene.add(ambient);

      //添加在模型的右上角高三倍设置一个光源 太阳
      const light = new THREE.DirectionalLight(0xffffff, 1);
      // 模型宽度
      const width = box.max.x - box.min.x;
      // 模型高度
      const height = box.max.y - box.min.y;
      // 模型深度
      const depth = box.max.z - box.min.z;
      light.position.set(width * 3, height * 3, depth * 3);
      scene.add(light);
// 点光源
      let point = new THREE.PointLight('#74beee',1);
      point.position.set(-width * 3, -height * 3, depth * 3); // 点光源位置
      scene.add(point); // 点光源添加到场景中
      //多设置几个光源
      const light3 = new THREE.DirectionalLight('#8dccee', 1);
      light3.position.set(-width * 3, -height * 3, depth * 3);
      scene.add(light3);
      const light4 = new THREE.HemisphereLight('#8dccee', 0.3);
      scene.add(light4);
      //包含关键帧动画的模型作为参数创建一个播放器
      mixer = new THREE.AnimationMixer(gltf.scene);
      //  获取gltf.animations[0]的第一个clip动画对象
      clipAction = mixer.clipAction(gltf.animations[0]); //创建动画clipAction对象
      clipAction.play(); //播放动画
//不循环播放
      clipAction.loop = THREE.LoopOnce;
// 物体状态停留在动画结束的时候
      clipAction.clampWhenFinished = true
      // 如果想播放动画,需要周期性执行`mixer.update()`更新AnimationMixer时间数据
      clock = new THREE.Clock();
    },
    undefined,
    error => {
      console.error(error);
    }
  );
  camera.position.z = 5;
  // 添加OrbitControls控制器
  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.05;
  controls.screenSpacePanning = false;
  controls.minDistance = 1;
  controls.maxDistance = 1000;
  const tag = labelTag({x: -580,y:50,z: -705});
  tagList.push(tag)
  scene.add(tag);//添加到指定的场景里
  renderLabel()
  animate();
  runLoop()
  renderer.domElement.addEventListener('click', handleModClick, false)
}

上方的初始方案中包含了一个基本的动画加载器由此我们可以完成一个基本的模型加载的场景创建
在这里插入图片描述
这是一个可以执行楼层分层爆炸的模型内置的动画由:

   //包含关键帧动画的模型作为参数创建一个播放器
      mixer = new THREE.AnimationMixer(gltf.scene);

完成捕捉及后续播放
step3
接下来我们完成园区的业务需求建设
1.场景需要有天空背景
2.场景需要有关键建筑的标注
3.场景的交互具有高亮环绕
4.场景具有漫游功能
基于以上我们开始增加需要的工具

  1. 场景漫游动画处理库
import TWEEN from '@tweenjs/tween.js';

2.场景天空环境即天空盒

    const urls = [
        '../sky/Above Day B_Cam_3_Right-X.png',//x正方形
        '../sky/Above Day B_Cam_2_Left+X.png',//x负方向
        '../sky/Above Day B_Cam_4_Up+Y.png',//y正方形
        '../sky/Above Day B_Cam_5_Down-Y.png',//y负方向
        '../sky/Above Day B_Cam_0_Front+Z.png',//z正方形
        '../sky/Above Day B_Cam_1_Back-Z.png'//z负方形
    ]
        const textureCube = new THREE.CubeTextureLoader().load(urls)
        scene.background = textureCube

3.场景后处理器

import {EffectComposer} from 'three/examples/jsm/postprocessing/EffectComposer';
import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass';
import {OutlinePass} from 'three/examples/jsm/postprocessing/OutlinePass';

在使用了后处理器后因为模型抗拒齿原因我们需要在额外补充一个

import {SMAAPass} from 'three/examples/jsm/postprocessing/SMAAPass';
      //抗锯齿后处理
 const smaaPass = new SMAAPass(container.clientWidth * pixelRatio, container.clientHeight * pixelRatio);

4.一个漫游动画控制的方法

export const createCameraTween = (pos2, pos) => {
    tween = new TWEEN.Tween({
        // 相机开始坐标
        x: camera.position.x,
        y: camera.position.y,
        z: camera.position.z,
        // 相机开始指向的目标观察点
        tx:  current.x,
        ty:   current.y,
        tz:   current.z,
    })
        .to({
            // 相机结束坐标
            x: pos.x,
            y: pos.y,
            z: pos.z,
            // 相机结束指向的目标观察点
            tx: pos.x,
            ty: pos.y,
            tz: pos.z,
        }, 2000)
        .onUpdate(function (obj) {
            // 动态改变相机位置
            camera.position.set(obj.x, obj.y, obj.z);
            // 动态计算相机视线
            camera.lookAt(pos.x, pos.y, -pos.z);
        })
        .start();
    animates();
}
const animates = (time) => {
    TWEEN.update(time);
    requestAnimationFrame(animates);
}

在使用glb/gltf模型中我们也常常会需要处理模型加载发暗,材质渲染失真的情况这里我们也一并加入到初始化的方案内

import {GammaCorrectionShader} from'three/examples/jsm/shaders/GammaCorrectionShader';
import {ShaderPass} from 'three/examples/jsm/postprocessing/ShaderPass';
import {RoomEnvironment} from 'three/examples/jsm/environments/RoomEnvironment';

由此我们以及基本完成了所有的加载需要的必备条件即要求,我们渲染一个大园区场景
在这里插入图片描述
在这里插入图片描述
场景后处理的效果业务由:

const renderOutline = (mod) => {
    if (buildIds.includes(mod.name)) {
        // 创建后处理对象EffectComposer,WebGL渲染器作为参数
        composer = new EffectComposer(renderer);
        renderPass = new RenderPass(scene, camera);
        composer.addPass(renderPass);
// 创建OutlinePass通道
        container = document.getElementById('mod') ? document.getElementById('mod') : document.getElementById('mod2');
        const v2 = new THREE.Vector2(container.clientWidth, container.clientHeight);
        const outlinePass = new OutlinePass(v2, scene, camera);
        // 创建伽马校正通道
        const gammaPass = new ShaderPass(GammaCorrectionShader);
        composer.addPass(gammaPass);
        const pixelRatio = renderer.getPixelRatio()
        //抗锯齿后处理
        const smaaPass = new SMAAPass(container.clientWidth * pixelRatio, container.clientHeight * pixelRatio);
        composer.addPass(smaaPass);
        outlinePass.selectedObjects = [mod];
        outlinePass.visibleEdgeColor.set('#a838ef');
        outlinePass.edgeThickness = 4;
        outlinePass.edgeStrength = 15;
        outlinePass.pulsePeriod = 3;
        composer.addPass(outlinePass);
        animateOutline()
        bus.$emit('showMod', mod)
    } else {
        clearOutline();
    }
}

由于业务延展很多不再过的的赘述,解决方案包含了动态标签切换,标记交互,灯光动态,场景灯光随相机,标签随相机,场景模型过滤,场景模型设备等状态动态更新,单楼层模型,室内模型控制切换即各类物联网设备交互等等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/141378.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mindspore mindyolo目标检测华为昇腾上推理使用

参考: https://github.com/mindspore-lab/mindyolo 使用案例: https://github.com/mindspore-lab/mindyolo/blob/master/GETTING_STARTED.md 安装: pip install mindyolo特别注意opencv-python、opencv-python-headless版本问题&#xff0…

Redis安装、配置

系列文章目录 第一章 Java线程池技术应用 第二章 CountDownLatch和Semaphone的应用 第三章 Spring Cloud 简介 第四章 Spring Cloud Netflix 之 Eureka 第五章 Spring Cloud Netflix 之 Ribbon 第六章 Spring Cloud 之 OpenFeign 第七章 Spring Cloud 之 GateWay 第八章 Sprin…

算法的复杂性

通常情况下,一个问题可能对应有多种解决方案,每种解决方案都是一种算法。因此,我们可能经常需要做一件事:从众多算法中挑选出一个最好的算法。所谓“最好”的算法,即最适合当前场景使用的算法。 不同的应用场景&#x…

springboot整合SSE技术开发经验总结及心得

springboot整合SSE技术开发经验总结及心得 一、开发背景二、快速了解SSE1、概念2、特性 三、开发思路四、代码演示1、引入依赖2、服务端代码3、后端定时任务代码 4、解决乱码的实体类4、前端代码 五、核心代码分析 一、开发背景 公司需要开发一个大屏界面,大屏页面…

使用内网穿透实现U8用友ERP本地部署与异地访问

文章目录 前言1. 服务器本机安装U8并调试设置2. 用友U8借助cpolar实现企业远程办公2.1 在被控端电脑上,点击开始菜单栏,打开设置——系统2.2 找到远程桌面2.3 启用远程桌面 3. 安装cpolar内网穿透3.1 注册cpolar账号3.2 下载cpolar客户端 4. 获取远程桌面…

【C++笔记】AVL树的模拟实现

【C笔记】AVL树的模拟实现 一、AVL树的概念二、AVL树的模拟实现2.1、定义节点2.2、插入2.3、旋转2.3.1、左单旋2.3.2、右单旋2.3.3、左右双旋2.3.4、右左双旋2.3.5、插入接口的整体代码实现 三、验证AVL树3.1、验证 一、AVL树的概念 二叉搜索树虽然在一般情况下可以提高查找的…

生成式AI以及当前趋势

ChatGPT 激发了人们的想象力和好奇心。自 2022 年 11 月推出后,短短两个月内其月活用户便达到 1 亿,成为有史以来增长速度最快的消费类应用和第一个杀手级的生成式 AI 应用。随着创新节奏的加快,想要紧跟生成式 AI 的发展速度,难度…

web前端-Gulp入门

web前端-Gulp入门 gulp的概述使用gulp准备工作gulp的常用APIgulp的常用插件gulpfile.js的初体验打包css文件打包scss文件打包js打包html打包images创建一个默认任务创建一个删除任务gulp启动服务创建一个监控任务 gulp的概述 gulp: 前端自动化打包固件工具&#xf…

Ansible playbook详解

playbook是ansible用于配置,部署,和被管理被控节点的剧本 playbook常用的YMAL格式:(文件名称以 .yml结尾) 1、文件的第一行应该以 "---" (三个连字符)开始,表明YMAL文件的开始。    2、在同一…

IIC子系统测温湿度

采用stm32MP157AAA芯片,温度传感器 si7006 0x40 1、在内核空间不支持浮点数进行打印,所以需要将读取到的数据拷贝到用户空间,执行用户程序打印 2、在probe函数中 分步注册字符设备驱动自动创建设备节点 3、在i2c驱动代码中,需要自…

通用的链栈实现(C++)

template<class T> class MyStack//链栈 { private:struct StackNode{T data;StackNode* next;StackNode(const T& val T(), StackNode* p nullptr) :data(val), next(p) {}//};StackNode* top;int cursize;void clone(const MyStack& s){Clear();cursize s.c…

cgo与调用c的回调函数指针

cgo直接调用函数&#xff0c;使用基本数据类型非常简单&#xff0c;包括一些结构体也比较简单&#xff0c;嵌套的稍微复杂些&#xff0c;但也可以&#xff0c;但有的时候&#xff0c;cgo调用c函数&#xff0c;会需要传递一个回调函数的指针&#xff0c;这时候就比较复杂了&…

office365 outlook邮件无法删除

是否遇到过&#xff0c;office365邮件存储满了&#xff0c;删除邮件无法删除&#xff0c;即便用web方式登录到outlook&#xff0c;删除邮件当时是成功的&#xff0c;但一会儿就回滚回来了&#xff0c;已删除的邮件&#xff0c;你想清空&#xff0c;最后清理后还是回到原样。 请…

YTM32的循环冗余校验CRC外设模块详解

YTM32的循环冗余校验CRC外设模块详解 文章目录 YTM32的循环冗余校验CRC外设模块详解引言原理与机制CRC算法简介从CRC算法到CRC硬件外设 应用要点&#xff08;软件&#xff09;CRC16 用例CRC32 用例 总结参考文献 引言 在串行通信帧中&#xff0c;为了保证数据在传输过程中的完…

基于Python优化图片亮度与噪点

支持添加噪点类型包括&#xff1a;添加高斯噪点、添加椒盐噪点、添加波动噪点、添加泊松噪点、添加周期性噪点、添加斑点噪点、添加相位噪点&#xff0c;还提供清除噪点的功能。 我们先看一下实测效果&#xff1a;&#xff08;test.jpg为原图&#xff0c;new.jpg为添加后的图片…

自动化测试的成本高效果差,那么自动化测试的意义在哪呢?

一、自动化测试的成本高效果差&#xff0c;那么自动化测试的意义在哪呢&#xff1f; 我觉得这个问题带有很强的误导性&#xff0c;是典型的逻辑陷阱之一。“自动化测试的成本高效果差”是真的吗&#xff1f;当然不是。而且我始终相信&#xff0c;回答问题的最好方式是把问题本身…

达索系统3DEXPERIENCE WORKS 2024流体仿真功能增强

设计工作中&#xff0c;网格划分和设计验证十分重要&#xff0c;它可以方便我们把复杂组件简单化处理&#xff0c;从而提升工作效率。 轻松应对&#xff0c;精准划分 在优化设计以获得更好的空气动力学性能时&#xff0c;需要了解空气在其周围产生的流动方式。达索系统3DEXPE…

(论文阅读29/100 人体姿态估计)

29.文献阅读笔记 简介 题目 DeepCut: Joint Subset Partition and Labeling for Multi Person Pose Estimation 作者 Leonid Pishchulin, Eldar Insafutdinov, Siyu Tang, Bjoern Andres, Mykhaylo Andriluka, Peter Gehler, and Bernt Schiele, CVPR, 2016. 原文链接 h…

STM32 X-CUBE-AI:Pytorch模型部署全流程

文章目录 概要版本&#xff1a;参考资料STM32CUBEAI安装CUBEAI模型支持LSTM模型转换注意事项模型转换模型应用1 错误类型及代码2 模型创建和初始化3 获取输入输出数据变量4 获取模型前馈输出模型应用小结 小结 概要 STM32 CUBE MX扩展包&#xff1a;X-CUBE-AI部署流程&#xf…

Accelerate 0.24.0文档 一:两万字极速入门

文章目录 一、概述1.1 PyTorch DDP1.2 Accelerate 分布式训练简介1.2.1 实例化Accelerator类1.2.2 将所有训练相关 PyTorch 对象传递给 prepare()方法1.2.3 启用 accelerator.backward(loss) 1.3 Accelerate 分布式评估1.4 accelerate launch1.4.1 使用accelerate launch启动训…