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. The model however, cannot receive any shadow from another model. I’ve tried to use obj.castShadow = true
and obj.receiveShadow = true
to one of the receiving shadow model object on the parent and the children as well but it shows no difference. Is there any way to cast a shadow to another model?
And the shadow.. it seems very rough. Is there any way to smoothen it?
Here’s my sandbox:
https://codesandbox.io/s/modest-newton-np1sw
Code:
import React, { Suspense, useMemo, useState } from "react"; import { Canvas } from "react-three-fiber"; import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader"; import { OrbitControls} from "drei"; import { Mesh } from "three"; import billboard from "../assets/models/billboard.obj"; import bridge from "../assets/models/bridge.obj"; 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 ShadowedModel = ({ modelPath }) => { const [obj, setObj] = useState(); useMemo(() => new OBJLoader().load(modelPath, setObj), [modelPath]); if (obj) { obj.castShadow = true; obj.receiveShadow = true; obj.traverse((children) => { if (children instanceof Mesh) { children.castShadow = true; children.receiveShadow = true; } }); } return obj ? <primitive object={obj} /> : null; }; const Lights = () => { return ( <> <ambientLight intensity={0.1} /> <spotLight castShadow position={[-50, 50, 20]} intensity={0.5} shadow-mapSize-shadowMapWidth={2048} shadow-mapSize-shadowMapHeight={2048} shadow-camera-left={-50} shadow-camera-right={50} shadow-camera-top={-50} shadow-camera-bottom={50} /> <pointLight position={[10, -10, -20]} intensity={0.3} /> <pointLight position={[0, 10, 5]} intensity={0.3} /> <spotLight intensity={1} position={[0, 1000, 0]} /> </> ); }; const Billboard = () => { return ( <mesh castShadow position={[-15, 5, -35]} scale={[0.05, 0.05, 0.05]} rotation={[0, 20, 0]} > <Model modelPath={billboard} /> </mesh> ); }; const Bridge = () => { return ( <mesh castShadow receiveShadow position={[10, -40, -80]} // position={[-80, -40, -150]} scale={[0.15, 0.15, 0.15]} rotation={[0, 10.2, 0]} > <ShadowedModel modelPath={bridge} /> </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: [0, 0, 5], fov: 60 }} > <OrbitControls enablePan={Boolean("Pan", true)} enableZoom={Boolean("Zoom", true)} enableRotate={Boolean("Rotate", true)} /> <Shadow /> <Suspense fallback={null}> <Bridge /> </Suspense> <Billboard /> <Lights /> </Canvas> </> ); }; export default MegatronModel;
Any help would be appreciated.
Thank you very much.
Advertisement
Answer
Your model is indeed receiving shadows. The problem is that you have several PointLight
s at full intensity that are washing everything out into white. Even shaded areas are blown out to white. See here, I’ve disabled all your PointLight
s and only kept the spotlight and ambient light so you can see the shadows again:
I recommend you use as few lights as possible to make rendering less resource-intensive. Adding so many lights could lower your framerate, overheat laptops, and drain more battery on cell-phones. For a pretty realistic lighting setup, I like using a single hemisphere light with a directional light like in this demo. Hemisphere makes it feel like there’s atmospheric light coming from the top, with reflected ground light from the bottom.
As far as pixelated shadows go, you’re using a large 2048×2048 map, but it’s spread out across too large an area. I see you’re trying to set left, right, top, bottom
distances but those only apply to DirectionalLight, which uses an orthographic camera. Left, right, top, & bottom properties don’t apply to SpotLight, which uses a perspective camera. If you want to make the Spotlight shadowmap narrower, use the .angle
property.