forked from natuka/web.puabadge.com
272 lines
7.3 KiB
Vue
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>
|