<template>
|
<div class="showModel" v-loading="loading">
|
<div :id="'container' + props.md5 + props.index" class="viewer-container" v-if="props.md5"></div>
|
<el-empty v-else description="暂无数据" image-size="80" />
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { ref, onMounted, defineProps,inject } from "vue";
|
import * as THREE from "three";
|
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
|
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
const props = defineProps<{md5:string,index:number}>();
|
const config: any = inject("config");
|
const loading = ref<boolean>(false);
|
onMounted(() => {
|
loading.value = true;
|
if(props.md5) {
|
initThree();
|
} else {
|
loading.value = false;
|
}
|
});
|
const initThree = () => {
|
const container = document.getElementById("container" + props.md5 + props.index);
|
const scene = new THREE.Scene();
|
const camera = new THREE.PerspectiveCamera(
|
75,
|
container.clientWidth / container.clientHeight,
|
0.1,
|
10000 // 增大远平面距离
|
);
|
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
renderer.setSize(container.clientWidth, container.clientHeight);
|
container.appendChild(renderer.domElement);
|
|
// 添加光源
|
const light = new THREE.DirectionalLight(0xffffff, 2);
|
light.position.set(5, 10, 7.5);
|
scene.add(light);
|
|
// 加载模型
|
const loader = new FBXLoader();
|
const token = localStorage.getItem(config.tokenKey);
|
loader.load(
|
config.requestCtx +
|
"/file/FileDownload/Download?md5=" +
|
props.md5 +
|
"&token=" +
|
token,
|
(object) => {
|
scene.add(object);
|
|
// 创建控件
|
const controls = new OrbitControls(camera, renderer.domElement);
|
controls.enableDamping = true;
|
controls.dampingFactor = 0.25;
|
controls.screenSpacePanning = false;
|
|
// 1. 计算模型尺寸和中心点
|
const box = new THREE.Box3().setFromObject(object);
|
const center = box.getCenter(new THREE.Vector3());
|
const size = box.getSize(new THREE.Vector3());
|
|
// 2. 计算合适的相机距离
|
const maxDim = Math.max(size.x, size.y, size.z);
|
const fov = camera.fov * (Math.PI / 180);
|
let cameraDistance = Math.abs(maxDim / (2 * Math.tan(fov / 2)));
|
|
// 3. 设置相机位置和方向
|
camera.position.copy(center);
|
camera.position.z += cameraDistance * 1.5; // 增加50%的额外空间
|
camera.lookAt(center);
|
|
// 4. 更新控件目标点
|
controls.target.copy(center);
|
controls.update();
|
|
// 5. 调整相机剪裁平面
|
const minDistance = cameraDistance * 0.1;
|
const maxDistance = cameraDistance * 10;
|
camera.near = minDistance > 0.1 ? minDistance : 0.1;
|
camera.far = maxDistance < 10000 ? maxDistance : 10000;
|
camera.updateProjectionMatrix();
|
|
function animate() {
|
requestAnimationFrame(animate);
|
controls.update();
|
renderer.render(scene, camera);
|
}
|
animate();
|
loading.value = false;
|
},
|
undefined,
|
(error) => {
|
console.error("加载模型失败:", error);
|
loading.value = false;
|
}
|
);
|
};
|
</script>
|
|
<style lang="less" scoped>
|
.showModel,
|
.viewer-container {
|
width: 100%;
|
height: 100%;
|
}
|
</style>
|