three.jsphysijs

How to draw the trajectory of a mesh with threejs


I'm trying to draw the trajectory of a projectile motion with threejs. Which is the best way to do that? Here is an example of it: http://www.physgl.org/index.php/welcome/logout Try the projectile motion demo and click run.

I thought of drawing a second mesh that follows the previous movement by obtaining the position of the mesh as it's moving, but that did not work. This is what I tried (this code) to get the position of the object moving:

box.geometry.computeBoundingBox();

    var boundingBox = box.geometry.boundingBox;

    var position = new THREE.Vector3();
    position.subVectors( boundingBox.max, boundingBox.min );
    position.multiplyScalar( 0.5 );
    position.add( boundingBox.min );

    position.applyMatrix4( box.matrixWorld );

    console.log(position.x + ',' + position.y + ',' + position.z);

Please Help. Thanks.


Solution

  • There are a few ways to go about tracking a trajectory. Here, I will show you some alternatives to your desired behavior, in addition to its solution.

    Solution A: Mark each step

    In your Physijs application, you should have a scene.simulate call and an event listener when the update has finished, so that you can loop through physics separately from the rendering process. It shouldn't be too hard to add a little extra code to place a marker of some sort every step into your scene, which preferably doesn't contain too many extra vertices (i.e. not too complex):

    var markSize = 2; // Tweak this to set marker size
    
    var markGeom = new THREE.BoxGeometry(markSize, markSize, markSize, 1, 1, 1);
    var markMat = new THREE.MeshBasicMaterial({color: "blue"});
    
    scene.addEventListener("update", function(){
    
        // Generate a box where projectile was last moved
        var marker = new THREE.Mesh(markGeom.clone(), markMat);
        marker.position.copy(projectile.position);
    
        // Display position!
        scene.add(marker);
    
        // Keep simulation going
        scene.simulate(undefined, 2);
    });
    

    In this code, projectile is the variable referencing your projectile Physijs mesh. Note that you shouldn't format this for your rendering loop, as you might be using requestAnimationFrame, which stops calling your rendering loop when the window (or tab) goes out of focus. It won't be pleasant when some client does that and gets a messed up trajectory. Plus, this tied directly into your Physijs stepping, which makes it extremely precise.

    Solution B: Dynamic arrow

    This is probably what you wanted in the first place. It creates an arrow which will show the direction and speed of the projectile:

    // Constructor: direction, origin, length, color in hexadecimal
    var arrowMark = new THREE.ArrowHelper(
        new THREE.Vector3(0, 1, 0), projectile.position, 0, 0x884400);
    
    function drawDir(){
        var pvel = projectile.getLinearVelocity();
    
        // Update arrow
        arrowMark.position.set(projectile.position);
        arrowMark.setDirection(pvel.normalize());
        arrowMark.setLength(pvel.length());
    }
    

    Yeah, that was kind of easy. Once again, projectile is referencing your projectile Physijs mesh. Just call drawDir every render call and you're good to go!

    The THREE.ArrowHelper documentation: ArrowHelper