Custom rendering primitives in CKML

Hi guys, we’ve been creating our own Cesium rendering primitives.
They work fine when used in simple tests, but now we want to integrate them into ckml files.

I’ve found some posts around here that explain how to add custom properties and process them, but what exactly is involved in supporting custom rendering primitives?
I’ve checked the Entity class and it seems all rendering primitives that Cesium implements are listed there as members of the Entity class.
Does this mean to support our own primitives we need to modify this Cesium class and add our own primitives there?
Or is there a way that does not require messing with Cesium internals?

I see that each Cesium primitive has its own xxGraphics.js and xxVisualizer.js classes.
I guess this means I will have to create one of those for each of our custom primitives?

I think I understand how the Graphics class work, they are instantiated in the ckml processors.
Not sure how the Visualizers work though and what they really do.

You can create your own CZML properties and hook them into the DataSource system without modifying any of the Cesium code.

The cesium-sensors plugin does just that - we add processing for CZML properties like agi_conicSensor, etc. along with corresponding Graphics, Visualizers, and Primitives.

Here’s an overview of the architecture of the DataSources layer in Cesium:

Entity - this object groups related graphics definitions together. The properties containing each built-in graphics type are listed in the class for performance reasons, but it also provides an addProperty function which can define additional custom properties that work the same way as the built-in properties. Specifically, an entity property needs to raise the definitionChanged event on the entity when the property changes.

Graphics - these store the definitional information describing how graphical properties change as a function of time. For example, an entity’s position property is typically a sampled property which interpolates an object’s position over time. Or, a property’s value could be fixed with respect to time, for example, a color property might be constant, while the show property or other properties may change over time.

Visualizer - these objects bridge the gap between the graphics and the actual Cesium primitives that are drawn in the scene. These objects know about a particular type of graphics, and each frame, they evaluate the current values of each of the definitional graphical properties at the current time, and then configure the primitives to match. Because this process runs each frame, there are a lot of performance optimizations in place in the built-in visualizers to avoid unnecessary calculations. As a very basic example, if a graphics’ show property is false, there’s no need to even calculate the value of other properties.

CzmlDataSource - this interprets data from CZML packets and constructs appropriate graphical properties and fills them with data. This may mean replacing properties with new definitions, or adding new samples or time intervals to an existing property.

Essentially, you can think of the Graphics properties as being stateless data-driven functions of time, f(t) -> v, while the primitives have no knowledge of time, so the visualizers evaluate the functions at the current time, and then apply those values onto the primitives (which are stateful) to be rendered.

The plugin points for each of these systems are:

CzmlDataSource - CzmlDataSource.updaters is an array of functions which are called with each incoming packet, to load the data into the entity’s properties. You can add your own processing functions to this array.

Visualizers - DataSourceDisplay.defaultVisualizersCallback is a function that constructs an array of visualizers for a given data source and scene. You can wrap this function and construct and add your own visualizers to the array.

Entity - addProperty defines an additional custom property. Typically you’ll call this from within the CzmlDataSource processing functions to create properties as needed.

I see, thanks for the extensive post, now I understand why the Graphics and Visualizer are needed, I am currently implementing my own now, let’s see if it works!

I got it working, just a little question about adding a custom Visualizer.
I was only able to get it working by creating and assigning the function wrapper before creating a Cesium Viewer.
Is this normal or there is another way?

Here’s my code:
var oldFunc = Cesium.DataSourceDisplay.defaultVisualizersCallback;
Cesium.DataSourceDisplay.defaultVisualizersCallback = function(scene, dataSource) {
var entities = dataSource.entities;
var result = oldFunc(scene, dataSource);
result.push(new ProxyVisualizer(scene, entities));
return result;

Yes, your code is correct. The sensors plugin works the same way: