123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- // var app = getApp(); //获取应用实例
- // const util = require('@/static/utils/util.js');
- // const config = require('@/services/urlConfig.js');
- // import requestConfig from '@/services/requestConfig.js';
- import * as THREE from 'three';
- import TWEEN from 'three/addons/libs/tween.module.js';
- import spaceTypes from '@/static/spaceTypesIE.js';
- let glbWidth = 300;//空间地板模型的真实尺寸
- let glbHeight = 300;
- export default {
- data() {
- return {
- gltfSpaceUrl: "https://dm.static.elab-plus.com/miniProgram/model/BP_AutoWall_WoodFloor1.glb", //模型地址
- // gltfSpaceUrl: "https://dm.static.elab-plus.com/3d/model/20230607/diban/diban.gltf", //模型地址
- // gltfSpaceUrl: "https://dm.static.elab-plus.com/miniProgram/model/BP_L_carpet01-1.gltf", //模型地址
- // gltfSpace1Url: "https://dm.static.elab-plus.com/miniProgram/model/BP_G_tiles01_1.gltf", //模型地址
- gltfSpace1Url: "https://dm.static.elab-plus.com/miniProgram/model/BP_G_tiles01.glb", //模型地址
- spaceTypes:spaceTypes,
- }
- },
- watch: {},
- methods: {
- // 加载地板模型
- loaderSpaceArr(list){
- if(!list || list.length==0){
- return false;
- }
- this.instancedSpaceMeshList = [];
- this.gltfSpaces = [];
- let comlist = list.filter(it=>it.spaceType!=14);//过滤花园的空间
- this.loaderCommonSpace(this.gltfSpaceUrl,comlist,1);
- let arrlist = list.filter(it=>it.spaceType==14);//花园的空间
- // this.loaderCommonSpace(this.gltfSpace1Url,arrlist,2);
- if(arrlist && arrlist.length>0){
- this.loaderGraseSpace(list);//加载草地的模型-所有地块都添加,填补房间里面的
- }
- },
- loaderCommonSpace(gltfSpaceUrl,list,type=1){
- var that = this;
- this.loader.load(gltfSpaceUrl, ( gltf ) => {
- console.log("地板模型加载成功")
- // gltf.scene.receiveShadow = true;//材质是否接收阴影
- gltf.scene.traverse((child)=> {
- if (child.isMesh && child.visible) {
- let instancedMesh = new THREE.InstancedMesh(child.geometry.clone(), child.material.clone(), list.length);
- this.instancedSpaceMeshList.push(instancedMesh);
- //设置每一块地板的实例值
- list.forEach((obj,i)=>{
- let positionX = obj.centerX / 100;
- let positionY = obj.centerY / 100;
- if(type==1){
- // glbWidth = glbHeight = 1500;
- }
- let scaleX = obj.spaceWidth / glbWidth;
- let scaleY = obj.spaceHeight / glbHeight;
-
- gltf.scene.position.set(positionX, 0, -positionY);
- gltf.scene.scale.set(scaleX, 1, scaleY);
- gltf.scene.updateMatrixWorld();//更新世界坐标-这样,子模型也同步更新了
-
- instancedMesh.setMatrixAt(i, child.matrixWorld);
- instancedMesh.instanceMatrix.needsUpdate = true;
- instancedMesh.setColorAt(i, child.material.color);
- instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额
- let gltfSpace = that.gltfSpaces.find(gltfSpace=>gltfSpace.spaceId == obj.spaceId);//判断是否已经添加过
- if(!gltfSpace){
- let position = new THREE.Vector3();//当前几何体的位置参数
- let scale = new THREE.Vector3();//当前几何体的缩放参数
- position.set(positionX, 0, -positionY);
- scale.set(scaleX, 1, scaleY);
- let md = {
- spaceId:obj.spaceId,//模型实例的唯一标识
- instancedMeshIndexList:[//标识网格实例数组的序号 以及 当前几何体 在网格实例的序号
- {instancedMeshIndex: this.instancedSpaceMeshList.length - 1, instancedAtIndex : i,
- color:instancedMesh.material.color.clone(),},
- ],
- spaceName:obj.spaceName,//几何体的id
- spaceType:obj.spaceType,
- position:position,
- scale:scale,
- isSizeLock:obj.isSizeLock,
- };
- that.gltfSpaces.push(md);
- }else{//添加另外一组实例
- gltfSpace.instancedMeshIndexList.push({
- instancedMeshIndex:this.instancedSpaceMeshList.length - 1, instancedAtIndex:i,
- color:instancedMesh.material.color.clone(),
- })
- }
- })
- instancedMesh.userType = "mesh";
- if(type==2){//花园
- instancedMesh.name = "花园";
- }else{//室内
- instancedMesh.name = "地板";
- }
- instancedMesh.receiveShadow = true;//材质是否接收阴影
- that.scene.add(instancedMesh);
- }
- });
- // this.pvCurPageName=="room_show"
- if(true){
- //给地板模型添加天花板
- list && list.forEach(obj=>{
- if(obj.spaceType!=14){//花园不加上面的墙
- let positionX = obj.centerX / 100;
- let positionY = obj.centerY / 100;
- // 天花板
- const planeGeometry = new THREE.PlaneGeometry(obj.spaceWidth / 100,obj.spaceHeight / 100);
- const planeMaterial = new THREE.MeshStandardMaterial({
- color:0xffffff,
- metalness: 0.4, // 设置金属度为1.0
- roughness: 1 // 设置粗糙度为0.5
- });
- const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial)
- planeMesh.rotation.x = Math.PI / 2 ; // 旋转 180 度
- planeMesh.position.set(positionX, 2.8, -positionY);
- planeMesh.userType = "mesh"
- const spaceObj = {
- spaceId:obj.spaceId,
- spaceWidth:obj.spaceWidth,
- spaceHeight:obj.spaceHeight
- }
- planeMesh.userData = spaceObj;
- that.scene.add(planeMesh);
- that.gltfSpaceRoofs.push(planeMesh);
- }
- })
- }
- });
- },
- //草地加载
- loaderGraseSpace(list){
- let glbWidth = 300;
- let glbHeight = 300;
- var that = this;
- console.log("草地模型加载成功")
- //将模型添加到场景中
- let texture = new THREE.TextureLoader().load("https://dm.static.elab-plus.com/miniProgram/grass.jpg");
- // let texture = new THREE.TextureLoader().load( "https://dm.static.elab-plus.com/miniProgram/Avatar_male.png" );
- texture.wrapS = THREE.RepeatWrapping;
- texture.wrapT = THREE.RepeatWrapping;
-
- list && list.forEach(obj=>{
- // 暂时手动过滤 2楼 儿童房和次卫 不添加草地
- if((obj.spaceId == 582 && obj.spaceName == "儿童房") || (obj.spaceId == 388 && obj.spaceName == "次卫")){
- return
- }
- let positionX = obj.centerX / 100;
- let positionY = obj.centerY / 100;
- let scaleX = obj.spaceWidth / 100;
- let scaleY = obj.spaceHeight / 100;
-
- texture = texture.clone();
- //使用纹理贴图材质
- texture.repeat.set(scaleX, scaleY);
-
- // let geometry = new THREE.PlaneGeometry(obj.spaceWidth/100, obj.spaceHeight/100);
- // let material = new THREE.MeshBasicMaterial({ map: texture });
- // let cube = new THREE.Mesh(geometry, material);
- let geometry = new THREE.BoxGeometry(obj.spaceWidth/100, 0.1, obj.spaceHeight/100);
- let colorMaterial = new THREE.MeshBasicMaterial({color: 0x626F44}); // 创建纯色材质对象
- let material = new THREE.MeshBasicMaterial({ map: texture });
- let cube = new THREE.Mesh(geometry, [colorMaterial, colorMaterial, material, colorMaterial, colorMaterial, colorMaterial]); // 使用 BoxGeometry 和纯色材质创建 Mesh 对象
-
- cube.name = "地板";
- cube.userType = "mesh";
- cube.userData = obj;//位置数据
- // 设置位置,旋转,缩放
- cube.position.set(positionX, -0.11, -positionY);
- // cube.rotation.x = -Math.PI / 2 ; // 旋转 180 度 PlaneGeometry 生效
- // cube.receiveShadow = true;//材质是否接收阴影
-
- //注释掉,不让草地进入空间列表中,不触发空间变化的动画过程,规避掉动画过程中的问题
- // let md = {
- // spaceId:obj.spaceId,//模型实例的唯一标识
- // spaceName:obj.spaceName,//几何体的id
- // spaceType:obj.spaceType,
- // position:cube.position,
- // scale:cube.scale,
- // isSizeLock:obj.isSizeLock,
- // };
- // that.gltfSpaces.push(md);
- that.scene.add(cube);
- })
- },
- //修改指定空间的颜色
- changeSpaceColor(spaceId,type=1){
- // 寻找地板
- const cube = this.gltfSpaces.find((item)=>{
- return item.spaceId == spaceId;
- })
- if(cube.instancedMeshIndexList){
- if(type==1){
- cube.instancedMeshIndexList.forEach(instanced=>{
- let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局InstancedMesh实例的位置
- let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例
- instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额
- let color = new THREE.Color(0xFF9F40); // 使用sRGB颜色值
- // color.convertSRGBToLinear(); // 将颜色值转换为线性颜色值
- instancedMesh.setColorAt(instanced.instancedAtIndex, color);//修改这个几何体的颜色
- })
- }else{
- cube.instancedMeshIndexList.forEach(instanced=>{
- let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局Instance
- let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例
- instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额
- instancedMesh.setColorAt(instanced.instancedAtIndex, instanced.color);//修改这个几何体的颜色
- });
- }
-
- }
-
- },
- //修改当前空间的面积大小-动画方案2
- changeSpacesAnim(curSpace){
- // 寻找地板
- const cube = this.gltfSpaces.find((item)=>{
- return item.spaceId == curSpace.spaceId;
- })
- console.log("空间移动目标",cube.spaceId, JSON.stringify(cube.position),JSON.stringify(cube.scale),
- curSpace.toPx, curSpace.toPz,curSpace.toScaleX, curSpace.toScaleZ);
- //初始形变值
- let x = cube.position.x;
- let z = cube.position.z;
- let scaleX = cube.scale.x;
- let scaleZ = cube.scale.z;
- //最终形变值
- let toPx = curSpace.toPx;
- let toPz = curSpace.toPz;
- let toScaleX = curSpace.toScaleX;
- let toScaleZ = curSpace.toScaleZ;
- if(cube.instancedMeshIndexList){
- let spaceInitMatrix = [];//空间动画时的初始变换矩阵
- cube.instancedMeshIndexList.forEach(instanced=>{
- let _index = instanced.instancedMeshIndex;//geometry实例 在 全局InstancedMesh实例的位置
- let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例
- let startMatrix = new THREE.Matrix4();//定义一个四维矩阵
- instancedMesh.getMatrixAt(instanced.instancedAtIndex,startMatrix);//获取当前几何体的四维矩阵到stratMatrix里面
- spaceInitMatrix.push({
- index:_index,
- matrix:startMatrix.clone(),
- color:instancedMesh.material.color.clone(),
- })
- });
- // console.warn("***cube***",cube.spaceId,Date.now(),JSON.stringify(spaceInitMatrix[0].matrix))
- var tween = new TWEEN.Tween({
- x: cube.position.x,
- z: cube.position.z,
- sx:cube.scale.x,
- sz:cube.scale.z
- })
- .to({
- x: curSpace.toPx,
- z: curSpace.toPz,
- sx:curSpace.toScaleX,
- sz:curSpace.toScaleZ
- }, 2000)
- .easing(TWEEN.Easing.Quadratic.InOut)
- .onUpdate((object)=> {
- //获取地板模型的geometry实例
- cube.instancedMeshIndexList.forEach(instanced=>{
- let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局InstancedMesh实例的位置
- let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例
- //获取对象实例的初始变换矩阵
- let tmp = spaceInitMatrix.find(it=>it.index==_index);
- let stratMatrix = tmp.matrix.clone(); //获取初始变换矩阵
- let scaleMatrix = new THREE.Matrix4(); //定义一个缩放变化矩阵
- let panMatrix = new THREE.Matrix4(); //定义一个平移变化矩阵
-
- scaleMatrix.makeScale(object.sx / scaleX,1,object.sz / scaleZ); //获得缩放变化矩阵
- panMatrix.makeTranslation(object.x - x,0,object.z - z); //获得平移变化矩阵
- stratMatrix.multiply(scaleMatrix).premultiply(panMatrix);//通过矩阵计算获得最终的形变矩阵
- instancedMesh.instanceMatrix.needsUpdate = true;//更新之前,必须开启开关
- instancedMesh.setMatrixAt(instanced.instancedAtIndex,stratMatrix);//更新几何体的世界矩阵
- if(this.curSpaceObj.spaceId==cube.spaceId){//当前选中的空间才变化颜色
- instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额
- let color = new THREE.Color(0xFF9F40); // 使用sRGB颜色值
- // color.convertSRGBToLinear(); // 将颜色值转换为线性颜色值
- instancedMesh.setColorAt(instanced.instancedAtIndex, color);//修改这个几何体的颜色
- }
- });
- }).onComplete(()=>{//这个回调很可能会很慢
- this.tweenCameraAnmaChange(false);
- console.warn("***changeSpacesAnim-over***")
- if(this.curSpaceObj.spaceId==cube.spaceId){//当前选中的空间才恢复颜色
- cube.instancedMeshIndexList.forEach(instanced=>{
- let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局Instance
- let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例
- let tmp = spaceInitMatrix.find(it=>it.index==_index);
- instancedMesh.instanceColor.needsUpdate = true;//打开颜色修改开关,不开,颜色是不能修改额
- instancedMesh.setColorAt(instanced.instancedAtIndex, tmp.color);//修改这个几何体的颜色
- });
- }
- });
- // 开始动画
- tween.start();
- this.tweenCameraAnmaChange(true)
- cube.position.x = curSpace.toPx;
- cube.position.z = curSpace.toPz;
- cube.scale.x = curSpace.toScaleX;
- cube.scale.z = curSpace.toScaleZ;
- }else{//有点问题规避下
- // 空间动画
- var tween = new TWEEN.Tween({
- x: scaleX,
- z: scaleZ,
- px:x,
- pz:z,
- })
- .to({
- x: toScaleX,
- z: toScaleZ,
- px:toPx,
- pz:toPz,
- }, 2000)
- .easing(TWEEN.Easing.Quadratic.InOut)
- .onUpdate((object)=> {
- cube.scale.x = object.x;
- cube.scale.z = object.z;
- cube.position.x = object.px;
- cube.position.z = object.pz;
- });
- // 开始动画
- tween.start();
- }
-
- // 屋顶尺寸调整
- const cubeRoof = this.gltfSpaceRoofs.find((item)=>{
- return item.userData.spaceId == curSpace.spaceId;
- })
- if(cubeRoof){
- let roofScaleX = curSpace.spaceObj.spaceWidth / cubeRoof.userData.spaceWidth
- let roofScaleY = curSpace.spaceObj.spaceHeight / cubeRoof.userData.spaceHeight
- // console.log("屋顶尺寸变化", curSpace.spaceObj, cubeRoof, roofScaleX, roofScaleY)
- cubeRoof.scale.set(roofScaleX,roofScaleY,1);//缩小为原来0.5倍
- cubeRoof.position.x = toPx;
- cubeRoof.position.z = toPz;
- }
- },
- //所有空间整体缩放-同时同步到数据里面
- allSpaceScale(){
- const centerOffset = new THREE.Vector3(0, 0, 0); // 假设中心点在几何体的正中心
- const scale = new THREE.Vector3(0.9, 1, 0.9); // 缩放尺度
- //实例化的默认中心是就原点也就是0 0 0 这个点,所以centerOffset也必须是原点
- // this.instancedMeshList.forEach((mesh)=>{
- // mesh.scale.copy(scale);
- // mesh.updateMatrix();
- // mesh.updateMatrixWorld();
- // mesh.updateMorphTargets();
- // mesh.geometry.computeVertexNormals();
- // })
- // this.instancedSpaceMeshList.forEach((mesh)=>{
- // mesh.scale.copy(scale);
- // mesh.updateMatrix();
- // mesh.updateMatrixWorld();
- // mesh.updateMorphTargets();
- // mesh.geometry.computeVertexNormals();
- // })
- // this.gltfLayouts.forEach((mesh)=>{
- // // mesh.scale.copy(scale);
- // })
-
- this.gltfSpaces.forEach(cube=>{
- let dis = centerOffset.clone().sub(cube.position);//获得差值向量
- // console.warn("***dis***",JSON.stringify(dis),JSON.stringify(cube.position),cube.spaceId);
- let x = dis.x * (1 - scale.x);//x轴需要移动的距离
- let y = dis.y * (1 - scale.y);//y轴需要移动的距离
- let z = dis.z * (1 - scale.z);//z轴需要移动的距离
-
- let pi = new THREE.Vector3();//新的中心点位置
- pi.x = cube.position.x + x;
- pi.y = cube.position.y + y;
- pi.z = cube.position.z + z;
- cube.scale.x = cube.scale.x * scale.x;//修改真实的比例
- cube.scale.z = cube.scale.z * scale.z;//
- cube.position.copy(pi);
- //同步信息到空间列表中
- let sapce = this.spaceList.find(it=>{ return it.spaceId==cube.spaceId});
- if(sapce){
- //更新空间中心点值
- sapce.centerX = pi.x * 100;
- sapce.centerY = -1* pi.z * 100;
- //更新空间宽度高度值
- sapce.spaceWidth = cube.scale.x * glbWidth;
- sapce.spaceHeight = cube.scale.z * glbHeight;
- }
- // let dir = new THREE.Vector3( 0, 10, 0 );;//当前几何体的位置参数
- // console.warn("***dis1***",JSON.stringify(pi),JSON.stringify(dir));
- // let length = 3;
- // let hex = 0xff0000;
- // let arrowHelper = new THREE.ArrowHelper( dir, pi, length, hex );
- // this.scene.add( arrowHelper );
-
- //这是矩阵运算处理缩放的方法-此为数学上的方案
- cube.instancedMeshIndexList.forEach(instanced=>{
- let _index = instanced.instancedMeshIndex;//第一个geometry实例 在 全局InstancedMesh实例的位置
- let instancedMesh = this.instancedSpaceMeshList[_index];//获取具体的网格实例
- let stratMatrix = new THREE.Matrix4();//定义一个四维矩阵
- instancedMesh.getMatrixAt(instanced.instancedAtIndex,stratMatrix);//获取当前几何体的四维矩阵到stratMatrix里面
- let scaleMatrix = new THREE.Matrix4().makeScale(scale.x, scale.y, scale.z);
- let inverseTranslationMatrix = new THREE.Matrix4().makeTranslation(x, y, z);
- stratMatrix.premultiply(inverseTranslationMatrix);
- stratMatrix.multiply(scaleMatrix);
- instancedMesh.instanceMatrix.needsUpdate = true;
- instancedMesh.setMatrixAt(instanced.instancedAtIndex,stratMatrix);//更新几何体的世界矩阵
- });
- })
- this.$nextTick(()=>{
- this.updateAllWallHandle();
- })
- setTimeout(() =>{
- this.updataPageData();//更新数据到各个对象里面
- this.calculateLayoutModelSize();//重新计算家具位置
- this.updateLables();//更新lable
- this.$nextTick(()=>{
- this.updateCareFul();//更新精细调整里面的空间
- this.updateSpanceData();//更新语音组件里面的空间
- })
- }, 100);
- }
- }
- }
|