fix
This commit is contained in:
192
src/component/HomePage/index/model/patternMaking3D/download.vue
Normal file
192
src/component/HomePage/index/model/patternMaking3D/download.vue
Normal file
@@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<div class="threeDownPage" ref="threeDownPage">
|
||||
<a-modal class="generalModel"
|
||||
v-model:visible="threeDown"
|
||||
:footer="null"
|
||||
width="77rem"
|
||||
height="65rem"
|
||||
:maskClosable="false"
|
||||
:mask="false"
|
||||
:centered="true"
|
||||
:closable="false"
|
||||
:get-container="() => $refs.threeDownPage"
|
||||
wrapClassName="#app"
|
||||
:keyboard="false"
|
||||
>
|
||||
<div class="generalModel_btn">
|
||||
<div class="generalModel_closeIcon" @click.stop="cancelDsign()">
|
||||
<svg width="46" height="46" viewBox="0 0 46 46" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="23" cy="23" r="23" fill="white" fill-opacity="0.3"/>
|
||||
<rect x="32.5063" y="12" width="3" height="29" rx="1.5" transform="rotate(45 32.5063 12)" fill="black"/>
|
||||
<rect x="34.6274" y="32.5059" width="3" height="29" rx="1.5" transform="rotate(135 34.6274 32.5059)" fill="black"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; height: 100%;">
|
||||
<div class="modal_title_text" style="text-align: center;">
|
||||
<div>Please select the image size</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="downItem" v-for="item,key in loadList">
|
||||
<div class="title">{{ key }}</div>
|
||||
<div class="keyList">
|
||||
<div class="item" :class="{active:(DSizeItem == select?.size && key == select?.sizeType)}" v-for="DSizeItem in item" @click="downloadIamge(DSizeItem,key)">
|
||||
{{ DSizeItem }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 100%; display: flex; margin-top: auto;">
|
||||
<div class="gallery_btn" @click="setDown" style="width: 13rem; margin-left: auto;">Download</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mark_loading" v-show="isShowMark">
|
||||
<a-spin size="large" />
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent,computed,ref,provide,nextTick,createVNode,toRefs, reactive, onMounted} from 'vue'
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { Https } from "@/tool/https";
|
||||
import { useStore } from "vuex";
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { getCookie } from "@/tool/cookie";
|
||||
import { Modal,message } from 'ant-design-vue';
|
||||
import {getUploadUrl,rgbToHsv,isMoible} from '@/tool/util'
|
||||
|
||||
export default defineComponent({
|
||||
components:{
|
||||
},
|
||||
props:{
|
||||
},
|
||||
emits:['submitBrandAdd'],
|
||||
setup(props,{emit}) {
|
||||
const {t} = useI18n()
|
||||
const store = useStore();
|
||||
const data = reactive({
|
||||
threeDown:false,
|
||||
isShowMark:Object(''),
|
||||
loadList:{
|
||||
aa:[{a:1}],
|
||||
bb:[{a:1}],
|
||||
cc:[{a:1}]
|
||||
},
|
||||
select:{
|
||||
sizeType:'',
|
||||
size:'',
|
||||
threeDSimpleId:-1,
|
||||
},
|
||||
})
|
||||
const dataDom = reactive({
|
||||
})
|
||||
const cancelDsign = ()=>{
|
||||
data.threeDown = false;
|
||||
}
|
||||
const getDowList = (id:any)=>{
|
||||
data.isShowMark = true
|
||||
let value = {
|
||||
threeDSimpleId:id,
|
||||
// threeDSimpleId:id,
|
||||
}
|
||||
Https.axiosPost(Https.httpUrls.getThreeDSize,{},{params:value}).then((res:any)=>{
|
||||
data.loadList = res.sizeTypeMap
|
||||
data.isShowMark = false
|
||||
data.select.threeDSimpleId = id
|
||||
}).catch((err:any)=>{
|
||||
data.isShowMark = false
|
||||
})
|
||||
}
|
||||
const setDown = ()=>{
|
||||
data.isShowMark = true
|
||||
let value = {
|
||||
...data.select,
|
||||
}
|
||||
Https.axiosGet(Https.httpUrls.downloadZip,{params:value,env:{binary:true,binaryType:'application/octet-stream'}}).then((res:any)=>{
|
||||
console.log(res)
|
||||
//anchor 标签下载
|
||||
let a = document.createElement('a');
|
||||
a.href = res.url;
|
||||
a.download = 'model.zip'; // 设置下载的文件名
|
||||
a.click(); // 触发下载
|
||||
URL.revokeObjectURL(a.href); // 释放 URL 对象
|
||||
|
||||
data.isShowMark = false
|
||||
}).catch((err:any)=>{
|
||||
data.isShowMark = false
|
||||
})
|
||||
}
|
||||
const openDown = (id:any)=>{
|
||||
data.threeDown = true;
|
||||
getDowList(id)
|
||||
}
|
||||
const downloadIamge = (DSizeItem:any,key:any)=>{
|
||||
data.select.sizeType = key
|
||||
data.select.size = DSizeItem
|
||||
}
|
||||
return{
|
||||
...toRefs(dataDom),
|
||||
...toRefs(data),
|
||||
cancelDsign,
|
||||
setDown,
|
||||
openDown,
|
||||
downloadIamge,
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.threeDownPage{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
:deep(.generalModel){
|
||||
.content{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
> .downItem{
|
||||
display: flex;
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1rem;
|
||||
text-align: center;
|
||||
> .title{
|
||||
margin-right: 1.5rem;
|
||||
width: 3.5rem;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
> .keyList{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
> .item{
|
||||
font-weight: 300;
|
||||
width: 5.5rem;
|
||||
height: 5.5rem;
|
||||
border: 1px solid #000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all .3s;
|
||||
&.active{
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
&:hover{
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
273
src/component/HomePage/index/model/patternMaking3D/index.vue
Normal file
273
src/component/HomePage/index/model/patternMaking3D/index.vue
Normal file
@@ -0,0 +1,273 @@
|
||||
<template>
|
||||
<div class="patternMaking3D">
|
||||
<div class="selectModel">
|
||||
<div class="heard">Clothing</div>
|
||||
<div class="list">
|
||||
<div v-for="item in modelList" class="modelItem" :class="{active:item.id == selectModel.id}" @click="setSelectModel(item)">
|
||||
<img :src="item.url" alt="">
|
||||
</div>
|
||||
<div v-show="!isNoData" class="material_content_list_loding">
|
||||
<span class="page_loading" v-show="!isShowLoading" v-observe></span>
|
||||
<span v-show="isShowLoading">
|
||||
<a-spin size="large" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="model" v-show="selectModel.id != -1">
|
||||
<div class="heard">
|
||||
<div class="text">Technical sketch</div>
|
||||
<div class="switch">
|
||||
back
|
||||
<a-switch v-model:checked="isFront" />
|
||||
front
|
||||
</div>
|
||||
</div>
|
||||
<div class="modelBox">
|
||||
<div v-show="!imgOrThree" class="img">
|
||||
<img v-show="isFront" :src="selectModel.threeDLayoutList?.[0]?.url" alt="">
|
||||
<img v-show="!isFront" :src="selectModel.threeDLayoutList?.[1]?.url" alt="">
|
||||
</div>
|
||||
<threeBox v-show="imgOrThree" ref="threeBox"></threeBox>
|
||||
</div>
|
||||
<div class="gallery_btn" v-show="!imgOrThree" @click="setImgOrThree(true)">3D view</div>
|
||||
<div class="gallery_btn" v-show="imgOrThree" @click="setImgOrThree(false)">Img view</div>
|
||||
</div>
|
||||
<div class="flatPatterm" v-show="selectModel.id != -1">
|
||||
<div class="heard">Flat pattern</div>
|
||||
<div class="modelBox">
|
||||
<div class="img">
|
||||
<img :src="selectModel.threeDPatternLayoutUrl" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="gallery_btn" @click="openDown()">Download</div>
|
||||
</div>
|
||||
<div class="download">
|
||||
<download ref="download"></download>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent,computed,ref,provide,nextTick,createVNode,toRefs, reactive} from 'vue'
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { Https } from "@/tool/https";
|
||||
import { useStore } from "vuex";
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import threeBox from "./three.vue"
|
||||
import download from "./download.vue"
|
||||
export default defineComponent({
|
||||
components:{
|
||||
threeBox,download
|
||||
},
|
||||
props:{
|
||||
},
|
||||
emits:[],
|
||||
setup(props,{emit}) {
|
||||
const store = useStore();
|
||||
const data = reactive({
|
||||
selectModel:{
|
||||
id:-1,
|
||||
} as any,
|
||||
modelList:[] as any,
|
||||
isShowMark:false,
|
||||
isNoData:false,
|
||||
isShowLoading:false,
|
||||
currentPage:1,
|
||||
pageSize:10,
|
||||
imgOrThree:false,
|
||||
isFront:false,
|
||||
})
|
||||
const setSelectModel = (item:any)=>{
|
||||
data.isShowMark = true
|
||||
const value = {
|
||||
threeDSimpleId:item.id,
|
||||
}
|
||||
Https.axiosPost(Https.httpUrls.getLayoutDetail,{},{params:value}).then((res:any)=>{
|
||||
data.selectModel = res
|
||||
data.selectModel.id = item.id
|
||||
data.isShowMark = false
|
||||
data.imgOrThree = false
|
||||
// if(data.imgOrThree){
|
||||
// dataDom.threeBox.openSetData()
|
||||
// }
|
||||
store.commit('setPatternMaking3D',item.id)
|
||||
}).catch((err:any)=>{
|
||||
data.isShowMark = false
|
||||
})
|
||||
}
|
||||
const dataDom = reactive({
|
||||
threeBox:null as any,
|
||||
download:null as any,
|
||||
})
|
||||
const openSetData = ()=>{
|
||||
nextTick(()=>{
|
||||
let id = store.state.HomeStoreModule.patternMaking3D
|
||||
if(id && data.selectModel.id == -1)setSelectModel({id})
|
||||
})
|
||||
}
|
||||
const getModelList = ()=>{
|
||||
if(data.isShowMark && !data.isNoData)return
|
||||
let value = {
|
||||
page: data.currentPage,
|
||||
size:data.pageSize,
|
||||
|
||||
}
|
||||
data.isShowLoading = true
|
||||
Https.axiosPost(Https.httpUrls.threeDPage,value).then(
|
||||
(rv: any) => {
|
||||
if(rv.content.length == 0)data.isNoData = true
|
||||
data.isShowLoading = false
|
||||
data.modelList.push(...rv.content)
|
||||
}
|
||||
).catch((res)=>{
|
||||
data.isNoData = true
|
||||
});
|
||||
}
|
||||
const setImgOrThree = (boolean:boolean)=>{
|
||||
data.imgOrThree = boolean
|
||||
if(boolean){
|
||||
nextTick(()=>{
|
||||
dataDom.threeBox.openSetData(data.selectModel)
|
||||
// dataDom.threeBox.openSetData(data.selectModel.threeDPatternLayoutUrl)
|
||||
})
|
||||
}
|
||||
}
|
||||
const downList = ()=>{
|
||||
let value = {
|
||||
|
||||
}
|
||||
Https.axiosGet(Https.httpUrls.threeDPage,value).then(
|
||||
|
||||
)
|
||||
}
|
||||
const openDown = ()=>{
|
||||
dataDom.download.openDown(data.selectModel.id)
|
||||
}
|
||||
return{
|
||||
...toRefs(dataDom),
|
||||
...toRefs(data),
|
||||
setSelectModel,
|
||||
openSetData,
|
||||
getModelList,
|
||||
setImgOrThree,
|
||||
openDown,
|
||||
}
|
||||
},
|
||||
directives:{
|
||||
observe:{
|
||||
mounted (el,binding) {
|
||||
// console.log(binding.instance);
|
||||
let this_:any = binding.instance
|
||||
this_.isShowMark = false
|
||||
this_.isNoData = false
|
||||
let parentDom = el.parentNode
|
||||
this_.getModelList()
|
||||
new IntersectionObserver(
|
||||
(entries, observer) => {
|
||||
// 如果不是相交,则直接返回
|
||||
// console.log(entries[0]);
|
||||
if (!entries[0].intersectionRatio) return;
|
||||
this_.currentPage += 1
|
||||
this_.getModelList()
|
||||
},
|
||||
).observe(el);
|
||||
},
|
||||
},
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.patternMaking3D{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
font-size: 1.4rem;
|
||||
> .selectModel,> .model,>.flatPatterm{
|
||||
padding: 3rem 2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
> .heard{
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
> .switch{
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
> .selectModel{
|
||||
width: 70rem;
|
||||
flex-shrink: 0;
|
||||
height: 100%;
|
||||
background: #f7f8fa;
|
||||
border-radius: 3rem;
|
||||
> .list{
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow-y: auto;
|
||||
align-content: flex-start;
|
||||
> .modelItem{
|
||||
width: calc(100% / 4 - 1rem);
|
||||
margin: .5rem;
|
||||
aspect-ratio: 1 / 1.2;
|
||||
border-radius: 2rem;
|
||||
border: 2px solid #D4D4D4;
|
||||
cursor: pointer;
|
||||
> img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
&.active{
|
||||
border: 2px solid #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
> .model ,> .flatPatterm{
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
> .modelBox{
|
||||
width: 100%;
|
||||
height: 20rem;
|
||||
height: 75rem;
|
||||
margin: auto;
|
||||
>.img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.material_content_list_loding{
|
||||
text-align: center;
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
.page_loading{
|
||||
display: block;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
.download{
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
391
src/component/HomePage/index/model/patternMaking3D/three.vue
Normal file
391
src/component/HomePage/index/model/patternMaking3D/three.vue
Normal file
@@ -0,0 +1,391 @@
|
||||
<template>
|
||||
<div class="three">
|
||||
<div class="model" ref="threeDom">
|
||||
|
||||
</div>
|
||||
<div class="load" v-show="load.state">
|
||||
<i class="fi fi-rr-cubes"></i>
|
||||
<div class="text">Load...</div>
|
||||
<div class="loadBox">
|
||||
<div class="schedule" :style="{width:load.progress+'%'}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent,computed,shallowRef,provide,nextTick,onMounted,toRefs, reactive} from 'vue'
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { Https } from "@/tool/https";
|
||||
import { useStore } from "vuex";
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
// @ts-ignore
|
||||
import * as THREE from 'three';
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
||||
|
||||
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
|
||||
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
|
||||
import { OutlinePass } from "three/addons/postprocessing/OutlinePass.js";
|
||||
import gsap from 'gsap';
|
||||
import { env } from 'echarts';
|
||||
|
||||
export default defineComponent({
|
||||
components:{
|
||||
},
|
||||
props:{
|
||||
},
|
||||
emits:[],
|
||||
setup(props,{emit}) {
|
||||
const store = useStore();
|
||||
const data = reactive({
|
||||
scene:shallowRef() as any,//场景
|
||||
group:shallowRef() as any,//组
|
||||
camera:shallowRef() as any,//相机
|
||||
renderer:shallowRef() as any,//渲染器
|
||||
pointLight:shallowRef() as any,//光
|
||||
controls:shallowRef() as any,//监听鼠标、键盘事件
|
||||
load:{
|
||||
state:false,
|
||||
progress:0 as any,
|
||||
}
|
||||
})
|
||||
const dataDom = reactive({
|
||||
threeDom:null as any,
|
||||
})
|
||||
const init = ()=>{
|
||||
data.scene = new THREE.Scene();
|
||||
data.group = new THREE.Group()
|
||||
data.scene.add(data.group)
|
||||
|
||||
//创建相机对象
|
||||
// this.camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
|
||||
data.camera = new THREE.PerspectiveCamera(45, dataDom.threeDom.offsetWidth / dataDom.threeDom.offsetHeight, 0.1, 10000);
|
||||
data.camera.position.set(0, 90, 6); //设置相机位置
|
||||
data.camera.lookAt(data.scene.position); //设置相机方向(指向的场景对象)
|
||||
|
||||
/**
|
||||
* 创建渲染器对象
|
||||
*/
|
||||
let width = dataDom.threeDom.offsetWidth; //窗口宽度
|
||||
let height = dataDom.threeDom.offsetHeight; //窗口高度
|
||||
data.renderer = new THREE.WebGLRenderer({
|
||||
antialias: true,
|
||||
logarithmicDepthBuffer: true,//深度缓存 防止模型闪烁重影
|
||||
});
|
||||
|
||||
// data.renderer.outpuEncoding = THREE?.RGBEEncoding//设置输出颜色编码格式
|
||||
|
||||
data.renderer.toneMapping = THREE.ACESFilmicToneMapping;//设置色调
|
||||
data.renderer.toneMappingExposure = 1.3;
|
||||
|
||||
data.renderer.shadowMap.enabled = true;
|
||||
data.renderer.setPixelRatio(window.devicePixelRatio);
|
||||
data.renderer.setSize(width, height); //设置渲染区域尺寸
|
||||
data.renderer.setClearColor(0xffffff, 1); //设置背景颜色
|
||||
dataDom.threeDom.innerHTML = '';
|
||||
dataDom.threeDom.appendChild(data.renderer.domElement);
|
||||
// 设置渲染器大小
|
||||
//环境光
|
||||
let ambient = new THREE.AmbientLight(0xffffff,.8);
|
||||
data.scene.add(ambient);
|
||||
data.controls = new OrbitControls(data.camera,data.renderer.domElement)//监听鼠标、键盘事件;
|
||||
// data.controls.minDistance = 500; // 设置相机与焦点的最小距离
|
||||
// data.controls.maxDistance = 4000; // 设置相机与焦点的最大距离
|
||||
data.controls.mouseButtons = {
|
||||
// LEFT:THREE.MOUSE.PAN, // 左键 拖动(默认旋转:ROTATE)
|
||||
LEFT:THREE.MOUSE.ROTATE, // 左键 拖动(默认旋转:ROTATE)
|
||||
MIDDLE:THREE.MOUSE.DOLLY, // 滑轮 缩放
|
||||
RIGHT:THREE.MOUSE.PAN // 右键 旋转(默认拖动:PAN)
|
||||
// RIGHT:THREE.MOUSE.ROTAafTE // 右键 旋转(默认拖动:PAN)
|
||||
}
|
||||
/**
|
||||
* 光源设置
|
||||
*/
|
||||
//点光源
|
||||
/**
|
||||
* AmbientLight 环境光
|
||||
PointLight 点光源
|
||||
DirectionalLight 平行光,比如太阳光
|
||||
SpotLight 聚光源
|
||||
*/
|
||||
data.pointLight = new THREE.DirectionalLight(0xffffff,.5);
|
||||
data.pointLight.intensity = 1.2
|
||||
data.pointLight.castShadow = true//开启阴影
|
||||
data.pointLight.shadow.mapSize = new THREE.Vector2(width, height)
|
||||
data.scene.add(data.pointLight); //点光源添加到场景中
|
||||
// data.pointLight.position.set(400, 200, 300); //点光源位置
|
||||
data.pointLight.position.y = 400;
|
||||
data.pointLight.position.z = 200;
|
||||
data.pointLight.position.x = 200;
|
||||
let floorGeometry = new THREE.PlaneGeometry(5000, 3000)//地板大小
|
||||
let floorMaterial = new THREE.MeshPhongMaterial({ color: "#7e7ab0", })
|
||||
let floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);
|
||||
floorMesh.rotation.x = -0.5 * Math.PI;
|
||||
floorMesh.receiveShadow = true;
|
||||
floorMesh.position.y = -0.001;
|
||||
data.scene.add(floorMesh);
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
// const texture = textureLoader.load('/3dModel/sketch-thick.jpg');
|
||||
data.scene.background = new THREE.Color("#eee");
|
||||
// data.scene.background = texture;
|
||||
|
||||
let openModel = (event:any)=>{
|
||||
let mouse=new THREE.Vector2();
|
||||
let raycaster=new THREE.Raycaster();
|
||||
mouse.x=(event.clientX/window.innerWidth)*2-1;
|
||||
mouse.y=-(event.clientY/window.innerHeight)*2+1;
|
||||
raycaster.setFromCamera(mouse, data.camera);
|
||||
let intersects = raycaster.intersectObjects(data.scene.children);
|
||||
return intersects
|
||||
}
|
||||
|
||||
dataDom.threeDom.ondblclick = (event:any)=>{
|
||||
let intersects = openModel(event);
|
||||
if(!intersects || intersects.length<=0) return
|
||||
const bbox = new THREE.Box3().setFromObject(intersects[0].object);
|
||||
const size = new THREE.Vector3();
|
||||
let target2 = bbox.getCenter(size);//获取选中包围起来后的中心坐标
|
||||
animateCamera(data.camera.position,intersects[0].point,data.controls.target,target2)
|
||||
}
|
||||
let isTweening = false;
|
||||
function animateCamera(current1:any, target1:any, current2:any, target2:any){
|
||||
if (isTweening) return
|
||||
isTweening = true
|
||||
let options = {
|
||||
x1: current1.x, // 相机当前位置x
|
||||
y1: current1.y, // 相机当前位置y
|
||||
z1: current1.z, // 相机当前位置z
|
||||
x2: current2.x, // 控制当前的中心点x
|
||||
y2: current2.y, // 控制当前的中心点y
|
||||
// z2: current2.z // 控制当前的中心点z
|
||||
}
|
||||
gsap.to(options,{
|
||||
x1: 0, // 新的相机位置x
|
||||
y1: target2.y, // 新的相机位置y
|
||||
z1: 2500, // 新的相机位置z
|
||||
x2: 0, // 新的控制中心点位置x
|
||||
y2: target2.y, // 新的控制中心点位置x
|
||||
duration:1,
|
||||
ease:'linear',
|
||||
onUpdate:()=>{
|
||||
data.camera.position.x = options.x1;
|
||||
data.camera.position.y = options.y1;
|
||||
data.camera.position.z = options.z1;
|
||||
data.controls.target.x = options.x2;
|
||||
data.controls.target.y = options.y2;
|
||||
// data.controls.target.z = object.z2;
|
||||
data.controls.update();
|
||||
},
|
||||
onComplete:()=>{
|
||||
isTweening = false
|
||||
}
|
||||
// z2: target2.z // 新的控制中心点位置x
|
||||
})
|
||||
}
|
||||
// let setHighlight = (obj:any)=>{
|
||||
// outlinePass.selectedObjects = obj;
|
||||
// }
|
||||
|
||||
|
||||
data.controls.enableDamping = true;
|
||||
let animate = function () {
|
||||
requestAnimationFrame(animate);
|
||||
// data.renderer.render(data.scene, data.camera);
|
||||
// model.rotation.x += 0.01; //旋转物体
|
||||
var vector = data.camera.position.clone()
|
||||
data.controls.update();
|
||||
data.renderer.render(data.scene, data.camera);
|
||||
// point.position.set(vector.x,vector.y,vector.z);
|
||||
// group.rotation.y += 0.01;
|
||||
|
||||
// composer.render();
|
||||
};
|
||||
animate();
|
||||
}
|
||||
const setModel = async (url:any)=>{
|
||||
clearModel()
|
||||
await addModel(url)
|
||||
// addMaterial()
|
||||
}
|
||||
const addMaterial = ()=>{
|
||||
//添加图片材质
|
||||
data.load.state = true
|
||||
let textureLoader = new THREE.TextureLoader()
|
||||
textureLoader.load('/3dModel/texture0.webp', // 图片放在public/textures目录下
|
||||
(texture:any) => {
|
||||
// 3. 配置纹理参数
|
||||
texture.wrapS = THREE.RepeatWrapping;
|
||||
texture.wrapT = THREE.RepeatWrapping;
|
||||
texture.repeat.set(1, 1); // 纹理重复次数
|
||||
texture.anisotropy = 32; // 提高纹理清晰度
|
||||
data.group?.traverse((child:any) => {
|
||||
if (child.isMesh) {
|
||||
// 5. 创建新材质(根据需求选择材质类型)
|
||||
const newMaterial = new THREE.MeshStandardMaterial({
|
||||
map: texture, // 基础颜色贴图
|
||||
roughness: 0.7, // 表面粗糙度 (0-1)
|
||||
metalness: 0.2, // 金属质感 (0-1)
|
||||
side: THREE.DoubleSide // 双面渲染
|
||||
});
|
||||
console.log(child)
|
||||
// 6. 替换原有材质
|
||||
child.material = newMaterial;
|
||||
|
||||
// 7. 如果需要单独控制某些子模型的UV
|
||||
if (child.geometry.attributes.uv) {
|
||||
// 可以在这里修改UV坐标
|
||||
const uvs = child.geometry.attributes.uv.array;
|
||||
// ...UV操作逻辑...
|
||||
}
|
||||
}
|
||||
data.load.state = false
|
||||
},(xhr:any) => { // 加载进度回调
|
||||
console.log(xhr.loaded , xhr.total)
|
||||
const percent = xhr.total == 0?100:(xhr.loaded / xhr.total * 100).toFixed(2);
|
||||
data.load.progress = percent
|
||||
// updateProgressBar(Number(percent));
|
||||
},(error:any) => {
|
||||
console.error('纹理加载失败:', error);
|
||||
data.load.state = false
|
||||
});
|
||||
})
|
||||
}
|
||||
const addModel = async (url:any)=>{
|
||||
await new Promise((resolve, reject) => {
|
||||
var fbxLoader = new GLTFLoader();
|
||||
let drac = new DRACOLoader()
|
||||
drac.setDecoderPath('/draco/')
|
||||
fbxLoader.setDRACOLoader(drac)
|
||||
// fbxLoader.load('/3dModel/222/1111.glb',
|
||||
fbxLoader.load(url,
|
||||
|
||||
(obj:any) => {
|
||||
let scene = obj.scene;
|
||||
var box = new THREE.Box3().setFromObject(scene);
|
||||
var center = box.getCenter(new THREE.Vector3());
|
||||
data.controls.target.copy(center);
|
||||
// data.controls.autoRotate = true
|
||||
data.camera.position.y = center.y;
|
||||
data.camera.position.z = 1000;
|
||||
data.pointLight.position.y = 250;
|
||||
data.pointLight.position.z = 1250;
|
||||
data.group.add(scene);
|
||||
resolve('')
|
||||
},(xhr:any) => { // 加载进度回调
|
||||
console.log(xhr.loaded , xhr.total)
|
||||
const percent = xhr.total == 0?100:(xhr.loaded / xhr.total * 100).toFixed(2);
|
||||
console.log(`模型加载进度: ${percent}%`);
|
||||
data.load.progress = percent
|
||||
// updateProgressBar(Number(percent));
|
||||
},(error:any) => { // 加载失败回调
|
||||
console.error('模型加载失败:', error);
|
||||
reject('')
|
||||
})
|
||||
})
|
||||
}
|
||||
const clearModel = ()=>{
|
||||
const oldGroup:any = data.group;
|
||||
data.group = new THREE.Group();
|
||||
data.scene.add(data.group);
|
||||
data.scene.remove(oldGroup);
|
||||
}
|
||||
// const loadThree = ()=>{
|
||||
|
||||
// init()
|
||||
// }
|
||||
const getModelUrl = (value:any)=>{
|
||||
console.log(12314343)
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
// Https.axiosGet(Https.httpUrls.getThreeDGlb,{params:{threeDSimpleId:value.id},env:{binary:true}}).then((rv)=>{
|
||||
// //二进制流转本地路径
|
||||
|
||||
// console.log(rv)
|
||||
// resolve(rv)
|
||||
// }).catch(()=>{
|
||||
// reject('')
|
||||
// })
|
||||
// //fetch get请求携带token
|
||||
|
||||
|
||||
// fetch("https://develop.api.aida.com.hk/api/project/getThreeDGlb?threeDSimpleId=1", {
|
||||
// headers:{
|
||||
// authorization:'Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiI4OCIsInN1YiI6IntcImNvdW50cnlcIjpcIkNoaW5hXCIsXCJpZFwiOjg4LFwibGFuZ3VhZ2VcIjpcIkVOR0xJU0hcIixcInVzZXJuYW1lXCI6XCJzaGJcIn0iLCJpYXQiOjE3NDMzNDkwNjQsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE3NTE5ODkwNjR9.gmL0JufYy9wd23qCY-ibwhgpXZ2X68WAiHSeC99I4x7cipWyxLaQmuIBk2SJSdWBm0tTN2Mx-etXO9a7MtQmpw',
|
||||
// }
|
||||
// }).then(res => {
|
||||
// return res.blob();
|
||||
// }).then((res) => {
|
||||
// var url = URL.createObjectURL(res);
|
||||
// console.log(url, res)
|
||||
// resolve(url)
|
||||
// }).catch(err => {
|
||||
// console.log(err);
|
||||
// })
|
||||
resolve(value.threeDSimpleUrl)
|
||||
})
|
||||
}
|
||||
const openSetData = async (value:any)=>{
|
||||
if(!data.scene){
|
||||
init()
|
||||
}
|
||||
data.load.state = true
|
||||
const modeUrl = await getModelUrl(value)
|
||||
await setModel(modeUrl)
|
||||
data.load.state = false
|
||||
}
|
||||
onMounted(()=>{
|
||||
})
|
||||
return{
|
||||
...toRefs(dataDom),
|
||||
...toRefs(data),
|
||||
openSetData,
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.three{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
> .model{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
> .load{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: rgba(0, 0, 0, .2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
color: #fff;
|
||||
> i{
|
||||
font-size: 3rem;
|
||||
}
|
||||
> .loadBox{
|
||||
width: 15rem;
|
||||
height: 1rem;
|
||||
border-radius: 1rem;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
> .schedule{
|
||||
height: 100%;
|
||||
background: greenyellow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user