|
@@ -0,0 +1,692 @@
|
|
|
+<template src="./webgl_rxdz_look.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 spaceTypes from '@/static/spaceTypesIE.js';
|
|
|
+ import TWEEN from 'three/addons/libs/tween.module.js';
|
|
|
+
|
|
|
+ var requestId = "";
|
|
|
+ const util = require('@/utils/util.js');
|
|
|
+ const config = require('@/services/urlConfig.js');
|
|
|
+ import loadModel from '@/mixins/loadModel.js';
|
|
|
+ import wallMethod from '@/mixins/wallMethod.js';
|
|
|
+ import floorMethod from '@/mixins/floorMethod.js';
|
|
|
+ import commonPageMethod from '@/mixins/commonPageMethod.js';
|
|
|
+ // const app = getApp(); //获取应用实例
|
|
|
+ export default {
|
|
|
+ mixins:[loadModel,floorMethod,wallMethod,commonPageMethod],
|
|
|
+ /**
|
|
|
+ * 页面的初始数据
|
|
|
+ */
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ pvCurPageName: "webgl_rxdz_look",
|
|
|
+ pvCurPageParams: null,
|
|
|
+ locusBehaviorName: "查看页面",
|
|
|
+ houseId: "",
|
|
|
+ pvId: 'p_2cmina_23080404',
|
|
|
+ navbar: {
|
|
|
+ showCapsule: 1,
|
|
|
+ title: '查看户型',
|
|
|
+ titleColor: '#fff',
|
|
|
+ navPadding: 0,
|
|
|
+ navPaddingBg:'transparent',
|
|
|
+ navBarColor: 'transparent',
|
|
|
+ navBackColor: 'transparent',
|
|
|
+ haveCallback: true, // 如果是 true 会接手 navbarBackClk
|
|
|
+ fromShare: false,
|
|
|
+ fromProject: 0,
|
|
|
+ shareToken: "",
|
|
|
+ pageName: this.pvCurPageName,
|
|
|
+ },
|
|
|
+ canvas:null,
|
|
|
+ id:'',// 户型编号
|
|
|
+ spaceList:[], // 空间列表
|
|
|
+ gltfSpaces:[], // 场景中地板模型数组
|
|
|
+ spaceId:null,
|
|
|
+ wallIds:[], // 空间墙体id
|
|
|
+ wallList:[], // 墙体数据
|
|
|
+ gltfWalls:[], // 场景中墙体模型数组
|
|
|
+ loader:null,
|
|
|
+ scene:null,
|
|
|
+ // sky:null,
|
|
|
+ camera:null,
|
|
|
+ controls:null,
|
|
|
+ curHouseObj: null,
|
|
|
+ controlStarPosition : { x:0, y:0, z:0}, //控制器初始位置
|
|
|
+ cameraStarPosition : { x:0, y:20, z:0} ,//摄像头初始位置
|
|
|
+ // cameraLastPosition: null, //摄像头上一次移动到的位置
|
|
|
+ // controlLastPosition: null, //观察点上一次移动到的位置
|
|
|
+ canvasHeight:430, //canvas视图的高度-计算得出
|
|
|
+ chooseMesh:null,//标记鼠标拾取到的mesh
|
|
|
+ progress:1, //进度条
|
|
|
+ myLoadingStatus:false,
|
|
|
+ repeatFlag:false, //重复点击
|
|
|
+ instancedFloorMesh:null,
|
|
|
+ instancedMeshList: [],
|
|
|
+ lableItem:[],
|
|
|
+ showLables:false,
|
|
|
+ gltfSpaceRoofs:[], // 屋顶模型数组
|
|
|
+ floorList:[],
|
|
|
+ floorId:null,
|
|
|
+ curData:null, //上一个页面传来的数据
|
|
|
+ curSpaceObj:null, //当前应该定位到的空间
|
|
|
+ isIOS:false,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ userId() {
|
|
|
+ return this.$store.state.userId;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch:{
|
|
|
+
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ cancelAnimationFrame(requestId, this.canvas)
|
|
|
+ this.worker && this.worker.terminate()
|
|
|
+ setTimeout(() => {
|
|
|
+ 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()
|
|
|
+ }
|
|
|
+ }, 0)
|
|
|
+ this.gltfWalls = [];
|
|
|
+ this.gltfSpaces = [];
|
|
|
+ this.gltfSpaceRoofs = [];
|
|
|
+ this.instancedMeshList = [];
|
|
|
+ this.instancedSpaceMeshList = [];
|
|
|
+ this.lableItem = [];
|
|
|
+ this.gltfLayouts = [];
|
|
|
+ this.instancedFurList = [];
|
|
|
+ TWEEN && TWEEN.removeAll();//清除所有的tween;
|
|
|
+ console.warn("***destroyed-webgl_rxdz_look***")
|
|
|
+ },
|
|
|
+ async mounted(options) {
|
|
|
+ var that = this;
|
|
|
+
|
|
|
+ this.houseId = this.$route.query.houseId?this.$route.query.houseId:'';
|
|
|
+ this.spaceId = this.$route.query.spaceId?this.$route.query.spaceId:'';
|
|
|
+ this.id = this.$route.query.id?this.$route.query.id:'';
|
|
|
+ console.warn("***mounted-webgl_rxdz_look****",this.id,this.$route.query)
|
|
|
+ this.isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
|
|
|
+ if(this.id){
|
|
|
+ this.getIdData()
|
|
|
+ }else{
|
|
|
+ this.$store.state.loadingMsg = "没有数据~";
|
|
|
+ }
|
|
|
+ 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 container = this.$refs.webgl;
|
|
|
+ let canvas3d = this.canvas = this.$refs.glcanvas;
|
|
|
+
|
|
|
+ let controls = null;
|
|
|
+ let camera = null, renderer = null, mixer = null;
|
|
|
+
|
|
|
+ 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 = false;//是否进入漫游状态
|
|
|
+
|
|
|
+ let stats;
|
|
|
+ let tweenCameraAnma = false; //表示当前是否处在动画过程中
|
|
|
+
|
|
|
+
|
|
|
+ init();
|
|
|
+ this.$store.state.loadingMsg="加载中...1%";
|
|
|
+ this.progress = 1;
|
|
|
+ this.clearEvent = clearEvent;
|
|
|
+ this.tweenCameraAnmaChange = tweenCameraAnmaChange;
|
|
|
+ this.updateLables = updateLables;
|
|
|
+ this.moveMeshCenterHandle = moveMeshCenterHandle;
|
|
|
+ this.cameraInit = cameraInit;
|
|
|
+ this.resetControl = resetControl;
|
|
|
+ function init() {
|
|
|
+
|
|
|
+ scene.background = new THREE.Color("#FFFFFF");
|
|
|
+
|
|
|
+ // 创建相机位置
|
|
|
+ camera = new THREE.PerspectiveCamera( 80, screenWidth / screenHeight, 0.1, 10000 );
|
|
|
+ camera.up.set(0, 1, 0);//俯视状态,将相机的up向量设置为z轴负方向
|
|
|
+ scene.add(camera);
|
|
|
+ that.camera = camera;
|
|
|
+
|
|
|
+ // 环境光会均匀的照亮场景中的所有物体
|
|
|
+ const ambientLight = new THREE.AmbientLight(0xFFEFE0, 3);
|
|
|
+ scene.add(ambientLight);
|
|
|
+ //平行光
|
|
|
+ const light = new THREE.DirectionalLight(0xFFF8E5, 3);
|
|
|
+ light.position.set(-3, 9, 3); //default; light shining from top
|
|
|
+ light.castShadow = true; // default false
|
|
|
+ // 默认情况下光投影相机区域是一个长宽高为10x10x500的长方体区域,光源投射方向为通过坐标原点
|
|
|
+ light.shadow.camera.left = -100; // default
|
|
|
+ light.shadow.camera.right = 100; // default
|
|
|
+ light.shadow.camera.top = 100; // default
|
|
|
+ light.shadow.camera.bottom = -100; // default
|
|
|
+
|
|
|
+ light.shadow.mapSize.width = 1024; // default
|
|
|
+ light.shadow.mapSize.height = 1024; // default
|
|
|
+ // light.shadow.camera.near = 0.1; // default
|
|
|
+ // light.shadow.camera.far = 500; // default
|
|
|
+
|
|
|
+ // light.shadow.bias = -0.01;
|
|
|
+ // light.shadow.radius = 1;
|
|
|
+ // light.shadow.darkness = 1; // 设置阴影强度为0.5
|
|
|
+ scene.add(light);
|
|
|
+ //antialias 这个值得设置为false,不然IOS上截图会失效
|
|
|
+ renderer = that.renderer = new THREE.WebGLRenderer({
|
|
|
+ canvas:canvas3d,
|
|
|
+ alpha: 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, screenHeight );
|
|
|
+ container.appendChild( renderer.domElement );
|
|
|
+
|
|
|
+
|
|
|
+ // controls.target = new THREE.Vector3( that.controlStarPosition.x, that.controlStarPosition.y, that.controlStarPosition.z );;
|
|
|
+
|
|
|
+ controls = new OrbitControls(camera, renderer.domElement);
|
|
|
+ controls.screenSpacePanning = true;
|
|
|
+ controls.enableDamping = true;
|
|
|
+ controls.minDistance = 1;
|
|
|
+ controls.maxDistance = 400;
|
|
|
+ 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;//启用摄像机的缩放
|
|
|
+
|
|
|
+ // stats = new Stats();
|
|
|
+ // container.appendChild(stats.dom);
|
|
|
+ // stats.domElement.style.top = '100px';
|
|
|
+ // 监听
|
|
|
+ window.addEventListener( 'resize', onWindowResize );
|
|
|
+ // raycaster = new THREE.Raycaster();
|
|
|
+ renderer.domElement.addEventListener('touchstart', onPointerStart, false);
|
|
|
+ renderer.domElement.addEventListener('touchmove', onPointerMove, false);
|
|
|
+ renderer.domElement.addEventListener('touchend', onPointerUp, false);
|
|
|
+ render();//重启渲染
|
|
|
+ cameraInit();
|
|
|
+ controls.saveState();//保存当前控制器的状态
|
|
|
+ }
|
|
|
+ //初始化相机位置
|
|
|
+ function cameraInit(){
|
|
|
+ camera.position.set(that.cameraStarPosition.x, that.cameraStarPosition.y, that.cameraStarPosition.z);
|
|
|
+ camera.lookAt(that.controlStarPosition.x,that.controlStarPosition.y,that.controlStarPosition.z);
|
|
|
+ }
|
|
|
+ //初始状态
|
|
|
+ function resetControl(){
|
|
|
+ controls.reset();
|
|
|
+ }
|
|
|
+ function tweenCameraAnmaChange (value) {
|
|
|
+ tweenCameraAnma = value
|
|
|
+ }
|
|
|
+ //取消事件监听-避免二次进入时触发多次事件
|
|
|
+ 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){
|
|
|
+ console.log('开始触摸事件:',that.overChange)
|
|
|
+ if(that.overChange){//形变中,不能相应用户操作
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //持续触摸中
|
|
|
+ function onPointerMove( event ) {
|
|
|
+ if(that.overChange){//形变中,不能相应用户操作
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ that.showLables = false;
|
|
|
+ }
|
|
|
+ //触摸结束
|
|
|
+ function onPointerUp(event) {
|
|
|
+ if(that.overChange){//形变中,不能相应用户操作
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // enableRender();
|
|
|
+ if(event.touches.length==0){
|
|
|
+ that.showLables = true;
|
|
|
+ updateLables();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //把摄像机移动的选中模型的正上方,观察点也变更为模型中心点,同时选中模型
|
|
|
+ function moveMeshCenterHandle(mesh = null,noChangeColor = true){
|
|
|
+ if(mesh){//如果传入了模型,则取模型
|
|
|
+ let spaceId = mesh.spaceId;//空间id
|
|
|
+ if(chooseMesh && spaceId == chooseMesh.spaceId){
|
|
|
+ console.warn("**moveMeshCenterHandle-重复选中了***")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ chooseMesh = mesh;
|
|
|
+ }
|
|
|
+ if(!chooseMesh){
|
|
|
+ console.warn("**moveMeshCenterHandle-没有数据***")
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ that.showLables = false;//隐藏
|
|
|
+ controls.enable = false;//控制器不响应用户的操作
|
|
|
+
|
|
|
+ // let object = chooseMesh;//当前选中的空间模型
|
|
|
+ // let spaceObj = object.userData;//获取空间模型的相关数据
|
|
|
+
|
|
|
+ let spaceObj = chooseMesh;//获取空间模型的相关数据
|
|
|
+ let cameraNewPosition ={};
|
|
|
+ let targetNewPosition ={};
|
|
|
+ let oldUp = {};
|
|
|
+ let newUp = {};
|
|
|
+ if (isUserContorl === false) { // 非漫游状态
|
|
|
+ cameraNewPosition = {
|
|
|
+ x:spaceObj.centerX/100,
|
|
|
+ y:camera.position.y,
|
|
|
+ z:-spaceObj.centerY/100,
|
|
|
+ }
|
|
|
+ //新的观察点的位置-取模型的中心点坐标,加上高度,由于模型都是贴地的,所以高度设置为0
|
|
|
+ targetNewPosition = {
|
|
|
+ x:spaceObj.centerX/100,
|
|
|
+ y:0,
|
|
|
+ z:-spaceObj.centerY/100,
|
|
|
+ }
|
|
|
+ oldUp = camera.up;//俯视状态
|
|
|
+ newUp = camera.up;
|
|
|
+ // that.cameraLastPosition = cameraNewPosition;//记录下上一次摄像头位置
|
|
|
+ // that.controlLastPosition = targetNewPosition;//记录下上一次观察点位置
|
|
|
+ }
|
|
|
+ console.warn("**moveMeshCenter***",isUserContorl,spaceObj,JSON.stringify(camera.position),JSON.stringify(controls.target)
|
|
|
+ ,cameraNewPosition,targetNewPosition,JSON.stringify(camera.up))
|
|
|
+ tweenCamera(camera.position,controls.target,cameraNewPosition,targetNewPosition,oldUp,newUp,600);
|
|
|
+ setTimeout(()=>{
|
|
|
+ that.showLables = true;
|
|
|
+ updateLables();
|
|
|
+ controls.enable = true;//控制器响应用户的操作
|
|
|
+ },601);//动画结束后回复原始状态
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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;
|
|
|
+ }
|
|
|
+ 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();
|
|
|
+ // console.warn("****onUpdate**",object.x1,object.y1,object.z1,object.x2,object.y2,object.z2)
|
|
|
+ }).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(controls.target.x,controls.target.y,controls.target.z);
|
|
|
+ tweenCameraAnma = false;
|
|
|
+ that.repeatFlag = false;//放开限制,可以再次点击
|
|
|
+ })
|
|
|
+ // 开始动画
|
|
|
+ tween.start();
|
|
|
+ }
|
|
|
+ function onWindowResize() {
|
|
|
+ camera.aspect = screenWidth / screenHeight;
|
|
|
+ camera.updateProjectionMatrix();
|
|
|
+ renderer.setSize( screenWidth, screenHeight );
|
|
|
+ }
|
|
|
+ //计算漫游时当前选中空间的观察点和摄像机的放置点位
|
|
|
+ //distance 表示要沿着视角移动的距离
|
|
|
+ function updateLables(){
|
|
|
+ if(!that.showLables){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ that.lableItem.forEach(lable =>{
|
|
|
+ let item = that.gltfSpaces[lable.cubeIndex].instancedMeshIndexList[0];//获取地板模型的第一个geometry实例
|
|
|
+ let _index = item.instancedMeshIndex;//第一个geometry实例 在 全局InstancedMesh实例的位置
|
|
|
+ let instancedMesh = that.instancedSpaceMeshList[_index];//获取具体的网格实例
|
|
|
+ let stratMatrix = new THREE.Matrix4();//定义一个四维矩阵
|
|
|
+ instancedMesh.getMatrixAt(item.instancedAtIndex,stratMatrix);//获取当前几何体的四维矩阵到stratMatrix里面
|
|
|
+ let position = new THREE.Vector3();//当前几何体的位置参数
|
|
|
+ position.setFromMatrixPosition(stratMatrix);//从四维向量中提取位置信息
|
|
|
+ // console.warn("***updateLables***",item.instancedAtIndex,JSON.stringify(position));
|
|
|
+ position.project(camera);
|
|
|
+ const x = (position.x * .5 + .5) * screenWidth;
|
|
|
+ const y = (position.y * -.5 + .5) * screenHeight;
|
|
|
+ lable.transform = `translate(-50%, -50%) translate(${x}px,${y}px)`;
|
|
|
+ })
|
|
|
+ }
|
|
|
+ function render() {
|
|
|
+ TWEEN && TWEEN.update();
|
|
|
+ // stats.update();
|
|
|
+ //不处在动画过程中,则可以处理移动等动作
|
|
|
+ if(tweenCameraAnma==false){
|
|
|
+ controls.update();
|
|
|
+ }
|
|
|
+ renderer.render(scene, camera);//单次渲染
|
|
|
+ requestId = requestAnimationFrame(render, canvas3d);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ clearHandle(){
|
|
|
+ this.clearEvent();
|
|
|
+ },
|
|
|
+ //楼层切换
|
|
|
+ floorChange(item){
|
|
|
+ if(this.floorId==item.layoutId){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ this.floorId = item.layoutId;
|
|
|
+
|
|
|
+ this.curHouseObj = this.curData.layoutStruct.find(it=>it.layoutId==item.layoutId);//更新当前具体的户型数据
|
|
|
+ // 遍历场景中的所有子对象,找到类型为Mesh的对象并移除
|
|
|
+ let deleList = this.scene.children.filter(object=>{
|
|
|
+ if(object.userType=="mesh" || object.userType=="layoutMesh"){
|
|
|
+ return object
|
|
|
+ }
|
|
|
+ })
|
|
|
+ // console.warn("***deleList***",deleList)
|
|
|
+ if(deleList && deleList.length>0){
|
|
|
+ this.showLables = false;//隐藏lable
|
|
|
+ this.scene.remove(...deleList);
|
|
|
+ }
|
|
|
+ this.gltfWalls = [];
|
|
|
+ this.gltfSpaces = [];
|
|
|
+ this.instancedMeshList = [];
|
|
|
+ this.instancedSpaceMeshList = [];
|
|
|
+ this.lableItem = [];
|
|
|
+ this.gltfLayouts = [];
|
|
|
+ this.instancedFurList = [];
|
|
|
+ this.wallList = [];
|
|
|
+ //恢复初始视角
|
|
|
+ this.cameraInit();
|
|
|
+ this.resetControl();
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.loadSpace();
|
|
|
+ }, 100);
|
|
|
+ // this.$emit("curHouseFloorChange", item);//通知页面,户型楼层发生了变更
|
|
|
+ },
|
|
|
+ async getIdData(){
|
|
|
+ let userId = this.userId || '';
|
|
|
+ let params = {
|
|
|
+ id: this.id,
|
|
|
+ brandId: $config.brandId,
|
|
|
+ houseId:this.houseId,
|
|
|
+ userId,
|
|
|
+ };
|
|
|
+ const res = await requestConfig('getCustomizedRecord', params);
|
|
|
+ if (res.success ) {
|
|
|
+ let single = res.list[0];
|
|
|
+ this.layoutStruct = JSON.parse(JSON.stringify(single));
|
|
|
+ this.setHouseDetail(this.layoutStruct)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 设置户型详情信息
|
|
|
+ * @param {Object} data 户型详情
|
|
|
+ */
|
|
|
+ setHouseDetail(data){
|
|
|
+ if(data && data.layoutStruct){
|
|
|
+ let curData = data;
|
|
|
+ this.curHouseObj = curData.layoutStruct.find(it=>it.floor==curData.curFloor);;
|
|
|
+ // this.spaceId = this.curHouseObj.spaceId;
|
|
|
+ console.warn("***curHouseObj***",this.curHouseObj)
|
|
|
+ this.floorList = [];
|
|
|
+ curData.layoutStruct && curData.layoutStruct.forEach(item=>{
|
|
|
+ this.floorList.push({
|
|
|
+ houseFloor:item.floor,
|
|
|
+ layoutId:item.layoutId,
|
|
|
+ });
|
|
|
+ })
|
|
|
+ let select = this.floorList.find(it=>it.houseFloor==this.curHouseObj.floor);
|
|
|
+ this.floorId = select ? select.layoutId : this.floorList[0].layoutId;
|
|
|
+ this.curData = curData;
|
|
|
+ console.warn("***floorList-init***",this.floorList,select)
|
|
|
+ // 加载户型
|
|
|
+ this.loadSpace();
|
|
|
+ }else{
|
|
|
+ this.curHouseObj = {}
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 添加文字标签
|
|
|
+ addWordLabel(){
|
|
|
+ if(!this.gltfSpaces || this.gltfSpaces.length <= 0){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 方案二
|
|
|
+ this.lableItem = [];
|
|
|
+ this.gltfSpaces.forEach((cube,index) =>{
|
|
|
+ // 给地板加上空间类型标注, 空间为链接空间的不显示
|
|
|
+ if(cube.spaceName && !cube.isSizeLock){
|
|
|
+ let name = spaceTypes[cube.spaceType - 1];
|
|
|
+ if(cube.spaceType==15){ //更改空间显示名称 X空间 类型 根据布局所属类型来显示
|
|
|
+ let layoutId = this.spaceList.find(it => it.spaceId == cube.spaceId).layoutId;
|
|
|
+ let layout = this.arrFrunList.find(it=>it.id == layoutId);
|
|
|
+ if(layout){
|
|
|
+ name = spaceTypes[layout.type - 1];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.lableItem.push(
|
|
|
+ {
|
|
|
+ text:name,
|
|
|
+ spaceId:cube.spaceId,
|
|
|
+ transform:'',
|
|
|
+ cubeIndex:index,
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.showLables = true;
|
|
|
+ this.updateLables();//更新lable
|
|
|
+ },
|
|
|
+ //obj 物体对象,type 是否改变颜色
|
|
|
+ moveMeshCenter(obj,type){
|
|
|
+ console.warn("**moveMeshCenter***",obj)
|
|
|
+ if(obj && this.gltfSpaces && this.gltfSpaces.length>0){
|
|
|
+ this.moveMeshCenterHandle(obj,type);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 绘制空间-即地板
|
|
|
+ async loadSpace(){
|
|
|
+ this.spaceList = [];
|
|
|
+ this.wallIds = [];
|
|
|
+ if(!this.curHouseObj){//减少重复请求
|
|
|
+ console.warn("***数据错误***")
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if(this.curHouseObj){
|
|
|
+ const spaceDetail = this.curHouseObj;
|
|
|
+ const spaceList = spaceDetail.houseJson;
|
|
|
+ // 交换centerX, centerY;上一页面已经处理过了,这里不在需要处理
|
|
|
+ for (let index = 0; index < spaceList.length; index++) {
|
|
|
+ var element = spaceList[index];
|
|
|
+ // const centerX = JSON.parse(JSON.stringify(element.centerX))
|
|
|
+ // element.centerX = element.centerY;
|
|
|
+ // element.centerY = centerX;
|
|
|
+ // 计算观察点向量(相对中心点)
|
|
|
+ let _actorLoaction = element.actorLocation.split(',');//x y z
|
|
|
+ let _x = parseInt(_actorLoaction[1]) || element.centerX;//观察点 X轴坐标
|
|
|
+ let _z = (parseInt(_actorLoaction[0])) || element.centerY;//观察点 Z轴坐标
|
|
|
+ let _presentX = (_x - element.centerX)/((element.spaceWidth/2) - 5);//5是墙壁厚度的一半-单位cm
|
|
|
+ let _presentY = (_z - element.centerY)/((element.spaceHeight/2) - 5);
|
|
|
+ element.presentX = _presentX;//观察点跟空间中心原点的距离比例
|
|
|
+ element.presentY = _presentY;
|
|
|
+ element.wallMoveValue = "[0,0,0,0]"
|
|
|
+ this.spaceList.push(element);
|
|
|
+ this.wallIds.push(element.wallId);
|
|
|
+ if(element.wallList){
|
|
|
+ this.wallList.push(JSON.parse(element.wallList));
|
|
|
+ }
|
|
|
+ if(element.isSelected){ // 默认选中空间
|
|
|
+ this.curSpaceObj = element;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(!this.curSpaceObj && this.spaceList.length > 0){
|
|
|
+ this.curSpaceObj = this.spaceList[0];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ console.log("该户型空间数据:", this.spaceList);
|
|
|
+ console.log("当前选中的空间:", this.curSpaceObj);
|
|
|
+ this.loaderSpaceArr(this.spaceList);
|
|
|
+ // 获取墙体数据并且绘制墙体
|
|
|
+ this.getHouseTypeSpaceWalls();
|
|
|
+ },
|
|
|
+ // 获取墙体数据
|
|
|
+ async getHouseTypeSpaceWalls(){
|
|
|
+ // let data = {id:this.wallIds}
|
|
|
+ // const res = await requestConfig('getHouseTypeSpaceWalls', data, true);
|
|
|
+ // console.log("墙体数据:", res.list)
|
|
|
+ // let wallList = [];
|
|
|
+ // if(res.success){
|
|
|
+ // wallList = this.wallList = res.list;
|
|
|
+ // }
|
|
|
+ let wallList = [];
|
|
|
+ if(this.wallList && this.wallList.length>0){
|
|
|
+ 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})
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.loadSpaceObjWalls(wallArr, wallList);
|
|
|
+ this.getOverallArrangementDetailsList(2);
|
|
|
+ },
|
|
|
+ // 加载单个空间墙体资源
|
|
|
+ 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.$nextTick(()=>{
|
|
|
+ this.moveMeshCenter(this.curSpaceObj);
|
|
|
+ this.progress = 100;
|
|
|
+ // this.$refs.myLoading.showLoading("加载中..." + this.progress + '%')
|
|
|
+ this.$store.state.loadingMsg="加载中..." + this.progress + '%';
|
|
|
+ this.$nextTick(()=>{
|
|
|
+ this.myLoadingStatus = false;
|
|
|
+ // this.$refs.myLoading.hideLoading();
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.addWordLabel(); // 添加文字标签
|
|
|
+ }, 610);
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+ @import "./webgl_rxdz_look.scss";
|
|
|
+</style>
|