File size: 3,384 Bytes
5b324f1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import {
    AmbientLight,
    Box3,
    Color,
    Group,
    Object3D,
    SRGBColorSpace,
    Vector3,
} from "three";
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";
import {ItemType, MapItem} from "@/interfaces/interfaces";
import {loadItemTypeModules} from "@/utils/three/model-loader";
import {ThreeSceneBase} from "@/utils/three/ThreeSceneBase";

export class MapPreviewerRenderer extends ThreeSceneBase {
    private controls: OrbitControls;
    private mapContainer: Group;
    private models: { [key: string]: Group };
    private mapItemList: Object3D[];

    constructor(canvas: HTMLCanvasElement) {
        super(canvas);
        this.scene.background = new Color(0xeeeeee);
        this.camera.fov = 45;
        this.renderer.outputColorSpace = SRGBColorSpace;
        this.mapContainer = new Group();
        this.models = {};
        this.mapItemList = [];
        this.requestAnimationFrameId = -1;

        this.scene.add(this.mapContainer);

        //创建灯光
        this.scene.add(new AmbientLight(0xffffff, 4.5));

        // 创建轨道控制器
        this.controls = new OrbitControls(this.camera, canvas);

        const loop = () => {
            this.requestAnimationFrameId = requestAnimationFrame(loop);

            this.controls.update();

            super.render();
        }

        loop();
    }

    public async loadModels(itemTypeList: ItemType[]) {
        this.setLoadingMaskVisible(true);
        const modelList = await loadItemTypeModules(itemTypeList.map((itemType) => itemType));
        const tempModelOBJ: { [key: string]: Group } = {};
        modelList.forEach((model) => {
            tempModelOBJ[model.id] = model.glft.scene;
        });
        this.models = tempModelOBJ;
        this.setLoadingMaskVisible(false);
    }

    public async loadMapItems(mapItemList: MapItem[]) {
        this.setLoadingMaskVisible(true);
        mapItemList.forEach((item) => {
            const tempModule = this.models[item.type.id].clone();
            tempModule.scale.set(0.5, 0.5, 0.5);
            tempModule.position.set(item.x + item.type.size / 2, 0, item.y + item.type.size / 2);
            tempModule.rotation.y = (Math.PI / 2) * item.rotation;
            this.mapContainer.add(tempModule);
        });
        this.setLoadingMaskVisible(false);
    }

    public async reloadMapItems(mapItemList: MapItem[]) {
        this.mapContainer.clear();
        await this.loadMapItems(mapItemList);
        this.lookAtCenter();
    }

    public lockCamera(isLock: boolean) {
        this.controls.enabled = !isLock;
        if (isLock) {
            this.lookAtCenter();
        }
    }

    public lookAtCenter() {
        // 获取场景中所有对象的中心点和最大高度
        const bbox = new Box3().setFromObject(this.mapContainer);

        const center = bbox.getCenter(new Vector3());
        const size = bbox.getSize(new Vector3());

        const maxSize = Math.max(...[size.x, size.z]);

        // 将相机移到合适的位置
        const distance = maxSize * Math.tan(this.camera.fov / 2) * 2;

        this.camera.position.set(center.x, center.y + distance * 1.2, center.z);
        this.camera.up.set(0, 0, -1);
        this.camera.lookAt(center);
        this.controls.target.set(center.x, center.y, center.z);
    }

    public destroy() {
        super.destroy();
    }
}