Rotating built-in entities but still following path

1. A concise explanation of the problem you're experiencing.

Hi, I have a CZML file with flight paths that I want to attach a Cesium cone graphic to. I have no problem attaching the cone and getting it to follow the path, but right now the cone is oriented with its base firmly on the ground. I wanted to orient the cone to be rotated 90 degrees such that it looks side ways. This is not a problem normally--I can set the orientation using headingPitchRollQuaternion, but then I sacrifice the ability to set the orientation of the cone to follow the path (i.e. make the entity point in the proper direction according to the path using the commented out VelocityOrientationProperty line shown below). Basically, I need to set the orientation of the cone to be rotated 90 degrees, but when I use the entity.orientation = new Cesium.VelocityOrientationProperty(entity.position); line afterwards, it doesn't do the 90 degree rotation.

2. A minimal code example. If you've found a bug, this helps us reproduce and repair it.

var viewer = new Cesium.Viewer('cesiumContainer');

var geocachePromise = Cesium.CzmlDataSource.load('/Apps/Sandcastle/output.czml');

var cylinder = new Cesium.CylinderGraphics({
            length: 200,
            topRadius: 1,
            bottomRadius: 200
        });

var headingPitchRoll = new Cesium.HeadingPitchRoll.fromDegrees(90,0,0);
var orientation = new Cesium.Quaternion.fromHeadingPitchRoll(headingPitchRoll);
console.log(orientation);

geocachePromise.then(function(dataSource) {
    // Add the new data as entities to the viewer
    viewer.dataSources.add(dataSource);
    
        // Get the array of entities
    var geocacheEntities = dataSource.entities.values;

    for (var i = 0; i < geocacheEntities.length; i++) {
        var entity = geocacheEntities[i];
        
        entity.cylinder = cylinder;
        entity.orientation = orientation;

        //entity.orientation = new Cesium.VelocityOrientationProperty(entity.position);
        //Can't set orientation again??
    }
});

3. Context. Why do you need to do this? We might know a better way to accomplish your goal.

Likewise, I would like a solution for this so that I can rotate external 3D gltf models (like an airplane) so that a) it's nose points in the correct direction and b) it's nose orients itself through the path timeline to turn according to the path direction/velocity.

4. The Cesium version you're using, your operating system and browser.

I am using Cesium 1.46, MacOS, and running the sandbox locally. Thanks so much!

Are you trying to rotate the entity again so that it would be rotated relative to the cylinder? If so, that won’t work because it’s a single entity with both a model and a cylinder attached, so they’ll both have the same orientation.

If I understand you correctly, an easier way to do this would be to create two separate entities, and have the cylinder follow the other entity with a callback property. Check out this Sandcastle example I put together. Hope this helps!

I forgot to say, in this example I manually rotate the cone so it’s on top of the entity like that, but you should be able to figure out any rotation relative to your entity.

If instead you wanted the cone to point in the same direction the truck is pointing in, you can set a dynamic CallbackProperty for the orientation the same way it’s done for position so it follows that as well.

Hi,

I think my problem might be a little simpler than your solution (which I am currently adjusting with in the sandbox) and my apologies for not better explaining it. I have attached a picture of cylinders attached to some entities. The entities are sample paths specified using cartographicDegrees. When I load in the paths, I attach the built-in Cesium cylinder to the paths and it works fine as shown in the picture. However, I want to rotate the cylinders such that the nose of the cone (the pointed end) follows the path and turns accordingly in the correct direction. I don’t have an external truck or other model that I want to attach to the path also, just the cylinders. Thanks!

I appreciate the picture!

Since there’s currently no way to set a relative orientation offset for a cylinder to the entity it’s attached to, I think you’ll need to make the cylinder its own entity, have it follow the actual entity along the path (which maybe is invisible) with a callback property, and then set its orientation to that of the entity it’s following with your offset.

Does that make sense?

That makes sense logically. Is there a way to set a relative orientation offset for any of Cesium’s built-in types (like ellipsoids, rectangles) or for external 3d-models (I’ve encountered this when some of my loaded in trucks/planes have traveled along the paths sideways or backwards)?

I see in your code example that the attached cone updates its position dynamically using the CallBack function. Is orientation done the same way in your code’s lines 9-25 or does it need to be done in the geoCache.then() function (because the VelocityOrientationProperty(entity.position) code is only called there at the end)? Thanks

There is currently no way to set relative orientation offset.

In my example the orientation does not update dynamically, but in the same way the position does, you can use another callback property for the orientation, and have it work just the same way (get the orientation of the tracked entity, add/subtract etc. and then return that)

Ok I have been playing around with the orientation and I think I’ll eventually be able to figure out how to rotate it 90 degrees using the values in the quaternion returned from orientation.getValue… I noticed that ran I changed the code for my czml file that the cone only appeared for one path (my czml file has multiple paths). Do you have insight onto why this happens?

var viewer = new Cesium.Viewer(‘cesiumContainer’, {shouldAnimate: true});

var geocachePromise = Cesium.CzmlDataSource.load(’/Apps/SandCastle/cooloutput.czml’);

var headingPitchRoll = new Cesium.HeadingPitchRoll.fromDegrees(10,20,50);
//var orientation = new Cesium.Quaternion.fromHeadingPitchRoll(headingPitchRoll);

var entityToFollow;

var cone = viewer.entities.add({
position: new Cesium.CallbackProperty(function(time, result){
if(entityToFollow){
var position = entityToFollow.position.getValue(time);
return position;
}
},false),
orientation: new Cesium.CallbackProperty(function(time, result){
if(entityToFollow){
var orientation = entityToFollow.orientation.getValue(time);
orientation.w = -0.707; //will experiment with changing properly soon
return orientation;
}
},false),
cylinder : {
length: 200,
topRadius: 50,
bottomRadius: 1
}
});

geocachePromise.then(function(dataSource) {
// Add the new data as entities to the viewer
viewer.dataSources.add(dataSource);

    // Get the array of entities
var geocacheEntities = dataSource.entities.values;

for (var i = 0; i < geocacheEntities.length; i++) {
    var entity = geocacheEntities[i];

    entityToFollow = entity;

    entity.orientation = new Cesium.VelocityOrientationProperty(entity.position);
   
}

});

Regarding the rotated model, glTF 2.0 models (the type of 3D models used by CZML) were corrected in Cesium to face +Z forwards per the specification. Internally Cesium uses +X as forward, so a new +Z to +X rotation was added for 2.0 models only. To fix models that are oriented incorrectly after this change, you can:

Apply a -90 degree rotation to the model’s heading. This can be done by setting the model’s orientation using the Entity API or from within CZML. See #6738 for more details.

Thanks,

Gabby

Ok thanks for the heads up. Regarding the rotation of built-in primitives, I tested Omar’s solution and it would only recognize one entity. But if you create a primitive for each path entity, then it will attach to all of the paths. Thanks for all the help