-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KITTYCAD_boundary_representation #2343
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This schema was automatically generated. It will likely require some tweaks to match the rest of the spec.
The Beyond that, there are some issues/discussions that may be related, e.g. #2306 or #1783 . It might be worthwhile checking these, to see whether there has been any previous discussion or similar proposals. |
The ideas in this extension have been developed on a branch of the Rust glTF library: https://github.com/alteous/gltf/blob/brep/gltf-json/src/extensions/kittycad_boundary_representation.rs This branch also contains the JSON schema generator: https://github.com/alteous/gltf/blob/brep/gltf-json/src/bin/generate_schema.rs |
I created a PR for adding it via #2345 , but should emphasize that there currently is no established policy for handling renamings of prefixes. Iff there is no existing extension with such a prefix, then we could probably handle that, but the goal of the prefixes is to provide some sort of stability/reliability for the actual, final extension name. Also have a look at the "Naming" section:
In this case, it might be something like The main reason for pointing to these issues is the encourage a form of "collaboration", with the goal of finding something that multiple people can agree on. For example (depending on the maturity of this PR and your own judgement!) you could consider to |
That's fine. By 'tentative' I was thinking along the lines of "another party might be interested in this" and therefore it could be made
That's a good point. The |
Leaving the option to change the prefix to (BTW: One could consider changing this to a 'Draft' unless it is supposed to be 'Ready For Review'. But admittedly, the processes here are not perfectly sorted out. I once started trying to clarify some aspects of the extension development process, but ... the PR at #2225 is itself still a 'Draft' 😬 ) |
This spec has several example JSON snippets for individual features, but I think it would be helpful to add a higher level JSON example near the top. This would help readers who wish to quickly review the overall structure of a Brep. |
{ | ||
"type": "curveType", | ||
"curveType": { | ||
"curveSpecificValue": 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is curveSpecificValue
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This snippet is meant to convey the general structure of a curve entry. The structure is similar to that of cameras where there is a type
field set to either "perspective"
or "orthographic"
and the camera-specific fields are put under camera.perspective
/camera.orthographic
respectively.
https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-camera
On a slightly unrelated note, this kind of sum type has been discussed in #2311.
} | ||
``` | ||
|
||
#### Circle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be more flexible for a curve to be "circular arc" rather than a "circle"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a good point. I think this is a matter of naming. All curves have an optional subdomain so they are meant to be flexible in this way already, i.e., a circle curve with a subdomain would be an arc of the circle.
} | ||
``` | ||
|
||
#### Torus (revolved circle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NURBS, RevolutionSurface, and Plane all seem like fundamental surface types to me, but torus
does not. Although, it's unclear if the object key here is just a human-readable name or if it defines the actual type of parametric surface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surfaces of revolution and extrusion are planned and in progress at the moment but haven't been added to this PR yet.
This particular section was intended to introduce a type of a parametric surface. Perhaps that could be made clearer.
Now that you mention it, I do wonder if it's worth having distinct types for cylinders and tori at all since they could be simply inferred as circle + extrusion/revolution.
extensions/2.0/Vendor/KITTYCAD_boundary_representation/README.md
Outdated
Show resolved
Hide resolved
I love that someone is interested in opening up a modern standard for Brep representation! As it now stands, this spec does not clearly leverage glTF's core strengths like its well-defined materials model, its animation model (skinning/morphing), and the node model (allows efficient mesh instancing and hierarchical transformations). I think "playing nicely" with all those features is possible, but the spec should probably make it clear how it all works. |
It's great to have another party interested too, thanks for your review! Modernising B-reps is exactly what we're trying to achieve here. Our main use case is for manufacturing. We want to be able to ship an exact boundary representation, an optional tessellation, and manufacturing data in one bundle. The JSON + binary design of glTF allows this data to be stored more densely than existing formats and with potentially more diverse metadata.
That's a great point. The intention is to integrate well the materials and node model. I'll expand on the documentation there. Solids are meant be to instantiated in the same way as meshes, i.e., they don't appear in the scene unless they are referenced in the node hierarchy. It's up to the application whether they render the pre-tessellated mesh approximation or do something with the B-rep directly. Animations targeting B-reps are expected to be limited to simple node transformations, i.e., translation, rotation, and scaling. |
@alteous all your responses make sense to me. My own interest is the architecture sector as opposed to manufacturing, but I think we'd both want the same things from a Brep format. I look forward to seeing how this develops, let me know if there's anything I can do to help. |
"start": [-1, -1, 0], | ||
"end": [1, -1, 0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the start
and end
fields of a line
be integers that refer to vertices
, rather than coordinates?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly. The idea here is that straight edges are a portion of a line curve. For example, an edge may span from vertex [-1, -1, -1] to vertex [1, 1, 1], but be associated with a line curve starting from [-2, -2, -2] in the direction [1, 1, 1].
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it could be either an indexed vertex or an explicit co-ordinate.
{
"curves": [
{
"type": "line",
"line": {
"start": 0,
"end": 1
}
},
{
"type": "line",
"line": {
"start": [0.0, 0.0, 0.0],
"end": [1.0, 1.0, 1.0]
}
}
]
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line curves have been simplified to a single form: an origin plus a normalised direction.
"start": 0, | ||
"end": 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fuzzy on the purpose of start
and end
, since the curve already has start and end points; also fuzzy as to why edges
exists at all -- couldn't a loop
refer to curves
directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edges typically join surfaces with differing surface equations. For example, consider the edge at the top of a closed cylinder which can be represented equivalently in three ways: a circle in 3D space, a circle on a planar surface in 2D space, or a line on a cylindrical surface in 2D space. The point of having edges is to allow all these curves to be provided: a 3D space curve is associated with the edge, and a 2D surface curves may be associated a with loop.
{
"loops": [
{
"edges": [0, 1, 2, 3],
"uvCurves": [0, 1, 2, 3]
},
{
// edges 0 & 1 are shared but have differing UV curves
"edges": [0, 1, 3 ,4],
"uvCurves": [4, 5, 6, 7]
}
],
"faces": [
{
"outerLoop": 0,
"surface": 0
},
{
"outerLoop": 1,
"surface": 1
}
],
"edges": [
{
"curve": [4],
...
}
]
}
|
||
### Shell | ||
|
||
A _shell_ is a collection of _faces_ in 3D space which form a 'watertight' volume. A shell is represented by the `Shell` data structure. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some applications might permit non-manifold modeling, in which case it would be desirable to allow shells to be non-closed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point. I'm thinking of reworking many of the data structures in this direction. In particular, I'm considering removing the outer/inner loop distinction in faces, perhaps replacing it with extra metadata in the loop data structure instead. The same idea can be applied to shells.
Many objects in boundary representation have two _orientation states_. Such objects are called _orientable_ objects. These are often given colloquial terms such as 'right/wrong side', 'up/down', 'in/out', 'forward/backward', et cetera. When referencing orientable objects, it is important to state which orientation of the object is desired. The orientation of a referenced object is described as being 'same-sense' or 'opposite-sense'. This extension utilizes the sign bit of floating point numbers to select the desired orientation. A positive sign selects the 'same-sense' and a negative sign selects the 'opposite-sense'. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the working group meeting, it was raised that -0
would likely be parsed as 0
by some JSON parsers. Also, it was raised that the IEEE754 specification says -0 == 0
should evaluate as true. These are both good points, so I will come up with an alternative.
I have a few ideas:
- Encode using an object
{ "index": 0, "reverse": true }
. This was actually the original proposal but since this use case is so common, this approach was deemed too verbose/bloated. - Use indices starting at 1. This avoids the tricky zeroth index but would be inconsistent with the core specification. I would like to avoid this one if possible.
- Encode as a string instead, i.e,.
"-0"
instead of-0
. This could work; however, it was raised this has its own set of problems. For example, glTF JSON permits additional integer representations such as exponential notation. - Move this data into the binary blob and encode as a one's complement integer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple more ideas:
- Encode using two integers per array, an index followed by a sign.
{
"edges": [
0, 1,
1, -1,
2, 1,
3, -1
]
}
- Encode the sign using a separate paired array, which could be omitted if all items are same-sense:
{
"edges": [0, 1, 2, 3],
"edgeOrientations": [1, -1, 1, -1]
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reworked this as an integer/orientation pair. It looks like this:
Before
{
"loops": [0, -1],
"surface": 0
}
After
{
"loops": [
[0, 1],
[1, -1]
],
"surface": [0, 1]
}
[index, 1]
could be implied by [index]
but I'll keep it explicit for now.
* Curves have been split into 2D and 3D variants. * Curve and surface domains have been removed. * Edges now have an interval for its curve parameter. * The 'xbasis' and 'normal' parameters have been replaced with 'xAxis' and 'yAxis' parameters. * Line curves have been reduced to a single form, that is, an origin and a normalised direction. * Weights in NURBS curves and surfaces are now independent from the control points. This allows B-splines curves and surfaces to be defined as a NURBS curve or surface without the weights array. * The definition of cylindrical, spherical, and toroidal surfaces have been simplified. All of the parameters are now contained within a single JSON object.
This is interesting, thanks! I agree with @prideout that it would be nice if we could find a way to represent smoothly curved geometry within the existing data structures of glTF, since it would avoid duplication, which can inevitably result in conflicting data. I have some thoughts and progress on this, though it's a pretty different concept from NURBS, or even from subdivision surfaces - it's more a form of curved triangles. I have a short write-up here: https://elalish.blogspot.com/2022/03/smoothing-triangle-meshes.html - I have some improvements I want to make first, but I'm interested in attempting a glTF extension on top of my EXT_mesh_manifold to enable this. Of course, I'm not sure how helpful it'll be for engines that are already NURBS-based, but I'm curious if anyone else is interested in trying a new approach to B-reps? One semantic nit: glTF meshes are boundary-representations. The difference between triangles and NURBS is first-order vs higher-order, and explicit edges vs implicit edges. I wrote up a taxonomy: https://elalish.blogspot.com/2022/03/solid-geometry-representations.html |
The glTF core specification provides geometric data in the form of polygonal meshes. Meshes are ubiquitous in hardware accelerated rendering of 3D models; however, since they are composed of flat faces, they cannot represent smooth surfaces accurately. Boundary representation ('B-rep') is an alternative approach, providing an accurate and flexible method of describing 3D shapes. In B-rep models, solid volumes are expressed as the composition of connected faces, bound by curves on surfaces, of which both are described by smooth parametric functions.
The aims of this extension are: (1) to reduce the processing required to import B-rep information when compared to existing formats such as STEP (ISO 10303); (2) to provide an open, royalty-free specification for B-rep data; and (3) to provide additional metadata alongside existing glTF-based manufacturing workflows.
The extension is intended to provide supplementary information to standard mesh-based glTF models. By providing the B-rep data alongside meshes, applications can render approximated previews of solid models without implementing a computationally expensive and complicated tessellation operation. Alternatively, to reduce the size of the asset, the extension could feasibly be used in place of mesh-based models.
Please refer to the README for a technical introduction.