146 lines
5.1 KiB
Vue
146 lines
5.1 KiB
Vue
<script setup lang="ts">
|
|
import { useLoop, useTresContext } from '@tresjs/core';
|
|
import { Box3, Object3D, Vector3 } from 'three';
|
|
import { degToRad } from 'three/src/math/MathUtils.js';
|
|
|
|
const props = defineProps(['number', 'count', 'models'])
|
|
const rotate = () => {
|
|
switch (props.number) {
|
|
case 1:
|
|
return degToRad(0)
|
|
case 2:
|
|
return degToRad(180)
|
|
case 3:
|
|
return degToRad(270)
|
|
case 4:
|
|
return degToRad(90)
|
|
}
|
|
}
|
|
const { seekByName } = useSeek()
|
|
const { scene, camera } = useTresContext()
|
|
|
|
const section_count = use_section_count()
|
|
const extra_section = use_extra_section()
|
|
const fence_section = use_fence_section()
|
|
const max_size = use_max_size()
|
|
const lamelle_count = use_lamelles_count()
|
|
const lamelle_height = use_lamelle_height()
|
|
|
|
const total = ref((section_count.value + ~~(!!extra_section.value)))
|
|
const position = ref(new Vector3())
|
|
|
|
const clickable_positions = reactive({
|
|
'top': [position.value.x, (lamelle_count.value + 1) * lamelle_height.value, 0],
|
|
'lam': [position.value.x, position.value.y * 0.5, 0]
|
|
})
|
|
const clickable_pointers = ref<any[]>([])
|
|
const clickable_refs = ref<any>([])
|
|
|
|
Object.entries(clickable_positions).map(el => {
|
|
const p = props.models.pointer.clone()
|
|
p.position.set(...el[1])
|
|
p.updateMatrixWorld()
|
|
p.name = `clickable_${props.number}_${el[0]}`
|
|
clickable_pointers.value.push(p)
|
|
clickable_refs.value.push(ref(p.name))
|
|
})
|
|
|
|
const count_pos = () => {
|
|
total.value = (section_count.value + ~~(!!extra_section.value))
|
|
|
|
const line = seekByName(scene.value, `line_${props.number}`)
|
|
const line_size = new Vector3()
|
|
const line_pos = new Vector3()
|
|
|
|
if (line && line.children.length) {
|
|
line.updateMatrixWorld()
|
|
new Box3().expandByObject(line).getSize(line_size)
|
|
line.getWorldPosition(line_pos)
|
|
}
|
|
const line1 = seekByName(scene.value, `line_1_inner`);
|
|
const line1_size = new Vector3()
|
|
const line1_pos = new Vector3()
|
|
if (line1) {
|
|
new Box3().expandByObject(line1).getSize(line1_size)
|
|
line1.getWorldPosition(line1_pos)
|
|
}
|
|
const k = ((line1_size.x / props.count) - line1_size.z) * 0.5
|
|
switch (props.number) {
|
|
case 1: break;
|
|
case 2:
|
|
position.value.z = line1_size.x * -1
|
|
position.value.x = line1_size.x - k * 2
|
|
break;
|
|
case 3:
|
|
position.value.z = line1_size.x * -1 + k
|
|
position.value.x = -1 * k
|
|
break;
|
|
case 4:
|
|
position.value.z = -1 * k
|
|
position.value.x = line1_size.x - k
|
|
break;
|
|
}
|
|
line?.updateMatrixWorld()
|
|
|
|
clickable_positions.top = [position.value.x, (lamelle_count.value + 1) * lamelle_height.value, 0];
|
|
clickable_positions.lam = [position.value.x, position.value.y * 0.5, 0];
|
|
}
|
|
watch(clickable_positions, () => {
|
|
clickable_refs.value.map((el: Ref<Object3D[]>) => {
|
|
const name = el.value[0].name.replace(`clickable_${props.number}_`, '')
|
|
if (name in clickable_positions) {
|
|
const p = clickable_positions[name as keyof typeof clickable_positions];
|
|
console.log(props.number, p, el.value[0].name)
|
|
el.value[0].position.set(p[0], p[1], p[2])
|
|
el.value[0].children[0].position.set(p[0], p[1], p[2])
|
|
el.value[0].updateMatrixWorld()
|
|
}
|
|
})
|
|
}, { deep: true })
|
|
|
|
onMounted(() => {
|
|
count_pos()
|
|
})
|
|
watch(() => [props.count, fence_section.value, section_count.value, extra_section.value, lamelle_count.value],
|
|
count_pos,
|
|
{ flush: 'post' }
|
|
)
|
|
|
|
const { onBeforeRender } = useLoop()
|
|
onBeforeRender(() => {
|
|
clickable_refs.value.map((el: any) => {
|
|
if (el.value[0] && el.value[0].children) {
|
|
el.value[0].children[0].lookAt(camera.value?.position);
|
|
el.value[0].children[0].rotateX(degToRad(90));
|
|
el.value[0].children[0].rotateZ(degToRad(15));
|
|
|
|
const dis_to_cam = camera.value?.position.distanceTo(el.value[0].position);
|
|
if (dis_to_cam) {
|
|
const scaling = (0.66 * dis_to_cam) / 100
|
|
el.value[0].children[0].scale.set(scaling, scaling, scaling);
|
|
el.value[0].updateMatrixWorld()
|
|
}
|
|
}
|
|
})
|
|
})
|
|
</script>
|
|
<template>
|
|
<TresGroup :name="`line_${props.number}`" :rotate-y="rotate()" :position-x="position.x" :position-y="position.y"
|
|
:position-z="position.z">
|
|
<TresGroup :name="`line_${props.number}_inner`">
|
|
<template v-for="i in props.count">
|
|
<template v-if="(i + (props.number - 1) * props.count) <= 1"
|
|
:key="(i + (props.number - 1) * props.count)">
|
|
<ModelFence :index="i" :models="props.models"
|
|
:last_element="(i + (props.number - 1) * props.count) == total"
|
|
:first_element="i == 1 && props.number == 1" />
|
|
</template>
|
|
</template>
|
|
</TresGroup>
|
|
<TresGroup name="pointer">
|
|
<template v-for="(p, i) in clickable_pointers">
|
|
<TresObject3D v-bind="p.clone()" :ref="clickable_refs[i]" :visible="false" />
|
|
</template>
|
|
</TresGroup>
|
|
</TresGroup>
|
|
</template> |