How to set the camera in Babylon.js to be in third person?

I managed to create a code where the cameras follow the "tank" object. But with the mouse, you can zoom in and out of the camera. Tell me how to set up the camera so that it moves like in GTA behind the car?

Here is an example from GTA Vice City. When playing, the camera follows the car and does not move. In my case, using the mouse, you can change the camera path. How to fix it and make it like in GTA?

enter image description here My code: "index.html"

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.min.js"></script>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="pointerLock.js"></script>
<title> Babylon FPS</title>
</head>
<body>

<canvas id="renderCanvas"></canvas>
<script src="main.js" type="module"></script>

</body>
</html>

main.js

window.addEventListener('DOMContentLoaded', function(){
            // get the canvas DOM element
            var canvas = document.getElementById('renderCanvas');

            // load the 3D engine
            var engine = new BABYLON.Engine(canvas, true);
            
            
             var createFollowCamera = function(scene,canvas,target){
              var camera = new BABYLON.FollowCamera("tankFollowCamera",new BABYLON.Vector3(10,0,10), scene);
              camera.heightOffset= 2;
              camera.rotationOffset = 180;
              camera.cameraAcceleration = .1;
              camera.maxCameraSpeed = 1;
              camera.lockedTarget = target;
              camera.attachControl(canvas, true);
              return camera;
            }
            

            // createScene function that creates and return the scene
            var createScene = function () {
                    var scene = new BABYLON.Scene(engine);
                    
                    var sun = new BABYLON.PointLight("Omni0", new BABYLON.Vector3(60, 100, 10), scene);
                    
                    

                  
                    

                    // Ground
                    var ground = BABYLON.Mesh.CreateGroundFromHeightMap("ground", "https://www.babylonjs-playground.com/textures/heightMap.png", 200, 200, 100, 0, 10, scene, false);
                    var groundMaterial = new BABYLON.StandardMaterial("ground", scene);
                    groundMaterial.diffuseTexture = new BABYLON.Texture("https://www.babylonjs-playground.com/textures/grass.png", scene);
                    groundMaterial.diffuseTexture.uScale = 6;
                    groundMaterial.diffuseTexture.vScale = 6;
                    groundMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
                    ground.position.y = -2.05;
                    ground.material = groundMaterial;

                    // Skybox
                        var skybox = BABYLON.Mesh.CreateBox("skyBox", 1000.0, scene);
                        var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
                        skyboxMaterial.backFaceCulling = false;
                        skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("https://www.babylonjs-playground.com/textures/TropicalSunnyDay", 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.disableLighting = true;
                        skybox.material = skyboxMaterial;        
                 
                
                var tank = new BABYLON.MeshBuilder.CreateBox("tank",{height:.5, depth:1, width:1},scene);
                var tankMaterial = new BABYLON.StandardMaterial("tankMaterial",scene);
                tankMaterial.diffuseColor = new BABYLON.Color3(1,0,5);
                
                tank.material = tankMaterial
                tank.position.y = 5;
                tank.speed = 1;
                tank.frontVector = new BABYLON.Vector3(0,0,1);
                
                
                
                
                //var camera = 
                createFollowCamera(scene,canvas,tank);
               
                console.log(tank.move);
                
                
                //set up input map
                var inputMap = {};
                  scene.actionManager = new BABYLON.ActionManager(scene);
                  scene.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnKeyDownTrigger, function (evt) {
                      inputMap[evt.sourceEvent.key] = evt.sourceEvent.type == "keydown";
                     
                  }));
                  scene.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnKeyUpTrigger, function (evt) {
                      inputMap[evt.sourceEvent.key] = evt.sourceEvent.type == "keydown";
                      
                  }));
                
                scene.onBeforeRenderObservable.add(function(){
                     if(tank){
                      if(inputMap["w"] || inputMap["ArrowUp"]){
                        tank.moveWithCollisions(tank.frontVector.multiplyByFloats(tank.speed,tank.speed,tank.speed));
                      }
                      if(inputMap["a"] || inputMap["ArrowLeft"]){
                         tank.rotation.y -= .1;
                         tank.frontVector = new BABYLON.Vector3(Math.sin(tank.rotation.y),0,Math.cos(tank.rotation.y));
                      }
                      if(inputMap["s"] || inputMap["ArrowDown"]){
                         tank.moveWithCollisions(tank.frontVector.multiplyByFloats(-tank.speed,-tank.speed,-tank.speed)); 
                      }
                      if(inputMap["d"] || inputMap["ArrowRight"]){
                         tank.rotation.y += .1;
                         tank.frontVector = new BABYLON.Vector3(Math.sin(tank.rotation.y),0,Math.cos(tank.rotation.y));
                       } 
                     }
                     
                      
                  })
                return scene;
              };
            
            
           
            // call the createScene function
            var scene = createScene();
            createPointerLock(scene); 
            // run the render loop
            engine.runRenderLoop(function(){
                scene.render();
            });

            // the canvas/window resize event handler
            window.addEventListener('resize', function(){
                engine.resize();
            });
        });

link to https://codepen.io/Smith37/pen/OJxdmaw


Solution 1:

You need to remove Babylon's default camera pointer input handling. You could remove all camera input handling:

  • camera.inputs.clear();

Or remove just the pointer handling:

  • ArcRotateCamera

    • camera.inputs.removeByType('ArcRotateCameraPointersInput');
  • FollowCamera

    • camera.inputs.removeByType('FollowCameraPointersInput');

Example:

  • https://codepen.io/kaliatech/pen/GROOZeZ

More info:

  • https://doc.babylonjs.com/divingDeeper/cameras/customizingCameraInputs
  • https://github.com/BabylonJS/Babylon.js/tree/master/src/Cameras/Inputs