Skip to content

Duplicate Model Rendering for Different Models #121

Description

@m6hdix

I am experiencing a bug when rendering multiple 3D models using react-three-map and react-three-fiber. Despite having different URLs for the models, the same model is rendered across all canvases. This issue occurs when trying to load multiple models that are close to each other on the map.

Use the provided MapPolygons component.
Ensure there are at least three models with distinct URLs that are close to each other geographically.
Observe that the same model is rendered in all canvases, even though their URLs are different.
Expected Behavior:
Each canvas should render the 3D model specified by its unique URL.

Actual Behavior:
All canvases render the same model, ignoring the distinct URLs.

Relevant Code:

import { Layer, Source, useMap, Marker } from "react-map-gl";
import { useLoader } from "@react-three/fiber";
import { Canvas } from "react-three-map/maplibre";
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
import { HemisphereLight } from "three";
import { BORDER_COLORS } from "../../Services/Constants/BorderColors";
import { POLYGON_COLORS } from "../../Services/Constants/PolygonColors";
import useRequest from "../../Services/Hooks/useRequest";
import { ClipLoader } from "react-spinners";

const FBXModel = memo(({ url, rotation, setLoading, uniqueKey }) => {
  const fbx = useLoader(FBXLoader, url, (loader) => {
    loader.manager.onStart = () => setLoading(true);
    loader.manager.onLoad = () => setLoading(false);
    loader.manager.onError = () => setLoading(false);
  });

  const fbxRef = useRef();
  return (
    <group ref={fbxRef} rotation={rotation} scale={0.0097} key={uniqueKey}>
      <hemisphereLight
        args={["#ffffff", "#60666C"]}
        intensity={12}
        key={`${uniqueKey}-light`}
      />
      <primitive object={fbx} key={`${uniqueKey}-primitive`} />
    </group>
  );
});

const MapPolygons = () => {
  const map = useMap();
  const bounds = map.current.getBounds();
  const [features, setFeatures] = useState([]);
  const [buildingModels, setBuildingModels] = useState([]);
  const [zoom, setZoom] = useState(map.current.getZoom());
  const [isLoading, setIsLoading] = useState(false);

  const { Request } = useRequest();

  useEffect(() => {
    const handleViewportChange = () => {
      setZoom(map.current.getZoom());
    };

    map.current.on("zoomend", handleViewportChange);

    return () => {
      map.current.off("zoomend", handleViewportChange);
    };
  }, [map]);

  useEffect(() => {
    window.Echo.channel("feature-status").listen(
      ".feature-status-changed",
      (e) => {
        const data = [];
        for (const feature of features) {
          if (parseInt(feature.id) === parseInt(e.data.id)) {
            feature.rgb = e.data.rgb;
          }
          data.push(feature);
        }

        setFeatures(data);
      }
    );
  }, [features]);

  useEffect(() => {
    if (bounds.getSouthWest().lng && zoom >= 14) {
      const loadBuildings = zoom >= 15 ? "&load_buildings=1" : "";
      Request(
        `features?points[]=${bounds.getSouthWest().lng},${
          bounds.getSouthWest().lat
        }&points[]=${bounds.getSouthEast().lng},${
          bounds.getSouthEast().lat
        }&points[]=${bounds.getNorthWest().lng},${
          bounds.getNorthWest().lat
        }&points[]=${bounds.getNorthEast().lng},${
          bounds.getNorthEast().lat
        }${loadBuildings}`
      ).then((response) => {
        const newFeatures = [];
        const newBuildingModels = [];
        for (const feature of response?.data?.data) {
          newFeatures.push({
            id: feature?.geometry?.feature_id,
            rgb: feature?.properties?.rgb,
            coordinates: feature?.geometry?.coordinates.map((coordinate) => [
              parseFloat(coordinate.x),
              parseFloat(coordinate.y),
            ]),
          });

          if (feature.building_models) {
            for (const model of feature.building_models) {
              newBuildingModels.push(model);
            }
          }
        }

        setFeatures((prevFeatures) => [...prevFeatures, ...newFeatures]);
        setBuildingModels((prevModels) => [
          ...prevModels,
          ...newBuildingModels,
        ]);
      });
    }
  }, [bounds.getSouthWest().lng, zoom]);

  return (
    <>
      {zoom >= 14 && (
        <Source
          id="polygons"
          type="geojson"
          data={{
            type: "FeatureCollection",
            features: features.map((polygon) => ({
              type: "Feature",
              properties: {
                id: polygon.id,
                fill: POLYGON_COLORS[polygon.rgb],
                border: BORDER_COLORS[polygon.rgb],
              },
              geometry: {
                type: "Polygon",
                coordinates: [polygon.coordinates],
              },
            })),
          }}
        >
          <Layer
            id="polygon-fill-layer"
            type="fill"
            paint={{
              "fill-color": ["get", "fill"],
            }}
          />
          <Layer
            id="polygon-outline-layer"
            type="line"
            paint={{
              "line-color": ["get", "border"],
              "line-width": 3,
            }}
          />
        </Source>
      )}
      {zoom >= 15 &&
        buildingModels.length > 0 &&
        buildingModels.map((model) => {
          return (
            <>
              {isLoading && <ClipLoader color="#36d7b7" />}
              <Canvas
                latitude={parseFloat(model.building.position.split(", ")[0])}
                longitude={parseFloat(model.building.position.split(", ")[1])}
                key={`${model.id}-canvas`}
              >
                <FBXModel
                  url={model.file.url}
                  rotation={[0, 0, 0]}
                  setLoading={setIsLoading}
                  uniqueKey={`${model.id}-model`}
                />
              </Canvas>
            </>
          );
        })}
    </>
  );
};

export default MapPolygons;

The models have different URLs and unique keys.
This issue is impacting the accurate visualization of 3D models on the map.
Environment:

image

Activity

  1. m6hdix commented on Aug 2, 2024

    @m6hdix
    Author

    help sir

  2. m6hdix commented on Aug 8, 2024

    @m6hdix
    Author

    I would appreciate it if you could respond, I'm even willing to donate

  3. RodrigoHamuy commented on Aug 8, 2024

    @RodrigoHamuy
    Owner

    Can you put this on a sandbox to be able to replicate? Here is a starting one you can fork https://codesandbox.io/p/sandbox/react-three-map-gettings-started-dhw34w

  4. m6hdix commented on Aug 8, 2024

    @m6hdix
    Author

    Hello RodrigoHamuy,

    Thank you for reviewing the issue I raised. I have created a sandbox environment to demonstrate the problem. Please note that this is just for testing purposes and not intended for production.

    Here is the link to the sandbox: https://codesandbox.io/p/live/176d120c-fd63-4726-b612-7f48d5e13b30

    Please make sure to install and enable the CORS error extension, and for the environments to load correctly, zoom in to 15x.

    I appreciate your time and look forward to your feedback.

    Best regards
    example video:

    2024-08-08.16-04-42.mp4
  5. RodrigoHamuy commented on Aug 8, 2024

    @RodrigoHamuy
    Owner

    Do you have a minimum example without having to install custom extensions?

    That sandbox is still a bit complicated for debugging.

    But I can see you are creating a new <Canvas> per model. Instead, I would recommend to use <NearCoordinates> instead.

  6. Repository owner locked and limited conversation to collaborators on Aug 9, 2024
  7. converted this issue into a discussion #122 on Aug 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions