Parcourir la source

Merge branch 'feature_AI优化' of elab-damai-h5/h5-webgl-program into develop

wangs il y a 1 an
Parent
commit
2284449fe5

+ 2 - 0
package.json

@@ -24,6 +24,7 @@
     "echarts": "^4.0.0",
     "element-ui": "2.15.8",
     "jquery": "^3.6.0",
+    "mint-ui": "^2.2.13",
     "qiniu-js": "^2.4.0",
     "three": "^0.154.0",
     "vue": "^2.6.14",
@@ -43,6 +44,7 @@
     "eslint": "^7.32.0",
     "eslint-plugin-vue": "^8.0.3",
     "node-sass": "^4.14.1",
+    "px2rem-loader": "^0.1.9",
     "sass-loader": "^7.3.1",
     "vue-template-compiler": "^2.6.14"
   },

+ 1 - 1
public/index.html

@@ -3,7 +3,7 @@
   <head>
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0">
 	<meta http-equiv="Access-Control-Allow-Origin" content="*">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
     <title><%= htmlWebpackPlugin.options.title %></title>

+ 21 - 5
src/components/newBottomCom/viewMask/viewMask.html

@@ -4,26 +4,27 @@
 	<el-carousel v-if="aiImagesList && aiImagesList.length>0" v-show="showAIImage" class="swiper" 
 	:autoplay="false" :loop="false" ref="carousel"
 	 @change="swiperChangeImg" :initial-index="currentIndex" :indicator-dots="false">
-		<el-carousel-item v-for="(item,index1) in aiImagesList" :key="index1">
+		<el-carousel-item v-for="(item,index1) in aiImagesList" :key="index1" >
 			<!-- <img @touchstart="mytouchstart" @touchmove="mytouchmove" @touchend="mytouchend" style="width:100%;height:100%;object-fit: cover;" mode="aspectFill" :src="item.image"></image> -->
 			<el-image 
 				@touchstart="mytouchstart" @touchmove="mytouchmove" @touchend="mytouchend"
+				@click="previewAction"
 			    style="width:100%;height:100%;cursor:none;"
 			    :src="item.image"
 				fit='cover'
-			    :preview-src-list="item.list">
+			    >
 			  </el-image>
 		</el-carousel-item>
 	</el-carousel>
 	<div class="indicator-view rows" v-if="aiImagesList && aiImagesList.length>1 && showAIImage">
 		<div class="indicator-item" :class="{'active': currentIndex == idx}" v-for="(item, idx) in aiImagesList" :key="idx"></div>
 	</div>
-	<div class="loading_more" v-if="aiFlag && aiImagesList.length>0 && showAIImage">
+	<!-- <div class="loading_more" v-if="aiFlag && aiImagesList.length>0 && showAIImage">
 		<img class="loading_img"
 			src="https://dm.static2.elab-plus.com/aiBeauty/aiBeauty3/icon_loading_Img.png"
 			mode="aspectFit"></image>
 			自动生成更多图片中{{random+'%'}}...
-	</div>
+	</div> -->
 	<div class="btn-view columns" v-if="showAIImage==false">
 		<!-- 切换视图-退出当前模式 -->
 		<div class="compareBtn btn1" @click.stop="showOrHideWebGl" v-if="aiImagesList && aiImagesList.length>0">
@@ -118,7 +119,22 @@
 		<span>当前AI使用火爆,请继续尝试</span>
 		<span slot="footer" class="dialog-footer">
 			<el-button @click.stop="cancelHandle();">取消等待</el-button>
-			<el-button type="primary" @click.stop="confirmHandle();">继续尝试</el-button>
+			<el-button type="primary" @click.stop="confirmHandle(1);">继续尝试</el-button>
+		</span>
+	</el-dialog>
+	<el-dialog
+		title="提醒"
+		:visible.sync="dialogAIVisible"
+		width="80%"
+		top="35vh"
+		:modal="false"
+		style="pointer-events: auto;"
+		:before-close="cancelHandle"
+		>
+		<span>AI开了小差,是否重新生成</span>
+		<span slot="footer" class="dialog-footer">
+			<el-button @click.stop="cancelHandle();">放弃生成</el-button>
+			<el-button type="primary" @click.stop="confirmHandle(0);">继续生成</el-button>
 		</span>
 	</el-dialog>
 </div>

+ 2 - 2
src/components/newBottomCom/viewMask/viewMask.scss

@@ -16,7 +16,7 @@
 .swiper{
 	position: relative;
 	width: 100%;
-	height:calc(100vh - 408px);
+	height:calc(100vh - 600px + 40px);
 	z-index: 12;
 	pointer-events: auto;
 	/deep/.el-image__preview{
@@ -24,7 +24,7 @@
 	}
 }
 /deep/.el-carousel__container{
-	height:calc(100vh - 408px);
+	height:calc(100vh - 600px + 40px);
 }
 .btn-view{
 	position: absolute;

+ 216 - 100
src/components/newBottomCom/viewMask/viewMask.vue

@@ -3,6 +3,7 @@
 </template>
 <script>
 	const util = require('@/utils/util.js').default;
+	import { MessageBox } from 'mint-ui';
 	// const config = require('@/services/url$config.js');
 	import touchHandle from '@/mixins/touchHandle.js';
 	// import requestConfig from '@/static/lib/requestConfig';
@@ -21,8 +22,9 @@
 				aiFlag:false,
 				aiImage: "",
 				inputBase64Url: "",
-				taskId: "", // 图生图任务ID
-				img2imgTimer: null,
+				aiPicId: "", // 图生图任务ID
+				randomTimer:null,
+				timer: null,
 				outTimer: null,
 				imageWidth: 750,
 				imageHeight: 448,
@@ -211,27 +213,23 @@
 						level:'5',
 						aiPicId:'',
 						resultImg:'',
-					},{
-						model:'lucataco/sdxl-controlnet',
-						level:'3',
-						aiPicId:'',
-						resultImg:'',
 					}
 				],
 				reqListReset:[
 					{
 						model:'deployments/elabgroup/elab-sdxl-controlnet-lora',
-						level:'5',
+						level:'3',
 						aiPicId:'',
 						resultImg:'',
 					},{
 						model:'batouresearch/sdxl-controlnet-lora',
-						level:'3',
+						level:'5',
 						aiPicId:'',
 						resultImg:'',
 					}
 				],
 				dialogVisible: false,
+				dialogAIVisible: false,
 			}
 		},
 		props:{
@@ -258,6 +256,19 @@
 			// if(this.seedItem){
 			// 	this.title = this.seedItem.seedText;
 			// }
+			wx.checkJsApi({
+				jsApiList: ['previewImage'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
+				success: function(res) {
+					// 以键值对的形式返回,可用的api值true,不可用为false
+					// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
+					console.warn("checkJsApi",res)
+					// alert('su'+ JSON.stringify(res))
+				},
+				fail:(err)=>{
+					console.warn("checkJsApi-err",err)
+					// alert('err'+ JSON.stringify(err) )
+				}
+			})
 			this.screenWidth = window.screen.width;
 			this.screenHeight = window.screen.height;
 			if(window.innerWidth && window.screen.width){
@@ -276,7 +287,7 @@
         },
 		beforeDestroy:function(){
 			console.warn("***beforeDestroy***");//更新到页面上的数据
-			this.clearInterval();
+			this.stopInterval();
 		},
 		computed: {
 			aiData() {
@@ -453,6 +464,22 @@
 				console.log("***leftScroll***",this.currentIndex,this.aiImagesList.length)
 				this.aiSubmit(2);//继续生成下一张
 			},
+			//预览图片-使用微信自带的预览功能,即H5中不可用
+			previewAction() {
+				if(window.__wxjs_environment === 'miniprogram'){
+					let imglist = this.aiImagesList.map(it=>it.image);
+					wx.previewImage({
+						current: this.currentIndex,
+						urls: imglist,
+						success: (res) => {
+							console.log('图片预览:', res);
+						},
+						fail:(err)=>{
+							console.warn('图片预览-err:', res);
+						}
+					})
+				}
+			},
 			//返回上一页
 			goback(){
 				this.$router.go(-1);
@@ -503,14 +530,6 @@
 					// this.disableAble = false;//可以点击
 				}
 			},
-			clearInterval() {
-				if (this.img2imgTimer) {
-					clearInterval(this.img2imgTimer);
-					this.img2imgTimer = null;
-				}
-				this.random = 1;
-				this.myloading = false;
-			},
 			//风格选择
 			selectStyle(idx){
 				if(this.curStyleIndex == idx){
@@ -539,18 +558,12 @@
 					return
 				}
 				this.aiFlag = true;
-				if (this.aiImage == "" || !this.aiImage) {
-					this.aiImage = ""; // https://dm.static.elab-plus.com/CE4/backImg.png
-				}
-				this.aiImage = "";
-			
-				this.clearInterval();
-				if(!this.showAIImage){
+				this.aiImage = "";//清空AI结果图
+				this.stopInterval();
+				// if(!this.showAIImage){
 					this.myloading = true;
-					this.loadingMsg = "设计中...";
-					// this.$store.state.loading = true;
-					// this.$store.state.loadingMsg="设计中...";
-				}
+					this.loadingMsg = "启动中";
+				// }
 				
 				// this.inputBase64Url = await this.shottingAction(2);//开始截图-返回的是base64的数据
 				// this.startServer();
@@ -630,25 +643,18 @@
 			},
 			//前置逻辑
 			async prevHandle(parmas){
-				return '';//暂不需要开启
 				//不是首次请求,则无需前置判断 用户上传的也不需要前置处理
-				if(this.subType!=0 || this.userInput){
+				if(this.subType!=0){
 					return '';
 				}
 				return new Promise(async (resolve, reject) => {
-					let imgRes = await requestConfig("generateTaskImgToImgForAliyun", parmas);
-					if (imgRes.success) {
-						let aiPicId = imgRes.single || '';
-						let res = await requestConfig('generateProcess', {
-							id: aiPicId
-						})
+					let _data = JSON.parse(JSON.stringify(parmas))
+					delete _data.webhook;
+					let res = await requestConfig("img2img_local", _data);
+					if (res.success) {
 						if (res.success && res.single) {
-							if(res.single.category == 'scheduler'){//命中了
-								let resultImg = res.single.urls[0];
-								resolve(resultImg);
-							}else{
-								resolve('');
-							}
+							let resultImg = res.single;
+							resolve(resultImg);
 						}else{
 							resolve('');
 						}
@@ -720,32 +726,51 @@
 					console.log("图生图结果:", res);
 					let that = this;
 					if (res.success && res.single) {
-						this.taskId = res.single;
+						this.aiPicId = res.single;
 						if(this.modelType==2){//精准设计
 							if(subType == 0){//首次
-								this.reqList[0].aiPicId = this.taskId;
+								this.reqList[0].aiPicId = this.aiPicId;
 							}else{//重试
-								this.reqListReset[0].aiPicId = this.taskId;
+								this.reqListReset[0].aiPicId = this.aiPicId;
 							}
 						}
-						if (!this.img2imgTimer) {
-							this.count = 0;
-							this.random = 1;
-							this.currentImg = false;//当次生成图还没有结果
-							this.img2imgTimer = setInterval(() => {
-								this.count ++;
-								this.getResultForImgToImg();
-							}, 1000);
-							this.setOutTimer();
+						if (this.aiPicId) {
+							this.startInterval();//开始轮询AI生成图的结果
+						}else{
+							this.stopInterval()
 						}
 					}else{
-						this.clearInterval()
-						this.aiFlag = false;
-						this.aiImage = "";
+						this.stopInterval()
 						this.showToast("渲染失败,请重试")
 					}
 				}
 			},
+			stopInterval() {
+				if (this.randomTimer) {
+					clearInterval(this.randomTimer);
+					this.randomTimer = null;
+				}
+				if (this.timer) {
+					// clearInterval(this.timer);
+					this.timer = null;
+				}
+				if (this.outTimer) {
+					clearTimeout(this.outTimer)
+					this.outTimer = null
+				}
+				this.subType = 0;
+				this.reqList.forEach(it=>{
+					it.aiPicId = '';
+					it.resultImg = '';
+				})
+				this.reqListReset.forEach(it=>{
+					it.aiPicId = '';
+					it.resultImg = '';
+				})
+				// this.random = 1;
+				this.myloading = false;
+				this.aiFlag = false;
+			},
 			//随机处理
 			randomHandle(resultImg){
 				if(this.timer || !resultImg){
@@ -755,16 +780,16 @@
 				var count = 1;
 				var process = 0;//进度
 				var randomNum = Math.floor(Math.random() * 4 + 5);//5-8随机数
-				this.img2imgTimer = setInterval(function() {
+				this.randomTimer = setInterval(function() {
 					process = parseInt(count * 100/(randomNum));
 					if(process>=100){
 						process = 99;
 					}
 					if (count < randomNum) {//没有到上限
-						if(!self.showAIImage){
-							// this.$store.state.loadingMsg='生成中…' + this.random + '%';
+						// if(!self.showAIImage){
+							self.myloading = true;
 							self.loadingMsg = '生成中…' + process + '%';
-						}
+						// }
 					}else{
 						self.myloading = false;
 						self.resultHandle(resultImg);
@@ -792,6 +817,19 @@
 					}
 				})
 			},
+			//开始生成AI图的轮询,每隔1s轮询一次
+			startInterval() {
+				if(this.timer){
+					return false;
+				}
+				let self = this;
+				this.count = 1;//轮询次数
+				var random = 0;
+				this.currentImg = false;//当次生成图还没有结果
+				this.timer = 1;
+				this.getOutPicture();//不在轮询,而是等结果
+				this.setOutTimer();//设置超时逻辑
+			},
 			//设置一个超时逻辑,到底指定时间后停止轮询,当前是90s
 			setOutTimer() {
 				if (this.outTimer) {
@@ -800,7 +838,7 @@
 				}
 				var self = this;
 				this.outTimer = setTimeout(function() {
-					if (self.img2imgTimer) {
+					if (self.timer) {
 						let hasResult = false;
 						if(self.modelType==2){//精准设计
 							let reqList = [];
@@ -818,31 +856,53 @@
 						}
 						console.warn("***hasResult***",hasResult)
 						if(!hasResult){//没有结果
-							self.clearInterval();//停止轮询
+							self.stopInterval();//停止轮询
 							// self.$message.warning("AI开了个小差,请稍后再试");
-							self.dialogVisible = true;//弹出超时提示
-							self.aiFlag = false;
-							self.aiImage = "";
+							// self.dialogVisible = true;//弹出超时提示
+							MessageBox.confirm('',{
+								title: '提示',
+								message: '当前AI使用火爆,请继续尝试?',
+								showCancelButton: true,
+								confirmButtonText:'继续尝试',
+								cancelButtonText:'取消等待',
+							}).then(action => {
+								console.warn("***MessageBox-action***",action)
+								if(action == 'confirm'){
+									self.confirmHandle(1);
+								}
+							}).catch(err=>{
+								console.warn("***MessageBox-err***",err)
+								if(err == 'cancel'){
+									self.cancelHandle();
+								}
+							});
+							// MessageBox.confirm('确定执行此操作?')
 						}
 					}
 					clearTimeout(self.outTimer);
 					self.outTimer = null
 				}, this.timeOut);
 			},
-			confirmHandle(){
+			confirmHandle(type){
 				console.log('用户点击确定')
 				this.dialogVisible = false;
-				this.subType = 1;
+				this.dialogAIVisible = false;
+				this.subType = type || 0;
 				this.startServer();
 			},
 			cancelHandle(){
 				console.log('用户点击取消')
 				this.dialogVisible = false;
+				this.dialogAIVisible = false;
 				this.subType = 0;
 			},
-			// 轮询获取图片结果
-			async getResultForImgToImg() {
-				if(this.modelType==2){//精准设计且当次新开始
+			//获取生成图结果
+			getOutPicture() {
+				if(this.timer==null){
+					console.warn("***当前轮询已经结束了1***")
+					return false;
+				}
+				if(this.modelType==2){//精准设计
 					let reqList = [];
 					if(this.subType == 0){//首次
 						reqList = this.reqList;
@@ -854,9 +914,10 @@
 					});
 				}
 				else{
-					this.singleHandle({aiPicId:this.taskId})
+					this.singleHandle({aiPicId:this.aiPicId})
 				}
 			},
+			//发出获取结果请求获取AI生成结果
 			async singleHandle(model){
 				if(!model || !model.aiPicId){
 					return false;
@@ -864,54 +925,108 @@
 				var parmas = {
 					id: model.aiPicId,
 				};
-				let res = await requestConfig("generateProcess", parmas);
+				let res = await requestConfig("getPredictions", parmas);
 				if (res.success && res.single) {
 					if(this.currentImg){//当前已经有生成图了
 						console.warn("***当前已经有最高级生成图了***")
 						return false;
 					}
-					if (res.single.urls) {
-						console.warn("图生图轮询结束: ", res);
+					if(this.timer==null){
+						console.warn("***当前轮询已经结束了***")
+						return false;
+					}
+					if (res.single.status == 'succeeded' && res.single.output) {
 						if(this.modelType==2){//精准设计
-							model.resultImg = res.single.urls[0];
+							model.resultImg = res.single.output;
 							if(model.level=='5'){//最高级了
 								this.currentImg = true;
-								this.resultHandle(res.single.urls[0])
+								setTimeout(()=>{
+									this.resultHandle(res.single.output)
+								},1500)
 							}
 						}else{
-							this.resultHandle(res.single.urls[0])
+							this.currentImg = true;
+							setTimeout(()=>{
+								this.resultHandle(res.single.output)
+							},1500)
 						}
 						console.warn("***有生成图了***",model)
-						
-					} else {
-						if (!res.success) {
-							this.showToast("渲染失败,请重试")
-							this.aiFlag = false;
-							this.aiImage = "";
-							this.clearInterval();
-						}else {
-							// this.random = parseInt(this.count * 2);
-							this.random = parseInt(this.count * 100/(this.timeOut/1000));
-							if(this.random>=100){
-								this.random = 99;
+					} 
+					if(this.modelType==2){//最高优先级返回没有图片,则处理进度条事宜
+						if(model.level=='5'){
+							this.processHandle(res.single);
+						}
+					}else{//普通设计
+						this.processHandle(res.single);
+					}
+				} else if (!res.success) {
+					this.stopInterval();//停止轮询
+					this.showToast("渲染失败,请重试")
+				}
+			},
+			//进度处理
+			processHandle(single){
+				console.warn("***single***",single.status,single.progress,this.count,single);
+				let self = this;
+				if(single.status=='starting'){//启动中的逻辑
+					if(this.count>=20){
+						this.stopInterval();//停止轮询
+						// this.dialogAIVisible = true;
+						MessageBox.confirm('',{
+							title: '提示',
+							message: 'AI开了小差,是否重新生成?',
+							showCancelButton: true,
+							confirmButtonText:'继续生成',
+							cancelButtonText:'放弃生成',
+						}).then(action => {
+							console.warn("***MessageBox-action***",action)
+							if(action == 'confirm'){
+								this.confirmHandle(0);
 							}
-							if(!this.showAIImage){
-								// this.$store.state.loadingMsg='生成中…' + this.random + '%';
-								this.loadingMsg = '生成中…' + this.random + '%';
-							}else{
+						}).catch(err=>{
+							if(err == 'cancel'){
+								this.cancelHandle();
 							}
-						}
+						});
+					}else{
+						this.myloading = true;
+						this.loadingMsg = '启动中';
 					}
+					this.count = this.count + 1;
+					this.getOutPicture();
+				}else if(single.status=='processing'){
+					let random = single.progress || 0;
+					if(random >= 100){
+						random = 99;
+					}
+					// uni.showLoading({
+					// 	icon: 'loading',
+					// 	title: '生成中…' + parseInt(random) + '%'
+					// })
+					// if(!this.showAIImage){
+						this.myloading = true;
+						this.loadingMsg = '生成中…' + parseInt(random) + '%';
+					// }
+					this.getOutPicture();
+				}else if(single.status=='succeeded'){
+					// uni.showLoading({
+					// 	icon: 'loading',
+					// 	title: '生成中…100%',
+					// 	duration:2000,
+					// })
+					// if(!this.showAIImage){
+						this.myloading = true;
+						this.loadingMsg = '生成中…100%';
+					// }
 				}
 			},
 			//返回结果处理
 			resultHandle(resultImg){
 				this.currentImg = true;
-				this.aiFlag = false;
-				this.random = 100;
+				// this.random = 100;
 				this.aiImage = resultImg;
 				this.showAIFlag = true;
-				let newImage = this.aiImage;
+				let newImage = resultImg;
 				let aiStyleName = this.styleList[this.curStyleIndex].styleName;
 				let _data = {
 					image:newImage,
@@ -951,7 +1066,7 @@
 					}
 					this.$store.dispatch('setAiData', cpAiData)
 				}
-				this.clearInterval();
+				this.stopInterval();
 				if(this.aiImagesList.length>1){
 					setTimeout(()=>{
 						// this.$refs.carousel.next();
@@ -960,6 +1075,7 @@
 				}
 			},
 			showToast(title,time=3000){
+				this.myloading = false;
 				this.$store.state.loading = true;
 				this.$store.state.loadingMsg = title || "";
 				setTimeout(()=>{

+ 3 - 0
src/main.js

@@ -9,6 +9,8 @@ import $ from 'jquery'; //引入JQuery
 import axios from '@/services/request.js'; //重新定义axios,向里面添加一些参数
 import '@/services/requestConfig.js'; //导入请求的拦截器
 // import '@/utils/rem.js'; //rem单位的使用
+import Mint from 'mint-ui';
+import 'mint-ui/lib/style.css';
 
 import '@/assets/common.css'; //公共样式
 import "@/assets/font/iconfont.css"; //引用公共icon库
@@ -22,6 +24,7 @@ import 'amfe-flexible';	//自动设置font-size的基准值
 // import checkPermission from "@/utils/permission";
 
 Vue.use(ElementUI); //导入ele-ui
+Vue.use(Mint);
 Vue.component('mynavbar', mynavbar)
 // Vue.prototype.$popUp = popUpComponent;
 // Vue.prototype.$preview = previewComponent;

+ 3 - 0
src/mixins/commonPageMethod.js

@@ -91,6 +91,9 @@ export default {
 				}
 				this.pvCloseHandle()
 			} else { // 进入页面
+				if(this.starRender && typeof(this.starRender)==='function'){
+					this.starRender();//开始webgl的渲染
+				}
 				this.pvShowHandle()
 			}
 		},

+ 185 - 0
src/mixins/filter.js

@@ -0,0 +1,185 @@
+function initVideoScene(videoId, containerId, callback) {
+    var _self = this;
+    var videoObj = document.getElementById(videoId);
+    var canvasObj;
+    var movieObj;
+    
+    var renderer;
+    var camera;
+    var scene;
+
+    var playflag = false;
+    var filter = 0;
+
+    /**
+     * 执行
+     */
+    _self.run = function(){
+        videoObj.play();
+        playflag = true;
+    }
+
+    /**
+     * 暂停
+     */
+    _self.pause = function(){
+        videoObj.pause();
+        playflag = false;
+    }
+
+    /**
+     * 修改滤镜
+     * @param {Number} type 可选 0 - 6; 
+     */
+    _self.changefilter = function(type){
+        if(type >= 0 && type <= 6){
+            filter = type;
+            movieObj.movieMaterial.uniforms.filterType.value = type;
+            movieObj.movieMaterial.uniforms.texture.needsUpdate = true;
+        }
+    }
+
+    /**
+     * 修改明暗
+     * @param {Number} value 可选 0.1 - 0.7; 
+     */
+    _self.changefilterLight = function(value){
+        if(filter == 3 && value <= 0.7 && value >= 0.1){
+            movieObj.movieMaterial.uniforms.lightLevel.value = value;
+            movieObj.movieMaterial.uniforms.texture.needsUpdate = true;
+        }
+    }
+
+    /**
+     * 修改噪点数
+     * @param {Number} value 可选 0.2 - 1.5; 
+     */
+    _self.changefilterGrid = function(value){
+        if(filter == 6 && value <= 1.5 && value >= 0.2){
+            movieObj.movieMaterial.uniforms.gridSize.value = value;
+            movieObj.movieMaterial.uniforms.texture.needsUpdate = true;
+        }
+    }
+
+    /**
+     * 加载图片纹理
+     */
+    _self.loadTexture = function(imgs,callback){
+        var len = imgs.length;
+        var Textures = [];
+
+        for (var i = 0; i < len; i++) {
+            var loader = new THREE.TextureLoader();
+            loader.load(
+                imgs[i],
+                function ( texture ) {
+                    Textures.push(texture);
+                    if(Textures.length == len && callback){
+                        callback(Textures);
+                    }
+                }
+            );
+        }
+    }
+
+    /**
+     * 添加图片
+     */
+    _self.addImg = function(imgTexture,transparent){
+        var imgObj;
+        var imageGeometry;
+        var imageMaterial;
+        imageGeometry = new THREE.PlaneGeometry(4, 3);
+        imageMaterial =  new THREE.MeshBasicMaterial();
+        imageMaterial.map = imgTexture;
+        imageMaterial.transparent = transparent;
+        imgObj = new THREE.Mesh(imageGeometry, imageMaterial);
+        // imgObj.position.set(0, 0, 0);
+        // imgObj.scale.set(1, 1, 1);
+        // imgObj.visible = true;
+        scene.add(imgObj);
+
+        return imageMaterial;
+    }
+
+    /**
+     * 修改图片
+     */
+    _self.changeImg = function(Material,imgTexture){
+        Material.map = imgTexture;
+    }
+
+    /**
+     * 初始化
+     */
+    function _init(){
+        _senceInit();
+        _movieInit();
+        _animate();
+    }
+    _init();
+
+    /**
+     * 动画
+     */
+    function _animate() {
+        if ((videoObj.currentTime > 0) && movieObj.movie.visible == false) {
+            movieObj.movie.visible = true;
+        }
+        
+        renderer.render(scene, camera);
+
+        if(playflag && callback){
+            var img = canvasObj.toDataURL("image/png")
+            callback(videoObj.currentTime,img);
+        }
+
+        requestAnimationFrame(function(){
+            _animate();
+        });
+    }
+
+    /**
+     * 场景初始化
+     */
+    function _senceInit(){
+        scene = new THREE.Scene();
+        window.scene = scene;
+
+        camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
+        camera.position.set(0, 0, 1);
+        scene.add(camera);
+
+        renderer = new THREE.WebGLRenderer({
+            antialias: true,
+            alpha: true
+        });
+        renderer.setSize(window.innerWidth, window.innerHeight);
+        canvasObj = renderer.domElement;
+        document.getElementById(containerId).appendChild(canvasObj);
+        renderer.setClearColor(0xffffff, 0);
+        renderer.setSize(videoObj.width, videoObj.height);
+    }
+
+    /**
+     * 视频初始化
+     */
+    function _movieInit(){
+        var movie;
+        var movieGeometry;
+        var movieMaterial;
+        movieMaterial = new ChromaKeyMaterial(videoId, videoObj.width, videoObj.height, 0x00ff05, 0);
+        movieGeometry = new THREE.PlaneGeometry(4, 3);
+        movieMaterial.side = THREE.DoubleSide;
+        movie = new THREE.Mesh(movieGeometry, movieMaterial);
+        movie.position.set(0, 0, 0);
+        movie.scale.set(1, 1, 1);
+        movie.visible = false;
+        scene.add(movie);
+        movieObj = {
+            movie:movie,
+            movieGeometry:movieGeometry,
+            movieMaterial:movieMaterial
+        }
+    }
+}

+ 29 - 0
src/pages/webgl_rxdz_vr/webgl_rxdz_vr.html

@@ -0,0 +1,29 @@
+<!--
+ * @Author: caodongdong caodongdoong@gmail.com
+ * @Date: 2023-05-17 15:46:34
+ * @LastEditors: caodongdong caodongdoong@gmail.com
+ * @LastEditTime: 2023-06-30 16:20:04
+ * @FilePath: \h5-uniApp-miniprogrgm\webgl\pages\webgl_rxdz\webgl_rxdz.html
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+-->
+<div class="main-view">
+	<mynavbar :barData='navbar' @navbarBackCallback="navbarBackClk" />
+	<!-- 主要操作视图 -->
+	<!-- <viewShell pageType="2" :spaceObj="curSpaceObj" @hideOrShowActor="hideOrShowActor"></viewShell> -->
+	<!-- <my-loading ref="myLoading" :myLoadingStatus="myLoadingStatus"></my-loading>
+	<div id="status" style="position:fixed;top:100px;left:30px;cursor:pointer;opacity:0.9;z-index:10000">
+		<canvas id="FPS" type="2d" style="width:80px;height:48px"></canvas>
+		<canvas id="MS" type="2d" style="width:80px;height:48px"></canvas>
+	</div> -->
+	<div id="mapDiv" ref="webgl"></div>
+	<canvas id="canvas_webgl" type="webgl" ref="glcanvas"
+		 width="100vw" 
+		:style="{'height':canvasHeight+'px'}">
+	</canvas>
+	<!-- AI结果覆盖层 -->
+	<!-- <viewMask ref="viewMask" @switchActor="switchActor" style="z-index: 13;"
+	  :spaceObj="curSpaceObj" ></viewMask> -->
+	<!-- 生成截屏的画布对象 -->
+	<canvas id="canvas" type="2d" :style="{'height':canvasHeight+'px','top':'100vh'}"></canvas>
+	<!-- <video id="video" style="display:none" autoplay playsinline src="https://dm.static.elab-plus.com/miniProgram/green.mp4"></video> -->
+</div>

+ 31 - 0
src/pages/webgl_rxdz_vr/webgl_rxdz_vr.scss

@@ -0,0 +1,31 @@
+.main-view{
+	width:100vw;
+	height:100vh;
+	overflow: hidden;
+}
+canvas { width:100vw; height:calc(100vh - 408px);z-index: 10;}
+#mapDiv{
+	background-color: #fff;
+}
+page {
+    -webkit-user-select: none;
+    user-select: none;
+    width: 100%;
+	height:100vh;
+    overflow-x: hidden;
+    overflow-y: hidden;
+}
+/* 生成截屏的画布对象 */
+#canvas {
+	width: 100vw;
+	z-index: -1;
+	// position: absolute;
+	left:0px;
+}
+.canvas-view{
+	position:relative;
+}
+.lable-view{
+	position:absolute;
+	width:100vw;
+}

+ 824 - 0
src/pages/webgl_rxdz_vr/webgl_rxdz_vr.vue

@@ -0,0 +1,824 @@
+<template src="./webgl_rxdz_vr.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/newBottomCom/viewShell/viewShell.vue';
+	import viewMask from '@/components/newBottomCom/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/);
+
+			// 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.myLoadingStatus = true;
+			this.clearEvent = clearEvent;
+			this.attendEvent = attendEvent;
+			this.tweenCameraAnmaChange = tweenCameraAnmaChange;
+			this.starRender = starRender; //对外暴露启动渲染的方法
+			this.stopRender = stopRender; //对外暴露停止渲染的方法
+
+			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 loader = new THREE.TextureLoader();
+				const texture = loader.load(
+					'https://dm.static.elab-plus.com/miniProgram/tears_of_steel_bridge_2k.jpg', () => {
+						const rt = new THREE.WebGLCubeRenderTarget(texture.image.height);
+						rt.fromEquirectangularTexture(renderer, texture);
+						scene.background = rt.texture;
+					});
+				//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(); //启动渲染
+				setTimeout(() => {
+					videoHandle()
+				}, 500);
+			}
+
+			function videoHandle() {
+				// let video = document.getElementById('video');
+
+				// let texture = new THREE.pointTexture(video);
+				// texture.colorSpace = THREE.SRGBColorSpace;
+
+				// 创建视频元素
+				var video = document.createElement('video');
+				video.src = 'https://dm.static.elab-plus.com/miniProgram/001.mp4'; // 视频文件的路径
+				// video.crossOrigin = "anonymous";this.crossOrigin = 'anonymous';
+				video.setAttribute("crossOrigin", "Anonymous");
+				video.loop = true;
+				video.muted = true;
+				// video.load();
+				video.play();
+				// 创建视频纹理
+				var texture = new THREE.VideoTexture(video);
+				// texture.colorSpace = THREE.SRGBColorSpace;
+				// texture.minFilter = THREE.LinearFilter;
+				// texture.magFilter = THREE.LinearFilter;
+				// texture.format = THREE.RGBFormat;
+
+				// 创建绿幕着色器
+				let greenScreenShader = {
+					uniforms: {
+						pointTexture: {
+							value: texture
+						},
+					},
+					vertexShader: `    
+						varying vec2 vUv;    
+						void main() {      
+							vUv = uv;      
+							gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);    
+						}  `,
+					// fragmentShader: `
+					// 	uniform sampler2D pointTexture;
+					// 		uniform float threshold;
+					// 		varying vec2 vUv;
+					// 		void main() {
+					// 			vec4 color = texture2D(pointTexture, vUv);
+					// 			float greenScreen = color.g - max(color.r, color.b);
+					// 			float alpha = 1.0 - smoothstep(threshold - 0.05, threshold + 0.05, greenScreen);
+					// 			gl_FragColor = vec4(color.rgb, alpha);
+					// 		}
+					// `,
+					// fragmentShader: `
+					// 	precision mediump float;
+					// 	uniform sampler2D pointTexture;
+					// 	uniform sampler2D colorlut;
+					// 	uniform vec3 color;
+					// 	uniform float videowidth;
+					// 	uniform float videoheight;
+					// 	uniform int filterType;
+					// 	uniform float gridSize;
+					// 	uniform float lightLevel;
+						
+					// 	varying vec2 vUv;
+					// 	float alter=3.0;
+					// 	float u_mode=0.0;
+					// 	float u_threshold=1.0;
+					// 	float u_clipBlack=0.5;
+					// 	float u_clipWhite=1.0;
+						
+					// 	float rgb2cb(float r, float g, float b){
+					// 		return 0.5 + -0.168736*r - 0.331264*g + 0.5*b;
+					// 	}
+					// 	float rgb2cr(float r, float g, float b){
+					// 		return 0.5 + 0.5*r - 0.418688*g - 0.081312*b;
+					// 	}
+					// 	float smoothclip(float low, float high, float x){
+					// 		if (x <= low){
+					// 			return 0.0;
+					// 		}
+					// 		if(x >= high){
+					// 			return 1.0;
+					// 		}
+					// 		return (x-low)/(high-low);
+					// 	}
+					// 	vec4 greenscreen(vec4 colora, float Cb_key,float Cr_key, float tola,float tolb, float clipBlack, float clipWhite){
+					// 		float cb = rgb2cb(colora.r,colora.g,colora.b);
+					// 		float cr = rgb2cr(colora.r,colora.g,colora.b);
+					// 		float alpha = distance(vec2(cb, cr), vec2(Cb_key, Cr_key));
+					// 		alpha = smoothclip(tola, tolb, alpha);
+					// 		float r = max(gl_FragColor.r - (1.0-alpha)*color.r, 0.0);
+					// 		float g = max(gl_FragColor.g - (1.0-alpha)*color.g, 0.0);
+					// 		float b = max(gl_FragColor.b - (1.0-alpha)*color.b, 0.0);
+					// 		if(alpha < clipBlack){
+					// 			alpha = r = g = b = 0.0;
+					// 		}
+					// 		if(alpha > clipWhite){
+					// 			alpha = 1.0;
+					// 		}
+					// 		if(clipWhite < 1.0){
+					// 			alpha = alpha/max(clipWhite, 0.9);
+					// 		}
+					// 		return vec4(r,g,b, alpha);
+					// 	}
+						
+					// 	void main()
+					// 	{
+					// 		gl_FragColor = texture2D( pointTexture, vUv );
+					// 		float tola = 0.0;
+					// 		float tolb = u_threshold/2.0;
+					// 		float cb_key = rgb2cb(color.r, color.g, color.b);
+					// 		float cr_key = rgb2cr(color.r, color.g, color.b);
+					// 		gl_FragColor = greenscreen(gl_FragColor, cb_key, cr_key, tola, tolb, u_clipBlack, u_clipWhite);
+					// 		if(u_mode > 0.5 && u_mode < 1.5){
+					// 				gl_FragColor = mix(vec4(1.0, 1.0, 1.0, 1.0), gl_FragColor, gl_FragColor.a);
+					// 				gl_FragColor.a = 1.0;
+					// 		}
+					// 		if(u_mode > 1.5 && u_mode < 2.5){
+					// 				gl_FragColor = vec4(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a, 1.0);
+					// 		}
+					// 		if(filterType==1){
+					// 			float gray = 0.2989*gl_FragColor.r+0.5870*gl_FragColor.g+0.1140*gl_FragColor.b;
+					// 			gl_FragColor = vec4(gray,gray,gray , gl_FragColor.a);
+					// 		}else if(filterType==2){
+					// 			vec3 tColor2 = texture2D( pointTexture, vec2(vUv[0]+(1.0/videowidth) , vUv[1]) ).rgb;
+					// 			vec3 tColor3 = texture2D( pointTexture, vec2(vUv[0]-(1.0/videowidth) , vUv[1]) ).rgb;
+					// 			vec3 tColor4 = texture2D( pointTexture, vec2(vUv[0]+(1.0/videowidth) , vUv[1]+(1.0/videoheight)) ).rgb;
+					// 			vec3 tColor5 = texture2D( pointTexture, vec2(vUv[0]-(1.0/videowidth) , vUv[1]-(1.0/videoheight)) ).rgb;
+					// 			vec3 tColor6 = texture2D( pointTexture, vec2(vUv[0]+(1.0/videowidth) , vUv[1]-(1.0/videoheight)) ).rgb;
+					// 			vec3 tColor7 = texture2D( pointTexture, vec2(vUv[0]-(1.0/videowidth) , vUv[1]+(1.0/videoheight)) ).rgb;
+					// 			vec3 tColor8 = texture2D( pointTexture, vec2(vUv[0] , vUv[1]+(1.0/videoheight)) ).rgb;
+					// 			vec3 tColor9 = texture2D( pointTexture, vec2(vUv[0] , vUv[1]+(1.0/videoheight)) ).rgb;
+					// 			vec3 tColor10 = texture2D( pointTexture, vec2(vUv[0]+(2.0/videowidth) , vUv[1]) ).rgb;
+					// 			vec3 tColor11 = texture2D( pointTexture, vec2(vUv[0]+(2.0/videowidth) , vUv[1]) ).rgb;
+					// 			gl_FragColor = vec4( (gl_FragColor.r+tColor2[0]+tColor3[0]+tColor4[0]+tColor5[0]+tColor6[0]+tColor7[0]+tColor8[0]+tColor9[0]+tColor10[0]+tColor11[0])/11.0,
+					// 			(gl_FragColor.g+tColor2[1]+tColor3[1]+tColor4[1]+tColor5[1]+tColor6[1]+tColor7[1]+tColor8[1]+tColor9[1]+tColor10[1]+tColor11[1])/11.0,
+					// 			(gl_FragColor.b+tColor2[2]+tColor3[2]+tColor4[2]+tColor5[2]+tColor6[2]+tColor7[2]+tColor8[2]+tColor9[2]+tColor10[2]+tColor11[2])/11.0,
+					// 			gl_FragColor.a);
+					// 		}else if(filterType==3){
+					// 			float brightr=gl_FragColor.r+lightLevel;
+					// 			float brightg=gl_FragColor.g+lightLevel;
+					// 			float brightb=gl_FragColor.b+lightLevel;
+					// 			gl_FragColor = vec4(brightr,brightg,brightb , gl_FragColor.a);
+					// 		}else if(filterType==4){
+					// 			float reverser=1.0 - gl_FragColor.r;
+					// 			float reverseg=1.0 - gl_FragColor.g;
+					// 			float reverseb=1.0 - gl_FragColor.b;
+					// 			gl_FragColor = vec4(reverser,reverseg,reverseb,gl_FragColor.a);
+					// 		}else if(filterType==5){
+								
+					// 			float dx = fract(sin(dot(vUv ,vec2(12.9898,78.233))) * 43758.5453);
+					// 			vec3 cResult = gl_FragColor.rgb + gl_FragColor.rgb * clamp( 0.1 + dx, 0.0, 1.0 );
+					// 			vec2 sc = vec2( sin( vUv.y * 4096.0 ), cos( vUv.y * 4096.0 ) );
+					// 			cResult += gl_FragColor.rgb * vec3( sc.x, sc.y, sc.x ) * 0.025;
+					// 			cResult = gl_FragColor.rgb + clamp( 0.35, 0.0,1.0 ) * ( cResult - gl_FragColor.rgb );
+					// 			if( false ) {
+					// 				cResult = vec3( cResult.r * 0.3 + cResult.g * 0.59 + cResult.b * 0.11 );
+					// 			}
+					// 			float oldr=0.393*cResult[0]+0.769*cResult[1]+0.189*cResult[2];
+					// 			float oldg=0.349*cResult[0]+0.686*cResult[1]+0.168*cResult[2];
+					// 			float oldb=0.272*cResult[0]+0.534*cResult[1]+0.131*cResult[2];
+					// 			gl_FragColor =  vec4( oldr,oldg,oldb , gl_FragColor.a);
+					// 		}else if(filterType==6){
+					// 			float average = ( gl_FragColor.r + gl_FragColor.g + gl_FragColor.b ) / 2.0;
+					// 			float s = sin( 0.5 ), c = cos( 0.5 );
+					// 			vec2 tex = vUv * vec2(videowidth,videoheight) - vec2(0,0);
+					// 			vec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * gridSize;
+					// 			float pattern =  ( sin( point.x ) * sin( point.y ) ) * 4.0;
+					// 			float seed = average * 10.0 - 5.0 + pattern ;
+					// 			gl_FragColor = vec4(  seed*0.3+gl_FragColor.r*0.7,seed*0.3+gl_FragColor.g*0.7 ,seed*0.3+gl_FragColor.b*0.7, gl_FragColor.a );
+					// 		}
+					// 	}
+					// `,
+					fragmentShader: `
+						uniform sampler2D pointTexture;
+						varying vec2 vUv;
+						void main() {
+						    vec4 color = texture2D(pointTexture, vUv);
+						    float threshold = 0.5;
+						    if (color.g > threshold) {
+								discard; 
+						    } else {
+								gl_FragColor = color;
+						    }
+						}
+					`,
+
+							// fragmentShader: `    
+							// 	uniform sampler2D pointTexture;
+							// 	uniform vec3 backColor;
+							// 	varying vec2 vUv;
+							// 	uniform float u_threshold;
+							// 	float u_clipBlack = 0.2;
+							// 	float u_clipWhite = 4.0;
+
+							// 	float rgb2cb(float r, float g, float b){ return 0.5 + -0.168736*r - 0.331264*g + 0.5*b; } 
+							// 	float rgb2cr(float r, float g, float b){ return 0.5 + 0.5*r - 0.418688*g - 0.081312*b; } 
+							// 	float smoothclip(float low, float high, float x){ if (x <= low){ return 0.0; } if(x >= high){ return 1.0; } return (x-low)/(high-low); }
+							// 	vec4 greenscreen(vec4 colora, float Cb_key,float Cr_key, float tola,float tolb, float clipBlack, float clipWhite)
+							// 	{ 
+							// 		float cb = rgb2cb(colora.r,colora.g,colora.b); 
+							// 		float cr = rgb2cr(colora.r,colora.g,colora.b); 
+							// 		float alpha = distance(vec2(cb, cr), vec2(Cb_key, Cr_key)); 
+							// 		alpha = smoothclip(tola, tolb, alpha); 
+							// 		float r = max(gl_FragColor.r - (1.0-alpha)*backColor.r, 0.0); 
+							// 		float g = max(gl_FragColor.g - (1.0-alpha)*backColor.g, 0.0); 
+							// 		float b = max(gl_FragColor.b - (1.0-alpha)*backColor.b, 0.0); 
+							// 		if(alpha < clipBlack){ alpha = r = g = b = 0.0; } 
+							// 		if(alpha > clipWhite){ alpha = 1.0; } 
+							// 		if(clipWhite < 1.0){ alpha = alpha/max(clipWhite, 0.9); } 
+							// 		return vec4(r,g,b, alpha); 
+							// 	}
+							// 	void main( void ) {
+
+							// 		gl_FragColor = vec4(texture2D(pointTexture, vUv).rgb, 1);
+
+							// 		float tola = 0.0; 
+							// 		float tolb = u_threshold/2.0; 
+							// 		float cb_key = rgb2cb(backColor.r, backColor.g, backColor.b); 
+							// 		float cr_key = rgb2cr(backColor.r, backColor.g, backColor.b); 
+							// 		gl_FragColor = greenscreen(gl_FragColor, cb_key, cr_key, tola, tolb, u_clipBlack, u_clipWhite);
+
+							// 	} 
+							// 	`,
+
+				};
+				// 创建绿幕材质
+				let greenScreenMaterial = new THREE.ShaderMaterial(greenScreenShader);
+
+				let geometry = new THREE.PlaneGeometry(16, 9);
+				// var geometry = new THREE.BoxGeometry(9, 9, 9);
+				// geometry.scale(0.5, 0.5, 0.5);
+				// 应用绿幕材质到对象上
+				let mesh = new THREE.Mesh(geometry, greenScreenMaterial);
+				mesh.position.set(0, 0, 0);
+				// mesh.rotation.x =  -Math.PI / 2 ;  // 旋转 180 度
+				// scene.add(object);
+				// const mesh = new THREE.Mesh(geometry, material);
+				// mesh.position.setFromSphericalCoords(radius, phi, theta);
+				mesh.lookAt(camera.position);
+				scene.add(mesh);
+			}
+
+			function tweenCameraAnmaChange(value) {
+				tweenCameraAnma = value
+			}
+
+			function attendEvent() {
+				renderer.domElement.addEventListener('touchstart', onPointerStart, false);
+				renderer.domElement.addEventListener('touchmove', onPointerMove, false);
+				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 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() {
+
+			},
+			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 + "㎡"
+				console.log("该户型空间数据:", this.spaceList);
+				console.log("当前选中的空间:", this.curSpaceObj);
+				// 获取墙体数据并且绘制墙体
+			},
+
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	@import "./webgl_rxdz_vr.scss";
+	/* @import "@/common/css/common.css"; */
+</style>

+ 10 - 0
src/router/index.js

@@ -9,6 +9,8 @@ import webgl_rxdz_roam from '@/pages/webgl_rxdz_roam/webgl_rxdz_roam.vue'
 import webgl_rxdz_look from '@/pages/webgl_rxdz_look/webgl_rxdz_look.vue'
 import webgl_rxdz_customize from '@/pages/webgl_rxdz_customize/webgl_rxdz_customize'
 
+import webgl_rxdz_vr from '@/pages/webgl_rxdz_vr/webgl_rxdz_vr.vue'
+
 Vue.use(Router)
 const router = new Router({
     mode: 'hash',
@@ -58,6 +60,14 @@ const router = new Router({
 			meta:{
 				keepAlive:false
 			}
+		},
+		{
+		    path: '/pages/webgl_rxdz_vr',
+		    name: 'webgl_rxdz_vr',
+		    component: webgl_rxdz_vr,
+			meta:{
+				keepAlive:false
+			}
 		}
 		
     ],

+ 6 - 0
src/services/request.js

@@ -14,6 +14,8 @@ axios.interceptors.request.use(function(config) {
 	}
 	if(!config.url.includes('aiGenerateImg/getResult') &&
 	!config.url.includes('aiGenerateImg/uploadImgControlNet') &&
+	!config.url.includes('aiGenerateImg/getPredictions') &&
+	!config.url.includes('aiGenerateImg/img2img_local') &&
 	!config.url.includes('aiGenerateImg/img2Img')){
 		requestCount++;//请求数+1
 	}
@@ -44,6 +46,8 @@ axios.interceptors.request.use(function(config) {
 axios.interceptors.response.use(function(response) {
 	if(!response.config.url.includes('aiGenerateImg/getResult') &&
 	!response.config.url.includes('aiGenerateImg/uploadImgControlNet') &&
+	!response.config.url.includes('aiGenerateImg/img2img_local') &&
+	!response.config.url.includes('aiGenerateImg/getPredictions') &&
 	!response.config.url.includes('aiGenerateImg/img2Img')){
 		requestCount = requestCount - 1;
 	}
@@ -56,6 +60,8 @@ axios.interceptors.response.use(function(response) {
 	console.log("***error***", error, requestCount)
 	if(	!error.config.url.includes('aiGenerateImg/getResult') &&
 		!error.config.url.includes('aiGenerateImg/uploadImgControlNet') &&
+		!error.config.url.includes('aiGenerateImg/img2img_local') &&
+		!error.config.url.includes('aiGenerateImg/getPredictions') &&
 		!error.config.url.includes('aiGenerateImg/img2Img')){
 		requestCount = requestCount - 1;
 	}

+ 4 - 0
src/services/requestConfig.js

@@ -34,6 +34,8 @@ const endpoints = {
 	generateTaskImgToImgForAliyun: 'elab-marketing-content/aiGenerateImg/img2Img', // 生成识别任务-阿里云(图生图)
 	generateTaskWordToImgForAliyun: 'elab-marketing-content/aiGenerateImg/addTaskWithWord2Img', // 生成识别任务-阿里云(文生图)
 	generateProcess: 'elab-marketing-content/aiGenerateImg/getResult', // 获取任务进度-阿里云
+	img2img_local: 'elab-marketing-content/aiGenerateImg/img2img_local', // 生成图第一次请求
+	getPredictions: 'elab-marketing-content/aiGenerateImg/getPredictions', // 获取任务进度-新版
 	shareDetail: '/elab-marketing-content/aiDreamHouse/V3.0/shareDetail', // 分享查看
 	// predictions: "https://api.replicate.com/v1/deployments/feathers-wing/spacely-realistic-style-softedge-a100/predictions", // 分享查看
 };
@@ -72,6 +74,8 @@ window.requestConfig = async(endpoint, options, isHideLoading = false, preventDo
         !requestOptions.url.includes('elab-marketing-analyse/heavenlyEye/getCompareMapTotalPopulation') &&
         !requestOptions.url.includes('aiGenerateImg/uploadImgControlNet') &&
         !requestOptions.url.includes('aiGenerateImg/img2Img') &&
+        !requestOptions.url.includes('aiGenerateImg/img2img_local') &&
+        !requestOptions.url.includes('aiGenerateImg/getPredictions') &&
         !requestOptions.url.includes('aiGenerateImg/getResult')
     ) {
         store.state.loading = true; //显示loading态