Vue.js2+Cesium1.103.0 十一、Three.js 炸裂效果

Vue.js2+Cesium1.103.0 十一、Three.js 炸裂效果

Demo

ThreeModelBoom.vue

<template>
  <div
    :id="id"
    class="three_container"
  />
</template>

<script>
/* eslint-disable eqeqeq */
/* eslint-disable no-unused-vars */
/* eslint-disable no-undef */
/* eslint-disable no-caller */
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
// import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
// import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js'
export default {
  name: 'ThreeModel',
  props: {
    size: {
      type: Number,
      default: 20
    },
    url: {
      type: String,
      default: 'three_container'
    },
    id: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      modelMixer: null,
      modelClock: null,
      modelAnimationAction: null,
      modelAnimationAction2: null,
      model: null,
      scene: null,
      camera: null,
      renderer: null,
      textureLoader: null,
      groupBox: null,
      control: null,
      enableRotate: null
    }
  },
  computed: {},
  watch: {},
  mounted() {
    window.cancelAnimationFrame(this.clearAnim)
    this.init()
  },
  beforeDestroy() {
    window.cancelAnimationFrame(this.clearAnim)
  },
  methods: {
    applyScalar(scalar) {
      if (!this.model) {
        return
      }
      this.model.traverse(function (value) {
        if (!value.isMesh || !value.worldDir) return
        // 爆炸公式
        value.position.copy(
          new THREE.Vector3()
            .copy(value.userData.oldPs)
            .add(
              new THREE.Vector3().copy(value.worldDir).multiplyScalar(scalar)
            )
        )
      })
    },
    async init() {
      const _this = this
      const element = document.getElementById(this.id)
      const width = element.clientWidth // 窗口宽度
      const height = element.clientHeight // 窗口高度
      // 场景
      this.scene = new THREE.Scene()
      // this.scene.background = new THREE.Color(0x000000, 0)
      this.scene.background = null

      // 相机
      const k = width / height // 窗口宽高比
      const s = 400 // 三维场景显示范围控制系数,系数越大,显示的范围越大
      // this.camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000) // 透视摄像机
      this.camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000) // 正交摄像机
      // 设置摄像机位置,相机方向逆X轴方向,倾斜向下看
      this.camera.position.set(0, 180, 360)
      // this.camera.rotation.order = 'YXZ'
      // 指向场景中心
      this.camera.lookAt(this.scene.position)

      // 渲染器
      this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
      // 设置环境
      this.renderer.setClearColor(0x000000, 0)
      // 设置场景大小
      this.renderer.setSize(800, 800)
      // 渲染器开启阴影效果
      this.renderer.shadowMap.enabled = true

      // 纹理加载器
      this.textureLoader = new THREE.TextureLoader()

      // 组合对象
      this.groupBox = new THREE.Group()

      // 坐标轴
      // const axes = new THREE.AxesHelper(1000)
      // this.scene.add(axes)

      // 点光源
      const point = new THREE.PointLight(0xffffff)
      point.position.set(500, 300, 400) // 点光源位置
      this.scene.add(point) // 点光源添加到场景中

      // 环境光
      const ambient = new THREE.AmbientLight(0xffffff, 0.8)
      this.scene.add(ambient)

      element.appendChild(this.renderer.domElement)

      // 相机控件
      this.control = new OrbitControls(this.camera, this.renderer.domElement)
      this.control.enableDamping = true
      // 动态阻尼系数 就是鼠标拖拽旋转灵敏度,阻尼越小越灵敏
      this.control.dampingFactor = 0.5
      // 是否可以缩放
      this.control.enableZoom = true
      // 是否自动旋转
      this.control.autoRotate = false
      // 设置相机距离原点的最近距离
      this.control.minDistance = 20
      // 设置相机距离原点的最远距离
      this.control.maxDistance = 1000
      // 是否开启右键拖拽
      this.control.enablePan = true
      // 上下翻转的最大角度
      this.control.maxPolarAngle = 1.5
      // 上下翻转的最小角度
      this.control.minPolarAngle = 0.0
      // 是否可以旋转
      this.enableRotate = true

      // 加载模型
      const loader = new GLTFLoader()
      await loader.load(
        this.url,
        gltf => {
          gltf.scene.name = 'Cesium_Air'
          gltf.scene.scale.set(_this.size, _this.size, _this.size) //  设置模型大小缩放
          gltf.scene.position.set(0, 0, 0)
          gltf.scene.translateY(0)
          _this.modelMixer = new THREE.AnimationMixer(gltf.scene)
          _this.modelClock = new THREE.Clock()
          if (gltf.animations.length > 0) {
            // http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/animation/AnimationAction
            _this.modelAnimationAction = _this.modelMixer.clipAction(
              gltf.animations[0]
            )
            _this.modelAnimationAction.timeScale = 1
            // _this.modelAnimationAction.loop = THREE.LoopOnce // 播放一次
            _this.modelAnimationAction.clampWhenFinished = true
          }
          _this.scene.add(gltf.scene)
          _this.model = gltf.scene

          // 模型包围盒
          const modelBox3 = new THREE.Box3()
          const meshBox3 = new THREE.Box3()

          // 获取模型的包围盒
          modelBox3.expandByObject(_this.model)
          // 计算模型的中心点坐标,这个为爆炸中心
          const modelWorldPs = new THREE.Vector3()
            .addVectors(modelBox3.max, modelBox3.min)
            .multiplyScalar(0.5)

          _this.model.traverse(function (value) {
            if (value.isMesh) {
              meshBox3.setFromObject(value)
              // 获取每个 mesh 的中心点,爆炸方向为爆炸中心点指向 mesh 中心点
              const worldPs = new THREE.Vector3()
                .addVectors(meshBox3.max, meshBox3.min)
                .multiplyScalar(0.5)
              if (isNaN(worldPs.x)) return
              // 计算爆炸方向
              value.worldDir = new THREE.Vector3()
                .subVectors(worldPs, modelWorldPs)
                .normalize()
              // 保存初始坐标
              value.userData.oldPs = value.getWorldPosition(new THREE.Vector3())
            }
          })
        },
        _xhr => {
          // console.log((_xhr.loaded / _xhr.total) * 100 + '% loaded')
        },
        _error => {
          // console.error(_error)
        }
      )

      const animate = () => {
        // 循环调用函数
        this.clearAnim = requestAnimationFrame(animate)
        // 更新相机控件
        this.control.update()
        // 渲染界面
        this.renderer.render(this.scene, this.camera)
        if (this.modelMixer) {
          // modelClock.getDelta() 方法获得两帧的时间间隔
          // 更新混合器相关的时间
          this.modelMixer.update(this.modelClock.getDelta())
        }
      }
      animate()
    }
  }
}
</script>


index.vue

<template>
  <div
    id="cesium-container"
    style="width: 100%; height: 100%;"
  >
    <div style="position: absolute;width: 400px;right: 50px;top: 100px;z-index: 9;">
      <div>
        <el-slider
          v-model="sliderVal"
          :min="0"
          :max="100"
          @input="handleChange"
        />
      </div>
    </div>
    <div class="model_container">
      <ThreeModel
        :id="'three_model_a'"
        ref="ThreeModelA"
        :url="'model/SnowyVillage.glb'"
        :size="5"
        class="three_model"
      />
    </div>
  </div>
</template>

<script>
import ThreeModel from './components/ThreeModelBoom.vue'

export default {
  components: {
    ThreeModel
  },
  data() {
    return {
      sliderVal: 0,
      paused: false
    }
  },
  computed: {},
  watch: {},
  mounted() {
    window.$InitMap()
  },
  methods: {
    handleChange(val) {
      this.$refs.ThreeModelA.applyScalar(val)
    }
  }
}
</script>

<style lang="scss">
.model_container {
  position: absolute;
  z-index: 999;
  left: 50%;
  top: 50%;
  transform: translateX(-50%) translateY(-50%);
  display: flex;
  .three_model {
    width: 800px;
    height: 800px;
  }
}
</style>

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

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

相关文章

20 MySQL(下)

文章目录 视图视图是什么定义视图查看视图删除视图视图的作用 事务事务的使用 索引查询索引创建索引删除索引聚集索引和非聚集索引影响 账户管理&#xff08;了解非DBA&#xff09;授予权限 与 账户的相关操作 MySQL的主从配置 视图 视图是什么 通俗的讲&#xff0c;视图就是…

(Windows )本地连接远程服务器(Linux),免密码登录设置

在使用VScode连接远程服务器时&#xff0c;每次打开都要输入密码&#xff0c;以及使用ssh登录或其它方法登录&#xff0c;都要本地输入密码&#xff0c;这大大降低了使用感受&#xff0c;下面总结了免密码登录的方法&#xff0c;用起来巴适得很&#xff0c;起飞。 目录 PowerSh…

数据仓库总结

1.为什么要做数仓建模 数据仓库建模的目标是通过建模的方法更好的组织、存储数据&#xff0c;以便在性能、成本、效率和数据质量之间找到最佳平衡点。 当有了适合业务和基础数据存储环境的模型&#xff08;良好的数据模型&#xff09;&#xff0c;那么大数据就能获得以下好处&…

深入了解Nginx:高性能的开源Web服务器与反向代理

一、Nginx是什么 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;也可以作为负载均衡器和HTTP缓存服务器使用。它采用事件驱动、异步非阻塞的处理方式&#xff0c;能够处理大量并发连接和高流量负载&#xff…

supervisorctl(-jar)启动配置设置NACOS不同命名空间

背景 由于需要在上海服务器上面配置B测试环境&#xff0c;原本上面已有A测试环境&#xff0c;固需要将两套权限系统分开 可以使用不同的命名空间来隔离启动服务 注&#xff1a;本文章均不涉及公司机密 1、新建命名空间 命名空间默认会有一个public&#xff0c;并且不能删除&a…

Java 中数据结构HashMap的用法

Java HashMap HashMap 是一个散列表&#xff0c;它存储的内容是键值对(key-value)映射。 HashMap 实现了 Map 接口&#xff0c;根据键的 HashCode 值存储数据&#xff0c;具有很快的访问速度&#xff0c;最多允许一条记录的键为 null&#xff0c;不支持线程同步。 HashMap 是…

自然语言处理2-NLP

目录 自然语言处理2-NLP 如何把词转换为向量 如何让向量具有语义信息 在CBOW中 在Skip-gram中 skip-gram比CBOW效果更好 CBOW和Skip-gram的算法实现 Skip-gram的理想实现 Skip-gram的实际实现 自然语言处理2-NLP 在自然语言处理任务中&#xff0c;词向量&#xff08;…

分布式集群框架——有关zookeeper的面试考点

3.掌握Zookeeper的概念 当涉及到大规模分布式系统的协调和管理时&#xff0c;Zookeeper是一个非常重要的工具。 1. 分布式协调服务&#xff1a;Zookeeper是一个分布式协调服务&#xff0c;它提供了一个高可用和高性能的环境&#xff0c;用于协调和同步分布式系统中的各个节点…

js深拷贝三种方法

使用递归函数实现深拷贝 const obj {name: zzz,age: 18,hobby: [篮球, 足球],family: {baby: baby}} // 深拷贝 数组 对象 一定要先筛数组再筛对象,因为万物皆对象function deepcopy(newObj, oldObj) {for (const k in oldObj) {// 判断值是否属于array类if (oldObj[k] i…

[Android AIDL] --- AIDL工程搭建

0 AIDL概念 AIDL&#xff08;Android Interface Definition Language&#xff09;是一种 IDL 语言&#xff0c;用于生成可以在 Android 设备上两个进程之间进行进程间通信&#xff08;IPC&#xff09;的代码。 通过 AIDL&#xff0c;可以在一个进程中获取另一个进程的数据和调…

FPGA VR摄像机-拍摄和拼接立体 360 度视频

本文介绍的是 FPGA VR 相机的第二个版本&#xff0c;第一个版本是下面这样&#xff1a; 第一版地址&#xff1a; ❝ https://hackaday.io/project/26974-vr-camera-fpga-stereoscopic-3d-360-camera ❞ 本文主要介绍第二版本&#xff0c;第二版本的 VR 摄像机&#xff0c;能够以…

从零做软件开发项目系列之八——系统部署调试

前言 软件项目的部署和调试工作是项目开发生命周期中的重要阶段&#xff0c;它涉及将开发完成的软件应用程序部署到目标环境并进行测试和调试&#xff0c;以确保系统能够正常运行并满足用户需求。本文将详细描述软件项目的部署和调试工作。 1 硬件基础设施和操作系统及基本软…

Python科研绘图--Task05

目录 SciencePlots 安装SciencePlots 安装LaTeX ① 安装 MikTex 和 Ghostscript ② 将软件的安装路径添加到系统环境变量中 SciencePlots 绘图示例 SciencePlots 虽然 Matplotlib 或 ProPlot 库能够绘制出插图结果&#xff0c;但用户还需要根据期刊的配图绘制要求进行…

Flink CDC介绍

1.CDC概述 CDC&#xff08;Change Data Capture&#xff09;是一种用于捕获和处理数据源中的变化的技术。它允许实时地监视数据库或数据流中发生的数据变动&#xff0c;并将这些变动抽取出来&#xff0c;以便进行进一步的处理和分析。 传统上&#xff0c;数据源的变化通常通过…

PCL common模块应用实例

目录 一、common模块中的头文件二、基本函数1、angles.h2、centriod.h3、common.h4、distance.h5、copy_point.h6、geometry.h参考链接本文由CSDN点云侠原创,

Excel:如何实现分组内的升序和降序?

一、POWER 1、构建辅助列D列&#xff0c;在D2单元格输入公式&#xff1a; -POWER(10,COUNTA($A$2:A2)3)C2 2、选中B1:D10&#xff0c;注意不能宣导A列的合并单元格&#xff0c;进行以下操作&#xff1a; 3、删除辅助列即可 二、COUNTA 第一步&#xff0c;D2建立辅助列&#xf…

day 6 c++

#include <iostream>using namespace std; class Animal { public:Animal(){cout << "训练员的无参构造" << endl;}virtual void perform(){} }; class Tiger:public Animal {string tezheng;string biaoyan; public:Tiger(){cout << "…

财务部发布《企业数据资源相关会计处理暂行规定》

导读 财务部为规范企业数据资源相关会计处理&#xff0c;强化相关会计信息披露&#xff0c;根据《中华人民共和国会计法》和相关企业会计准则&#xff0c;制定了《企业数据资源相关会计处理暂行规定》。 加gzh“大数据食铁兽”&#xff0c;回复“20230828”获取材料完整版 来…

对class文件进行base64编码

使用以下代码 package org.springframework.cloud.gateway.sample;import org.springframework.util.Base64Utils;import java.io.*; import java.nio.charset.StandardCharsets;public class EncodeShell {public static void main(String[] args){byte[] data null;try {In…

2024王道408数据结构P144 T18

2024王道408数据结构P144 T18 思考过程 首先还是先看题目的意思&#xff0c;让我们在中序线索二叉树里查找指定结点在后序的前驱结点&#xff0c;这题有一点难至少对我来说…我讲的不清楚理解一下我做的也有点糊涂。在创建结构体时多两个变量ltag和rtag&#xff0c;当ltag0时…