How to create animated paths to a specific areas [RESOLVED]

you will find attached a metro station that I exported from blender.


I control the camera by adding “ArcRotateCamera()”.
I want to create points on specific areas, when I click there will be a path to the point click like this demonstration Interface interactive

I want to interact with my interface by moving the camera to the clicked area.

you will find attached my poor code

 <!DOCTYPE html>
 <html>

<head>
	<!--<meta charset="UTF-8">-->
       <style>
    html, body {
        overflow: hidden;
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        font-family: OpenSans, tahoma, arial, sans-serif;
        color:white;
    }

    canvas {
        width: 100%;
        height: 100%;
        touch-action: none;
    }
</style>
<script src="/babylonTest/babylon.js"></script>
</head>

<body>
<canvas id="renderCanvas" touch-action="none"></canvas> <!--//touch-action="none" for best 
results from PEP-->
<script src="/babylonTest/coffrageScene.js"></script>
</body>

and the coffrageScene.js

   var canvas = document.getElementById("renderCanvas"); // Get the canvas element 
   var engine = new BABYLON.Engine(canvas, true); // Generate the BABYLON 3D engine

    BABYLON.SceneLoader.Load("", "coffrage.babylon", engine, function (scene) {

        //as this .babylon example hasn't camera in it, we have to create one
        var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 7, new BABYLON.Vector3(0, 
       0, 0), scene);
        //camera.setPosition(new BABYLON.Vector3(0, 10, 0));

        camera.attachControl(canvas, false);
       
        scene.clearColor = new BABYLON.Color3(2, 1, 1);
        //scene.ambientColor = new BABYLON.Color3.Red;


        engine.runRenderLoop(function() {
             if (camera.beta < 0.1)
          camera.beta = 0.1;
        else if (camera.beta > (Math.PI / 2) * 0.92)
          camera.beta = (Math.PI / 2) * 0.92;

            scene.render();
        });

        window.addEventListener("resize", function () {
            engine.resize();
        });
    });

Best Regards

Anes

Help please :disappointed_relieved::disappointed_relieved::disappointed_relieved::disappointed_relieved:

don’t cry. :slight_smile:

maybe this is what you are seeking for:

or that:

1 Like

What I would do:

  • create mesh objects in blender that defines the different positions that the camera can take, like this one: image
  • when you import your scene, put these objects in a list
  • for each of these meshes, add an action to them that move the camera when they are clicked on:
mesh.actionManager.registerAction(
    new BABYLON.InterpolateValueAction(
        BABYLON.ActionManager.OnPickTrigger,
        myCamera,
        'position',
        mesh.position,
        1000
    )
);

I mean, I never tried that before, but it might work :smiley: When I started my answer, I was going to suggest adding an pointer observer that triggers the animation system, but I found that mesh.actionManager was doing both already. See more details on the action manager here: Use Actions - Babylon.js Documentation

NOTE: The paths will be straight paths. If you were to use curved trajectories, you would need to draw those trajectories in Blender, and to import them in BabylonJS would be a bit tricky (but I have some code to do it :smiley: ) .

Let us know how it goes!

1 Like

Thank youu so much, you are a hero :hugs::hugs::hugs::hugs:
I’ll eat and I’ll start it, I’ll break your head with questions :stuck_out_tongue:

thanks I’ll try it

If I were trying to accomplish this, I would most likely place my camera on a path. If you build an array of points in 3D space, you can then add points to the path by adding them to the array. Then you could draw a nice curved path so that the camera isn’t linear.

Here’s a simple script I wrote to generate nice random curved splines:

for (let px = 0; px < 4; px++) {
X = Math.floor(Math.random() * (maxX - minX + 1)) + minX;
Y = Math.floor(Math.random() * (5 - (-5) + 1)) + (-5);
Z = Math.floor(Math.random() * (20 - 5 + 1)) + 5;
path.push(new BABYLON.Vector3(X, Y, Z));
if (Xvalue === 1) {
minX -= 30;
maxX -= 30;
} else {
minX += 30;
maxX += 30;
}
}
const catmullRom = BABYLON.Curve3.CreateCatmullRomSpline(
path,
20
);

I know you don’t wish to make the paths random, but that’s a much simpler task. You can then update the path by using the path3D.update(); function. Keep in mind that this will recompute your tangents, normals, and bi-normals. Reguardless, you will need to set your camera animation on the path and initially compute your tangents, normals, and bi-normals. Here’s a script that I wrote to place meshes on a path.

const path3d = new BABYLON.Path3D(catmullRom.getPoints());
const tangents = path3d.getTangents(); // array of tangents to the curve
const normals = path3d.getNormals(); // array of normals to the curve
const binormals = path3d.getBinormals(); // array of binormals to curve
const speed = Math.floor(Math.random() * (7 - 3 + 1)) + 3;
// const speed = 1
const animationPosition = new BABYLON.Animation(
‘animPos’, ‘position’, speed,
BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
);
const animationRotation = new BABYLON.Animation(
‘animRot’, ‘rotation’, speed,
BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
);
const keysPosition = [];
const keysRotation = [];
for (let p = 0; p < catmullRom.getPoints().length; p++) {
keysPosition.push({
frame: p,
value: catmullRom.getPoints()[p]
});

keysRotation.push({
  frame: p,
  value: BABYLON.Vector3.RotationFromAxis(normals[p], binormals[p], tangents[p])
});

}

animationPosition.setKeys(keysPosition);
animationRotation.setKeys(keysRotation);

vehicle.animations = [
animationPosition,
animationRotation
];

scene.beginAnimation(vehicle, 0, 100, true);

For more information, please refer to the path 3D docs:
https://doc.babylonjs.com/how_to/how_to_use_path3d

To make scripting the paths much easier, I generally make the lines visible while coding. Here’s an example of this:
const line = BABYLON.Mesh.CreateLines(‘path’, catmullRom.getPoints(), scene);
line.color = new BABYLON.Color3(1, 0, 0);

Galen

2 Likes

If you wanted to take @Galen’s idea further then A Carriage Following a Track - Babylon.js Documentation shows you how to take a path you build and create normals, binormals and tangents so that as the camera moves along the path you can get it to also change the direction it is looking at. The examples for that section use a universal camera but an arc rotate camera is possible as well as this ride in a roller coaster shows https://www.babylonjs-playground.com/#SQFG0Q#11.

1 Like

Something I hadn’t though of before but attaching the camera to the canvas allows you to look around with the mouse and pointer as you travel https://www.babylonjs-playground.com/#SQFG0Q#12

@Galen, thank you for ur reply,
I’m trying to use ur solution and because I wante to generate a path between two specific points A and B,
so I create a function that returnes “a stright ligne path”:

     function MyPath(CameraPosition, GoalPosition){
        var path=[];
    for(var i=0;i<11;i++)
      {
	   var directionalVector=new BABYLON.Vector3((GoalPosition.x-CameraPosition.x), 
          (GoalPosition.y-CameraPosition.y),(GoalPosition.z-CameraPosition.z))
	var X = CameraPosition.x+directionalVector.x*0.1*i;
	var Y = CameraPosition.y+directionalVector.y*0.1*i;
	var Z = CameraPosition.z+directionalVector.z*0.1*i;
	path.push(new BABYLON.Vector3(X,Y,Z));
}
    const catmullRom = BABYLON.Curve3.CreateCatmullRomSpline(path,20);
    return catmullRom;
}

I used “BABYLON.Curve3” to generate my stright line path, because I don’t know an other BABYLON object that draw lines.

I called my funcion in my scene script with :

MyCurve= MyPath(camera.position,MyGoal);

while camera.position & MyGoal are known.

Now I’ll create a new function “MoveCameraThrough” to set my camera in the path.

Am I on the right path ?

Anes

Your process appears correct. Just follow the template I posted with all of the functions to animate your camera along the path. Just keep in mind that the camera animation is dramatically altered by re-ordering your tangents, normals, and bi-normals. This is generlly where it gets a bit difficult to understand. However, in the example I posted, the camera will follow the path along the z axis with a Y axis up orientation.

FYI - a CatmullRomSpline is a curve, so you might want to subdivide your path for a smooth transition in your camera animation.

Galen

Thank u Galen, I create a function MoveCameraThrough(), based on the steps you gave me., and the camera moves through the stright line path that I define.
here is the MoveCameraThrough function :

    function MoveCameraThrough( scene , camera, MyCurve)
{
const path3d = new BABYLON.Path3D(MyCurve.getPoints());
const tangents = path3d.getTangents(); // array of tangents to the curve
const normals = path3d.getNormals(); // array of normals to the curve
const binormals = path3d.getBinormals(); // array of binormals to curve
const speed = 2*Math.floor(Math.random() * (7 - 3 + 1)) + 3; // const speed = 1
const animationPosition = new BABYLON.Animation('animPos', 'position', speed, 
BABYLON.Animation.ANIMATIONTYPE_VECTOR3, 
BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
const animationRotation = new BABYLON.Animation('animRot', 'rotation', speed, 
BABYLON.Animation.ANIMATIONTYPE_VECTOR3, 
BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
const keysPosition = [];
const keysRotation = [];

for (let p = 0; p < MyCurve.getPoints().length; p++) {
keysPosition.push({
frame: p,
value: MyCurve.getPoints()[p]
});
keysRotation.push({
frame: p,
value: BABYLON.Vector3.RotationFromAxis(normals[p], binormals[p], tangents[p])
});

animationPosition.setKeys(keysPosition);
animationRotation.setKeys(keysRotation);

camera.animations=[
animationPosition,
animationRotation
 ];
scene.beginAnimation(camera, 0, 200, true);
}
}  

and this is my createScene() function :

 var createScene2=function()
{
        var scene = new BABYLON.Scene(engine);
        camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 2, 5, new 
BABYLON.Vector3(0,0,0), scene);
        camera.attachControl(canvas, true);
        var light1 = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(1, 1, 0), scene);
        var light2 = new BABYLON.PointLight("light2", new BABYLON.Vector3(0, 1, -1), scene);
        var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {}, scene);
        var MyGoal = new BABYLON.Vector3(0,5,5);
        MyCurve= MyPath(position, MyGoal);
        MoveCameraThrough(scene, camera , MyCurve);
        return scene

}
the problem is when I call scene.render after the camera reset from initial position, I try to define it outside the createScene function but it doesn’t work

Anes

1 Like

Hello,

You might wrap your MoveCameraThrough code inside a RegisterBeforeRender function and set this inside of your scene. Unless you’re calling your scene inside a larger application, I personally wouldn’t wrap my scene inside a separate function.

You’ll find that the people on this forum are here for all the right reasons, and love to assist others to help grow the community. I personally like to answer questions, as I know enough now to understand much of the framework (after 5 years); and many questions pose a challenge for me and help me build a greater understanding.

Galen

I just used this script First Steps - Babylon.js Documentation, and define a scene inside a function and after I’ll call it by :

 var scene= createScene2();

then :

       engine.runRenderLoop(function () {
           scene.render();
       	}); 

I didn’t see how to use Register beforeRender cuz it needs scene object

    scene.RegisterBeforeRender(function(){});

and my MoveThroughCamera function has scene as attribute.

You don’t want to define your camera position outside of the render loop. This will not register. You want to define your camera positions and rotations inside your render loop at runtime. Nad if you want to set your camera transforms outside your render loop, then wrap the function inside a RegisterBeforeRender function inside of your render loop.

I have to leave for the hospital now, so I’ll be out of touch for a while. However, you appear very close to understanding the structure of the render engine, so I’m sure you’ll get the help you need here. I’ll try and check in - in a few days if I’m able.

Galen

If it is just a simple straight line movement of the camera maybe this will give you an idea. You need to replace the boxes with your markers of course in your model https://www.babylonjs-playground.com/#DXE1CV#1

Click on a box.

@Galen @JohnK @Necips @Nodragem

finally I solved the problem based on @Galen code
the camera reset problem was the “true” in :

   scene.beginAnimation(camera, 0, 200, true);

because it defines if the animation loops :stuck_out_tongue:, I didn’t see that

Thank u guys see you in other issues lol

1 Like