0

I'm currently new and learning about three.js. And i'm using react-three-fiber to make it happen with React, but i stumbled upon a problem. It cannot cast a shadow to the model whatsoever. I've tried to use obj.castShadow = true on the parent and the children as well but it shows no difference.

Here's my sandbox link :
https://codesandbox.io/s/sleepy-satoshi-8eckc?file=/src/components/Model.js

Any help would be appreciated. Thank you.

1 Answers1

0

After experimenting, it turns out that i accidentally set the shadow-camera-far to 50. My bad.

So here's what my final code looks like

const PerspectiveCamera = (props) => {
  const cam = useRef();
  const { setDefaultCamera } = useThree();
  useFrame(() => cam.current.updateMatrixWorld());
  useHelper(cam, CameraHelper, 1, "hotpink");

  return <perspectiveCamera ref={cam} {...props} />;
};

const Model = ({ modelPath }) => {
  const [obj, setObj] = useState();
  useMemo(() => new OBJLoader().load(modelPath, setObj), [modelPath]);
  if (obj) {
    obj.castShadow = true;
    obj.traverse((children) => {
      if (children instanceof Mesh) {
        children.castShadow = true;
      }
    });
  }
  return obj ? <primitive object={obj} /> : null;
};

const Lights = () => {
  const refLight1 = useRef();
  const refLight2 = useRef();
  const refLight3 = useRef();
  useHelper(refLight1, PointLightHelper, 5);
  useHelper(refLight2, PointLightHelper, 5);
  useHelper(refLight3, DirectionalLightHelper, 5);

  return (
    <>
      <ambientLight intensity={0.1} />
      <directionalLight
        ref={refLight3}
        castShadow
        position={[50, 20, 80]}
        intensity={0.5}
        shadow-mapSize-shadowMapWidth={2048}
        shadow-mapSize-shadowMapHeight={2048}
        shadow-camera-left={-10}
        shadow-camera-right={10}
        shadow-camera-top={-50}
        shadow-camera-bottom={10}
      />
      <pointLight ref={refLight1} position={[10, -10, -20]} intensity={0.3} />
      <pointLight ref={refLight2} position={[0, 10, 5]} intensity={0.3} />
      <spotLight intensity={1} position={[0, 1000, 0]} />
    </>
  );
};

const Billboard = () => {
  return (
    <mesh
      castShadow
      position={[-18, 5, -35]}
      scale={[0.05, 0.05, 0.05]}
      rotation={[0, 8, 0]}
    >
      <Model modelPath={billboard} />
    </mesh>
  );
};

const Shadow = () => {
  return (
    <group>
      <mesh
        receiveShadow
        rotation={[-Math.PI / 2, 0, 0]}
        position={[-20, -32, -40]}
      >
        <planeBufferGeometry attach="geometry" args={[500, 500]} />
        <meshLambertMaterial attach="material" color={"lightblue"} />
      </mesh>
    </group>
  );
};

const MegatronModel = () => {
  return (
    <>
      <Canvas
        shadowMap
        colorManagement
        camera={{ position: [-150, 5, 0], fov: 60 }}
      >
        <PerspectiveCamera position={[-10, 5, 40]} fov={60} />
        <OrbitControls
          enablePan={Boolean("Pan", true)}
          enableZoom={Boolean("Zoom", true)}
          enableRotate={Boolean("Rotate", true)}
        />
        <axesHelper />
        <Shadow />
        <Billboard />
        <Lights />
      </Canvas>
    </>
  );
};

export default MegatronModel;
  • Small hint, try to use useLoader which makes loading assets simpler. Also check out gltfjsx, which allows you to write out nicely declaratively. You don't need to traverse, you supply put castShadow on the meshes directly. – hpalu Nov 14 '20 at 08:51
  • Alright, thanks for the tip! Will try that later to top off my code. Thank you. – Lovelycroissant Nov 14 '20 at 11:40