Moving 3D model

1,142 views
Skip to first unread message

Premkumar Jayaseelan

unread,
Jun 11, 2015, 9:30:55 AM6/11/15
to cesiu...@googlegroups.com
Hi,

I wanted to move the model dynamically using keyboard shortcuts. I could not find relevant article on that. 

So for now, I'm trying to move the model on click. When click on the model. The model has to move in one direction (increment the value 1 on tick). Find below the sandcastle code for that.


var selectedMesh; var i=0;

var viewer = new Cesium.Viewer('cesiumContainer', {
    infoBox: false,
    selectionIndicator: false
});

var handle = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

function createModel(url, height) {
    viewer.entities.removeAll();

    var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
    var heading = Cesium.Math.toRadians(135);
    var pitch = 0;
    var roll = 0;
    var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, heading, pitch, roll);

    var entity = viewer.entities.add({
        name: url,
        position: position,
        orientation: orientation,
        model: {
            uri: url,
            minimumPixelSize: 128
        }
    });
    viewer.trackedEntity = entity;


    viewer.clock.onTick.addEventListener(function () {
        if (selectedMesh) {
            console.log("Before 0 : " + selectedMesh.primitive.modelMatrix[12]);
            selectedMesh.primitive.modelMatrix[12] = selectedMesh.primitive.modelMatrix[12] + 1;
            console.log("After 0 : " + selectedMesh.primitive.modelMatrix[12]);
        } 
    });
}

handle.setInputAction(function (movement) {
    console.log("LEFT CLICK");
    var pick = viewer.scene.pick(movement.position);
    if (Cesium.defined(pick) && Cesium.defined(pick.node) && Cesium.defined(pick.mesh)) {

        if (!selectedMesh) {
            selectedMesh = pick;
        }
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

var options = [{
    text: 'Aircraft',
    onselect: function () {
        createModel('../../SampleData/models/CesiumAir/Cesium_Air.bgltf', 5000.0);
    }
}, {
    text: 'Ground vehicle',
    onselect: function () {
        createModel('../../SampleData/models/CesiumGround/Cesium_Ground.bgltf', 0);
    }
}, {
    text: 'Milk truck',
    onselect: function () {
        createModel('../../SampleData/models/CesiumMilkTruck/CesiumMilkTruck.bgltf', 0);
    }
}, {
    text: 'Skinned character',
    onselect: function () {
        createModel('../../SampleData/models/CesiumMan/Cesium_Man.bgltf', 0);
    }
}];

Sandcastle.addToolbarMenu(options);


When I click, the model is moving for the first time. After that, It stays on the same place. I've printed the value in the console. It seems the value is not changing. I'm not sure about the problem here. or I'm implementing the transformation wrongly.

Any kind of help is appreciated. Thanks in advance.

Mike LP

unread,
Jun 12, 2015, 9:58:07 AM6/12/15
to cesiu...@googlegroups.com, vlrp...@gmail.com
I highly recommend taking a look at the Monster Milktruck from the Google Earth Developers Samples.

Premkumar Jayaseelan

unread,
Jun 12, 2015, 10:30:52 AM6/12/15
to cesiu...@googlegroups.com, vlrp...@gmail.com

Thank you Mike. I manage to do changing position using keys. Now the facing some challenge on retaining the value. I've more than one model. While click on the model I'm selecting and performing translation / rotation. Once I click the second model I'm loosing the translation / rotation of the previous model. The modelMatrix is set to default values again. 

I'm not sure about the behavior of selected mesh modelMatrix. Find below the code.

           var heading = 0.0, pitch = 0.0, roll = 0.0, long = 0.0, lat = 0.0, alt = 0.0;
           var selectedMesh;

            /* MOUSE LEFT BUTTON DOWN */
            handle.setInputAction(function(movement){
                var pick = this.scene.pick(movement.position);
                if (Cesium.defined(pick) && Cesium.defined(pick.node) && Cesium.defined(pick.mesh)) {
                    selectedMesh = pick;
                    heading = 0.0, pitch = 0.0, roll = 0.0;
                } else {
                    this.selectedMesh = null;
                }
            }, Cesium.ScreenSpaceEventType.LEFT_DOWN);

         

        viewer.clock.onTick.addEventListener(function() {
           
                       if (!selectedMesh) {

                    return;
                }

                /* Rotation */
                var headingDegree = degreesToRadians(heading);
                var pitchDegree = degreesToRadians(pitch);
                var rollDegree = degreesToRadians(roll);
                var headingQuat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Z, -headingDegree);
                var pitchQuat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Y, -pitchDegree);
                var rollQuat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_X, -rollDegree);
                var headingPitchQuat = Cesium.Quaternion.multiply(headingQuat, pitchQuat, new Cesium.Quaternion());
                var rotationQuaternion = Cesium.Quaternion.multiply(headingPitchQuat, rollQuat, new Cesium.Quaternion());
                var rotationMatrix = Cesium.Matrix3.fromQuaternion(rotationQuaternion, new Cesium.Matrix3());

                var currentRotation = new Cesium.Cartesian3();
                            Cesium.Matrix4.getRotation(selectedMesh.primitive.modelMatrix, currentRotation);

                var newRotation = Cesium.Matrix3.multiply(currentRotation, rotationMatrix, new Cesium.Matrix3());
               
                var currentTranslation = new Cesium.Cartesian3();
                Cesium.Matrix4.getTranslation(this.selectedMesh.primitive.modelMatrix, currentTranslation);
                currentTranslation.x += long;
                currentTranslation.y += lat;
                currentTranslation.z += alt;

                this.selectedMesh.primitive.modelMatrix = Cesium.Matrix4.fromRotationTranslation(newRotation, currentTranslation, new Cesium.Matrix4());
            });
        }

       document.addEventListener('keyup', (e) => {
                if (e.keyCode === 'A'.charCodeAt(0)) {
                    heading -= 1;
                } else if (e.keyCode === 'S'.charCodeAt(0)) {
                    heading += 1;
                } else if (e.keyCode === 'Z'.charCodeAt(0)) {
                    pitch -= 2;
                } else if (e.keyCode === 'X'.charCodeAt(0)) {
                    pitch += 2;
                } else if (e.keyCode === 'Q'.charCodeAt(0)) {
                    roll -= 2;
                } else if (e.keyCode === 'W'.charCodeAt(0)) {
                    roll += 2;
                } else if (e.keyCode === 'O'.charCodeAt(0)) {
                    lat -= 1;
                } else if (e.keyCode === 'P'.charCodeAt(0)) {
                    lat += 1;
                } else if (e.keyCode === 'K'.charCodeAt(0)) {
                    long -= 1;
                } else if (e.keyCode === 'L'.charCodeAt(0)) {
                    long += 1;
                }else if (e.keyCode === 'N'.charCodeAt(0)) {
                    alt -= 1;
                } else if (e.keyCode === 'M'.charCodeAt(0)) {
                    alt += 1;
                }

            }, false);


I'm expecting that, the changes I'm doing with the selectedMesh should reflect in the actual mesh. So when I select the same model again. It should have the configured configuration. 

Any clue on this issue?

Mike LP

unread,
Jun 12, 2015, 2:05:21 PM6/12/15
to cesiu...@googlegroups.com, vlrp...@gmail.com
The only thing that is popping out at me is that you're mixing "this.selectedMesh" and "selectedMesh".  I recommend debugging your application using console.log messages and breakpoints to figure out what is happening to the states of your models.

Premkumar Jayaseelan

unread,
Jun 15, 2015, 7:18:45 AM6/15/15
to cesiu...@googlegroups.com, vlrp...@gmail.com
Here is a complete code of the issue. Just paste the code in sandcastle and you could replicate the below scenario.

Scenario:

1. Switch to full screen mode.
2. Select the model and use keys (Q,W,A,S,Z,X,O,P,K,L,N,M) to rotate and translation.
3. select the another model.

Issue: The first model transformation will be reset. I'm updating the "modelMatrix". of the selected mesh.

var selectedMesh;
var i = 0;

var heading = 0.0,
    pitch = 0.0,
    roll = 0.0,
    long = 0.0,
    lat = 0.0,
    alt = 0.0;

var viewer = new Cesium.Viewer('cesiumContainer', {
    infoBox: false,
    selectionIndicator: false
});

var handle = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

function createModel(url, height) {

    var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
    var heading = Cesium.Math.toRadians(135);
    var pitch = 0;
    var roll = 0;
    var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, heading, pitch, roll);

    var entity = viewer.entities.add({
        name: url,
        position: position,
        orientation: orientation,
        model: {
            uri: url,
            minimumPixelSize: 128
        }
    });
    viewer.trackedEntity = entity;
}

function degreesToRadians (val) {
    return val * Math.PI / 180;
}


viewer.clock.onTick.addEventListener(function() {

    if (!selectedMesh) {
        return;
    }
console.log(selectedMesh);
    /* Rotation */
    var headingDegree = degreesToRadians(heading);
    var pitchDegree = degreesToRadians(pitch);
    var rollDegree = degreesToRadians(roll);
    var headingQuat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Z, -headingDegree);
    var pitchQuat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Y, -pitchDegree);
    var rollQuat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_X, -rollDegree);
    var headingPitchQuat = Cesium.Quaternion.multiply(headingQuat, pitchQuat, new Cesium.Quaternion());
    var rotationQuaternion = Cesium.Quaternion.multiply(headingPitchQuat, rollQuat, new Cesium.Quaternion());
    var rotationMatrix = Cesium.Matrix3.fromQuaternion(rotationQuaternion, new Cesium.Matrix3());

    var currentRotation = new Cesium.Cartesian3();
    Cesium.Matrix4.getRotation(selectedMesh.primitive.modelMatrix, currentRotation);

    var newRotation = Cesium.Matrix3.multiply(currentRotation, rotationMatrix, new Cesium.Matrix3());

    var currentTranslation = new Cesium.Cartesian3();
    Cesium.Matrix4.getTranslation(selectedMesh.primitive.modelMatrix, currentTranslation);
    currentTranslation.x += long;
    currentTranslation.y += lat;
    currentTranslation.z += alt;

    selectedMesh.primitive.modelMatrix = Cesium.Matrix4.fromRotationTranslation(newRotation, currentTranslation, new Cesium.Matrix4());
});

document.addEventListener('keyup', function(e) {
handle.setInputAction(function(movement) {
    console.log("LEFT CLICK");
    var pick = viewer.scene.pick(movement.position);
    if (Cesium.defined(pick) && Cesium.defined(pick.node) && Cesium.defined(pick.mesh)) {
        heading = 0.0,    pitch = 0.0,    roll = 0.0,    long = 0.0,    lat = 0.0,    alt = 0.0;
            selectedMesh = pick;
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

createModel('../../SampleData/models/CesiumAir/Cesium_Air.bgltf', 10);

createModel('../../SampleData/models/CesiumGround/Cesium_Ground.bgltf', 0);


Appreciate your support.

Matthew Amato

unread,
Jun 15, 2015, 7:50:30 PM6/15/15
to cesiu...@googlegroups.com
The problem is that you are modifying the primitive directly and not the Entity associated with the primitive.  The Entity system is overwriting your changes to make sure the primitive matches the Entity.  The easiest way to fix this is to modify the entity.position and entity.orientation properties instead of the modelMatrix.


--
You received this message because you are subscribed to the Google Groups "cesium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Premkumar Jayaseelan

unread,
Jun 16, 2015, 1:46:58 AM6/16/15
to cesiu...@googlegroups.com
Thanks @Matthew.

If I've a single model, then I shall go and set value to the entity.position or entity.orientation property. Similar to this example (http://mramato.github.io/Demos/FOSS4GNA2015/interpolation.html).Here I'm picking the models dynamically and I'm not getting the position and orientation of the pick object. 

Can you please guide me, how I can update the position and orientation on the selected model dynamic (selectedMesh)?

Premkumar Jayaseelan

unread,
Jun 23, 2015, 4:55:02 AM6/23/15
to cesiu...@googlegroups.com
Any suggestion for this post guys!

Mike LP

unread,
Jun 24, 2015, 9:44:01 AM6/24/15
to cesiu...@googlegroups.com, vlrp...@gmail.com
If you wrap your models in an entity 

var position = Cesium.Cartesian3.fromDegrees(
    plane.position.lon,
    plane.position.lat,
    plane.position.alt
);

viewer.entities.add({
    id: plane.id,
    model: {
        uri: plane.modelUrl
    },
    position : position,
    orientation: Cesium.Transforms.headingPitchRollQuaternion(
        position,
        plane.orientation.heading,
        plane.orientation.pitch,
        plane.orientation.roll
    )
});


You can than modify the position and orientation at the entity level that the scene.pick returned.  Your model will stay pristine. 

At this point if you want to specifically modify the model's mesh you can drill down into the model on the entity and manipulate away.

Premkumar Jayaseelan

unread,
Jun 25, 2015, 6:36:38 AM6/25/15
to cesiu...@googlegroups.com, vlrp...@gmail.com
Hi Mike,

Thank you for taking time to respond my post.

I'm having the same code as you suggested. Please have a look on the below code (complete sandcastle code is listed in the previous reply). Can you make the changes in the sandcastle code and send me the updated code please.


function createModel(url, height) {
    var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
    var heading = Cesium.Math.toRadians(135);
    var pitch = 0;
    var roll = 0;
    var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, heading, pitch, roll);

    var entity = viewer.entities.add({
        name: url,
        position: position,
        orientation: orientation,
        model: {
            uri: url,
            minimumPixelSize: 128
        }
    });
    viewer.trackedEntity = entity;
}

createModel('../../SampleData/models/CesiumAir/Cesium_Air.bgltf', 10);

createModel('../../SampleData/models/CesiumGround/Cesium_Ground.bgltf', 0);


Thank you!

Mike LP

unread,
Jun 26, 2015, 9:45:44 AM6/26/15
to cesiu...@googlegroups.com, vlrp...@gmail.com
Have you checked out some of the older posts in the forum about moving models programmatically?

Premkumar Jayaseelan

unread,
Jun 29, 2015, 12:57:04 AM6/29/15
to cesiu...@googlegroups.com, vlrp...@gmail.com
Thanks Mike,

I've already tried that approach. It is also the same as your suggestion. It works well for the single model. 

The below code is from the old post. You could see the model transformation and orientation changes inside onTick event.The positionModel takes model as input. In my case, I will pick the model dynamically and passing it to the positionModel. When I use pick, I'm have access to model.primitive.modelMatrix instead of model.modelMatrix.

var createModel = function(lon, lat, alt, heading, pitch, roll) {
   var model = scene.primitives.add(Cesium.Model.fromGltf({
       url : '../../SampleData/models/CesiumAir/Cesium_Air.gltf'
   }));

   model.readyToRender.addEventListener(function(model) {
       // Play and loop all animations at half-spead
       model.activeAnimations.addAll({
           speedup : 0.5,
           loop : Cesium.ModelAnimationLoop.REPEAT
       });

       viewer.clock.onTick.addEventListener(function() {
           positionModel(model, lon, lat, alt, heading, pitch, roll);
           positionCamera(model);
           
           //lon = lon+0.00001;
           //lat = lat+0.000005;
           //alt = alt+0.01;
           heading += 0.01;
           pitch += 0.05;
           roll += 0.1;
       });
   });
};

Is there is a way to change the model transformation and orientation dynamically?

Mike LP

unread,
Jul 4, 2015, 1:32:43 PM7/4/15
to cesiu...@googlegroups.com, vlrp...@gmail.com
Have you tried using Matt's suggestion for using an Entity instead of a Model?  You can still attach the model to the entity and it should simplify the movements and orientations.

...

Premkumar Jayaseelan

unread,
Jul 7, 2015, 7:31:42 AM7/7/15
to cesiu...@googlegroups.com, vlrp...@gmail.com
Thank you for taking time to reply Mike.

I believe Matt was suggested the below logic. If I make the entity as a global variable, then I'm having access to entity.position and entity.orientation. else not. Since, I'm loading many model and selecting the models dynamically and want to perform movement and orientation. 

function createModel(url, height) {
   viewer.entities.removeAll();

   var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
   var heading = Cesium.Math.toRadians(135);
   var pitch = 0;
   var roll = 0;
   var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, heading, pitch, roll);

    var entity = viewer.entities.add({
       name: url,
       position: position,
       orientation: orientation,
       model: {
           uri: url,
           minimumPixelSize: 128
       }
   });
   viewer.trackedEntity = entity;
}


To achieve that I've used the below pick function. But I'm not having the property called position and orientation.

handle.setInputAction(function(movement) {
   console.log("LEFT CLICK");
   var pick = viewer.scene.pick(movement.position);
   if (Cesium.defined(pick) && Cesium.defined(pick.node) && Cesium.defined(pick.mesh)) {
           selectedMesh = pick;
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);


Can you please confirm, whether I've followed Matt's suggestion or I understand it wrongly... If so, please guide me to give some proper solution for this.You can find the complete code here.

Appreciate your support.

Mike LP

unread,
Jul 10, 2015, 10:05:13 AM7/10/15
to cesiu...@googlegroups.com, vlrp...@gmail.com
Haven't forgotten you, I'm catching up on the forums from my vacation so I'll have something for you either later today or over the weekend.
...

Premkumar Jayaseelan

unread,
Jul 13, 2015, 1:31:36 AM7/13/15
to cesiu...@googlegroups.com, vlrp...@gmail.com
Thank you so much Mike :) 

I'm waiting for you!

Premkumar Jayaseelan

unread,
Jul 13, 2015, 9:23:15 AM7/13/15
to cesiu...@googlegroups.com
Hello Mike,

I've fixed the issue. By changing the position and orientation from the below code. I could retain the value of the selected model dynamically. I'm not sure, whether this is the right way to fix the problem. Please advice if there is a better solution than this. 

   selectedMesh.id.position._value = currentTranslation;
   selectedMesh.id.orientation._value = newRotation;

Thank you!
Reply all
Reply to author
Forward
Message has been deleted
0 new messages