Skip to content

Conversation

@markschlosseratbentley
Copy link

@markschlosseratbentley markschlosseratbentley commented Sep 11, 2025

This PR is one result of splitting up #87 into more granular work.

This PR exists strictly for planning/feedback - this extension (BENTLEY_materials_line_style), once ready, should be submitted as a separate PR to KhronosGroup. This starts with Bentley's minimum requirements as a baseline.

@pmconne pmconne changed the title Elaborate and propose glTF extension BENTLEY_materials_line_style BENTLEY_materials_line_style Nov 13, 2025
@pmconne
Copy link

pmconne commented Nov 13, 2025

The glTF convention appears to be to name extensions based on the glTF object to which they apply. Rename to BENTLEY_material_line_style (singular "material").

@danielzhong danielzhong changed the title BENTLEY_materials_line_style BENTLEY_material_line_style Nov 13, 2025
@danielzhong danielzhong marked this pull request as ready for review November 13, 2025 18:08
@markschlosseratbentley
Copy link
Author

I changed copyright as suggested by @weegeekps.

@markschlosseratbentley
Copy link
Author

@pmconne @danielzhong Same question as this #91 (comment) applies to this PR.

Copy link

@weegeekps weegeekps left a comment

Choose a reason for hiding this comment

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

I have a few concerns about this one. I worry that the pattern sequence is going to require too much additional processing on the renderer side that could easily be done during creation.

One of the biggest benefits of glTF, and one we rely heavily on within 3D Tiles, is that it takes an approach of trying to make it as easy as possible to go straight to the GPU with minimal processing. There are sometimes exceptions to this rule, but they're rare.

@@ -0,0 +1,23 @@
{
"$schema": "http://json-schema.org/draft-04/schema",

Choose a reason for hiding this comment

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

This needs to be updated. We are using https://json-schema.org/draft/2020-12/schema now.

Choose a reason for hiding this comment

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

Updated! Thanks!

},
"pattern": {
"type": "string",
"description": "Arbitrary-length bitfield string representing on/off pattern. '-' = lit, ' ' = unlit."

Choose a reason for hiding this comment

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

This is complex enough that we should include a full explanation of how this works including examples. You can use gltf_detailedDescription for this. A good example can be found in the transmission extension.

This extension introduces two primary properties controlling line appearance:

- `width`: the pixel width of the rendered line
- `pattern`: a string of arbitrary length representing a repeating sequence of lit (`-`) and unlit (` `) pixels
Copy link

@weegeekps weegeekps Nov 20, 2025

Choose a reason for hiding this comment

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

I'm uncertain about this approach. It feels somewhat antithetical to the spirit of glTF to me, given that we're dealing with an arbitrary length string that dictates which pixels are lit and unlit.

The most appropriate way to handle this within glTF is to store it within the binary buffer. (see: §3.6 Binary Data Storage) The accessor for it can be a scalar byte. This allows for very efficient and compact storage that can be quickly sent to the GPU ready to be used immediately, with no additional transcoding required. Given the need for tessellation with wide lines, this seems especially prudent since you'll want the pipeline to be as fast as possible, and this would allow you to just pass the data straight to the vertex shader.

If there isn't another technical reason you need this to be a string, I strongly recommend you change this.

Choose a reason for hiding this comment

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

@pmconne FYI

Copy link

@pmconne pmconne Nov 21, 2025

Choose a reason for hiding this comment

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

For context, iTwin.js supports a fixed list of 11 patterns which we encode into a single shared texture. We think that the extension should be more general, supporting arbitrary patterns.

My initial thought about how to implement it was to append to that shared texture a new row for each unique new pattern encountered while decoding glTF. But I do lean towards @weegeekps' suggestion to instead encode patterns into glTF textures.

However, I would like to see some optimization on the encoding (e.g., refer to an external texture URL instead of encoding dash pattern texture per glTF) and/or decoding (e.g., recognizing duplicate patterns and avoiding allocating many mostly-duplicate GL textures) side.

Choose a reason for hiding this comment

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

refer to an external texture URL instead of encoding dash pattern texture per glTF

Be aware that using an external texture URL does mean that if that texture is unavailable, the glTF won't be able to render correctly. Optimizing on the decoding side is likely the best option.

Choose a reason for hiding this comment

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

During our team call, @eringram, @ggetz, @danielzhong and I myself discussed this topic.

Instead of textures, the possibility came up of specifying another GPU-ready format like a 16-bit number with bits specifying an on-off pattern. That could be passed down easily as a uniform (much more easily than a string). Then an implementation provides a shader in charge of processing it.

This is similar to how Cesium encodes patterns (thanks @ggetz): https://cesium.com/learn/ion-sdk/ref-doc/PolylineDashMaterialProperty.html (see dashPattern property).

I'll be on vacation next week (Nov 24-Nov 28) but wanted to get these thoughts on here before EOD.

Copy link

@pmconne pmconne Nov 25, 2025

Choose a reason for hiding this comment

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

I am fine with using an unsigned limited-width integer to encode the pattern. However, do note that iTwin.js' Invisible pattern requires 32 bits, not 16. Your spec would need to specify endianness (does the pattern start at the low bit or the high bit).

Copy link

@pmconne pmconne Nov 25, 2025

Choose a reason for hiding this comment

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

And frankly I'd be fine with limiting it to 16 bits and encoding Invisible as 0x0001 instead of 0x00000001. @weegeekps would the integer bit pattern work for you?

Choose a reason for hiding this comment

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

I think the integer bit pattern would be fine. You don't need to specify endianness, as everything in glTF must be little-endian. Found in §3.6.1.1:

All buffer data defined in this specification (i.e., geometry attributes, geometry indices, sparse accessor data, animation inputs and outputs, inverse bind matrices) MUST use little endian byte order.

If this is a problem, and there is a technical reason you must be able to support big-endian, let me know and we can talk through it.

Copy link

Choose a reason for hiding this comment

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

It's not about byte-endianness, it's about being explicit about how to correlate a bit to a position along the length of the line string.

Choose a reason for hiding this comment

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

Sorry, my point is I'd encourage you to use a little-endian style approach with the pattern starting at the low-bit, to keep it aligned with what most expect from glTF.


The pattern should be continuous along the length of each continuous line string or line loop.

Implementations may choose to aggregate the set of unique dash patterns into a texture with one row per pattern to be indexed by the shader program when applying a line style's pattern.

Choose a reason for hiding this comment

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

Going further into my point about the pattern, a small texture map that contains the patterns and is stored in the buffer also would be an excellent "glTF-centric" approach to solving this problem. In fact, I almost like the texture idea a bit better: it's easier to produce, use, and maintain than raw data.

Check out the KHR_materials_specular extension to see how we handled this for specularTexture.

@markschlosseratbentley markschlosseratbentley changed the title BENTLEY_material_line_style BENTLEY_materials_line_style Nov 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants