Skip to content

BufferPrimitiveCollection: Material API#13313

Merged
donmccurdy merged 14 commits intomainfrom
donmccurdy/feat/bufferprimitivecollection-materials
Mar 24, 2026
Merged

BufferPrimitiveCollection: Material API#13313
donmccurdy merged 14 commits intomainfrom
donmccurdy/feat/bufferprimitivecollection-materials

Conversation

@donmccurdy
Copy link
Copy Markdown
Member

@donmccurdy donmccurdy commented Mar 17, 2026

Description

Material API for BufferPoint, BufferPolyline, and BufferPolygon collections.

As discussed recently, putting style-related properties directly on BufferPrimitive objects doesn't scale well to supporting multiple renderers and rendering styles, so I'm splitting these properties off into new, packable material classes.

Why new material classes? Unlike the BufferPrimitive classes — where breaking from existing APIs was really necessary for our performance goals — I don't think there's any fundamental reason that BufferPrimitiveMaterial "needs" to be distinct from existing material types like PolylineOutlineMaterial and PolylineDashMaterial. But (1) working out how to share existing materials is non-trivial, (2) existing materials don't appear to cover points and polygons, and (3) our timeline is somewhat tight. So I think that designing a "common" material system to be shared by existing and Buffer- vector collections can be left as a future consideration.

Features

topology color outlineColor outlineWidth size width
point
line
polygon

My intention would be to support color / outlineColor / outlineWidth for all three topologies "soon", but this seems like enough to start testing. Transparency and polygon offset will also be useful. Dashed outlines and arrows might be good additions later.

In a small change from earlier BufferPoint iterations, I've renamed 'pixelSize' to 'size'. This is meant to better match the 'pointSize' naming in Cesium3DTileStyle, and the line.width property which doesn't include a 'pixel' prefix, at the cost of no longer matching the naming convention of PointGraphics.

Example

import {BufferPoint, BufferPointCollection, BufferPointMaterial, Color} from 'cesium';

const material = new BufferPointMaterial({
  size: 8,
  color: Color.WHITE,
  outlineColor: Color.CYAN,
  outlineWidth: 2,
});

const collection = new BufferPointCollection({...});

// (a) apply material at initialization
collection.add({position, material}, point);

// (b) apply material as update
point.setMaterial(material);

Note that after calling setMaterial(...), no reference to the BufferPrimitiveMaterial instance is held, and any subsequent changes to the material will have no effect until setMaterial(...) is called again. The collection simply updates the relevant buffers on each call.

Preview

material-api.webm

Issue number and link

Testing plan

See attached unit tests.

Sandcastle example
import * as Cesium from "cesium";

const viewer = new Cesium.Viewer("cesiumContainer");

const collection = new Cesium.BufferPolylineCollection({
  primitiveCountMax: 1024,
  vertexCountMax: 1024,
});

viewer.scene.primitives.add(collection);

const degreesArray = [-105.0, 40.0, -100.0, 38.0, -105.0, 35.0, -100.0, 32.0];

const positions = Cesium.Cartesian3.packArray(
  Cesium.Cartesian3.fromDegreesArray(degreesArray),
  new Float64Array((degreesArray.length * 3) / 2),
);

const material = new Cesium.BufferPolylineMaterial({
  color: Cesium.Color.GOLDENROD,
  width: 8,
});

const polyline = new Cesium.BufferPolyline();
collection.add({ positions, material }, polyline);

Author checklist

  • I have submitted a Contributor License Agreement
  • I have added my name to CONTRIBUTORS.md
  • I have updated CHANGES.md with a short summary of my change
  • I have added or updated unit tests to ensure consistent code coverage
  • I have updated the inline documentation, and included code examples where relevant
  • I have performed a self-review of my code

PR Dependency Tree

This tree was auto-generated by Charcoal

@github-actions
Copy link
Copy Markdown
Contributor

Thank you for the pull request, @donmccurdy!

✅ We can confirm we have a CLA on file for you.

Copy link
Copy Markdown
Contributor

@danielzhong danielzhong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like BufferPrimitiveCollection.byteLength is not currently used anywhere in the render path, 3d tiles cache logic, or similar runtime systems?

Anyway, for this PR, should we still update BufferPrimitiveCollection.byteLength in BufferPrimitiveCollection.js to include this._materialView.byteLength?

* @property {Color} [color=Color.WHITE]
* @property {BufferPolylineMaterial} [material=BufferPolylineMaterial.DEFAULT_MATERIAL]
* @property {TypedArray} [positions]
* @property {number} [width=1]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

result.width = options.width ?? 1; has already been removed, please remember update the docs accordingly.

Also, the JSDoc/examples for BufferPointCollection, BufferPolylineCollection, and BufferPolygonCollection still reference the old color initialization and setColor() workflow. Since this PR moves styling to material classes, those examples should we update to use material / setMaterial() instead?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch – I think I've updated all the documentation now.

I'd like for the type checker to either catch errors like the unused width, or to extend the BufferPrimitiveMaterialOptions so we don't have to duplicate so much here, but I think that's currently blocked by #10455.

@donmccurdy
Copy link
Copy Markdown
Member Author

donmccurdy commented Mar 18, 2026

It looks like BufferPrimitiveCollection.byteLength is not currently used anywhere in the render path, 3d tiles cache logic, or similar runtime systems?

That's correct, I believe collection.byteLength is unused other than unit tests now. I suspect it's helpful enough for testing and debugging that it's worth keeping, but could be talked out of it. :)

EDIT: I'm also not familiar with the 3D tiles caching yet — if it could benefit from the collection.byteLength information that's definitely a factor. Note that resources linked to the render context aren't yet counted.


Anyway, for this PR, should we still update BufferPrimitiveCollection.byteLength in BufferPrimitiveCollection.js to include this._materialView.byteLength?

Good call, I'd forgotten to add the new buffer to collection.byteLength yes. Updated in implementation and unit tests, thanks!

Comment on lines +1293 to +1307
/**
* Internal-only, supported in Vector Tiles with 3D Tiles 2.0.
* @memberof Cesium3DTileStyle.prototype
* @type {StyleExpression}
* @ignore
*/
lineWidth: {
get: function () {
return this._lineWidth;
},
set: function (value) {
this._lineWidth = getExpression(this, value);
this._style.lineWidth = getJsonFromExpression(this._lineWidth);
},
},
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm taking the liberty of adding a lineWidth property to Cesium3DTileStyle.js here, for alpha testing. That said... it isn't implemented in any stable part of the 3D Tiles spec, including the older vector tiles format, so I've omitted it from published types and documentation with the @ignore JSDoc tag above.

Comment on lines +145 to +152
showSizeAndColorArray[i * 3 + 1] = material.size;
showSizeAndColorArray[i * 3 + 2] = AttributeCompression.encodeRGB8(
material.color,
);

outlineWidthAndOutlineColorArray[i * 2] = 0; // TODO: Material API.
outlineWidthAndOutlineColorArray[i * 2] = material.outlineWidth;
outlineWidthAndOutlineColorArray[i * 2 + 1] =
AttributeCompression.encodeRGB8(Color.WHITE); // TODO: Material API.
AttributeCompression.encodeRGB8(material.outlineColor);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer for the material to take care of packing itself into vertex attributes, rather than making the renderer know about that, but ... for now I think that gets into too many questions of how we'll bridge the draped / non-draped rendering code paths, and if/when we want to try to consolidate materials with existing vector data types in Cesium.js.

Copy link
Copy Markdown
Contributor

@danielzhong danielzhong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved! All my review comments have been addressed, and it looks good to go on my end.

@danielzhong
Copy link
Copy Markdown
Contributor

It looks like there are some test errors that need to be fixed before merging. @donmccurdy

@donmccurdy donmccurdy added this pull request to the merge queue Mar 24, 2026
@donmccurdy donmccurdy removed this pull request from the merge queue due to a manual request Mar 24, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to Branch Protection failures Mar 24, 2026
You're not authorized to push to this branch. Visit "About protected branches" for more information.
github-merge-queue bot pushed a commit that referenced this pull request Mar 24, 2026
…vecollection-materials

BufferPrimitiveCollection: Material API
@donmccurdy donmccurdy force-pushed the donmccurdy/feat/bufferprimitivecollection-materials branch 2 times, most recently from 16b5f0e to 5cd8ba3 Compare March 24, 2026 14:21
@donmccurdy donmccurdy added this pull request to the merge queue Mar 24, 2026
Merged via the queue into main with commit 17bbc95 Mar 24, 2026
17 of 18 checks passed
@donmccurdy donmccurdy deleted the donmccurdy/feat/bufferprimitivecollection-materials branch March 24, 2026 14:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants