0

I made a react map component using maptiler docs. Then i added a 3d gltf object into the map and placed correctly. now my target is to load a custom react component when someone clicked the object, but then issue is ,i didnt get click event correctly. i can easily get map coordinates. but i need the exact click event on 3d object which i clicked. where am i wrong ?

import React, { useEffect, useRef, useState } from "react";
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import * as maptilersdk from "@maptiler/sdk";
import "@maptiler/sdk/dist/maptiler-sdk.css";

const ThreeDModel = () => {
    const mapContainerRef = useRef(null);
    const [dishComponent, setDishComponent] = useState(false);

    useEffect(() => {
        maptilersdk.config.apiKey = "xxxxxxxxxxxxxxx";
        const map = (window.map = new maptilersdk.Map({
            container: mapContainerRef.current,
            style: maptilersdk.MapStyle.STREETS,
            zoom: 18,
            center: [148.9819, -35.3981],
            pitch: 60,
            antialias: true,
        }));

        // const marker = new maptilersdk.Marker().setLngLat([148.9819, -35.3981]).addTo(map);

        // parameters to ensure the model is georeferenced correctly on the map
        var modelOrigin = [148.9819, -35.39847];
        var modelAltitude = 5;
        var modelRotate = [Math.PI / 2, 0, 0];

        var modelAsMercatorCoordinate = maptilersdk.MercatorCoordinate.fromLngLat(modelOrigin, modelAltitude);

        // transformation parameters to position, rotate and scale the 3D model onto the map
        var modelTransform = {
            translateX: modelAsMercatorCoordinate.x,
            translateY: modelAsMercatorCoordinate.y,
            translateZ: modelAsMercatorCoordinate.z,
            rotateX: modelRotate[0],
            rotateY: modelRotate[1],
            rotateZ: modelRotate[2],
            /* Since our 3D model is in real world meters, a scale transform needs to be
             * applied since the CustomLayerInterface expects units in MercatorCoordinates.
             */
            scale: modelAsMercatorCoordinate.meterInMercatorCoordinateUnits(),
        };

        // parameters and transformations remain the same

        const customLayer = {
            id: "3d-model",
            type: "custom",
            renderingMode: "3d",
            onAdd: function (map, gl) {
                this.camera = new THREE.PerspectiveCamera();
                this.scene = new THREE.Scene();

                const directionalLight = new THREE.DirectionalLight(0xffffff);
                directionalLight.position.set(0, -70, 100).normalize();
                this.scene.add(directionalLight);

                const directionalLight2 = new THREE.DirectionalLight(0xffffff);
                directionalLight2.position.set(0, 70, 100).normalize();
                this.scene.add(directionalLight2);

                const loader = new GLTFLoader();
                loader.load("https://docs.maptiler.com/sdk-js/assets/34M_17/34M_17.gltf", (gltf) => {
                    gltf.scene.traverse((child) => {
                        if (child.isMesh) {
                            child.material.depthWrite = true;
                            child.userData = { name: "clicked on dish" };
                            setDishComponent(true);
                            // Set custom data for each object
                        }
                    });
                    this.scene.add(gltf.scene);
                });

                this.map = map;
                this.renderer = new THREE.WebGLRenderer({
                    canvas: map.getCanvas(),
                    context: gl,
                    antialias: true,
                });
                this.renderer.autoClear = false;

                // Bind the onClick function to the customLayer object
                this.onClick = this.onClick.bind(this);

                // Add event listener for mouse clicks on the canvas
                map.getCanvas().addEventListener("click", this.onClick);
            },
            onClick: function (event) {
                const mouse = new THREE.Vector2();
                const canvas = this.map.getCanvas();
                const rect = canvas.getBoundingClientRect();
                mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
                mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

                const raycaster = new THREE.Raycaster();
                raycaster.setFromCamera(mouse, this.camera);

                const intersects = raycaster.intersectObjects(this.scene.children, true);

                if (intersects.length > 0) {
                    const clickedObject = intersects[0].object;
                    const objectName = clickedObject.userData.name;
                    alert("Clicked object: " + objectName);
                }
            },

            render: function (gl, matrix) {
                const rotationX = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0), modelTransform.rotateX);
                const rotationY = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 1, 0), modelTransform.rotateY);
                const rotationZ = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 0, 1), modelTransform.rotateZ);

                const m = new THREE.Matrix4().fromArray(matrix);
                const l = new THREE.Matrix4()
                    .makeTranslation(modelTransform.translateX, modelTransform.translateY, modelTransform.translateZ)
                    .scale(new THREE.Vector3(modelTransform.scale, -modelTransform.scale, modelTransform.scale))
                    .multiply(rotationX)
                    .multiply(rotationY)
                    .multiply(rotationZ);

                this.camera.projectionMatrix = m.multiply(l);
                this.renderer.state.reset();
                this.renderer.render(this.scene, this.camera);
                this.map.triggerRepaint();
            },
        };

        map.on("style.load", () => {
            map.addLayer(customLayer);
        });

        map.on("click", function (e) {
            const lat = e.lngLat.lat;
            const lng = e.lngLat.lng;
            console.log(lat, lng);
        });
    }, []);

    return (
        <div>
            <div ref={mapContainerRef} style={{ position: "absolute", top: 0, bottom: 0, width: "100%" }}></div>
        </div>
    );
};

export default ThreeDModel;
SOORAJ SR
  • 17
  • 7

0 Answers0