<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Babylon.js L-system Fractal Example</title> <script src="https://cdn.babylonjs.com/babylon.js"></script> <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script> <style> canvas { width: 100%; height: 100%; touch-action: none; } </style> </head> <body> <canvas id="renderCanvas"></canvas> <script> window.addEventListener('DOMContentLoaded', function () { var canvas = document.getElementById('renderCanvas'); var engine = new BABYLON.Engine(canvas, true); var createScene = function () { var scene = new BABYLON.Scene(engine); // Create a camera var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 10, BABYLON.Vector3.Zero(), scene); // Create a light var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene); // Create an array to hold the spheres var spheres = []; // Load the texture and bump map var texture = new BABYLON.Texture("https://www.babylonjs-playground.com/textures/floor.png", scene); var bumpMap = new BABYLON.Texture("https://www.babylonjs-playground.com/textures/floor_n.jpg", scene); // Define the L-system rules and starting axiom var rules = { F: "F+F-F-F+F" }; var axiom = "F-F-F-F"; var angle = Math.PI / 2; var length = 1; var iterations = 3; // Generate the L-system string var lSystemString = axiom; for (var i = 0; i < iterations; i++) { var newString = ""; for (var j = 0; j < lSystemString.length; j++) { var char = lSystemString.charAt(j); if (rules[char]) { newString += rules[char]; } else { newString += char; } } lSystemString = newString; } // Create a fountain of spheres that follow the L-system string var position = BABYLON.Vector3.Zero(); var direction = BABYLON.Vector3.Forward(); for (var i = 0; i < lSystemString.length; i++) { var char = lSystemString.charAt(i); if (char === "F") { // Create a new sphere var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {diameter: length, segments: 16}, scene); sphere.position = position.clone(); sphere.material = new BABYLON.StandardMaterial("texture", scene); sphere.material.diffuseTexture = texture; sphere.material.bumpTexture = bumpMap; spheres.push(sphere); // Animate the texture of the sphere var textureAnimation = new BABYLON.Animation("textureAnimation", "material.diffuseTexture.uOffset", 60, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE); var keys = []; keys.push({frame: 0, value:0}); keys.push({frame: 100, value: 1}); textureAnimation.setKeys(keys); sphere.material.diffuseTexture.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE; sphere.material.diffuseTexture.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE; sphere.material.diffuseTexture.uScale = 10; sphere.material.diffuseTexture.vScale = 10; sphere.animations.push(textureAnimation); scene.beginAnimation(sphere, 0, 100, true); // Animate the sphere var animation = new BABYLON.Animation("myAnimation", "position", 30, BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE); keys = []; keys.push({frame: 0, value: position.clone()}); position.addInPlace(direction.scale(length)); keys.push({frame: 100, value: position.clone()}); animation.setKeys(keys); sphere.animations.push(animation); scene.beginAnimation(sphere, 0, 100, true); } else if (char === "+") { // Rotate clockwise direction.rotateByQuaternionToRef(BABYLON.Quaternion.RotationAxis(BABYLON.Vector3.Up(), -angle), direction); } else if (char === "-") { // Rotate counterclockwise direction.rotateByQuaternionToRef(BABYLON.Quaternion.RotationAxis(BABYLON.Vector3.Up(), angle), direction); } } return scene; } var scene = createScene(); engine.runRenderLoop(function () { scene.render(); }); window.addEventListener('resize', function () { engine.resize(); }); }); </script> </body> </html>