React/Next with Babylon - Procedural Terrain Generation


Started playing around with Babylon.js and procedural terrain generation recently. I started right off the bat by wrapping Babylon in React, which I use through Next.js.

Consider this code:

 export default function Canvas({ engineOptions, onRender, 
         onSceneReady, sceneOptions, proceduralTerrainConfig }: 
         ICanvasProps): JSX.Element {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const { dimension, 
              seed } = proceduralTerrainConfig;

  useEffect(() => {
    const canvas = canvasRef.current;
    if (canvas) {
      const engine = new Engine(canvas, true, engineOptions, true);
      const noise = withSeed(seed)(dimension, scale, octaves, persistence, lacunarity);
      const scene = createScene(engine, sceneOptions, noise, multiplier, dimension);

      if (scene.isReady()) {
      } else {
        scene.onReadyObservable.addOnce((scene) => {
          return onSceneReady(scene);

      engine.runRenderLoop(() => {
        if (typeof onRender === "function") {

      const resize = (): void => {

      return function cleanup() {
        if (window) {
          window.removeEventListener("resize", resize);
    }, [canvasRef, seed, dimension, multiplier, scale, octaves, 
    persistence, lacunarity]);

    return <canvas ref={canvasRef} className={styles.canvas} />;

As you can see, I’m injecting new dimension, scale, multiplier and other such terrain generation data from outside the component. That’s because I set up some sliders to play around with them and get accustomed to these new principles in a more visual way.

So, is there a way, or someplace in there I should pinpoint, to change the scene? I would have to create new noise/scene and then apply it. So what’s the best way? Right now it’s recreating the engine and canvas. I’m sure there’s a better way.

EDIT: The code formatter is not very friendly.

I was using this block in the createScene function:

   const vertexData = new VertexData();
   const { colors, indices, positions } = 
   createTerrainData(dimension, noise, multiplier);
   vertexData.positions = positions;
   vertexData.indices = indices;
   vertexData.colors = colors;
   vertexData.normals = (empty Array);
   vertexData.indices, vertexData.normals);

So all I had to do was extract it, put it in its own useEffect() hook and it now works. I’ve got weird stuff happening when I use the dimension one but I’ll figure something out.

1 Like