lumalabs / luma-web-examples

Luma Interactive Scenes (captures) Web Examples, use lumalabs.ai captures directly in your three.js or other WebGL projects!
https://lumalabs.ai/luma-web-library
MIT License
345 stars 38 forks source link

Luma takes over the scene depth and conflicts with threejs GLTFs. #31

Open ChristopherTrimboli opened 3 months ago

ChristopherTrimboli commented 3 months ago

Screencast from 2024-07-18 12-34-29.webm

  useEffect(() => {
    Object.values(materials).forEach((material) => {
      material.depthTest = false;
      material.needsUpdate = true;
    })

    Object.values(nodes).forEach((node) => {
      node.renderOrder = 9000;
    })
  }, [materials, nodes])

I've tried stuff like this to no avail.

bill9109 commented 2 weeks ago

Did you find a way to solve this problem?

ChristopherTrimboli commented 2 weeks ago

I found the solution... finally...

/*
Auto-generated by: https://github.com/pmndrs/gltfjsx
Command: npx gltfjsx@6.5.2 ./public/glbs/simple-brown-desk.glb --output ./app/components/gltf/SimpleBrownDesk.tsx 
Author: Thunder (https://sketchfab.com/thunderpwn)
License: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
Source: https://sketchfab.com/3d-models/simple-dirty-desk-fec8ded4a31549be8aaaad7c9bf414d2
Title: Simple dirty Desk
*/

import * as THREE from "three";
import React, { useEffect, useMemo } from "react";
import { useGLTF } from "@react-three/drei";
import { GLTF } from "three-stdlib";

type GLTFResult = GLTF & {
  nodes: {
    Cube__0: THREE.Mesh;
  };
  materials: {
    ["Scene_-_Root"]: THREE.MeshStandardMaterial;
  };
};

export function Model(props: JSX.IntrinsicElements["group"]) {
  const { nodes, materials } = useGLTF(
    "/glbs/simple-brown-desk.glb"
  ) as GLTFResult;

  /**
   * Clone all materials to ensure each instance has its own unique material.
   * This prevents shared state conflicts when materials are modified elsewhere
   * (e.g., by LumaSplats or other scene components).
   */
  const clonedMaterials = useMemo(() => {
    const newMaterials: Record<string, THREE.MeshStandardMaterial> = {};

    Object.entries(materials).forEach(([key, material]) => {
      const clonedMaterial = material.clone();

      if (clonedMaterial.map) {
        clonedMaterial.map = clonedMaterial.map.clone();
      }

      if (clonedMaterial.normalMap) {
        clonedMaterial.normalMap = clonedMaterial.normalMap.clone();
      }
      if (clonedMaterial.roughnessMap) {
        clonedMaterial.roughnessMap = clonedMaterial.roughnessMap.clone();
      }

      newMaterials[key] = clonedMaterial;
    });

    return newMaterials;
  }, [materials]);

  /**
   * Cleanup function to dispose of cloned materials when the component unmounts
   * or when materials change. This prevents memory leaks.
   */
  useEffect(() => {
    return () => {
      Object.values(clonedMaterials).forEach((material) => {
        material.dispose();

        if (material.map) material.map.dispose();
        if (material.normalMap) material.normalMap.dispose();
        if (material.roughnessMap) material.roughnessMap.dispose();
      });
    };
  }, [clonedMaterials]);

  return (
    <group {...props}>
      <group scale={0.01}>
        <mesh
          geometry={nodes.Cube__0.geometry}
          material={clonedMaterials["Scene_-_Root"]}
          rotation={[-Math.PI / 2, 0, 0]}
          scale={1.166}
        />
      </group>
    </group>
  );
}

useGLTF.preload("/glbs/simple-brown-desk.glb");

image

My guess is GLTFJSX virtual scene bugs this out.

Add this clonedMaterials system into the GLTF component.