|
@@ -0,0 +1,945 @@
|
|
|
+<template src="./webgl_rxdz_test_roam.html"></template>
|
|
|
+<script>
|
|
|
+ import * as THREE from 'three';
|
|
|
+ import Stats from 'three/addons/libs/stats.module.js';
|
|
|
+ import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
|
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
|
|
+
|
|
|
+ import TWEEN from 'three/addons/libs/tween.module.js';
|
|
|
+ import {getStorage} from '@/utils/localStorage';
|
|
|
+ var requestId = "";
|
|
|
+ const util = require('@/utils/util.js').default;
|
|
|
+ // import util from '@/utils/util.js';
|
|
|
+ // const config = require('@/services/urlConfig.js');
|
|
|
+ // import requestConfig from '@/static/lib/requestConfig.js';
|
|
|
+ import viewShell from'@/components/newQCCom/viewShell/viewShell.vue';
|
|
|
+ import viewMask from'@/components/newQCCom/viewMask/viewMask.vue';
|
|
|
+
|
|
|
+ // import { RGBELoader } from '@/webgl/jsm/loaders/RGBELoader.js';
|
|
|
+ import screenshot from '@/mixins/screenshot.js';
|
|
|
+ import floorMethod from '@/mixins/floorMethod.js';
|
|
|
+ import loadModel from '@/mixins/loadModel.js';
|
|
|
+ import wallMethod from '@/mixins/wallMethod.js';
|
|
|
+ import commonPageMethod from '@/mixins/commonPageMethod.js';
|
|
|
+ // import commonPageMethod from '@/common/commonPageMethod.js';
|
|
|
+ // const app = getApp(); //获取应用实例
|
|
|
+ export default {
|
|
|
+ components:{viewShell,viewMask},
|
|
|
+ mixins:[screenshot,loadModel,floorMethod,wallMethod,commonPageMethod],
|
|
|
+ /**
|
|
|
+ * 页面的初始数据
|
|
|
+ */
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ pvCurPageName: "room_show",
|
|
|
+ locusBehaviorName: "房间展示",
|
|
|
+ pvCurPageParams: null,
|
|
|
+ houseId: "",
|
|
|
+ pvId: 'p_2cmina_23080402',
|
|
|
+ canvas:null,
|
|
|
+ navbar: {
|
|
|
+ showCapsule: 1,
|
|
|
+ title: '客厅',
|
|
|
+ titleColor: '#000',
|
|
|
+ navPadding: 0,
|
|
|
+ navPaddingBg:'transparent',
|
|
|
+ navBarColor: 'transparent',
|
|
|
+ navBackColor: 'transparent',
|
|
|
+ haveCallback: true, // 如果是 true 会接手 navbarBackClk
|
|
|
+ fromShare: false,
|
|
|
+ fromProject: 0,
|
|
|
+ shareToken: "",
|
|
|
+ pageName: this.pvCurPageName,
|
|
|
+ },
|
|
|
+ id:'',// 户型编号
|
|
|
+ spaceList:[], // 空间列表
|
|
|
+ gltfSpaces:[], // 场景中地板模型数组
|
|
|
+ gltfSpaceRoofs:[],
|
|
|
+ curSpaceObj:null, // 当前选中的空间
|
|
|
+ // curSpaceIndex:-1, // 当前选中的空间索引
|
|
|
+ spaceId:null,
|
|
|
+ wallIds:[], // 空间墙体id
|
|
|
+ // wallList:[], // 墙体数据
|
|
|
+ gltfWalls:[], // 场景中墙体模型数组
|
|
|
+ loader:null,
|
|
|
+ scene:null,
|
|
|
+ // sky:null,
|
|
|
+ camera:null,
|
|
|
+ controlStarPosition : { x:0, y:0, z:0}, //控制器初始位置
|
|
|
+ cameraStarPosition : { x:0, y:20, z:0} ,//摄像头初始位置
|
|
|
+ cameraLastPosition: null, //摄像头上一次移动到的位置
|
|
|
+ controlLastPosition: null, //观察点上一次移动到的位置
|
|
|
+ canvasHeight:408, //canvas视图的高度-计算得出
|
|
|
+ chooseMesh:null,//标记鼠标拾取到的mesh
|
|
|
+ shottingImg: [],
|
|
|
+ progress:1, //进度条
|
|
|
+ myLoadingStatus:false,
|
|
|
+ // textGeoList:[],
|
|
|
+ repeatFlag:false, //重复点击
|
|
|
+ // skyPlan: null, // 天空盒子
|
|
|
+ instancedMeshList: [],
|
|
|
+ screenshotResolve:null,
|
|
|
+ actors:[],
|
|
|
+ showDownView:true,//默认显示下载按钮
|
|
|
+ currentActor:null,
|
|
|
+ circleGroup:null,//圆形地标
|
|
|
+ isIOS:false,
|
|
|
+ defaulIndex:null, //默认视角的序号
|
|
|
+ // aiImagesList:[
|
|
|
+ // // "https://dm.static.elab-plus.com/miniProgram/plus_IM01.png",
|
|
|
+ // // "https://dm.static.elab-plus.com/miniProgram/plus_IM02.png",
|
|
|
+ // // "https://dm.static.elab-plus.com/miniProgram/plus_IM03.png",
|
|
|
+ // // "https://dm.static.elab-plus.com/miniProgram/plus_IM04.png",
|
|
|
+ // ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ cancelAnimationFrame(requestId, this.canvas)
|
|
|
+ this.worker && this.worker.terminate()
|
|
|
+ if (this.renderer instanceof THREE.WebGLRenderer) {
|
|
|
+ // 遍历场景中的所有子对象,找到类型为Mesh的对象并移除
|
|
|
+ let deleList = this.scene.children.filter(object=>{
|
|
|
+ if (object instanceof THREE.Mesh) {
|
|
|
+ return object
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if(deleList && deleList.length>0){
|
|
|
+ this.scene.remove(...deleList);
|
|
|
+ }
|
|
|
+ this.scene.traverse(function(object) {
|
|
|
+ if (object instanceof THREE.Mesh) {
|
|
|
+ if(object.geometry && typeof(object.geometry.dispose)=='function'){
|
|
|
+ object.geometry.dispose();
|
|
|
+ }
|
|
|
+ if(object.material && typeof(object.material.dispose)=='function'){
|
|
|
+ object.material.dispose();
|
|
|
+ }
|
|
|
+ if(object.texture && typeof(object.texture.dispose)=='function'){
|
|
|
+ object.texture.dispose();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.renderer.clear();
|
|
|
+ this.renderer.dispose();
|
|
|
+ this.renderer.forceContextLoss();
|
|
|
+ this.renderer.context = null;
|
|
|
+ this.renderer.domElement = null;
|
|
|
+ this.renderer = null;;
|
|
|
+ this.clearHandle()
|
|
|
+ }
|
|
|
+ TWEEN && TWEEN.removeAll();//清除所有的tween;
|
|
|
+ console.warn("***beforeDestroy-webgl_rxdz_roam***");
|
|
|
+ },
|
|
|
+ mounted(options) {
|
|
|
+ var that = this;
|
|
|
+ // alert("JavaScript 堆大小限制: "+performance.memory.jsHeapSizeLimit
|
|
|
+ // +"\n已使用的 JavaScript 堆大小: "+performance.memory.usedJSHeapSize
|
|
|
+ // +"\nJavaScript 堆的总大小: "+performance.memory.totalJSHeapSize);
|
|
|
+ console.warn("***webgl_rxdz_roam-options***",this.$route.query)
|
|
|
+ this.isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
|
|
|
+ if(this.isIOS){
|
|
|
+ this.curHouseObj = JSON.parse(getStorage('curHouseObj'));
|
|
|
+ this.wallList = JSON.parse(getStorage('wallList'));
|
|
|
+ }else{
|
|
|
+ this.curHouseObj = this.$store.state.curHouseObj;
|
|
|
+ this.wallList = this.$store.state.wallList;
|
|
|
+ }
|
|
|
+ // alert("***mounted-webgl_rxdz_roam***"+this.isIOS + this.curHouseObj)
|
|
|
+ let screenWidth = window.screen.width;
|
|
|
+ let screenHeight = window.screen.height;
|
|
|
+ if(window.innerWidth && window.screen.width){
|
|
|
+ screenWidth = Math.min(window.innerWidth,window.screen.width)
|
|
|
+ }
|
|
|
+ if(window.innerHeight && window.screen.height){
|
|
|
+ screenHeight = Math.min(window.innerHeight,window.screen.height)
|
|
|
+ }
|
|
|
+ let unit = screenWidth / 750;//单位rpm 对应 px 的值
|
|
|
+ this.canvasHeight = screenHeight - (600 * unit) + (40 * unit);
|
|
|
+ this.houseId = this.$route.query.houseId?this.$route.query.houseId:'';
|
|
|
+ this.spaceId = this.$route.query.spaceId?this.$route.query.spaceId:'';
|
|
|
+ let container = this.$refs.webgl;
|
|
|
+ let canvas3d = this.canvas = this.$refs.glcanvas;
|
|
|
+ //uniapp 兼容写法,因为uni的页面对象的Vue 实例是$vm
|
|
|
+
|
|
|
+ let camera = null, renderer = null;
|
|
|
+ let needRender = false; //是否需要渲染 false表示不需要渲染;true 表示需要渲染
|
|
|
+ let loader = this.loader = new GLTFLoader();
|
|
|
+ let scene = this.scene = new THREE.Scene();
|
|
|
+ let raycaster = null;
|
|
|
+ let mouse = new THREE.Vector2();
|
|
|
+ let chooseMesh = this.chooseMesh;//标记鼠标拾取到的mesh
|
|
|
+ let isUserContorl = true;//是否进入漫游状态-默认是
|
|
|
+ //漫游时变量
|
|
|
+ let onPointerDownMouseX = 0, onPointerDownMouseY = 0,
|
|
|
+ lon = 0;
|
|
|
+ let fingerCount = 0; //触摸时的手指数目
|
|
|
+ let startTime = 0; //非漫游时的移动变量
|
|
|
+ let tweenCameraAnma = false; //表示当前是否处在动画过程中
|
|
|
+ let controls = null,boundary=null;
|
|
|
+ let stats;
|
|
|
+ init();
|
|
|
+ // this.$refs.myLoading.showLoading("加载中...1%")
|
|
|
+ this.$store.state.loadingMsg="加载中...1%";
|
|
|
+ // this.myLoadingStatus = true;
|
|
|
+ this.progress = 1;
|
|
|
+ this.clearEvent = clearEvent;
|
|
|
+ this.attendEvent = attendEvent;
|
|
|
+ // this.meshRoam = meshRoam;
|
|
|
+ this.tweenCameraAnmaChange = tweenCameraAnmaChange;
|
|
|
+ this.switchActor = switchActor;
|
|
|
+ this.starRender = starRender;//对外暴露启动渲染的方法
|
|
|
+ this.stopRender = stopRender;//对外暴露停止渲染的方法
|
|
|
+ this.positionCamer = positionCamer;
|
|
|
+ if(this.curHouseObj && this.curHouseObj.id){
|
|
|
+ this.setHouseDetail(this.curHouseObj);
|
|
|
+ }
|
|
|
+ function init() {
|
|
|
+
|
|
|
+ scene.background = new THREE.Color("#FFFFFF");
|
|
|
+ // scene.environment = new THREE.Color("#F2F2F2");
|
|
|
+ // 创建一个HDR贴图加载器
|
|
|
+ // const rgbeloader = new RGBELoader();
|
|
|
+ // // 加载HDR贴图
|
|
|
+ // rgbeloader.load('https://dm.static.elab-plus.com/miniProgram/environment.hdr', (texture) => {
|
|
|
+ // // 将HDR贴图设置为场景的环境贴图
|
|
|
+ // texture.mapping = THREE.EquirectangularReflectionMapping;
|
|
|
+ // scene.environment = texture;
|
|
|
+ // })
|
|
|
+
|
|
|
+ // 创建相机位置
|
|
|
+ camera = new THREE.PerspectiveCamera(90, screenWidth / that.canvasHeight, 0.1, 10000 );
|
|
|
+ // camera.up.set(0, 1, 0);//俯视状态,将相机的up向量设置为z轴负方向 {x:0,y:1,z:0}
|
|
|
+ // camera.position.set(that.cameraStarPosition.x, that.cameraStarPosition.y, that.cameraStarPosition.z);
|
|
|
+ scene.add(camera);
|
|
|
+ that.camera = camera;
|
|
|
+
|
|
|
+ // 环境光会均匀的照亮场景中的所有物体
|
|
|
+ const ambientLight = new THREE.AmbientLight(0xFFEFE0, 3.5);
|
|
|
+ scene.add(ambientLight);
|
|
|
+ //平行光
|
|
|
+ const light = new THREE.DirectionalLight(0xFFF8E5, 2.5);
|
|
|
+ light.position.set(5, 7, 3); //default; light shining from top
|
|
|
+ if(!that.isIOS){
|
|
|
+ light.castShadow = true; // default false
|
|
|
+ // 默认情况下光投影相机区域是一个长宽高为10x10x500的长方体区域,光源投射方向为通过坐标原点
|
|
|
+ light.shadow.camera.left = -100; // 这个区域内产生阴影
|
|
|
+ light.shadow.camera.right = 100; // 这个区域内产生阴影
|
|
|
+ light.shadow.camera.top = 100; // 这个区域内产生阴影
|
|
|
+ light.shadow.camera.bottom = -100; // 这个区域内产生阴影
|
|
|
+
|
|
|
+ light.shadow.mapSize.width = 1024; // 影响阴影的清晰度
|
|
|
+ light.shadow.mapSize.height = 1024; // 影响阴影的清晰度
|
|
|
+ }
|
|
|
+
|
|
|
+ scene.add(light);
|
|
|
+
|
|
|
+ //antialias 这个值得设置为false,不然IOS上截图会失效
|
|
|
+ renderer = that.renderer = new THREE.WebGLRenderer( {
|
|
|
+ canvas:canvas3d,
|
|
|
+ alpha: true,
|
|
|
+ antialias:true,
|
|
|
+ preserveDrawingBuffer: true,
|
|
|
+ });
|
|
|
+ if(!that.isIOS){
|
|
|
+ renderer.shadowMap.enabled = true;//产生阴影
|
|
|
+ renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 阴影属性
|
|
|
+ }
|
|
|
+ renderer.outputEncoding = THREE.sRGBEncoding;
|
|
|
+ renderer.outputColorSpace = THREE.SRGBColorSpace;
|
|
|
+ // renderer.toneMappingExposure = 0.1;//色调映射的曝光级别。默认是1
|
|
|
+ renderer.toneMapping = THREE.NoToneMapping;//色调映射
|
|
|
+ renderer.physicallyCorrectLights = true;//关键参数,模拟物理光照影响,必须设置为true
|
|
|
+
|
|
|
+ renderer.setPixelRatio(window.devicePixelRatio);
|
|
|
+ renderer.setSize(screenWidth, that.canvasHeight);
|
|
|
+ container.appendChild( renderer.domElement );
|
|
|
+
|
|
|
+ controls = new OrbitControls( camera, renderer.domElement );
|
|
|
+ controls.enableDamping = true;//启动缓动
|
|
|
+ controls.minDistance = 0.0001;
|
|
|
+ controls.maxDistance = 10;
|
|
|
+ controls.minPolarAngle = 0;// 默认0
|
|
|
+ controls.maxPolarAngle = Math.PI / 2; // 默认Math.PI,即可以向下旋转到的视角。
|
|
|
+ // controls.target.set( that.controlStarPosition.x, that.controlStarPosition.y, that.controlStarPosition.z);
|
|
|
+ controls.enableZoom = true;//启用摄像机的缩放
|
|
|
+ controls.enablePan = true;//禁用摄像机平移
|
|
|
+ controls.enableRotate = true;//启用摄像机水平或垂直旋转
|
|
|
+ // controls.zoomToCursor = true;
|
|
|
+
|
|
|
+ // controls.target.copy(camera.position);
|
|
|
+ // controls.update();
|
|
|
+ // 监听相机移动事件-限制只能在当前空间范围内移动
|
|
|
+ controls.addEventListener('change', () => {
|
|
|
+ // 检查相机位置是否超出边界框
|
|
|
+ if (boundary && !boundary.containsPoint(camera.position)) {
|
|
|
+ let clampedPosition = new THREE.Vector3( );
|
|
|
+ boundary.clampPoint(camera.position,clampedPosition);
|
|
|
+ if(clampedPosition){
|
|
|
+ camera.position.copy(clampedPosition);
|
|
|
+ // controls.target.copy(clampedPosition);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // controls.target = new THREE.Vector3( );;
|
|
|
+ // camera.lookAt(that.controlStarPosition.x,that.controlStarPosition.y,that.controlStarPosition.z);
|
|
|
+ raycaster = new THREE.Raycaster();
|
|
|
+ // stats = new Stats();
|
|
|
+ // container.appendChild(stats.dom);
|
|
|
+ // stats.domElement.style.top = '100px';
|
|
|
+ attendEvent();//注册监听事件
|
|
|
+ starRender(); //启动渲染
|
|
|
+ }
|
|
|
+ function tweenCameraAnmaChange (value) {
|
|
|
+ tweenCameraAnma = value
|
|
|
+ }
|
|
|
+ function attendEvent () {
|
|
|
+ renderer && renderer.domElement && renderer.domElement.addEventListener('touchstart', onPointerStart, false);
|
|
|
+ renderer && renderer.domElement && renderer.domElement.addEventListener('touchmove', onPointerMove, false);
|
|
|
+ renderer && renderer.domElement && renderer.domElement.addEventListener('touchend', onPointerUp, false);
|
|
|
+ }
|
|
|
+ //取消事件监听-避免二次进入时触发多次事件
|
|
|
+ function clearEvent(){
|
|
|
+ console.warn("**clearEvent****")
|
|
|
+ renderer && renderer.domElement && renderer.domElement.removeEventListener('touchstart', onPointerStart);
|
|
|
+ renderer && renderer.domElement && renderer.domElement.removeEventListener('touchmove', onPointerMove );
|
|
|
+ renderer && renderer.domElement && renderer.domElement.removeEventListener('touchend', onPointerUp );
|
|
|
+ }
|
|
|
+ // 手指移动开始
|
|
|
+ function onPointerStart(event){
|
|
|
+ startTime = (new Date()).getTime();
|
|
|
+ fingerCount = event.touches.length;//手指个数
|
|
|
+ console.log('开始触摸事件:',lon,fingerCount,camera.position.y)
|
|
|
+ if (fingerCount === 1) {
|
|
|
+ // 只有一个手指时记录当前点的坐标作为平移起始点
|
|
|
+ onPointerDownMouseX = event.changedTouches[0].clientX;
|
|
|
+ onPointerDownMouseY = event.changedTouches[0].clientY;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //持续触摸中
|
|
|
+ function onPointerMove( event ) {
|
|
|
+ fingerCount = event.touches.length;//手指个数
|
|
|
+ }
|
|
|
+ //触摸结束
|
|
|
+ function onPointerUp(event) {
|
|
|
+ fingerCount = event.touches.length;//手指个数
|
|
|
+ console.warn("***触摸结束***",fingerCount,startTime)
|
|
|
+ if(fingerCount==0){
|
|
|
+ let now = new Date().getTime()
|
|
|
+ if (Math.abs(event.changedTouches[0].clientX - onPointerDownMouseX) < 10
|
|
|
+ && Math.abs(event.changedTouches[0].clientY - onPointerDownMouseY) < 10
|
|
|
+ && (now - startTime) < 300 ){
|
|
|
+ checkIntersection(event);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //射线检测handle
|
|
|
+ function checkIntersection(event) {
|
|
|
+ let x = (event.changedTouches[0].clientX / screenWidth) * 2 - 1;
|
|
|
+ let y = -(event.changedTouches[0].clientY / that.canvasHeight) * 2 + 1;
|
|
|
+ mouse.x = x;
|
|
|
+ mouse.y = y;
|
|
|
+ //更新射线
|
|
|
+ raycaster.setFromCamera(mouse, camera);
|
|
|
+ let intersects = raycaster.intersectObjects(scene.children,true);
|
|
|
+ console.warn("***checkIntersection***",intersects.length)
|
|
|
+ if (intersects.length > 0) {
|
|
|
+ //找到最近的那个网格模型物体
|
|
|
+ let mesh = intersects.find((it) => {
|
|
|
+ if(it.object && it.object.isMesh == true
|
|
|
+ && it.object.parent && it.object.parent.name == 'actor'
|
|
|
+ && it.object.parent.visible == true){
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ //拾取到了视角,就不继续拾取了
|
|
|
+ if(mesh){
|
|
|
+ moveActor(mesh.object.parent);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ mesh = intersects.find((it) => {
|
|
|
+ if(it.object && it.object.isInstancedMesh
|
|
|
+ && (it.object.name == '地板' || it.object.name == '花园') && it.object.visible == true){
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ //拾取到了地板
|
|
|
+ if(mesh){
|
|
|
+ let floor = mesh.object;
|
|
|
+ let index = mesh.instanceId;//射线相交是的实例序号
|
|
|
+ let spaceId = that.gltfSpaces[index].spaceId;//获取选中实例的空间id
|
|
|
+ if(floor.name == "花园"){//花园
|
|
|
+ return false;
|
|
|
+ let selectMesh = that.gltfSpaces.find(it=>{return it.spaceType==14 && it.instancedMeshIndexList[0].instancedAtIndex==index})
|
|
|
+ spaceId = selectMesh.spaceId;
|
|
|
+ }else{//室内
|
|
|
+ // floor.name = "地板";
|
|
|
+ let selectMesh = that.gltfSpaces.find(it=>{return it.spaceType!=14 && it.instancedMeshIndexList[0].instancedAtIndex==index})
|
|
|
+ spaceId = selectMesh.spaceId;
|
|
|
+ }
|
|
|
+ // let spaceId = that.gltfSpaces[index].spaceId;//获取选中实例的空间id
|
|
|
+ console.warn("***checkIntersection-地板***",floor,index,spaceId,that.spaceId)
|
|
|
+ //当前拾取到的是本空间的底部-意味着用户点击了地板
|
|
|
+ if(floor && spaceId == that.spaceId){
|
|
|
+ moveCarmer(mesh.point);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //自动切换视角
|
|
|
+ function switchActor (toIndex=null) {
|
|
|
+ if(!that.currentActor){
|
|
|
+ this.$message.warning("没有当前视角!");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(!that.actors || that.actors.length==0){
|
|
|
+ this.$message.warning("没有视角!");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(toIndex!=null){//存在要去往的视角
|
|
|
+ moveActor(that.actors[toIndex]);
|
|
|
+ }else{
|
|
|
+ let index = that.currentActor.userIndex;//当前视角的序号
|
|
|
+ let nextIndex = (index + 1) % that.actors.length;
|
|
|
+ //移动到对应的视角去
|
|
|
+ moveActor(that.actors[nextIndex]);
|
|
|
+ that.defaulIndex = nextIndex;//更新下默认视角
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //移动到选中的位置-地板
|
|
|
+ function moveCarmer (point) {
|
|
|
+ //还在动画中,不能点击切换
|
|
|
+ if(tweenCameraAnma == true){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ let _x = point.x - camera.position.x;//x轴移动的距离
|
|
|
+ let _z = point.z - camera.position.z;//z轴移动的距离
|
|
|
+ let cameraNewPosition = {x:camera.position.x + _x,y:1.5,z:camera.position.z + _z};
|
|
|
+ let targetNewPosition = {x:controls.target.x + _x,y:1.5,z:controls.target.z + _z};
|
|
|
+ let oldUp = {x:0,y:1,z:0};
|
|
|
+ let newUp = {x:0,y:1,z:0};
|
|
|
+ moveTip(cameraNewPosition)
|
|
|
+ // console.warn("**moveCarmer***",lon,JSON.stringify(cameraNewPosition),JSON.stringify(targetNewPosition))
|
|
|
+ tweenCamera(camera.position,controls.target,cameraNewPosition,targetNewPosition,oldUp,newUp,2000);
|
|
|
+ setTimeout(()=> {
|
|
|
+ that.circleGroup.visible = false;
|
|
|
+ }, 2000);
|
|
|
+ }
|
|
|
+ //创建地标
|
|
|
+ function creatMoveTip(position){
|
|
|
+ if(!that.circleGroup){
|
|
|
+ that.circleGroup = new THREE.Group();
|
|
|
+ let geometry = new THREE.CircleGeometry( 0.2, 32 );
|
|
|
+ let material = new THREE.MeshBasicMaterial( { transparent: true } );
|
|
|
+ let circle = new THREE.Mesh( geometry, material );
|
|
|
+ circle.position.set(position.x,0.01,position.z);
|
|
|
+ circle.rotation.x = -Math.PI / 2;
|
|
|
+ // let geometry1 = new THREE.CircleGeometry( 0.4, 32 );
|
|
|
+ // let circle2 = new THREE.Mesh( geometry1, material );
|
|
|
+ // circle2.position.set(position.x,0.01,position.z);
|
|
|
+ // 使用贴图
|
|
|
+ const textureLoader = new THREE.TextureLoader();
|
|
|
+ textureLoader.load('https://dm.static.elab-plus.com/miniProgram/circlemap1.png', function(texture) {
|
|
|
+ material.map = texture; // 将贴图应用于材质的map属性
|
|
|
+ material.needsUpdate = true; // 更新材质
|
|
|
+ });
|
|
|
+ that.circleGroup.add(circle);
|
|
|
+ scene.add(that.circleGroup);
|
|
|
+ that.circleGroup.visible = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //移动地标
|
|
|
+ function moveTip(position){
|
|
|
+ if(!that.circleGroup){
|
|
|
+ that.circleGroup = new THREE.Group();
|
|
|
+ let geometry = new THREE.CircleGeometry( 0.2, 32 );
|
|
|
+ let material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
|
|
|
+ let circle = new THREE.Mesh( geometry, material );
|
|
|
+ circle.position.set(position.x,0.01,position.z);
|
|
|
+ circle.rotation.x = -Math.PI / 2;
|
|
|
+ // let geometry1 = new THREE.CircleGeometry( 0.4, 32 );
|
|
|
+ // let circle2 = new THREE.Mesh( geometry1, material );
|
|
|
+ // circle2.position.set(position.x,0.01,position.z);
|
|
|
+ that.circleGroup.add(circle);
|
|
|
+ scene.add(that.circleGroup);
|
|
|
+ }else{
|
|
|
+ that.circleGroup.visible = true;
|
|
|
+ that.circleGroup.children[0].position.set(position.x,0.01,position.z);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //移动视角点位
|
|
|
+ function moveActor (obj) {
|
|
|
+ clearEvent();//注销事件监听
|
|
|
+ // console.warn("***moveActor***",obj)
|
|
|
+ that.currentActor = obj;//记录下当前的视角对象 mesh网格模型
|
|
|
+ let cameraNewPosition = obj.position;
|
|
|
+ let targetNewPosition = obj.targetNewPosition;
|
|
|
+ let oldUp = {x:0,y:1,z:0}; //俯视
|
|
|
+ let newUp = {x:0,y:1,z:0}; //正视
|
|
|
+ // moveTip(cameraNewPosition);
|
|
|
+ // console.warn("**moveActor***",JSON.stringify(cameraNewPosition),JSON.stringify(targetNewPosition))
|
|
|
+ tweenCamera(camera.position,controls.target,cameraNewPosition,targetNewPosition,oldUp,newUp,2000);
|
|
|
+ lon = 0;
|
|
|
+ setTimeout(()=> {
|
|
|
+ attendEvent()
|
|
|
+ // that.circleGroup.visible = false;
|
|
|
+ }, 2000);
|
|
|
+ }
|
|
|
+ //初始化点位视角
|
|
|
+ function initActor(){
|
|
|
+ if(!chooseMesh){
|
|
|
+ console.error("[drawActor],没有选中的空间数据")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ let spaceObj = chooseMesh;//获取选中的空间模型的相关数据
|
|
|
+ if(!spaceObj.actors){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ let defaulIndex = spaceObj.actors.findIndex(it=>it.isSelected==true);
|
|
|
+ if(defaulIndex == -1){
|
|
|
+ defaulIndex = 0;
|
|
|
+ }
|
|
|
+ that.defaulIndex = defaulIndex;//记录下默认视角
|
|
|
+ that.actors = [];
|
|
|
+ spaceObj.actors.forEach((actor,index)=>{
|
|
|
+ // let model = gltf.scene; // 获取模型
|
|
|
+ // let cloneModel = model.clone(true);//赋值模型,准备复用
|
|
|
+ // cloneModel.children.map((v,i)=>{
|
|
|
+ // if(v.material){
|
|
|
+ // v.material = model.children[i].material.clone()
|
|
|
+ // }
|
|
|
+ // })
|
|
|
+ // let cube = cloneModel;
|
|
|
+ let cube = {};
|
|
|
+ cube.name = "actor";
|
|
|
+ cube.userType = "mesh";
|
|
|
+ //新的摄像机的位置-新的摄像机角度是倾斜角度,所以z值需要计算,高度设置为模型高度的2倍
|
|
|
+ let _actorLoaction = actor.actorLocation.split(',');//x y z
|
|
|
+ let _actorTransform = actor.actorTransform.split(',');//旋转角度,取第三个值
|
|
|
+ let _hd = THREE.MathUtils.degToRad(parseInt(_actorTransform[2]));//将度转化为弧度。
|
|
|
+ let _hdY = THREE.MathUtils.degToRad(parseInt(_actorTransform[1]));//Y轴方向上将度转化为弧度。
|
|
|
+ // if(parseInt(_actorLoaction[1])==0){//X轴
|
|
|
+ // _actorLoaction[1] = spaceObj.centerX;
|
|
|
+ // }
|
|
|
+ // if(parseInt(_actorLoaction[0])==0){//Y轴
|
|
|
+ // _actorLoaction[0] = spaceObj.centerY;
|
|
|
+ // }
|
|
|
+ let X_C = parseInt(_actorLoaction[0]);//X轴偏移量
|
|
|
+ let Y_C = -parseInt(_actorLoaction[1]);//Y轴偏移量-取反,UE里面的Y轴方向跟Three.js相反
|
|
|
+ let px = spaceObj.centerX + X_C;
|
|
|
+ let py = -spaceObj.centerY + Y_C;//UE里面的centerY值跟Three.js Y轴相反;获得真实的坐标值
|
|
|
+ let position = {
|
|
|
+ x:(parseInt(px))/100,
|
|
|
+ y:1.5,
|
|
|
+ z:(parseInt(py))/100,//模型Y轴坐标系正负值跟webglZ轴是相反的
|
|
|
+ }
|
|
|
+ //新的观察点的位置-取模型的中心点坐标,加上高度,由于模型都是贴地的,所以高度设置为1.5
|
|
|
+ let targetNewPosition = {
|
|
|
+ x:position.x + Math.sin(_hd),
|
|
|
+ y:1.5 + Math.tan(_hdY),
|
|
|
+ z:(position.z - Math.cos(_hd)),
|
|
|
+ }
|
|
|
+ cube.position = position;
|
|
|
+ cube.userIndex = index;
|
|
|
+ cube.actorEum = index;
|
|
|
+ cube.targetNewPosition = targetNewPosition;
|
|
|
+ // console.warn("*actors*",cube,defaulIndex)
|
|
|
+ that.actors.push(cube);//添加视角
|
|
|
+ if(index == defaulIndex){//隐藏当前视角
|
|
|
+ that.currentActor = cube;//记录下当前的视角对象 mesh网格模型
|
|
|
+ let param = {
|
|
|
+ type: 'CLK', //埋点类型
|
|
|
+ clkId: 'clk_2cmina_23080411', //点击ID
|
|
|
+ clkName: 'visualangle_clk', //点击前往的页面名称
|
|
|
+ clkParams: {
|
|
|
+ locusName: "预制视角",
|
|
|
+ type:that.actors[index].actorEum
|
|
|
+ }
|
|
|
+ };
|
|
|
+ util.trackRequest(param);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ //计算当前选中空间的平视时的观察点和摄像机的放置点位
|
|
|
+ function roamPositionHandle(lon=''){
|
|
|
+ if(!chooseMesh){
|
|
|
+ console.error("[roamPositionHandle],没有选中的空间数据")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ let spaceObj = chooseMesh;//获取选中的空间模型的相关数据
|
|
|
+ //获取视角
|
|
|
+ let defaultActor = null;
|
|
|
+ if(spaceObj.actors && spaceObj.actors.length>0){
|
|
|
+ defaultActor = spaceObj.actors.find(it=>it.isSelected==true);
|
|
|
+ if(!defaultActor){
|
|
|
+ defaultActor = spaceObj.actors[0];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let _actorLoaction = defaultActor.actorLocation.split(',');//x y z
|
|
|
+ let _actorTransform = defaultActor.actorTransform.split(',');//旋转角度,取第三个值
|
|
|
+ let _hd = THREE.MathUtils.degToRad(parseInt(_actorTransform[2]) + lon);//将度转化为弧度。
|
|
|
+ let _hdY = THREE.MathUtils.degToRad(parseInt(_actorTransform[1]));//Y轴方向上将度转化为弧度。
|
|
|
+ // if(parseInt(_actorLoaction[1])==0){//X轴
|
|
|
+ // _actorLoaction[1] = spaceObj.centerX;
|
|
|
+ // }
|
|
|
+ // if(parseInt(_actorLoaction[0])==0){//Y轴
|
|
|
+ // _actorLoaction[0] = spaceObj.centerY;
|
|
|
+ // }
|
|
|
+ let X_C = parseInt(_actorLoaction[0]);//X轴偏移量-UE原因
|
|
|
+ let Y_C = -parseInt(_actorLoaction[1]);//Y轴偏移量-取反,UE里面的Y轴方向跟Three.js相反
|
|
|
+ let px = spaceObj.centerX + X_C;
|
|
|
+ let py = -spaceObj.centerY + Y_C;
|
|
|
+ //新的摄像机的位置-新的摄像机角度是倾斜角度,所以z值需要计算,高度设置为模型高度的2倍
|
|
|
+ let cameraNewPosition = {
|
|
|
+ x:(parseInt(px))/100,
|
|
|
+ y:1.5,
|
|
|
+ z:(parseInt(py))/100,//模型Y轴坐标系正负值跟webglZ轴是相反的
|
|
|
+ }
|
|
|
+ if(cameraNewPosition){
|
|
|
+ let minX = 0,maxX = 0,minY = 0,maxY = 0;//0.1 是模型墙壁厚度
|
|
|
+ minX = (spaceObj.centerX - (spaceObj.spaceWidth/2))/100 + 0.1;
|
|
|
+ maxX = (spaceObj.centerX + (spaceObj.spaceWidth/2))/100 - 0.1;
|
|
|
+ maxY = ((-spaceObj.centerY + (spaceObj.spaceHeight/2))/100 - 0.1);
|
|
|
+ minY = ((-spaceObj.centerY - (spaceObj.spaceHeight/2))/100 + 0.1);
|
|
|
+ //新的坐标轴不在房间范围内,则不能移动
|
|
|
+ if(cameraNewPosition.x<minX || cameraNewPosition.x>maxX
|
|
|
+ ||cameraNewPosition.z<minY || cameraNewPosition.z>maxY){//不在房间范围
|
|
|
+ let _x = ((spaceObj.spaceWidth/2) - 15)*defaultActor.presentX + spaceObj.centerX;
|
|
|
+ let _z = ((spaceObj.spaceHeight/2) - 15)*defaultActor.presentY + (-spaceObj.centerY);
|
|
|
+ cameraNewPosition.x = _x/100;
|
|
|
+ cameraNewPosition.z = _z/100;
|
|
|
+ console.warn("**roamPositionHandle-观察点不在空间范围-强制修正观察点位置****",JSON.stringify(cameraNewPosition))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //新的观察点的位置-取模型的中心点坐标,加上高度,由于模型都是贴地的,所以高度设置为1.5
|
|
|
+ let targetNewPosition = {
|
|
|
+ x:cameraNewPosition.x + Math.sin(_hd),
|
|
|
+ y:1.5 + Math.tan(_hdY),
|
|
|
+ z:(cameraNewPosition.z - Math.cos(_hd)),
|
|
|
+ }
|
|
|
+ let lookPosition = {
|
|
|
+ x:cameraNewPosition.x + (Math.sin(_hd)*0.01),
|
|
|
+ y:1.5 + Math.tan(_hdY),
|
|
|
+ z:(cameraNewPosition.z - (Math.cos(_hd))*0.01),
|
|
|
+ }
|
|
|
+ return {cameraNewPosition,targetNewPosition,lookPosition}
|
|
|
+ }
|
|
|
+ //直接定位到摄像头位置
|
|
|
+ function positionCamer(mesh=null,needAni=false){
|
|
|
+ if(mesh){//如果传入了模型,则取模型
|
|
|
+ chooseMesh = mesh;
|
|
|
+ }
|
|
|
+ if(!chooseMesh){
|
|
|
+ console.error("[positionCamer],没有选中的空间数据")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(!chooseMesh.actors || chooseMesh.actors.length==0){
|
|
|
+ chooseMesh.actors = [{
|
|
|
+ actorLocation:chooseMesh.actorLocation,
|
|
|
+ actorTransform:chooseMesh.actorTransform,
|
|
|
+ isSelected:true,
|
|
|
+ presentX:chooseMesh.presentX,
|
|
|
+ presentY:chooseMesh.presentY,
|
|
|
+ }]
|
|
|
+ }
|
|
|
+ boundary = new THREE.Box3(
|
|
|
+ new THREE.Vector3(chooseMesh.centerX/100 - chooseMesh.spaceWidth/100/2 + 0.1, 0, -chooseMesh.centerY/100 - chooseMesh.spaceHeight/100/2 + 0.1), // 边界框的最小点
|
|
|
+ new THREE.Vector3(chooseMesh.centerX/100 + chooseMesh.spaceWidth/100/2 - 0.1, 2.7, -chooseMesh.centerY/100 + chooseMesh.spaceHeight/100/2 - 0.1) // 边界框的最大点
|
|
|
+ );
|
|
|
+ initActor();//初始化视角
|
|
|
+ let data = roamPositionHandle();
|
|
|
+ let cameraNewPosition = data.cameraNewPosition;
|
|
|
+ let targetNewPosition = data.targetNewPosition;
|
|
|
+ targetNewPosition.z = targetNewPosition.z + 0.5;//增加偏差,防止极点翻转问题?不知道为啥会有用
|
|
|
+ let lookPosition = data.lookPosition;
|
|
|
+ creatMoveTip(cameraNewPosition);//创建移动的地标
|
|
|
+ if(needAni){
|
|
|
+ let oldUp = {x:0,y:1,z:0}; //俯视
|
|
|
+ let newUp = {x:0,y:1,z:0}; //正视
|
|
|
+ tweenCamera(camera.position,controls.target,cameraNewPosition,targetNewPosition,oldUp,newUp,2000);
|
|
|
+ }else{
|
|
|
+ camera.position.set(cameraNewPosition.x, cameraNewPosition.y, cameraNewPosition.z);
|
|
|
+ controls.target.set(lookPosition.x,lookPosition.y,lookPosition.z);
|
|
|
+ // controls.target.set(cameraNewPosition.x,cameraNewPosition.y,cameraNewPosition.z);
|
|
|
+ // controls.target.copy(camera.position);
|
|
|
+ camera.lookAt(targetNewPosition.x,targetNewPosition.y,targetNewPosition.z);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // oldP 相机原来的位置
|
|
|
+ // oldT target原来的位置
|
|
|
+ // newP 相机新的位置
|
|
|
+ // newT target新的位置
|
|
|
+ function tweenCamera(oldP, oldT, newP, newT, oldUp, newUp, time=1000) {
|
|
|
+ if(JSON.stringify(oldP) == JSON.stringify(newP) && JSON.stringify(oldT) == JSON.stringify(newT)){
|
|
|
+ that.repeatFlag = false;//放开限制,可以再次点击
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!chooseMesh) {
|
|
|
+ that.repeatFlag = false;//放开限制,可以再次点击
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ tweenCameraAnma = true;
|
|
|
+ var tween = new TWEEN.Tween({
|
|
|
+ x1: oldP.x, // 相机x
|
|
|
+ y1: oldP.y, // 相机y
|
|
|
+ z1: oldP.z, // 相机z
|
|
|
+ x2: oldT.x, // 控制点的中心点x
|
|
|
+ y2: oldT.y, // 控制点的中心点y
|
|
|
+ z2: oldT.z, // 控制点的中心点z
|
|
|
+ x3: oldUp.x, // 控制点的中心点x
|
|
|
+ y3: oldUp.y, // 控制点的中心点y
|
|
|
+ z3: oldUp.z // 控制点的中心点z
|
|
|
+ })
|
|
|
+ .to({
|
|
|
+ x1: newP.x,
|
|
|
+ y1: newP.y,
|
|
|
+ z1: newP.z,
|
|
|
+ x2: newT.x,
|
|
|
+ y2: newT.y,
|
|
|
+ z2: newT.z,
|
|
|
+ x3: newUp.x, // up向量
|
|
|
+ y3: newUp.y, // 控制点的中心点y
|
|
|
+ z3: newUp.z // 控制点的中心点z
|
|
|
+ }, time)
|
|
|
+ .easing(TWEEN.Easing.Quadratic.InOut)
|
|
|
+ .onUpdate((object)=> {
|
|
|
+ camera.position.x = object.x1;
|
|
|
+ camera.position.y = object.y1;
|
|
|
+ camera.position.z = object.z1;
|
|
|
+ // let newTarget = new THREE.Vector3(object.x3,object.y3,object.z3);
|
|
|
+ // camera.up.copy(newTarget);
|
|
|
+ camera.lookAt(object.x2,object.y2,object.z2);
|
|
|
+ // controls.target.x = object.x2;
|
|
|
+ // controls.target.y = object.y2;
|
|
|
+ // controls.target.z = object.z2;
|
|
|
+ // controls.update();
|
|
|
+ }).onComplete(()=>{
|
|
|
+ controls.target.x = newT.x;
|
|
|
+ controls.target.y = newT.y;
|
|
|
+ controls.target.z = newT.z;
|
|
|
+ //修正最后的视角
|
|
|
+ // let up = new THREE.Vector3(newUp.x,newUp.y,newUp.z);
|
|
|
+ // camera.up.copy(up);
|
|
|
+ camera.lookAt(newT.x,newT.y,newT.z);
|
|
|
+ tweenCameraAnma = false;
|
|
|
+ that.repeatFlag = false;//放开限制,可以再次点击
|
|
|
+ })
|
|
|
+ // 开始动画
|
|
|
+ tween.start();
|
|
|
+ }
|
|
|
+
|
|
|
+ function stopRender () {
|
|
|
+ needRender = false;
|
|
|
+ }
|
|
|
+ function starRender () {
|
|
|
+ if(needRender==true){//如果已经在渲染中了,则不能再次开启,避免渲染过多
|
|
|
+ false;
|
|
|
+ }
|
|
|
+ needRender = true;
|
|
|
+ render();//开始渲染
|
|
|
+ }
|
|
|
+ function render() {
|
|
|
+ if(needRender==false){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ TWEEN && TWEEN.update();
|
|
|
+ // stats.update();
|
|
|
+ renderer.render(scene, camera);//单次渲染
|
|
|
+ requestId = requestAnimationFrame(render, canvas3d);
|
|
|
+ if (that.screenshotResolve) {
|
|
|
+ stopRender();
|
|
|
+ that.screenshotResolve()
|
|
|
+ that.screenshotResolve = null;//释放Promise
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ // computed: {
|
|
|
+ // curHouseObj() {
|
|
|
+ // return this.$store.state.curHouseObj;
|
|
|
+ // },
|
|
|
+ // wallList() {
|
|
|
+ // return this.$store.state.wallList;
|
|
|
+ // },
|
|
|
+ // },
|
|
|
+ methods: {
|
|
|
+ navbarBackClk() {
|
|
|
+ if(!this.$refs.viewMask){
|
|
|
+ this.$router.go(-1);
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (this.$refs.viewMask.showAIImage) {
|
|
|
+ this.$refs.viewMask.showOrHideWebGl();//隐藏显示的AI生图
|
|
|
+ // if(this.currentActor.userIndex!=this.defaulIndex){//当前不是默认视角了
|
|
|
+ this.switchActor(this.defaulIndex);//切换到默认视角
|
|
|
+ // }
|
|
|
+ } else {
|
|
|
+ this.$router.go(-1);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ switchActor(){},
|
|
|
+ positionCamer(){},
|
|
|
+ clearHandle(){
|
|
|
+ this.clearEvent();
|
|
|
+ },
|
|
|
+ save(){
|
|
|
+ this.$refs.viewMask.save();//下载
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 设置户型详情信息
|
|
|
+ * @param {Object} data 户型详情
|
|
|
+ */
|
|
|
+ setHouseDetail(data){
|
|
|
+ if(data){
|
|
|
+ this.id = data.id;
|
|
|
+ this.spaceId = this.$route.query.spaceId?this.$route.query.spaceId:'';
|
|
|
+ console.warn("***curHouseObj***",data)
|
|
|
+ // 加载户型
|
|
|
+ this.loadSpace();
|
|
|
+ }else{
|
|
|
+ this.curHouseObj = {}
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 绘制空间-即地板
|
|
|
+ async loadSpace(){
|
|
|
+ this.spaceList = [];
|
|
|
+ this.wallIds = [];
|
|
|
+ if(!this.curHouseObj || !this.spaceId){//减少重复请求
|
|
|
+ alert("数据错误")
|
|
|
+ console.warn("***数据错误***")
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if(this.curHouseObj){
|
|
|
+ const spaceDetail = this.curHouseObj;
|
|
|
+ const spaceList = JSON.parse(spaceDetail.houseJson);
|
|
|
+ // 交换centerX, centerY;上一页面已经处理过了,这里不在需要处理
|
|
|
+ for (let index = 0; index < spaceList.length; index++) {
|
|
|
+ var element = spaceList[index];
|
|
|
+ // const centerX = JSON.parse(JSON.stringify(element.centerX))
|
|
|
+ if(!element.actors || element.actors.length==0){
|
|
|
+ element.actors = [{
|
|
|
+ actorLocation:element.actorLocation,
|
|
|
+ actorTransform:element.actorTransform,
|
|
|
+ isSelected:true,
|
|
|
+ }]
|
|
|
+ }
|
|
|
+ element.actors.forEach(actor=>{
|
|
|
+ let _actorLoaction = actor.actorLocation.split(',');//x y z
|
|
|
+ let X_C = parseInt(_actorLoaction[0]);//X轴偏移量-UE原因
|
|
|
+ let Y_C = -parseInt(_actorLoaction[1]);//Y轴偏移量-取反,UE里面的Y轴方向跟Three.js相反
|
|
|
+ let _x = element.centerX + X_C;
|
|
|
+ let _z = -element.centerY + Y_C;//centerY 要取反,因为UE里面是反向的
|
|
|
+
|
|
|
+ // let _x = parseInt(_actorLoaction[1]) || element.centerX;//观察点 X轴坐标
|
|
|
+ // let _z = parseInt(_actorLoaction[0]) || element.centerY;//观察点 Z轴坐标
|
|
|
+ let _presentX = (_x - element.centerX)/((element.spaceWidth/2) - 10);//10是墙壁厚度-单位cm
|
|
|
+ let _presentY = (_z + element.centerY)/((element.spaceHeight/2) - 10);
|
|
|
+ //注意如果一开始就设置大超过空间大小,则处理成贴近空间边界
|
|
|
+ actor.presentX = Math.abs(_presentX)>1 ? (_presentX>1?1:-1) : _presentX;//观察点跟空间中心原点的距离比例
|
|
|
+ actor.presentY = Math.abs(_presentY)>1 ? (_presentY>1?1:-1) : _presentY;
|
|
|
+ })
|
|
|
+ element.wallMoveValue = "[0,0,0,0]"
|
|
|
+ this.spaceList.push(element);
|
|
|
+ this.wallIds.push(element.wallId);
|
|
|
+
|
|
|
+ if(element.spaceId == this.spaceId){ // 默认选中空间
|
|
|
+ this.curSpaceObj = element;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(!this.curSpaceObj && this.spaceList.length > 0){
|
|
|
+ this.curSpaceObj = this.spaceList[0];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let curSpaceArea = parseFloat((this.curSpaceObj.spaceWidth * this.curSpaceObj.spaceHeight) / 10000).toFixed(1);
|
|
|
+ this.navbar.title = this.curSpaceObj.spaceName + " " + curSpaceArea + "㎡";
|
|
|
+ document.title = this.navbar.title;
|
|
|
+ console.log("该户型空间数据:", this.spaceList);
|
|
|
+ console.log("当前选中的空间:", this.curSpaceObj);
|
|
|
+ this.positionCamer(this.curSpaceObj);
|
|
|
+ this.loaderSpaceArr(this.spaceList);//绘制地板
|
|
|
+ // 获取墙体数据并且绘制墙体
|
|
|
+ this.getHouseTypeSpaceWalls();
|
|
|
+ },
|
|
|
+ changeSpace(spaceId){
|
|
|
+ console.warn("***changeSpace***",spaceId,this.spaceId)
|
|
|
+ if(spaceId == this.spaceId){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ this.spaceId = spaceId;
|
|
|
+ this.curSpaceObj = this.spaceList.find(it=>it.spaceId == spaceId);
|
|
|
+ this.positionCamer(this.curSpaceObj,true);
|
|
|
+ let curSpaceArea = parseFloat((this.curSpaceObj.spaceWidth * this.curSpaceObj.spaceHeight) / 10000).toFixed(1);
|
|
|
+ this.navbar.title = this.curSpaceObj.spaceName + " " + curSpaceArea + "㎡";
|
|
|
+ document.title = this.navbar.title;
|
|
|
+ },
|
|
|
+ // 获取墙体数据
|
|
|
+ async getHouseTypeSpaceWalls(){
|
|
|
+ let wallList = [];
|
|
|
+ if(this.wallList){
|
|
|
+ wallList = this.wallList;
|
|
|
+ }else{
|
|
|
+ let data = {id:this.wallIds}
|
|
|
+ const res = await requestConfig('getHouseTypeSpaceWalls', data, true);
|
|
|
+ // console.log("墙体数据:", res.list)
|
|
|
+ if(res.success){
|
|
|
+ wallList = this.wallList = res.list;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let wallArr = []
|
|
|
+ for (let index = 0; index < wallList.length; index++) {//每个空间对应一个数据
|
|
|
+ let element = JSON.parse(wallList[index].wallJson);
|
|
|
+ let space = this.spaceList.find(space=>space.spaceId==element.spaceId);
|
|
|
+ this.computeWallHandleOld(space,element);//提前计算
|
|
|
+ for (let i = 0; i < element.wallData.length; i ++) {//对应空间里面的4个方向的墙壁数据
|
|
|
+ let wallData = element.wallData[i];
|
|
|
+ //对应方向的墙壁的墙体模型数据列表,每一面墙可能有多个模型
|
|
|
+ for (let j = 0; j < wallData.wallModelData.length; j ++) {
|
|
|
+ let wallModelData = wallData.wallModelData[j];
|
|
|
+ wallArr.push({spaceId:element.spaceId, wallModelData:wallModelData, wallDirection:wallData.wallDirection})
|
|
|
+ // console.log("wallModelData", element,wallData.wallDirection, wallModelData.wallType );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.loadSpaceObjWalls(wallArr, wallList);
|
|
|
+ this.getOverallArrangementDetailsList();//
|
|
|
+ },
|
|
|
+ // 加载单个空间墙体资源
|
|
|
+ async loadSpaceObjWalls(wallArr, wallList){
|
|
|
+ // 加载远程墙体模型资源
|
|
|
+ let startTime = new Date().getTime();
|
|
|
+ // console.log("wallArr:", wallArr)
|
|
|
+ let promise_list = [];
|
|
|
+ let realWallArr = this.preWallData(wallArr);
|
|
|
+ let arrLength = realWallArr.length;
|
|
|
+ realWallArr && realWallArr.forEach((item,index) => {
|
|
|
+ promise_list.push(
|
|
|
+ new Promise((resolve, reject) => {
|
|
|
+ this.loadWallModels(item, wallList, arrLength , resolve);
|
|
|
+ })
|
|
|
+ )
|
|
|
+ });
|
|
|
+ Promise.all(promise_list).then(()=>{
|
|
|
+ let endTime = new Date().getTime();
|
|
|
+ console.log("墙体模型全部加载完成,时间:",endTime - startTime);
|
|
|
+ // 设置空间数组的墙体信息
|
|
|
+ // this.setSpaceListWallInfo();
|
|
|
+ this.$nextTick(()=>{
|
|
|
+ // this.moveMeshCenter(this.curSpaceObj);
|
|
|
+ this.progress = 100;
|
|
|
+ // this.$refs.myLoading.showLoading("加载中..." + this.progress + '%')
|
|
|
+ this.$nextTick(()=>{
|
|
|
+ this.myLoadingStatus = false;
|
|
|
+ // this.$refs.myLoading.hideLoading();
|
|
|
+ // this.meshRoam(this.curSpaceObj);//开始漫游,必须先选中模型
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+ @import "./webgl_rxdz_test_roam.scss";
|
|
|
+ /* @import "@/common/css/common.css"; */
|
|
|
+</style>
|