Flight Path over 3D Model

Hi Everyone,

hope you can help me with my problem I’m new to CesiumJS. I’m currently building a real time flight tracker for my drone. The drone is sending postion updates to my laptop which then feeds the new position update into my CesiumJS application. The implementation took inspiration form the [Build a Flight Tracker – Cesium](Build a Flight Tracker – Cesium exmaple and from the HeadingPitchRoll - Cesium Sandcastle example.

The tracker works fine flight path is updated and the 3D Model moves correctly. The only thing which doesn’t work and annoys is that the Flight Path overlays the 3D Model and not like in the examples that the flight bath comes from within the 3D Model. I can’t find any setting or instruction how to fix that.

Hope someone can help me! Thanks a lot in advance!
Thomas

Hi @briddl1305,
Thanks for your post and welcome to the Cesium community.

I’m not sure what exactly you mean when you describe

the Flight Path overlays the 3D Model and not like in the examples that the flight bath comes from within the 3D Model

Could you provide a screenshot or video of the effect you are seeing that you would like to change?

Hopefully we can help you get this resolved shortly.
Thanks,
Luke

Hi Luke,

Thanks for the fast Response. Sorry for the bad description. Unfortunately I have only my phone at hand and the project ia on my computer. What I meant is if you look on the sandcastle example the flight path seams always to come from inside the 3d model or the 3d model is rendered above the flight path, when I try it the flight path seams to be alway on the outside of the 3d model. So you cant see the the 3d model very well. And it is visible from all sides. I dont know if it has something to do with the 3d model I use because my code uses more or less the linked source in my first post. Main difference is that my flight path is gets new values every 300 ms from an external source.

Hi Luke,
I think I found the issue. Not relay sure if this is really the case but after comparing Cesium 3D Models (Cesium_Air & CesiumDrone) with my 3D model in blender, I think the issue is where the Origin of the 3D Model is placed.It seams that the flight trail/track connects to the origin of the first part of 3D model. For Cesium_Air it is directly in the Center of the Model, for CesiumDrone it is the the top of the Baseplate of the Quadcopter, or the origin of the Back Faced Antenna.

I’m not sure if origin and “first part of 3D model” is understandable, my background is more in the embedded world and I’m rather new to Cesium and 3d models.

Can you confirm my observations?
Thanks a lot!
Thomas

Hi Again,
now I am competently out of clues. After uploading the 3D model into Cesium Ion and using the model in a sandcastle example it also works fine it seams the issue is only when working with my local hosted instance… Think something on my client side is wrong… have check. So my assumption was wrong.

Hi @briddl1305 ,

Thanks for following up and providing more description of your use case and where you are running into issues.

Is it possible for you to share a link to the sandcastle example you referenced https://sandcastle.cesium.com/. Being able to see your code will make it much easier for us to understand your issue and help debug.

You can also attach screenshots showing the overlay issue you references in the initial message too if that would help.

Thanks and hope we can help get you on the right path.
Best,
Luke

Register for the 2025 Cesium Developer Conference, June 23-25, Philadelphia.

Hi @Luke_McKinstry,


Find attached the images with the overlayed path. Expected behavioure would be like in the Sandcastle example ( Callback Position Property - Cesium Sandcastle)

In the picture with the side view the path is before the 3D model, Thats a known issue and can be ignored.

Next is the source code. Data samples are received via websocket and then attached to the path.

<template>
    <div id="cesiumContainer" class="cesium-container"></div>
</template>

<script setup lang="ts">
import { useWebSocket } from "@vueuse/core";
import { Cartesian3, Ion, Math as CesiumMath, Viewer } from "cesium";
import * as Cesium from "cesium";
import { onMounted, watchEffect } from "vue";
import { Position } from "../models/Position.ts";


const emit = defineEmits<{
    created: [viewer: Viewer];
}>();


onMounted(async () => {
    Ion.defaultAccessToken =
        "";

    // Set the Default View that is being moved to when the "Home" Button is clicked
    let extent = Cesium.Rectangle.fromDegrees(-8, 45, 29, 57);
    Cesium.Camera.DEFAULT_VIEW_RECTANGLE = extent;
    Cesium.Camera.DEFAULT_VIEW_FACTOR = 0;

    // Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
    const viewer = new Viewer("cesiumContainer", {
        shouldAnimate: true,
        animation: false,
        timeline: false,
        sceneMode: Cesium.SceneMode.SCENE2D,
        mapProjection: new Cesium.WebMercatorProjection(),
        baseLayer: new Cesium.ImageryLayer(
            new Cesium.OpenStreetMapImageryProvider({
                url: import.meta.env.VITE_OSM,
            }),
        ),
    });

    Cesium.CesiumTerrainProvider.fromUrl(
        import.meta.env.VITE_TERRAIN_PROVIDER,
    ).then((terrainProvider) => (viewer.terrainProvider = terrainProvider));

    viewer.camera.flyTo({
        destination: Cartesian3.fromDegrees(XX.XX, XX.XX, XXX),
        orientation: {
            heading: CesiumMath.toRadians(0.0),
            pitch: CesiumMath.toRadians(-15.0),
        },
    });

    type DronePosition = {
        heading: number;
        drone_id: string;
        position: Position;
    };

    type Message = {
        drone_position: undefined | DronePosition;
    };

    const { status, data, send, open, close } = useWebSocket<string>(
        import.meta.env.VITE_DATA,
    );

    watchEffect(() => {
        if (data.value !== null) {
            const messages = JSON.parse(data.value) as Message[];
            for (let i = 0; i < messages.length; i++) {
                const message = messages[i];

                let id = "";
                let location = new Position(0.0, 0.0, 0.0);
                let heading = 0.0;

                if (message.drone_position !== undefined) {
                    const position = message.drone_position;
                    id = position.drone_id;
                    location = position.position;
                    heading = position.heading;
                }
                
                const entity = viewer.entities.getOrCreateEntity(id);
                entity.path = new Cesium.PathGraphics({
                    show: true,
                    resolution: 1,
                    leadTime: 0,
                    trailTime: 1200,
                    material:
                        new Cesium.PolylineGlowMaterialProperty({
                            glowPower: 0.3,
                            color: Cesium.Color.RED,
                        }),
                    width: 10,
                })
                                
                if (entity.properties === undefined) {
                    entity.properties = new Cesium.PropertyBag();
                }
                const cartesian = Cartesian3.fromDegrees(
                    location.longitude,
                    location.latitude,
                    location.altitude,
                );

                if (!(entity.position instanceof Cesium.SampledPositionProperty)) {
                    const posProp = new Cesium.SampledPositionProperty();
                    const time = Cesium.JulianDate.now();
                    Cesium.JulianDate.addSeconds(time, 1, time);
                    posProp.addSample(time, cartesian);
                    entity.position = new Cesium.SampledPositionProperty();
                } else {
                    const time = Cesium.JulianDate.now();
                    Cesium.JulianDate.addSeconds(time, 1, time);
                    entity.position.addSample(time, cartesian);
                }
                

                // set 3D model of entity
                if (entity.model === undefined) {
                    entity.model = new Cesium.ModelGraphics({
                        uri: "./CesiumDrone.glb",
                        minimumPixelSize: 128,
                        maximumScale: 20000,
                        scale: 0.05,
                    });
                }

                let heading_correct;
                if (heading > 0.0) {
                    heading_correct = (heading % 360) + 90;
                } else {
                    heading_correct = heading + 360 + 90;
                }

                const heading_rad = Cesium.Math.toRadians(heading_correct);
                const pitch = 0;
                const roll = 0;
                const hpr = new Cesium.HeadingPitchRoll(heading_rad, pitch, roll);
                const orientation = new Cesium.ConstantProperty(
                    Cesium.Transforms.headingPitchRollQuaternion(cartesian, hpr)
                );
                entity.orientation = orientation;
            }
        }
    });

    emit("created", viewer);
});
</script>

<style>
@import "../../public/static/Cesium/Widgets/widgets.css";
</style>```

Thank

Some aspects are (also) not clear for me, but from the description, it sounds like it may indeed be related to the origin of the 3D model.

Two points to explore (and maybe better understand the issue):

  • When you replace the model from the CallbackPositionPorperty Sandcastle with your model, is it displayed correctly?
  • Can you provide the model (as a ZIP with a GLB, either as an attachment here or via private message/mail)? Maybe that brings some insights…

Hi @Marco13,

yes if i upload my model into Ion and use it with

const resource = await Cesium.IonResource.fromAssetId(XXXXX);

it works fine. It has the wrong orientation, but I know how to fix that. But the flight path works as intented not like in the picture I posted before.

Thanks!
Thomas.

@Marco13 :
Forgot in my last post. I don’t think that the issue is the 3D Model any longer. Did checks in both direction. Used Cesium 3D Models from Cesium Github in my Source Code and I used my 3D Model in the sand castle examples via Cesium ION. Result was everytime the same. in Sandcastle with the example code it works also fine with my 3D models. If I use the Cesium 3d Model in my source code it does not work.

I finaly could recreate the Issue:

Sandcastle Example with the Issue

when the viewer is created with

sceneMode: Cesium.SceneMode.SCENE2D

The flight path will overlay the 3D Model. When switching to 3D World View the Issue persists.

Is this the desired behavior?

Probably not… and there are some pretty confusing and surprising elements to this.

The most striking indicator that this is indeed a bug is the following: As you mentioned,

  • when starting with sceneMode: Cesium.SceneMode.SCENE2D, then it is not displayed properly
  • when starting without that (i.e. in the default 3D view), it is displayed properly

but…

  • when starting in 3D mode, and switching to 2D, it is displayed properly!
  • when starting in 2D mode, and switching to 3D, it is not displayed properly.
    • unless… one starts in 2D mode and with orderIndependentTranslucency: false and then switches to 3D :zany_face:

So … there seems to be something wrong on a pretty low level: Whether the bug appears or not depends on the initial 2D/3D mode, but is unaffected by switching the mode, but affected by the orderIndependentTranslucency setting…

More generally, the transparency seems to be important: When changing the PolylineGlowMaterialProperty into a PolylineOutlineMaterialProperty, or a plain material: Cesium.Color.YELLOW, then it seems to be displayed properly in all cases.

So… all this may warrant further investigations, although I think that even the current observations could be tracked as a bug. (If there is not already an issue that captures the underlying cause. I found some issues that might be related, like Polyline z index doesn't work in 2D · Issue #8302 · CesiumGS/cesium · GitHub (even though this refers to polylines, my gut feeling is that the underlying cause may be the same as for path) but no “obvious” culprit until now…)

In the meantime: Maybe setting the material of the path to
material: Cesium.Color.YELLOW,
(instead of the PolylineGlowMaterialProperty) could be a viable workaround for you…?

1 Like

Good Morning @Marco13,

this coresponse with my observations. Yes switching the color or starting in 3D mode is fine for me.

Would be nice if someone could add the information here when the issue is fixed.

Thank you to both of you @Marco13 and @Luke_McKinstry!

Regards
Thomas

1 Like

@jjhembd @Luke_McKinstry If this should be tracked in an issue, just drop me a note. (Similarly, if you already know an issue that represents the underlying cause. Otherwise, I’d have to search for possible duplicates (anything related to “2D” and “Transparency”)).

1 Like

I’m not very familiar with PathGraphics, but the doc calls it a polyline :slight_smile:

 * Describes a polyline defined as the path made by an {@link Entity} as it moves over time.

Given that, I added a link to this example in the issue @Marco13 mentioned (Polyline z index doesn't work in 2D · Issue #8302 · CesiumGS/cesium · GitHub). I think it makes sense to track them together for now.

The issue talks about the zIndex property in particular, but… I could imagine (or rather: assume) that the path is internally converted into the same rendering structures as the polyline (maybe with some sort of ‘default’ zIndex? And maybe a wrong zIndex? …). In any case: Having the backlink from this issue to this thread should be sufficient.