|
|
|
@ -70,7 +70,7 @@ |
|
|
|
</template> |
|
|
|
<script setup> |
|
|
|
import TransformEdit from '@/components/propertyEdit/TransformEdit.vue' |
|
|
|
import { ref, onMounted, nextTick, reactive, watch } from 'vue' |
|
|
|
import { ref, onMounted, nextTick, reactive, watch, getCurrentInstance, onUnmounted, onBeforeUnmount } from 'vue' |
|
|
|
import * as THREE from 'three' |
|
|
|
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' |
|
|
|
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader' |
|
|
|
@ -92,7 +92,7 @@ const transformEditCtl = ref(null) |
|
|
|
// Three.js 场景相关 |
|
|
|
let scene, camera, renderer, controls |
|
|
|
let statsControls, axesHelper, gridHelper |
|
|
|
let gui, tcontrols, modelGroup |
|
|
|
let gui, tcontrols, modelGroup, resizeObserver |
|
|
|
|
|
|
|
const restate = reactive({ |
|
|
|
targetColor: '#ff0000', |
|
|
|
@ -116,7 +116,29 @@ onMounted(() => { |
|
|
|
nextTick(() => { |
|
|
|
initThree() |
|
|
|
initGUI() |
|
|
|
|
|
|
|
const viewerDom = canvasContainer.value |
|
|
|
if (resizeObserver) { |
|
|
|
resizeObserver.unobserve(viewerDom) |
|
|
|
} |
|
|
|
resizeObserver = new ResizeObserver(handleResize) |
|
|
|
resizeObserver.observe(viewerDom) |
|
|
|
|
|
|
|
window['model3dView'] = getCurrentInstance() |
|
|
|
window['model3dViewRenderer'] = renderer |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
onBeforeUnmount(() => { |
|
|
|
cleanupThree() |
|
|
|
|
|
|
|
const viewerDom = canvasContainer.value |
|
|
|
if (resizeObserver) { |
|
|
|
resizeObserver.unobserve(viewerDom) |
|
|
|
} |
|
|
|
|
|
|
|
window['model3dView'] = null |
|
|
|
window['model3dViewRenderer'] = null |
|
|
|
}) |
|
|
|
|
|
|
|
watch(() => restate.targetColor, (newVal) => { |
|
|
|
@ -221,11 +243,6 @@ function initThree() { |
|
|
|
// tcontrols.size = 1 |
|
|
|
// tcontrols.space = 'local' |
|
|
|
scene.add(tcontrols.getHelper()) |
|
|
|
|
|
|
|
// 创建ResizeObserver实例并传入处理函数 |
|
|
|
const resizeObserver = new ResizeObserver(handleResize) |
|
|
|
// 开始观察指定的DOM元素 |
|
|
|
resizeObserver.observe(viewerDom) |
|
|
|
} |
|
|
|
|
|
|
|
// 动画循环 |
|
|
|
@ -397,6 +414,9 @@ function handleTextureUpload(file) { |
|
|
|
|
|
|
|
file = file.raw |
|
|
|
|
|
|
|
// 移除旧模型 |
|
|
|
cleaupModel() |
|
|
|
|
|
|
|
const fileName = file.name.toLowerCase() |
|
|
|
const reader = new FileReader() |
|
|
|
reader.onerror = (error) => { |
|
|
|
@ -435,12 +455,7 @@ function handleMtlUpload(file) { |
|
|
|
file = file.raw |
|
|
|
|
|
|
|
// 移除旧模型 |
|
|
|
if (modelGroup) { |
|
|
|
scene.remove(modelGroup) |
|
|
|
} |
|
|
|
tcontrols.detach() |
|
|
|
transformEditCtl.value.detach() |
|
|
|
modelGroup = null |
|
|
|
cleaupModel() |
|
|
|
|
|
|
|
const fileName = file.name.toLowerCase() |
|
|
|
const reader = new FileReader() |
|
|
|
@ -528,11 +543,7 @@ function handleFileChange(file) { |
|
|
|
file = file.raw |
|
|
|
|
|
|
|
// 移除旧模型 |
|
|
|
if (modelGroup) { |
|
|
|
scene.remove(modelGroup) |
|
|
|
} |
|
|
|
tcontrols.detach() |
|
|
|
transformEditCtl.value.detach() |
|
|
|
cleaupModel() |
|
|
|
|
|
|
|
const fileName = file.name.toLowerCase() |
|
|
|
const reader = new FileReader() |
|
|
|
@ -582,6 +593,76 @@ function handleFileChange(file) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function cleaupModel() { |
|
|
|
if (modelGroup) { |
|
|
|
scene.remove(modelGroup) |
|
|
|
} |
|
|
|
tcontrols.detach() |
|
|
|
transformEditCtl.value.detach() |
|
|
|
} |
|
|
|
|
|
|
|
function cleanupThree() { |
|
|
|
// 移除旧模型 |
|
|
|
if (scene) { |
|
|
|
scene.traverse((obj) => { |
|
|
|
// 释放几何体 |
|
|
|
if (obj.geometry) { |
|
|
|
obj.geometry.dispose() |
|
|
|
} |
|
|
|
|
|
|
|
// 释放材质 |
|
|
|
if (obj.material) { |
|
|
|
if (Array.isArray(obj.material)) { |
|
|
|
obj.material.forEach(m => m.dispose()) |
|
|
|
} else { |
|
|
|
obj.material.dispose() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 释放纹理 |
|
|
|
if (obj.texture) { |
|
|
|
obj.texture.dispose() |
|
|
|
} |
|
|
|
|
|
|
|
// 释放渲染目标 |
|
|
|
if (obj.renderTarget) { |
|
|
|
obj.renderTarget.dispose() |
|
|
|
} |
|
|
|
|
|
|
|
// 移除事件监听(如 OrbitControls) |
|
|
|
if (obj.dispose) { |
|
|
|
obj.dispose() |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
if (modelGroup) { |
|
|
|
scene.remove(modelGroup) |
|
|
|
} |
|
|
|
// 清空场景 |
|
|
|
scene.children = [] |
|
|
|
|
|
|
|
modelGroup = null |
|
|
|
} |
|
|
|
|
|
|
|
if (gui) { |
|
|
|
gui.destroy() |
|
|
|
} |
|
|
|
if (tcontrols) { |
|
|
|
tcontrols.dispose() |
|
|
|
} |
|
|
|
if (statsControls) { |
|
|
|
statsControls.dom.remove() |
|
|
|
} |
|
|
|
|
|
|
|
if (renderer) { |
|
|
|
renderer.dispose() |
|
|
|
renderer.forceContextLoss() |
|
|
|
console.log('WebGL disposed, memory:', renderer.info.memory) |
|
|
|
renderer.domElement = null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
</script> |
|
|
|
<style scoped lang="less"> |
|
|
|
.model3d-view { |
|
|
|
|