Files
ece.suwa3d.com/src/components/modelGsplat/index.vue
T
2025-06-05 09:25:26 +08:00

272 lines
7.3 KiB
Vue

<script lang="ts" setup>
import { ref } from 'vue'
import * as SPLAT from 'gsplat'
import { showSuccessToast, showToast } from 'vant'
const props = defineProps({
modelFile: { type: String, default: () => '' },
pid: { type: Number, default: 0 },
})
const emit = defineEmits([
'changeBackgound',
'rotateControl',
'handleProgress',
'handleLoaded',
])
const scene = new SPLAT.Scene()
const camera = new SPLAT.Camera()
const splat = ref(null)
const color = new SPLAT.Color32()
const renderer = new SPLAT.WebGLRenderer()
const controls = new SPLAT.OrbitControls(camera, renderer.canvas)
const STATE = {
NONE: -1,
MOVE: 0,
ZOOM_OR_PAN: 1,
POSITION_MOVE: 1,
}
const mouseInfo = ref({ startX: 0, startY: 0, isDown: false, startPointerDistance: 0, state: STATE.NONE })
// let model, scene, camera, renderer, controls;
const preventStop = ref(false)
const autoRotate = ref(false)
const rotateInterval = ref(null)
const twoFirst = ref(true)
const lastPoint = ref(
{
touchStartX1: 0,
touchStartY1: 0,
touchStartX2: 0,
touchStartY2: 0,
},
)
watch(() => props.modelFile, (val, oldVal) => {
if (val) {
main(val)
// setTimer()
}
}, {
immediate: true,
})
const initCameraRotation = ref(null)
const initCameraPosition = ref(null)
const initCameraScale = ref(null)
const initialRotation = ref(null)
const DEG2RAD = Math.PI / 180
let animationFrameId
// onMounted(async () => {
// await main()
// })
// 监听组件销毁事件
onBeforeUnmount(() => {
// 销毁 Three.js 模型
splat.value = null
// 清理渲染器
renderer.dispose()
if (animationFrameId)
cancelAnimationFrame(animationFrameId)
if (renderer.canvas.parentNode)
renderer.canvas.parentNode.removeChild(renderer.canvas)
})
async function main(val) {
// 初始背景
renderer.canvas.style.background = 'transparent'
controls.orbitSpeed = 3 // 设置相机旋转速度
// 初始化模型
const url = val;
// const url = 'https://suwa3d-test.oss-cn-shanghai.aliyuncs.com/plys/151322_superpoint.ply'
// const url = "https://suwa3d-test.oss-cn-shanghai.aliyuncs.com/test/glbs/auto/195231.splat";
// const url = "https://suwa3d-test.oss-cn-shanghai.aliyuncs.com/test/glbs/auto/192571.splat";
splat.value = await SPLAT.Loader.LoadAsync(url, scene, (e) => {
if(e == 1) {
emit("handleLoaded")
}else {
emit("handleProgress",e * 100)
}
});
console.log("splat.value", splat.value)
// splat.value = await SPLAT.PLYLoader.LoadAsync(url, scene, (e) => {
// console.log('e', e)
// if (e == 1)
// emit('handleLoaded')
// else
// emit('handleProgress', e * 100)
// })
const rotation = new SPLAT.Vector3(-3.2, -0.5, 0)
splat.value.rotation = SPLAT.Quaternion.FromEuler(rotation)
splat.value.position = new SPLAT.Vector3(0, -0.8, 0)
splat.value.scale = new SPLAT.Vector3(1.5, 1.5, 1.5)
splat.value.applyPosition()
splat.value.applyRotation()
splat.value.applyScale()
// splat.value.scale = new SPLAT.Vector3(1, 1, 1)
const frame = () => {
controls.update()
renderer.render(scene, camera)
animationFrameId = requestAnimationFrame(frame)
}
animationFrameId = requestAnimationFrame(frame)
// 获取到初始状态的位置
initCameraRotation.value = camera.rotation
initCameraPosition.value = camera.position
initCameraScale.value = camera.scale
initialRotation.value = splat.value.rotation.clone()
// 监听缩放\旋转操作
renderer.canvas.addEventListener('touchmove', (event) => {
// console.log("camera.rotation", camera.rotation)
// handleTouchStart(event)
})
}
// -------------------------------事件-------------------------------
// 设置背景颜色
const changeColorChild = (type, index, param) => {
renderer.canvas.style.background = param
emit('changeBackgound', index)
}
// 设置自定义背景
const changeTransparent = (type, index, param) => {
renderer.canvas.style.background = 'transparent'
emit('changeBackgound', index)
}
// 按钮事件
const controlEvent = (val) => {
// let data = localStorage.get("positionData");
// let foundData = false;
// data.filter(item=>{
// if (item.pid == props.pid && props.pid > 0 && !foundData) {
// foundData = true;
if (val == 1) {
ResetPosition()
} else if (val == 2) {
// 保存当前位置
initCameraRotation.value = camera.rotation;
initCameraPosition.value = camera.position;
initCameraScale.value = camera.scale;
showSuccessToast('保存成功'.$t)
} else if (val == 3) {
spin()
} else if (val == 4) {
spin()
}
// })
}
const ResetPosition = () => {
if(!autoRotate.value) {
camera.rotation = initCameraRotation.value
camera.position = initCameraPosition.value
camera.scale = initCameraScale.value
const rotation = new SPLAT.Vector3(0, -count.value, 0)
splat.value.rotation = SPLAT.Quaternion.FromEuler(rotation)
// splat.value.scale = new SPLAT.Vector3(0.5, 0.5, 0.5)
splat.value.applyRotation()
// splat.value.applyScale();
// splat.value.rotation = SPLAT.Quaternion.FromAxisAngle(new SPLAT.Vector3(0, 1, 0), DEG2RAD * 87);
// splat.value.applyRotation();
console.log('splat.value.scale', splat.value.scale)
}
}
// 旋转
const spin = () => {
if (!autoRotate.value) {
if (preventStop.value)
return
setTimer()
} else {
clearTimer()
}
}
const count = ref(0);
// 开启自动旋转
const setTimer = () => {
const val = initCameraRotation.value;
clearInterval(rotateInterval.value);
rotateInterval.value = setInterval(() => {
const a = 0.03
const rotation = new SPLAT.Vector3(0, a, 0)
splat.value.rotation = SPLAT.Quaternion.FromEuler(rotation)
splat.value.applyRotation()
count.value +=0.03
// let cameraRotation = new SPLAT.Vector3(0, a, 0)
// camera.position = new SPLAT.Vector3(x, y, z);
// console.log("initCameraRotation", scene.objects[0])
// val.y -=0.05;
// camera.rotation = SPLAT.Quaternion.FromAxisAngle(val, DEG2RAD * 87);
}, 100)
autoRotate.value = true
emit('rotateControl', true)
}
// 关闭自动旋转
const clearTimer = () => {
clearInterval(rotateInterval.value)
rotateInterval.value = null
autoRotate.value = false
emit('rotateControl', false)
}
const onKeyDown = (event: KeyboardEvent) => {
// Use i, j, k, l to move the camera around
let translation = new SPLAT.Vector3()
if (event.key === 'j')
translation = translation.add(new SPLAT.Vector3(-1, 0, 0))
if (event.key === 'l')
translation = translation.add(new SPLAT.Vector3(1, 0, 0))
if (event.key === 'i')
translation = translation.add(new SPLAT.Vector3(0, 0, 1))
if (event.key === 'k')
translation = translation.add(new SPLAT.Vector3(0, 0, -1))
camera.position = camera.position.add(translation)
// Use u to set a random look target near the origin
if (event.key === 'u') {
const target = new SPLAT.Vector3(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5)
controls.setCameraTarget(target)
}
// Use space to reset the camera
if (event.key === ' ') {
camera.position = new SPLAT.Vector3()
camera.rotation = new SPLAT.Quaternion()
}
}
window.addEventListener('keydown', onKeyDown)
defineExpose({
changeColorChild,
changeTransparent,
ResetPosition,
controlEvent,
})
</script>
<template>
<div>
<!-- <canvas ref="glcanvas"></canvas> -->
</div>
</template>
<style lang="less" scoped>
.viewer {
/* width: 100vw;
height: 100vh; */
}
</style>