<head>
    <link href="https://fonts.googleapis.com/css2?family=Rajdhani:wght@500&display=swap" rel="stylesheet">
     <title>BABYLON js Template by Hitesh Sahu</title>
    </head>
<body>
    <div class="container"> 
      <div class="container"><canvas id="renderCanvas" class="container" /></div>
      <div class="footer"><a href = "https://hiteshsahu.com/lab">See More in Lab 🧪</a></div> 
     <div class="header"><h2>BABYLON JS Template by Hitesh Sahu<h2></div>
</div>
</body>
<link href="https://fonts.googleapis.com/css2?family=Lobster&display=swap" rel="stylesheet">

#renderCanvas {
    position: absolute;
  width: 100%;
  height: 100%;
  touch-action: none;
   left:  0%;
  right: 0%;
  bottom:0%;
  top: 0%;
} 

 html, body {
  overflow: hidden;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
font-family: 'Rajdhani', sans-serif;
    color: white;
  font-size: large;

}

a:link, a:visited {
  background-color: #f44336;
  color: white;
  padding: 14px 25px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
}

.container {
  position: relative;
  height: 100%;
  width: 100%;
}

.header {
  position: absolute;
  left:0;
  right:0;
  top:0;
  padding-left:10px;
    text-align: center;

}

.footer {
  position: absolute;
  right:0;
  bottom:0;
  margin:5px;
  padding:5px;
}

a:hover, a:active {
  background-color: red;
}

.center {
  position: absolute;
  background-color: #00bfa5;
  left:  0%;
  right: 0%;
  bottom:0%;
  top: 0%;
  margin:10px;
  padding:10px;
}

const GROUND_SIZE = 30
const VELOCITY = 70
const MIN_HEIGHT = 3;
const MAX_HEIGHT = 1
const TEXTURE_FOLDER = "https://www.babylonjs-playground.com/textures/"
const TEXTURES= {
  Wood: "https://images.pexels.com/photos/172288/pexels-photo-172288.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
  Dirt: TEXTURE_FOLDER+ "ground.jpg",
  Ground: TEXTURE_FOLDER+ "ground.jpg",
  Fur: "https://images.pexels.com/photos/801243/pexels-photo-801243.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"
}
let projectiles= []
const options = {
    highlightPickedItem: false,
    useSkyBox: true,
    showFog: true
}

var lastClickedMesh = null


    //------------------- init Scene---------------------

    var canvas = document.getElementById("renderCanvas");
    var engine = new  BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });

    var scene = new BABYLON.Scene(engine);
    scene.clearColor = BABYLON.Color3.FromHexString("#263238")


    //Add Physics
    var ammo = new BABYLON.CannonJSPlugin(true);
    scene.enablePhysics(new BABYLON.Vector3(0, -10, 0), ammo);

    // --------------------Add Camera--------------------
    var camera = new BABYLON.ArcRotateCamera("Camera",
        Math.PI / 2, Math.PI / 2, 40, BABYLON.Vector3.Zero(), scene);
    camera.setTarget(BABYLON.Vector3.Zero());
    camera.attachControl(canvas, true);
    camera.lowerBetaLimit = 0.1;
    camera.upperBetaLimit = (Math.PI / 2) * 0.9;
    camera.lowerRadiusLimit = 3;
    camera.upperRadiusLimit = GROUND_SIZE * 2;
    camera.setPosition(new BABYLON.Vector3(GROUND_SIZE / 2, 5, GROUND_SIZE / 2))

    //-------------------- Lights -------------------------------

    //Light for Gtlf
    var ambientLight = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
    ambientLight.intensity = 0.25;

    //SunLight 
    // var sunLight = new BABYLON.DirectionalLight("dir01", new BABYLON.Vector3(-1, -10, -1), scene);
    // sunLight.position = new BABYLON.Vector3(GROUND_SIZE , GROUND_SIZE / 4, GROUND_SIZE );
    // sunLight.intensity = 5;

    var sunLight = new BABYLON.SpotLight("sunLight",
             new BABYLON.Vector3(GROUND_SIZE/2 , GROUND_SIZE / 2, GROUND_SIZE/2),
               new BABYLON.Vector3(-1, -1, -1),
                                          Math.PI/2 , 1, scene);
    sunLight.diffuse =  BABYLON.Color3.FromHexString("#e25822")
    sunLight.diffuse = new BABYLON.Color3.FromHexString("#F96229"); //(1, 1, 1);
    sunLight.specular = new BABYLON.Color3.FromHexString("#FCE13D");
   sunLight.intensity = 5;


    //Imposter for sun
    var lightImposter = BABYLON.Mesh.CreateSphere("lightImposter", 10, 2, scene);
    var lightImposterMat = new BABYLON.StandardMaterial("lightImposterMat", scene);
    lightImposterMat.diffuseColor = new BABYLON.Color3(1, 1, 0);
    lightImposterMat.emissiveColor = new BABYLON.Color3(1, 1, 0);
    lightImposter.material = lightImposterMat
    lightImposter.position = sunLight.position;

    // Shadows
    var shadowGenerator = new BABYLON.ShadowGenerator(1024, sunLight);
    shadowGenerator.darkness = .25
    shadowGenerator.useExponentialShadowMap = true;

    //Make meshes glow
    new BABYLON.GlowLayer("glow", scene, {
        mainTextureFixedSize: 1024,
        blurKernelSize: 64
    });

    //---------------Skybox----------------------
    if (options.useSkyBox) {
        var skyboxMesh = BABYLON.Mesh.CreateBox("skyBox", GROUND_SIZE * 4, scene);
        var skyboxMaterial = new BABYLON.StandardMaterial("skyboxMaterial", scene);
        skyboxMaterial.backFaceCulling = false;
        skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture(TEXTURE_FOLDER+ "skybox", scene);
        skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
        skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
        skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
        skyboxMaterial.reflectionTexture.boundingBoxSize = null;
        skyboxMesh.material = skyboxMaterial;
    }

    //Fog!
    if(options.showFog){
    scene.fogMode = BABYLON.Scene.FOGMODE_LINEAR;
    scene.fogColor = scene.clearColor;
    scene.fogDensity = 0.01;
    scene.fogStart = 20.0;
    scene.fogEnd =  100.0;
      }


    //------------------Add Ground---------------
    var groundMesh = BABYLON.MeshBuilder.CreateGroundFromHeightMap("groundMesh",
        TEXTURE_FOLDER+"heightMap.png",
        {
            width: GROUND_SIZE,
            height: GROUND_SIZE,
            subdivisions: 100,
            minHeight: MIN_HEIGHT,
            maxHeight: MAX_HEIGHT,
            onReady: () => {
                var groundMaterial = new BABYLON.StandardMaterial("ground", scene);
                groundMaterial.diffuseTexture = new BABYLON.Texture(TEXTURES.Dirt, scene);
                groundMaterial.diffuseTexture.uScale = 3;
                groundMaterial.specularColor = BABYLON.Color3.Black()

                groundMesh.material = groundMaterial;
                // //Shadow
                groundMesh.receiveShadows = true;
                groundMesh.isPickable = true

                //Physics
                groundMesh.physicsImpostor =
                    new BABYLON.PhysicsImpostor(groundMesh,
                        BABYLON.PhysicsImpostor.HeightmapImpostor,
                        {
                            mass: 0,
                            restitution: 0.5,
                            friction: 1
                        }, scene);
            }

        }, scene);


    //------------------Meshes---------------------------
    var sphereMesh = BABYLON.MeshBuilder.CreateSphere("sphereMesh",
        { diameter: 2, segments: 32 }, scene);
    sphereMesh.position.y = 5;
    shadowGenerator.addShadowCaster(sphereMesh);

    var mat = new BABYLON.StandardMaterial("toto", scene);
    mat.specularTexture = new BABYLON.Texture(TEXTURE_FOLDER+"specularglossymap.png", scene);
    mat.specularPower = 64;
    mat.useGlossinessFromSpecularMapAlpha = true;
    mat.diffuseColor = BABYLON.Color3.Black();
    mat.roughness = 3;
    mat.reflectionTexture = new BABYLON.CubeTexture(TEXTURE_FOLDER +"skybox", scene);
    sphereMesh.material = mat;
   sphereMesh.physicsImpostor = new BABYLON.PhysicsImpostor(sphereMesh,      BABYLON.PhysicsImpostor.SphereImpostor,{
            mass: 0.5,
            restitution: 1,
            friction: .25
        }, scene);

    // Add and manipulate meshes in the scene
    var boxMesh = BABYLON.MeshBuilder.CreateBox("boxMesh", {
        height: 2,
        width: 2,
        depth: 2,
        updatable: true

    });
    shadowGenerator.addShadowCaster(boxMesh);
    boxMesh.position.y = 5
    boxMesh.physicsImpostor = new BABYLON.PhysicsImpostor(boxMesh, BABYLON.PhysicsImpostor.BoxImpostor, {
            mass: 0.5,
            restitution: 1,
            friction: .25
        }, scene);

    var boxMaterial = new BABYLON.StandardMaterial("boxMaterial", scene);
    boxMaterial.diffuseTexture = new BABYLON.Texture(TEXTURES.Wood, scene);
    boxMesh.material = boxMaterial;

   for(let i= 0; i<20; i++)  {
       boxMesh.clone("boxMesh")
     }

 for(let i= 0; i<10; i++)  {
       boxMesh.clone("boxMesh")
     sphereMesh.clone("boxMesh")
     }

    // create particles
    var particle = BABYLON.MeshBuilder.CreateSphere(
        "sphere",
        { diameter: 0.25, segments: 3 },
        scene
    );
    var particleMaterial = new BABYLON.StandardMaterial("texture", scene);
    particleMaterial.diffuseColor = new BABYLON.Color3(1, 0, 0);
    particle.material = particleMaterial;
    particle.isVisible = false;

    let vertexes = boxMesh.getVerticesData(
        BABYLON.VertexBuffer.PositionKind
    );
    for (let vertex = 0; vertex < vertexes.length; vertex += 3) {
        let vertexMesh = particle.createInstance("s" + vertex)
        vertexMesh.position = BABYLON.Vector3.FromArray(vertexes, vertex);
        vertexMesh.parent = boxMesh
    }


    //-----------Event loop ----------------------------------
    var angle = 0;
    scene.registerBeforeRender(() => {
      
         camera.alpha += 0.0025 * scene.getAnimationRatio();

        angle += 0.01;

        //Reset if out of bound
        scene.meshes.forEach(mesh => {
            if (mesh.position.y < -10) {
                if (mesh.name === "boxMesh") {
                    mesh.position = new BABYLON.Vector3(
                        randomBetween(-GROUND_SIZE / 4, GROUND_SIZE / 4),
                        randomBetween(5, 15),
                        randomBetween(-GROUND_SIZE / 4, GROUND_SIZE / 4)
                    );
                    mesh.physicsImpostor.setLinearVelocity(BABYLON.Vector3.Zero());
                    mesh.physicsImpostor.setAngularVelocity(BABYLON.Vector3.Zero());
                }
            }
        });
    });

    scene.onKeyboardObservable.add((kbInfo) => {
        switch (kbInfo.type) {
            case BABYLON.KeyboardEventTypes.KEYUP:
                //console.log("KEY UP: ", kbInfo.event.keyCode);
                switch (kbInfo.event.keyCode) {
                    case 87: //W
                        break;

                    case 65: //A
                        break;

                    case 83: //S
                        break;

                    case 68: //D
                        break;

                    case 32: //SPACE
                        break;
                }
                break;
        }
    });

    var h1 = new BABYLON.HighlightLayer("hl", scene);

    scene.onPointerObservable.add((pointerInfo) => {
        switch (pointerInfo.type) {
            case BABYLON.PointerEventTypes.POINTERDOWN:
                let pickInfo = pointerInfo.pickInfo;
                if (pickInfo.hit) {
                    // Shoot new Ball
                    let position = pickInfo.ray.origin;
                    let velocity = pickInfo.ray.direction.scale(VELOCITY);
                    shootBullet(position, velocity, scene)

                    //Do something with Picked Mesh
                    let pickedMesh = pickInfo.pickedMesh;

                    // HighLight Selected
                    if (pickedMesh) {
                        if (lastClickedMesh) {
                            h1.removeMesh(lastClickedMesh);
                        }
                        lastClickedMesh = pickedMesh;
                        if (options.highlightPickedItem)
                            h1.addMesh(lastClickedMesh, BABYLON.Color3.Green());

                        //Apply Bullet Force
                        pickedMesh.applyImpulse(
                            new BABYLON.Vector3(
                                Math.random() * 5,
                                Math.random() * 15,
                                Math.random() * 5
                            ),
                            pickedMesh.position
                        );
                    }
                }
                break;
            case BABYLON.PointerEventTypes.POINTERUP:
                break;
            case BABYLON.PointerEventTypes.POINTERMOVE:
                break;
            default:
                break;
        }
    });

randomBetween = (max = 0, min = 0) => Math.floor(Math.random() * (max + 1 - min)) + min;

shootBullet = (position, velocity, scene) => {
        if (projectiles.length > 10) {
            projectiles.shift().dispose();
        }

        var ballMesh = BABYLON.Mesh.CreateSphere("boxMesh", 16, 2, scene);
        ballMesh.position = position;
        let ballmaterial = new BABYLON.StandardMaterial("cover", scene);
        ballmaterial.diffuseTexture = new BABYLON.Texture(
            TEXTURES.Fur
        );
        ballmaterial.emissiveTexture = new BABYLON.Texture(
             TEXTURES.Fur
        );
        ballMesh.material = ballmaterial;
        ballMesh.position.copyFrom(position);
        ballMesh.physicsImpostor = new BABYLON.PhysicsImpostor(
            ballMesh,
            BABYLON.PhysicsImpostor.SphereImpostor,
            { mass: .5, restitution: 0.2 },
            scene
        );
        ballMesh.physicsImpostor.setLinearVelocity(velocity);
        ballMesh.physicsImpostor.setAngularVelocity(new BABYLON.Quaternion(2, 0, 2, 0));
        projectiles.push(ballMesh);
    };

engine.runRenderLoop(() => {
    if (scene) scene.render();
});

// Resize
window.addEventListener("resize", () => {
    engine.resize();
});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://code.jquery.com/pep/0.4.2/pep.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js
  3. https://preview.babylonjs.com/ammo.js
  4. https://preview.babylonjs.com/cannon.js
  5. https://preview.babylonjs.com/Oimo.js
  6. https://preview.babylonjs.com/libktx.js
  7. https://preview.babylonjs.com/earcut.min.js
  8. https://preview.babylonjs.com/babylon.js
  9. https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js
  10. https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js
  11. https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js
  12. https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js
  13. https://preview.babylonjs.com/loaders/babylonjs.loaders.js
  14. https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js
  15. https://preview.babylonjs.com/gui/babylon.gui.min.js