0

I'm working on a Three.js project (React) using the @react-three/fiber and @react-three/drei libraries. My goal is to place markers on the surface of a terrain .glb model based on specific coordinates. However, I'm facing an issue where the markers are being positioned below the model instead of on its surface.

import React, { useEffect, useRef, useState } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import { PresentationControls, Stage, useGLTF } from "@react-three/drei";
import * as THREE from "three";

function Model({ setLandscape, ...props }) {
  const gltf = useGLTF("/landscape_free.glb");

  useEffect(() => {
    setLandscape(gltf.scene);
  }, [gltf, setLandscape]);

  return <primitive object={gltf.scene} {...props} scale={[0.8, 0.8, 0.8]} />;
}

function Marker({ initialPosition, landscape }) {
  const ref = useRef();

  useEffect(() => {
    if (landscape && ref.current) {
      const raycaster = new THREE.Raycaster();
      const direction = new THREE.Vector3(0, -1, 0); // Cast downward

      const positionAdjusted = initialPosition.clone();
      positionAdjusted.y += 1; // Move ray origin slightly above the model

      raycaster.set(positionAdjusted, direction);

      const intersects = raycaster.intersectObject(landscape, true);
      if (intersects.length > 0) {
        ref.current.position.copy(intersects[0].point);
      } else {
        console.warn("No intersection found for marker at", initialPosition);
      }
    }
  }, [initialPosition, landscape]);

  const { scene } = useGLTF("/pointer.glb");
  return <primitive object={scene} ref={ref} scale={[0.01, 0.01, 0.01]} />;
}

const coordinates = [
  new THREE.Vector3(0, 0.034, 0),
  new THREE.Vector3(-0.4, 0.2, -0.4),
  new THREE.Vector3(-0.4, 0.1, -0.4),
];

function Map() {
  const [landscape, setLandscape] = useState(null);

  useEffect(() => {
    if (landscape) {
      const boundingBox = new THREE.Box3().setFromObject(landscape);
      console.log("Landscape bounding box:", boundingBox);
      console.log("Min:", boundingBox.min);
      console.log("Max:", boundingBox.max);
    }
  }, [landscape]);

  return (
    <div>
      <Canvas
        dpr={[1, 2]}
        shadows
        camera={{ fov: 45 }}
        style={{
          position: "absolute",
          width: "100%",
          height: "100%",
          touchAction: "none",
        }}
      >
        <PresentationControls
          speed={1.5}
          global
          zoom={1}
          polar={[-0.1, Math.PI / 4]}
        >
          <Stage environment="sunset">
            {coordinates.map((coord, index) => (
              <Marker
                key={index}
                initialPosition={coord}
                landscape={landscape}
              />
            ))}
            <Model scale={0.8} setLandscape={setLandscape} />
          </Stage>
        </PresentationControls>
      </Canvas>
    </div>
  );
}

export default Map;

My glb model is this one: https://sketchfab.com/3d-models/landscape-free-05a23d3d1c1d4e78aee7fc9257bf5332

Problems:

  • I have three coordinates but only one marker is shown.
  • Marker is shown below the model

How it is displayed in the browser

I tried Raycasting to show it above the model but it did not work.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.