123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- <template>
- <div ref="map_container_ref" :class="['three-map', props.className]" :style="{
- width: props.width,
- height: props.height
- }"></div>
- </template>
- <script setup lang="ts">
- import { useInitThree } from "./useInitThree";
- import { ref, watch, onMounted, shallowRef, inject,toRaw } from "vue";
- import { useGLTFLoader } from "@/hooks/useGLTFLoader";
- import {
- Group,
- Mesh,
- MeshBasicMaterial,
- Vector3,
- SphereGeometry,
- Sprite,
- TextureLoader,
- Texture, RepeatWrapping, Box3
- } from "three";
- import { useRayCast } from "./useRayCast";
- import { coordinate_src, cycle_light_src, Floor } from "./Constants";
- import { createImgSprite, createSphere, useConnectPoint } from "@/hooks/useMesh";
- import { getRandomIntInclusive, isMesh } from "@/hooks/Utils";
- import { connect_point_inject_key } from "../../global";
- import { Character } from "../Character/Character";
- import { character_src } from "../Character/Constants";
- import { PathFinder } from "../PathFinder/PathFinder";
- const props = defineProps<{
- className: string,
- width: string,
- height: string,
- floorId: string,
- }>();
- const {
- map_conn_points,
- graph
- } = inject(connect_point_inject_key)!;
- // 坐标点texture
- const texture_loader = new TextureLoader();
- let coordinate_texture: Texture | undefined;
- texture_loader.load(coordinate_src, (texture) => {
- coordinate_texture = texture;
- });
- // 连通点texture
- let cycle_light_texture: Texture | undefined;
- texture_loader.load(cycle_light_src, (texture) => {
- cycle_light_texture = texture;
- cycle_light_texture.wrapS = RepeatWrapping;
- cycle_light_texture.repeat.set(2, 1);
- });
- const cur_map = shallowRef<Group | null>(null);
- const map_file_cache: Record<string, Group> = {};
- // 选择的坐标点Mesh(起始点/终点)
- const startPoint = shallowRef<Group | null>(null);
- const endPoint = shallowRef<Group | null>(null);
- let ray_cast: ReturnType<typeof useRayCast> | null = null;
- const map_container_ref = ref<HTMLElement>();
- const {
- scene,
- camera,
- renderer,
- clock,
- controls,
- renderCSS2D
- } = useInitThree(map_container_ref);
- const character = new Character(camera, scene, character_src, new Vector3(0, 0, 0));
- const path_finder = new PathFinder();
- // 连通点
- const { renderConnectPoint } = useConnectPoint(scene);
- // 切换地图
- const setfloorId = async (scene_url: string) => {
- if (cur_map.value) {
- cur_map.value.traverse(item => {
- if (isMesh(item)) {
- item.material.dispose();
- }
- });
- clearPointHelper();
- scene.remove(cur_map.value);
- }
- let map: Group;
- if (map_file_cache[scene_url]) {
- map = map_file_cache[scene_url];
- } else {
- map = (await useGLTFLoader(Floor[scene_url])).scene;
- map_file_cache[scene_url] = map;
- }
- map.traverse(item => {
- console.log(item);
- if (isMesh(item) && item.name.includes("NavMesh")) {
- item.material.visible = false;
- path_finder.setZoneData(props.floorId, item);
- }
- });
- cur_map.value = map;
- scene.add(map);
- const bbox = new Box3().setFromObject(map);
- const center = new Vector3();
- bbox.getCenter(center);
- // 设置控制器目标点为模型中心
- controls.target.copy(center);
- camera.position.copy(center).add(new Vector3(0, 60, 50)); //3d视角
- controls.update();
- // renderConnectPoint(map_conn_points.get(scene_url)!, graph.getAdjList(), cycle_light_texture as Texture);
- if (ray_cast) {
- if (!ray_cast.intersect.value) {
- ray_cast.onRayCast(map, handleMapClick);
- } else {
- ray_cast.setIntersect(map);
- }
- }
- };
- const switch3D = (is3D) => {
- const bbox = new Box3().setFromObject(cur_map.value);
- const center = new Vector3();
- bbox.getCenter(center);
- controls.target.copy(center);
- if (is3D) {
- camera.position.copy(center).add(new Vector3(0, 60, 50)); //3d视角
- controls.update();
- } else {
- camera.position.copy(center).add(new Vector3(0, 75, 0)); //2d视角
- controls.update();
- }
- }
- onMounted(() => {
- ray_cast = useRayCast(map_container_ref.value as HTMLElement, camera);
- watch(() => props.floorId, setfloorId, { immediate: true });
- });
- const clearPointHelper = () => {
- if (startPoint.value) {
- // const sphere = select_point.value.getObjectByName("sphere") as Mesh<SphereGeometry, MeshBasicMaterial>;
- const sprite = startPoint.value.getObjectByName("sprite") as Sprite;
- // sphere.material.dispose();
- sprite.material.dispose();
- scene.remove(startPoint.value);
- startPoint.value = null;
- }
- if (endPoint.value) {
- // const sphere = select_point.value.getObjectByName("sphere") as Mesh<SphereGeometry, MeshBasicMaterial>;
- const sprite = endPoint.value.getObjectByName("sprite") as Sprite;
- // sphere.material.dispose();
- sprite.material.dispose();
- scene.remove(endPoint.value);
- endPoint.value = null;
- character.removeToScene();
- character.clearPath();
- }
- };
- const renderPointHelper = (point: Vector3) => {
- if (startPoint.value && endPoint.value) clearPointHelper();
- const group = new Group();
- group.userData.position = point;
- // const sphere = createSphere(.1, 0xff9900, point);
- const sprite = createImgSprite(
- coordinate_texture as Texture,
- point,
- 0.15,
- 0.02
- );
- // group.add(sphere);
- group.add(sprite);
- scene.add(group);
- if (startPoint.value) {
- endPoint.value = group;
- insideNavigation(props.floorId, startPoint.value.userData.position, endPoint.value.userData.position);
- console.log( startPoint.value.userData.position);
- console.log( endPoint.value.userData.position);
-
- } else {
- startPoint.value = group;
- }
- };
- // 室内导航方案(会初始化地图)
- const insideNavigation = (zone: string, start_pos: Vector3, end_pos: Vector3) => {
- // controls.enabled = false;
- // character.setPathLineColor(`rgb(${getRandomIntInclusive(0, 255)}, ${getRandomIntInclusive(0, 255)}, ${getRandomIntInclusive(0, 255)})`);
- createPath(zone, start_pos, end_pos);
- };
- // 单地图两点间的导航路径(不会初始化地图)
- const createPath = (zone: string, start_pos: Vector3, end_pos: Vector3) => {
- const path = path_finder.queryPath(zone, start_pos, end_pos);
- character.addToScene(start_pos);
- path.unshift(start_pos);
- character.setPath(path);
- };
- const handleMapClick = (point: Vector3) => {
- renderPointHelper(point);
- };
- renderer.setAnimationLoop(() => {
- const delta = clock.getDelta();
- renderer.render(scene, camera);
- if (cycle_light_texture) {
- cycle_light_texture.offset.x -= 0.005;
- }
- renderCSS2D(scene, camera);
- });
- defineExpose({
- startPoint,
- clearPointHelper,
- switch3D
- });
- </script>
- <style scoped lang="scss">
- .three-map {
- // border: 1px solid #ccc;
- overflow: hidden;
- }
- </style>
|