I just figured I’d make a note here that I was surprised at the number of light sources I could pump out using the light.includedOnlyMeshes feature. No problem with 1000 objects + instances with 1000 light sources minus the increasingly recursive compilation times.
Kind of curious if Babylon will see Forward+ in the future, but I guess you can kind of fake it as long as you are fine with a really long initial shader compilation as you get into the 700+ light source range. It’s a nice thing to go with instances otherwise. Can you export these scenes after you’ve done the initial compilation so you don’t have to do it more than once? That’s the only major drawback to this method if I wanted to actually deliver something.
Here’s a single threaded test with 20K objects on a single thread with WebGPU. About 35FPS average which is pretty impressive to me. (RTX 3070 so overqualified)
Like exportable cached? I see a number of tools around for that just not sure how it all works.
Is there one bulk array call to set the lights/objects in the scene? Just doing it in series makes it recursive AF. I’ve been messing around with transpilers and automated pipelines lately so am just wondering what’s going on under the hood for it to get exponentially slower when you set things up linearly.
So in terms of setting up the scene though, pretty sure what’s happening is each time I create a light or object it’s going through and rebuilding the whole pipeline, is there a way around that? Takes a good minute to compile with 1000 lights/objects, just not clear if there’s a fast order of operations there.
I wrote this in like 10 min but I am working on a game demo rn so this is of interest to me to speed up the scene creation with all the sources, though I’ll probably use max 100 lights in practice.
<html>
<head>
<title>BabylonJS Example</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
</head>
<body>
FPS: <span id="fps">0</span><br/>
<canvas id="renderCanvas" touch-action="none" width="100%" height="100%" style="position:absolute; z-index:2; width:100%; height:100%;"></canvas>
<span style="position:absolute">Compiling a 1000 light source shader is slow... (Note this is a single threaded test). Compiled:<span id="cp">0</span></span>
<script>
const setupScene = async () => {
// Get the canvas element
const canvas = document.getElementById("renderCanvas");
// Initialize BabylonJS
const engine = new BABYLON.Engine(canvas);
//const engine = new BABYLON.WebGPUEngine(canvas);
//engine.initAsync().then(async () => {
// Create a basic BabylonJS scene
const scene = new BABYLON.Scene(engine);
const N = 1000;
const rtN = Math.sqrt(N);
// Add a camera
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI/2, Math.PI / 2, 150, new BABYLON.Vector3(3*rtN/2, 3*rtN/2, 0), scene);
camera.attachControl(canvas, true);
// Store light data for rotation
const lights = [];
// Create 1000 instances with point lights
for (let i = 0; i < N; i++) {
if(i % 100 === 0) {
document.getElementById('cp').innerText = i;
await new Promise((res)=>{setTimeout(()=>{res(true);},0.001);});
}
// Create a sphere instance
let sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {diameter: 1}, scene);
sphere.position.x = (i % rtN) * 3;
sphere.position.y = Math.floor(i / rtN) * 3;
// Create a point light for each sphere with random color
let pointLight = new BABYLON.PointLight("pointLight" + i, new BABYLON.Vector3(sphere.position.x, sphere.position.y, sphere.position.z), scene);
pointLight.includedOnlyMeshes.push(sphere);
// Random color
pointLight.diffuse = new BABYLON.Color3(Math.random(), Math.random(), Math.random());
// Store light data
lights.push({
light: pointLight,
sphere: sphere,
angle: Math.random() * Math.PI * 2, // Initial angle
rotationSpeed: (Math.random() > 0.5 ? -1 : 1) * 0.02, // Random rotation speed and direction
radius: 2
});
// Create additional instances projecting in the Z direction to show additional scene complexity
for (let j = 1; j <= 2; j++) {
let sphereInstance = sphere.createInstance("sphereInstance" + i + "_" + j);
sphereInstance.position = sphere.position.clone();
sphereInstance.position.z += j * 2; // Adjust Z position
}
}
let divFps = document.getElementById("fps")
// Start the render loop
engine.runRenderLoop(() => {
// Update light positions
lights.forEach((data) => {
data.angle += data.rotationSpeed;
data.light.position.x = data.sphere.position.x + data.radius * Math.cos(data.angle);
data.light.position.z = data.sphere.position.z + data.radius * Math.sin(data.angle);// Keep Y position constant to maintain a horizontal orbit
data.light.position.y = data.sphere.position.y + data.radius * Math.sin(data.angle);
});
scene.render();
divFps.innerHTML = engine.getFps().toFixed()
});
// Resize the engine on window resize
window.addEventListener('resize', function(){
engine.resize();
});
// });
}
setupScene();
</script>
</body>
</html>