98 lines
3.2 KiB
Vue
98 lines
3.2 KiB
Vue
<script setup lang="ts">
|
|
import { reactive, ref, watch } from 'vue';
|
|
import { SRGBColorSpace } from 'three';
|
|
import { TresCanvas, } from '@tresjs/core';
|
|
import { useGLTF, OrbitControls } from '@tresjs/cientos';
|
|
import { useItem } from '../../stores/item';
|
|
import { useRawData } from '../../stores/raw_data';
|
|
import { IMAGE_URL } from '../../constants';
|
|
|
|
const raw_dataStore = useRawData()
|
|
const pageStore = useItem()
|
|
|
|
const camera = ref()
|
|
const controls = ref()
|
|
const models = ref([] as model3DType[])
|
|
|
|
const controlsState = reactive({
|
|
enableDamping: true,
|
|
maxPolarAngle: (Math.PI / 2) - 0.07,
|
|
minAzimuthAngle: (Math.PI / 2) - 0.20,
|
|
enablePan: false,
|
|
enableZoom: false,
|
|
autoRotate: true,
|
|
})
|
|
|
|
const loadModels = async () => {
|
|
camera.value.minDistance = raw_dataStore.data.min_distance;
|
|
camera.value.maxDistance = raw_dataStore.data.max_distance;
|
|
const d = raw_dataStore.data.max_distance * 0.5;
|
|
camera.value.position.set(d, d, d)
|
|
for (let index = 0; index < raw_dataStore.data.elements.length; index++) {
|
|
const element = raw_dataStore.data.elements[index];
|
|
const item = {} as model3DType
|
|
|
|
if (element.name == 'ground') continue
|
|
|
|
item.modelUrl = `${IMAGE_URL}/${element.model_file}`
|
|
let { scene: loaded_scene } = await useGLTF(item.modelUrl)
|
|
item.modelFile = loaded_scene
|
|
item.id = element.id
|
|
item.name = element.name
|
|
|
|
if (!element.is_enabled) {
|
|
item.modelFile.visible = false
|
|
}
|
|
|
|
if (item.modelFile.children[0]) {
|
|
item.modelFile.children[0].position.set(
|
|
item.modelFile.children[0].position.x + element.x_pos,
|
|
item.modelFile.children[0].position.y + element.y_pos,
|
|
item.modelFile.children[0].position.z + element.z_pos
|
|
)
|
|
item.modelFile.children[0].updateMatrixWorld(true)
|
|
}
|
|
models.value.push(item)
|
|
}
|
|
}
|
|
|
|
if (!raw_dataStore.data.id && pageStore.page.id) {
|
|
await raw_dataStore.load({ source: pageStore.page.id })
|
|
await loadModels();
|
|
controls.value.autoRotate = true
|
|
controls.value.value.update()
|
|
}
|
|
|
|
watch(() => pageStore.page.id, async () => {
|
|
await raw_dataStore.load({ source: pageStore.page.id })
|
|
await loadModels()
|
|
controls.value.autoRotate = true
|
|
controls.value.value.update()
|
|
|
|
})
|
|
</script>
|
|
<template>
|
|
<div class="main">
|
|
<h1 class="main-title">
|
|
{{ raw_dataStore.data.name }}
|
|
</h1>
|
|
<div class="main-desc">
|
|
<p v-for="p in (raw_dataStore.data.description || '').replace(/(\n|\r)+/g, '\n').split('\n')">
|
|
{{ p }}
|
|
</p>
|
|
</div>
|
|
<div class="main-canvas">
|
|
<TresCanvas :output-encoding="SRGBColorSpace">
|
|
<TresPerspectiveCamera ref="camera" />
|
|
<OrbitControls v-bind="controlsState" make-default ref="controls" />
|
|
<TresGroup ref="scene">
|
|
<template v-for="item in models">
|
|
<TresGroup :name="item.name">
|
|
<TresObject3D v-bind="item.modelFile.clone()" />
|
|
</TresGroup>
|
|
</template>
|
|
</TresGroup>
|
|
</TresCanvas>
|
|
</div>
|
|
</div>
|
|
</template> |