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

news2024/11/17 10:55:08

在非使用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();
    }
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

创建maven的 java web项目

创建maven的 java web项目 创建出来的项目样子 再添加java和resources文件夹 一定要如图有文件夹下有图标才代表被IDEA识别,不让是不行的 没有的话在File——ProjectStructure中进行设置

EasyDarwin开源流媒体服务器

文章目录 前言一、EasyDarwin 简介二、EasyDarwin 主要功能特点三、安装部署四、推拉流测试1、进入控制页面2、推流测试3、拉流测试 前言 本文介绍一个十分实用的高性能开源 RTSP 流媒体服务器:EasyDarwin。 一、EasyDarwin 简介 EasyDarwin 是基于 go 语言研发&a…

域名反查Api接口——让您轻松查询域名相关信息

在互联网发展的今天,域名作为网站的唯一标识符,已经成为了企业和个人网络营销中不可或缺的一部分。为了方便用户查询所需的域名信息,API接口应运而生。本文将介绍如何使用挖数据平台《域名反查Api接口——让您轻松查询域名相关信息》进行域名…

【Java笔试强训】Day10(CM62 井字棋、HJ87 密码强度等级)

CM62 井字棋 链接:井字棋 题目: 给定一个二维数组board,代表棋盘,其中元素为1的代表是当前玩家的棋子,0表示没有棋子,-1代表是对方玩家的棋子。当一方棋子在横竖斜方向上有连成排的及获胜(及…

Ps:通过显示大小了解图像的打印尺寸

在 Photoshop 中,如果想了解文档窗口中的图像打印出来之后的实质大小,只要知道两个数值即可。 第一个数值是图像分辨率(也称“文档分辨率”)的大小,可在Ps菜单:图像/图像大小 Image Size对话框中查询或设置…

linux 安装 mini conda,linux下安装 Miniconda

下载地址 https://docs.conda.io/projects/miniconda/en/latest/index.html 安装conda mkdir -p ~/miniconda3 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh bash ~/miniconda3/miniconda.sh -b -u -p ~/mini…

第1关:构造函数与析构函数的实现

题目&#xff1a;根据.h写出.cpp 考点&#xff1a; 1.链表的默认构造&#xff0c; 拷贝构造&#xff0c;传参构造以及析构函数等。 代码&#xff1a; /********** BEGIN **********/ #include <cstdlib> #include <cstring> #include "LinkedList.h&…

Java 设计模式——组合模式

目录 1.概述2.结构3.实现3.1.抽象构件3.2.容器构件3.3.叶子节点3.4.测试 4.分类5.使用场景6.优点 1.概述 &#xff08;1&#xff09;大家对于上面这个图片肯定非常熟悉&#xff0c;上图我们可以看做是一个文件系统&#xff0c;对于这样的结构我们称之为树形结构。在树形结构中可…

JDK并发修改异常的一个“BUG“

很多电商公司早期的架构都是基于PHP&#xff0c;所以我身边会有很多很厉害的PHP老哥&#xff0c;但现在都在写Java。昨天看到他在看Java的并发修改异常&#xff0c;正打算秀一波操作&#xff0c;却被他的一个问题难住了&#xff1a; public class ForeachTest {public static …

【EI会议征稿】第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024)

第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024) The 3rd International Academic Conference on Blockchain, Information Technology and Smart Finance 第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024) 将于2024年2月23-25日在马来西亚举行。本次会…

Java+Spring Cloud +UniApp +MySql智慧工地综合管理云平台源码

智慧工地围绕工程现场人、机、料、法、环及施工过程中质量、安全、进度、成本等各项数据满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效. 智慧工地综合管理云平台源码&#xff0c;PC监管端、项目端&#xff1b;APP监管端、项目端、数据可视化大屏端源码&#xf…

计算机毕业设计 基于SpringBoot的失踪人员信息发布与管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

小白看CLIP代码解析

CLIP代码解析 CLIP演示代码&#xff08;以cifar100举例&#xff09;补充11. 为什么选用100*image_feature&#xff1f;2. 为什么使用L2规范点积&#xff0c;而不直接使用点积&#xff1f; cifar100的所有类别model.encode_image >> VisionTransformer补充21. 为什么加入c…

2023亚太杯数学建模C题思路解析

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料5 最后 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 2023年第十三…

蓝桥杯第三场双周赛(AK)

题目非常典型&#xff0c;很适合学算法。 1111 第 3 场算法双周赛 - 蓝桥云课 双十一的祈祷 题意&#xff1a;求的个位数。 思路&#xff1a;只需要求个位数&#xff0c;因此此题等效于求 ,可用快速幂或者直接看出为1。 #include <bits/stdc.h> using namespace std; …

矩阵置零00

题目链接 矩阵置零 题目描述 注意点 使用 原地 算法 解答思路 思路是需要存储每一行以及每一列是否有0&#xff0c;因为要尽可能使用更少的空间&#xff0c;且新设置为0的格子不能对后续的判断产生影响&#xff0c;所以要在原有矩阵上存储该信息先用两个参数存储第一行和第…

关于反弹Shell个人的一些理解与学习收获

反弹Shell 概念&#xff1a; 反弹shell(reverse shell)&#xff0c;就是控制端(攻击者所有)监听某TCP/UDP端口&#xff0c;被控端发起请求到该端口&#xff0c;并将其命令行的输入输出转发到控制端。reverse shell与telnet&#xff0c;ssh等标准shell对应&#xff0c;本质上是…

Linux 本地zabbix结合内网穿透工具实现安全远程访问浏览器

前言 Zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。能监视各种网络参数&#xff0c;保证服务器系统的安全运营&#xff1b;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问题。 本地zabbix web管理界面限制在只能局域…

OpenMMlab导出yolov3模型并用onnxruntime和tensorrt推理

导出onnx文件 直接使用脚本 import torch from mmdet.apis import init_detector, inference_detectorconfig_file ./configs/yolo/yolov3_mobilenetv2_8xb24-ms-416-300e_coco.py checkpoint_file yolov3_mobilenetv2_mstrain-416_300e_coco_20210718_010823-f68a07b3.pth…

计算机网络期末复习-Part5

1、CRC计算 看例题&#xff1a;待发送序列为101110&#xff0c;生成多项式为X31&#xff0c;计算CRC校验码 先在待发送序列末尾添加与生成多项式次数相同的零&#xff0c;在上述例子中&#xff0c;生成多项式是X^3 1&#xff0c;所以需要添加3个零&#xff0c;待发送序列变成…