Newer
Older
KaiFengPC / src / views / sponeScreen / projectHM / gongchenkanbani_comp / modalSJ.vue
@zhangdeliang zhangdeliang 11 days ago 5 KB update
<template>
  <!-- 项目模型实景管理 -->
  <div class="projectModalM">
    <div id="QuanJing" ref="threeDom" v-if="ifHasUrl" v-loading="modalLoading"></div>
    <!-- 暂无数据 -->
    <div v-else class="noData">暂无全景图片</div>
  </div>
</template>

<script setup>
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; //控制器
import gsap from 'gsap';
import { CSSRulePlugin } from 'gsap/CSSRulePlugin';
import bus from '@/bus';
const { proxy } = getCurrentInstance();
gsap.registerPlugin(CSSRulePlugin); // 引入css插件,完成某些css动画

const AllData = ref({
  show: false,
  numer: '0%',
  imgUrl: '', //渲染的目标图片
  imgWidth: 1200, //渲染宽度px
  imgHeight: 560, //渲染高度px
});
const ifHasUrl = ref(true);
const modalLoading = ref(true);

// 初始化模型
let SceneModal = new THREE.Scene();
const CameraModal = new THREE.PerspectiveCamera(30, AllData.value.imgWidth / AllData.value.imgHeight, 0.1, 5000);
const Renderer = new THREE.WebGLRenderer({
  antialias: true,
  alpha: true, //开启alpha
});
// 控制器
const Controls = new OrbitControls(CameraModal, Renderer.domElement);

// 注意:此处为threejs的DOM,需要将threejs的场景渲染进去
const threeDom = ref();

// 首页进入相机的视角,这个视角可以在三维模型中建立一个摄像机获取摄像机的坐标,如C4D,非常准确.
const cameraPosition = {
  x: 500,
  y: 400,
  z: -200,
};
const cameraLookat = {
  x: 0,
  y: 0,
  z: 0,
};
// 声明一个方法传入参数可以在不同的地方调用相机
const cameraReset = (position, lookAt, time = 1) => {
  gsap.to(CameraModal.position, {
    x: position.x,
    y: position.y,
    z: position.z,
    duration: time,
    ease: 'power4.out',
    // onComplete: function () {
    // 这是相机运动完成的回调,可以执行其他的方法.
    // }
  });
  gsap.to(CameraModal.lookAt, {
    x: lookAt.x,
    y: lookAt.y,
    z: lookAt.z,
    duration: time,
    ease: 'power4.out',
  });
  gsap.to(CameraModal.target, {
    x: lookAt.x,
    y: lookAt.y,
    z: lookAt.z,
    duration: time,
    ease: 'power4.out',
  });
};

const initThreeScene = () => {
  // 使动画循环使用时阻尼或自转 意思是否有惯性
  Controls.enableDamping = true;
  // 动态阻尼系数 就是鼠标拖拽旋转灵敏度
  Controls.dampingFactor = 0.1;
  // 是否可以旋转
  Controls.enableRotate = true;
  // 是否可以缩放与速度
  Controls.enableZoom = true;
  // 设置相机距离原点的最远距离
  // Controls.minDistance = 1;
  // 设置相机距离原点的最远距离
  Controls.maxDistance = 900;
  Controls.autoRotate = true;
  Controls.autoRotateSpeed = 1.0;

  // 是否开启右键拖拽
  Controls.enablePan = false;
  // Controls.addEventListener("change", render);
  //render的相关设置
  // Renderer.setPixelRatio(window.devicePixelRatio);
  Renderer.setSize(AllData.value.imgWidth, AllData.value.imgHeight);
  Renderer.inputEncoding = true;
  // Renderer.outputEncoding = THREE.sRGBEncoding;
  // Renderer.setClearColor(0xd0d0d0, 1);
  // 将renderer渲染进DOM里面
  threeDom.value.appendChild(Renderer.domElement);
};
// 设置页面自适应
const onWindowResize = () => {
  CameraModal.aspect = AllData.value.imgWidth / AllData.value.imgHeight;
  CameraModal.updateProjectionMatrix();
  Renderer.setSize(AllData.value.imgWidth, AllData.value.imgHeight);
};
window.addEventListener('resize', onWindowResize, false);
//  完成以上步骤基本的场景已经配置完成

cameraReset(cameraPosition, cameraLookat);

const Render = () => {
  requestAnimationFrame(Render);
  Controls.update(); // 轨道控制器的更新
  Renderer.clear(); // 清除画布
  Renderer.render(SceneModal, CameraModal);
};

// 初始化加载模型
function initModal(imgUrl) {
  modalLoading.value = true;
  let event = {};
  // 单张纹理图的加载
  event.onLoad = function () {
    AllData.value.show = false;
    modalLoading.value = false;
  };
  event.onProgress = function (url, num, total) {
    let value = ((num / total) * 100).toFixed(2) + '%';
    console.log('加载进度的百分比:', value);
    AllData.value.numer = value;
    modalLoading.value = false;
  };
  event.onError = function (e) {
    console.log('图片加载出现错误', e);
    AllData.value.show = false;
    modalLoading.value = false;
  };
  // 设置加载管理器
  const loadingManager = new THREE.LoadingManager(event.onLoad, event.onProgress, event.onError);
  const textureLoader = new THREE.TextureLoader(loadingManager);
  var material = new THREE.MeshBasicMaterial(); //材质
  var texture = textureLoader.load(imgUrl);
  material.map = texture;
  // var skyBox = new THREE.Mesh(new THREE.SphereBufferGeometry(600, 600, 600), material);
  var skyBox = new THREE.Mesh(new THREE.SphereGeometry(600, 600, 600), material);
  skyBox.geometry.scale(1, 1, -1);
  SceneModal.add(skyBox);
}
onMounted(() => {
  bus.on('getProjectData', v => {
    ifHasUrl.value = v.projectpicture.length > 0 ? true : false;
    if (ifHasUrl.value) {
      initModal(v.projectpicture[0].url); //初始化
      initThreeScene();
      Render();
    }
  });
});
onBeforeUnmount(() => {
  bus.off('getProjectData');
  SceneModal.remove(skyBox); //删除组
  SceneModal = null;
});
</script>

<style lang="scss" scoped>
.projectModalM {
  #QuanJing {
    width: 100%;
    height: 100%;
  }
  .noData {
    font-size: 20px;
    text-align: center;
    margin-top: 10%;
    color: #fff;
  }
}
</style>