I am new to babylonjs and I have developed babylonjs application with imperative method. However, when I integrate ReactBabylon library, the shadow of the mesh only appear on StandardMaterial ground.
Here is the full source code including the main App as entrypoint, Camera component, Lights component, SceneSetup component and ShadowGround component
import { useState, useEffect } from "react";
import { Vector3 } from "@babylonjs/core";
import { Scene, Engine } from "react-babylonjs";
import "@babylonjs/loaders";
import Camera from "./components/Camera.js"
import ShadowGround from "./components/ShadowGround.js";
import Lights from "./components/Lights";
import SceneSetup from "./components/SceneSetup.js";
import Furniture from "./components/Furniture.js";
import DiningChair from "./assets/furnitures/dining_chair.glb";
import Sofa from "./assets/furnitures/sofa.glb";
const App = () => {
const [shadowGenerator, setShadowGenerator] = useState(null);
useEffect(() => {
}, [shadowGenerator]);
return (
<Engine antialias adaptToDeviceRatio canvasId="babylon-js">
<Scene>
<SceneSetup />
<Camera />
<Lights setShadowGeneratorRef={setShadowGenerator}/>
<ShadowGround position={new Vector3(0, -5, 0)} />
{shadowGenerator && (
<>
<Furniture
key={`chair-${shadowGenerator.getLight()?.name}`}
shadowGenerator={shadowGenerator}
model={DiningChair}
position={new Vector3(-5, -5, -3)}
scaling={new Vector3(4, 4, 4)}
rotation={new Vector3(0, 0, 0)}
/>
<Furniture
key={`sofa-${shadowGenerator.getLight()?.name}`}
shadowGenerator={shadowGenerator}
model={Sofa}
position={new Vector3(5, -5, -3)}
scaling={new Vector3(4, 4, 4)}
rotation={new Vector3(0, 0, 0)}
/>
</>
)}
</Scene>
</Engine>
);
};
export default App;
import { Vector3, StandardMaterial } from "@babylonjs/core";
import { ShadowOnlyMaterial } from "@babylonjs/materials";
import { useScene } from "react-babylonjs";
console.log("ShadowOnlyMaterial exists:", ShadowOnlyMaterial);
const ShadowGround = ({ position }) => {
const scene = useScene();
return (
<ground
name="ground"
width={200}
height={200}
position={position}
receiveShadows
onCreated={(ground) => {
console.log("Ground created:", ground);
console.log("Scene lights:", scene.lights);
const shadowMaterial = new ShadowOnlyMaterial("shadowMat", scene);
shadowMaterial.alpha = 1.0;
ground.material = shadowMaterial;
}}
/>
);
};
export default ShadowGround;
import { Vector3, ShadowGenerator } from "@babylonjs/core";
const Lights = ({ setShadowGeneratorRef }) => {
return (
<>
<hemisphericLight
name="hemisphericLight"
intensity={0.3}
direction={new Vector3(0, 1, 0)}
/>
<directionalLight
name="directionalLight"
intensity={1}
direction={new Vector3(0, -1, 1)} // Ensure correct shadow direction
position={new Vector3(0, 10, -10)} // Adjusted to cast shadows correctly
onCreated={(instance) => {
instance.shadowEnabled = true;
const shadowGenerator = new ShadowGenerator(2048, instance);
setShadowGeneratorRef(shadowGenerator);
}}
/>
</>
);
};
export default Lights;
import { useEffect } from "react";
import { useScene } from "react-babylonjs";
import { SceneLoader, PointerDragBehavior, Vector3 } from "@babylonjs/core";
import "@babylonjs/loaders";
const Furniture = ({ shadowGenerator, model, position, scaling, rotation }) => {
const scene = useScene();
useEffect(() => {
if (!scene || !shadowGenerator) return;
SceneLoader.ImportMeshAsync("", model, "", scene)
.then((result) => {
const furniture = result.meshes[0];
furniture.position = position;
furniture.scaling = scaling;
furniture.rotation = rotation;
const dragBehavior = new PointerDragBehavior({
dragPlaneNormal: new Vector3(0, 1, 0),
});
furniture.addBehavior(dragBehavior);
// Ensure shadow is added before rendering
shadowGenerator.addShadowCaster(furniture, true);
furniture.receiveShadows = true;
console.log(
"Shadow casters:",
shadowGenerator.getShadowMap()?.renderList
);
console.log("Furniture mesh:", furniture);
console.log("Is furniture casting shadows?", furniture.receiveShadows);
console.log("Light used for shadows:", shadowGenerator.getLight());
})
.catch((err) => console.error("Error loading GLB:", err));
}, [scene, shadowGenerator, model, position, scaling, rotation]);
return null;
};
export default Furniture;
import { Vector3 } from "@babylonjs/core";
const Camera = () => {
return (
<freeCamera
name="camera"
position={new Vector3(0, 0, -10)}
setTarget={[Vector3.Zero()]}
fov={1.6}
onCreated={(camera) => {
camera.inputs.clear();
}}
/>
);
};
export default Camera;
import { useEffect } from "react";
import { useScene } from "react-babylonjs";
import { HDRCubeTexture } from "@babylonjs/core";
import background from "../assets/backgrounds/background.hdr";
const SceneSetup = () => {
const scene = useScene();
useEffect(() => {
if (!scene) return;
const hdrTexture = new HDRCubeTexture(background, scene, 1024);
hdrTexture.level = 10;
scene.environmentTexture = hdrTexture;
scene.createDefaultSkybox(hdrTexture, true, 1000);
}, [scene]);
};
export default SceneSetup;
I have tried to work with ChatGPT to troubleshoot the issue, with all the log messages and using a plain mesh object. But it just don’t work.
With ShadowOnlyMaterial
With StandardMaterial
My current version of @babylonjs/core and @babylonjs/materials are:
── @babylonjs/core@7.47.2
├─┬ @babylonjs/gui@7.47.2
│ └── @babylonjs/core@7.47.2 deduped
├─┬ @babylonjs/loaders@7.47.2
│ └── @babylonjs/core@7.47.2 deduped
├─┬ @babylonjs/materials@7.47.2
│ └── @babylonjs/core@7.47.2 deduped
├─┬ babylonjs-hook@0.1.1
│ └── @babylonjs/core@7.47.2 deduped
└─┬ react-babylonjs@3.2.2
└── @babylonjs/core@7.47.2 deduped
Other libraries in package.json
“react”: “^18.3.1”,
“react-babylonjs”: “^3.2.2”,
“react-dom”: “^18.3.1”,