remove raycaster
This commit is contained in:
parent
2768ee9877
commit
e88b91476b
|
@ -1100,7 +1100,7 @@
|
|||
"kind": 6,
|
||||
"importPath": "back.object.models",
|
||||
"description": "back.object.models",
|
||||
"peekOfCode": "class Scene3D(models.Model):\n name = models.CharField(\n max_length=120,\n )\n elements = models.ManyToManyField(Element3D)\n min_distance = models.IntegerField(\n validators=[MinValueValidator(1), MaxValueValidator(200)], blank=True, null=True\n )\n max_distance = models.IntegerField(\n validators=[MinValueValidator(2), MaxValueValidator(200)], blank=True, null=True",
|
||||
"peekOfCode": "class Scene3D(models.Model):\n name = models.CharField(\n max_length=120,\n )\n elements = models.ManyToManyField(Element3D)\n min_distance = models.IntegerField(\n validators=[MinValueValidator(1), MaxValueValidator(400)], blank=True, null=True\n )\n max_distance = models.IntegerField(\n validators=[MinValueValidator(2), MaxValueValidator(500)], blank=True, null=True",
|
||||
"detail": "back.object.models",
|
||||
"documentation": {}
|
||||
},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
||||
import { Box3, Vector2, Vector3 } from 'three';
|
||||
import { useTresContext, useSeek, useRenderLoop } from '@tresjs/core';
|
||||
import { ref, watch } from 'vue';
|
||||
import { Box3, Color, Group, Mesh, MeshStandardMaterial, PointLight, SphereGeometry, Vector3 } from 'three';
|
||||
import { useTresContext, useSeek } from '@tresjs/core';
|
||||
import { useGLTF } from '@tresjs/cientos'
|
||||
|
||||
import { IMAGE_URL, SERVER_URL, } from '../../constants'
|
||||
|
@ -20,8 +20,9 @@ function shadows_and_pos(scene: any) {
|
|||
const models = ref<model3DType[]>([])
|
||||
const clickable = ref<clickableAreaType[]>([])
|
||||
const clickable_objects = ref<any[]>([])
|
||||
const clickable_items = ref<any[]>([])
|
||||
const sidebar = usePromoSidebar();
|
||||
const { controls, raycaster, camera, scene } = useTresContext()
|
||||
const { controls, camera, scene } = useTresContext()
|
||||
const { seekByName } = useSeek()
|
||||
|
||||
const loadModels = async () => {
|
||||
|
@ -46,7 +47,6 @@ const loadModels = async () => {
|
|||
let { scene: loaded_scene } = await useGLTF(item.modelUrl)
|
||||
shadows_and_pos(loaded_scene)
|
||||
item.modelFile = loaded_scene
|
||||
|
||||
item.name = element.name
|
||||
|
||||
models.value.push(item)
|
||||
|
@ -60,7 +60,34 @@ const loadModels = async () => {
|
|||
const element = clickable.value[index];
|
||||
const find_element = seekByName(scene.value, element.object_name)
|
||||
if (!find_element) continue
|
||||
const res_array = find_element.isGroup ? find_element?.children : [find_element]
|
||||
const res_array = (find_element as Group).isGroup ? find_element?.children : [find_element]
|
||||
if (find_element && !(find_element as Group).isGroup) {
|
||||
const world_position = new Vector3();
|
||||
(find_element as Mesh).geometry.boundingBox.getCenter(world_position);
|
||||
(find_element as Mesh).localToWorld(world_position);
|
||||
|
||||
const light = new PointLight()
|
||||
light.position.set(world_position.x, world_position.y * 5, world_position.z)
|
||||
light.color = index % 2 ? new Color('red') : new Color('green');
|
||||
light.power = 10000;
|
||||
|
||||
const point = new Mesh(new SphereGeometry(2, 16, 16), new MeshStandardMaterial({
|
||||
color: light.color,
|
||||
emissive: light.color,
|
||||
emissiveIntensity: 100
|
||||
}))
|
||||
point.position.set(light.position.x, light.position.y, light.position.z)
|
||||
point.name = `${element.id}_clickable`
|
||||
// light.add(point)
|
||||
|
||||
clickable_items.value.push(light)
|
||||
clickable_items.value.push(point)
|
||||
clickable_objects.value.push({
|
||||
name: point.name,
|
||||
target: element.id,
|
||||
object: point,
|
||||
})
|
||||
}
|
||||
for (let index = 0; index < res_array.length; index++) {
|
||||
const r = res_array[index];
|
||||
let res = {
|
||||
|
@ -82,52 +109,28 @@ const loadModels = async () => {
|
|||
new Vector3(box_size.x * 0.5, box_size.y * 0.5, box_size.z * 0.5),
|
||||
new Vector3(box_size.x * -0.5, box_size.y * -0.5, box_size.z * -0.5),
|
||||
)
|
||||
console.log(box_size)
|
||||
}
|
||||
|
||||
controls.value.enabled = true;
|
||||
props.loaded()
|
||||
}
|
||||
loadModels()
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', clickEvent)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('click', clickEvent)
|
||||
})
|
||||
const pointer = reactive({ x: 0, y: 0 })
|
||||
const clickEvent = (event: MouseEvent) => {
|
||||
console.time('raycaster')
|
||||
const x = (event.clientX / window.innerWidth) * 2 - 1
|
||||
const y = - (event.clientY / window.innerHeight) * 2 + 1
|
||||
if (x == pointer.x && y == pointer.y) return
|
||||
if (!camera.value) return
|
||||
|
||||
pointer.x = x
|
||||
pointer.y = y
|
||||
raycaster.value.setFromCamera(new Vector2(pointer.x, pointer.y), camera.value);
|
||||
|
||||
const intersects = raycaster.value.intersectObjects(clickable_objects.value.map(el => el.object));
|
||||
const names = intersects.map(el => el.object.name ?? false).filter(Boolean)
|
||||
if (names.length) {
|
||||
const clicks = clickable_objects.value.find(el => names.includes(el.name))
|
||||
if (!clicks) return
|
||||
const target = clickable.value.find(el => el.id == clicks.target)
|
||||
if (!target) return
|
||||
const sidebar_data = {
|
||||
title: target.name,
|
||||
description: target.description
|
||||
} as PromoSidebarData
|
||||
if (target?.target) {
|
||||
sidebar_data.target = target.target.toString()
|
||||
sidebar_data.target_name = target.target_name
|
||||
}
|
||||
sidebar.open()
|
||||
sidebar.setData(sidebar_data)
|
||||
const openSidebar = (id: number) => {
|
||||
const target = clickable.value.find(el => el.id == id)
|
||||
if (!target) return
|
||||
const sidebar_data = {
|
||||
title: target.name,
|
||||
description: target.description
|
||||
} as PromoSidebarData
|
||||
if (target?.target) {
|
||||
sidebar_data.target = target.target.toString()
|
||||
sidebar_data.target_name = target.target_name
|
||||
}
|
||||
console.timeEnd('raycaster')
|
||||
sidebar.setData(sidebar_data)
|
||||
sidebar.open()
|
||||
}
|
||||
|
||||
loadModels()
|
||||
watch(() => props.source, () => {
|
||||
const loaded = seekByName(scene.value, 'loaded')
|
||||
if (loaded) {
|
||||
|
@ -143,5 +146,9 @@ watch(() => props.source, () => {
|
|||
<TresObject3D v-bind="item.modelFile.clone()" />
|
||||
</TresGroup>
|
||||
</template>
|
||||
<template v-for="item in clickable_items">
|
||||
<TresObject3D v-if="item.type == 'PointLight'" v-bind="item.clone()" />
|
||||
<TresMesh v-else @click="() => openSidebar(item.name.replace('_clickable', ''))" v-bind="item" />
|
||||
</template>
|
||||
</TresGroup>
|
||||
</template>
|
|
@ -3,9 +3,9 @@ import { reactive, ref, watch } from 'vue';
|
|||
import type { Ref } from 'vue'
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { PointLight, Vector3 } from 'three';
|
||||
import { Vector3 } from 'three';
|
||||
import { TresCanvas } from '@tresjs/core';
|
||||
import { CameraControls, useProgress, StatsGl, OrbitControls, MapControls } from '@tresjs/cientos'
|
||||
import { StatsGl, OrbitControls } from '@tresjs/cientos'
|
||||
|
||||
import Env from './env.vue'
|
||||
import LoadModels from './load_models.vue'
|
||||
|
@ -33,7 +33,7 @@ const camera = ref()
|
|||
const cameraPosition = ref([1, 1, 1]) as unknown as Ref<Vector3>
|
||||
|
||||
const controlsState = reactive({
|
||||
maxPolarAngle: (Math.PI / 2) - 0.02,
|
||||
maxPolarAngle: (Math.PI / 2) - 0.05,
|
||||
minAzimuthAngle: (Math.PI / 2) - 0.02,
|
||||
})
|
||||
const models_loading = ref(false)
|
||||
|
@ -41,14 +41,6 @@ const set_model_load_status = () => {
|
|||
models_loading.value = !models_loading.value
|
||||
}
|
||||
|
||||
const point_light = new PointLight('#00d', 1000, 200)
|
||||
point_light.intensity = 10000
|
||||
point_light.position.set(-100, 100, 5)
|
||||
point_light.castShadow = true
|
||||
point_light.shadow.bias = -0.01
|
||||
point_light.shadow.mapSize.width = 512 * 10
|
||||
point_light.shadow.mapSize.height = 512 * 10
|
||||
|
||||
const route = useRoute()
|
||||
const source = ref(route.params.target ? (route.params.target.toString() + '/') : '1/')
|
||||
watch(() => route.params.target, () => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { usePromoSidebar } from '../../stores/promo_sidebar';
|
|||
const sidebar = usePromoSidebar()
|
||||
const sidebar_obj = ref()
|
||||
|
||||
onClickOutside(sidebar_obj, () => sidebar.close())
|
||||
// onClickOutside(sidebar_obj, () => sidebar.close())
|
||||
</script>
|
||||
<template>
|
||||
<div class="sidebar" :class="[{ 'open': sidebar.is_open }]" ref="sidebar_obj">
|
||||
|
@ -22,7 +22,7 @@ onClickOutside(sidebar_obj, () => sidebar.close())
|
|||
<RouterLink class="btn" :to="`/promo/main/${sidebar.target}`" v-if="sidebar.target">
|
||||
{{ sidebar.target_name }}
|
||||
</RouterLink>
|
||||
|
||||
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -60,34 +60,35 @@ onClickOutside(sidebar_obj, () => sidebar.close())
|
|||
margin: 1rem 0;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
.btn {
|
||||
color: white;
|
||||
transition: .2s linear;
|
||||
background: #0B63F6;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 7px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
min-width: 300px;
|
||||
min-height: 60px;
|
||||
display: inline-flex;
|
||||
font-family: 'Nunito', sans-serif;
|
||||
font-size: 22px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1.3px;
|
||||
font-weight: 700;
|
||||
color: #313133;
|
||||
background: #4FD1C5;
|
||||
background: linear-gradient(90deg, rgba(129,230,217,1) 0%, rgba(79,209,197,1) 100%);
|
||||
border-radius: 1000px;
|
||||
box-shadow: 12px 12px 24px rgba(79,209,197,.64);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
box-shadow: 0 0 0 2px white, 0 0 0 4px #3C82F8;
|
||||
}
|
||||
.btn {
|
||||
color: white;
|
||||
transition: .2s linear;
|
||||
background: #0B63F6;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 7px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
min-width: 300px;
|
||||
min-height: 60px;
|
||||
display: inline-flex;
|
||||
font-family: 'Nunito', sans-serif;
|
||||
font-size: 22px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1.3px;
|
||||
font-weight: 700;
|
||||
color: #313133;
|
||||
background: #4FD1C5;
|
||||
background: linear-gradient(90deg, rgba(129, 230, 217, 1) 0%, rgba(79, 209, 197, 1) 100%);
|
||||
border-radius: 1000px;
|
||||
box-shadow: 12px 12px 24px rgba(79, 209, 197, .64);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
box-shadow: 0 0 0 2px white, 0 0 0 4px #3C82F8;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -37,6 +37,7 @@ interface clickableAreaType {
|
|||
object_name: string;
|
||||
source: number;
|
||||
target: number;
|
||||
target_name?: string
|
||||
}
|
||||
interface PromoSidebarData {
|
||||
title: string
|
||||
|
|
|
@ -20,8 +20,10 @@ export const usePromoSidebar = defineStore('promo_sidebar', {
|
|||
this.$state = Object.assign(this.$state, data)
|
||||
},
|
||||
close() {
|
||||
this.$reset()
|
||||
this.is_open = false
|
||||
if (this.is_open) {
|
||||
this.$reset()
|
||||
this.is_open = false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue