Skip to content
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

Primitive Shapes #12

Merged
merged 59 commits into from
Dec 12, 2022
Merged
Changes from 5 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
6a67443
Create geometric-primitives.md
aevyrie Apr 21, 2021
3f4c7e0
Correct typo
aevyrie Apr 21, 2021
fa1fc1c
Adding details
aevyrie Apr 22, 2021
7f5f21f
Incremental updates
aevyrie Apr 24, 2021
9a890e7
Update rfcs/geometric-primitives.md
aevyrie Apr 24, 2021
175b8a0
Update rfcs/geometric-primitives.md
aevyrie Apr 24, 2021
b43acde
Update rfcs/geometric-primitives.md
aevyrie Apr 24, 2021
3533994
Apply suggestions from code review
aevyrie Apr 24, 2021
68f5485
Update all the things
aevyrie Apr 30, 2021
08565cc
Merge branch 'patch-1' of https://github.com/aevyrie/rfcs into patch-1
aevyrie Apr 30, 2021
66d8c9d
Add meshing section.
aevyrie Apr 30, 2021
ceac06d
Added plane
aevyrie Apr 30, 2021
88af32e
Add primitives and use demonstration
aevyrie May 1, 2021
e6a7275
Update rfcs/geometric-primitives.md
aevyrie May 3, 2021
f8c8fbe
Update rfcs/geometric-primitives.md
aevyrie May 3, 2021
6c9cbfd
Update rfcs/geometric-primitives.md
aevyrie May 7, 2021
da6871e
wip updates
aevyrie May 12, 2021
47ea3b6
Update table and rename
aevyrie May 17, 2021
5e84667
Rewrite all the things.
aevyrie May 25, 2021
f663bd1
Rename primitive-shapes.md to 12-primitive-shapes.md
aevyrie May 25, 2021
cef33e9
Update 12-primitive-shapes.md
aevyrie May 25, 2021
9dd6b67
Update 12-primitive-shapes.md
aevyrie May 25, 2021
b67f30e
Update 12-primitive-shapes.md
aevyrie May 25, 2021
47bcc26
Update 12-primitive-shapes.md
aevyrie May 25, 2021
7d58f91
Correct Mat3 -> Mat2
aevyrie May 25, 2021
a2aa8cf
Fix AABB error in table
aevyrie May 25, 2021
bd9d5e2
Update 12-primitive-shapes.md
aevyrie May 26, 2021
0f25cfe
Typo
aevyrie May 26, 2021
b3fcd7d
Add notes to bounding/collision
aevyrie Jun 1, 2021
cede313
Clarify traits as reference only
aevyrie Jun 1, 2021
5e381f6
improve bounding/collision discussion
aevyrie Jun 1, 2021
019047e
Add notes about Parry types
aevyrie Jun 3, 2021
24dbd0b
Update 12-primitive-shapes.md
aevyrie Jul 26, 2021
9ef4d2e
Merge branch 'bevyengine:main' into patch-1
aevyrie Oct 10, 2021
f37352e
Fix markdown lint violations
Weibye Oct 26, 2021
c50b330
Fixing typo
Weibye Oct 27, 2021
bc99e5b
Merge pull request #1 from Weibye/primitive-shapes
aevyrie Dec 8, 2021
e164fa5
Merge pull request #3 from Weibye/fix-typo
aevyrie Dec 8, 2021
cc192cb
Explicitly naming x2d or x3d where it makes sense
Weibye Oct 26, 2021
2ff5978
Rename Box2d to Rectangle
Weibye Oct 26, 2021
e88a42a
Removing unresolved question
Weibye Oct 26, 2021
2a33756
Fix typo
Weibye Nov 6, 2021
5222ee8
Moving 2d shapes ontop
Weibye Nov 6, 2021
fbcc8da
Moving 2d shapes before 3d shapes
Weibye Nov 6, 2021
bafe5a5
Adding descriptions to table
Weibye Nov 6, 2021
3494f3a
Collecting and rewording 2d / 3d section
Weibye Nov 6, 2021
2ac6358
Update rfcs/12-primitive-shapes.md
Weibye Nov 6, 2021
5ec59ee
2d before 3d consistency
Weibye Dec 13, 2021
550e522
Merge pull request #2 from Weibye/name-consolidation
aevyrie Jan 3, 2022
46ae46c
Removing point as a primitive type
Weibye Dec 13, 2021
7a5e2c1
Remove angle as a component
Weibye Jan 23, 2022
ca533b1
merging 'bounding and collision' with 'where are the transforms'
Weibye Jan 23, 2022
957bfca
Merge pull request #4 from Weibye/dev/remove-point
aevyrie Jan 23, 2022
dc58497
Merge pull request #5 from Weibye/remove-angle
aevyrie Jan 23, 2022
be92586
Merge pull request #6 from Weibye/where-transforms
aevyrie Jan 23, 2022
7981ae8
Update rfcs/12-primitive-shapes.md
aevyrie Jan 23, 2022
f632b2b
Removing torus and placing non-convex in future work
Weibye Apr 24, 2022
69e3ab0
Merge pull request #7 from Weibye/non-convex
aevyrie Apr 25, 2022
03eaf5f
Update rfcs/12-primitive-shapes.md
aevyrie Aug 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions rfcs/geometric-primitives.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Feature Name: `geometric-primitives`

## Summary

Lightweight geometric primitive types for use across bevy engine crates, and as interoperability types for external libraries.

## Motivation

This would provide a standard way to model primitives across the bevy ecosystem to prevent ecosystem fragmentation amongst plugins.

## Guide-level explanation

Geometric primitives are lightweight representations of geometry that describe the type of geometry as well as fully defined dimensions. These primitives are *not* discrete meshes, but the underlying precise geometric definition. For example, a circle is:

```rust
pub struct Circle {
origin: Point,
radius: f32,
}
```

Geometric primitives have a defined shape, size, position, and orientation. Position and orientation are **not** handled by bevy's `Transform` systems. These are fundamental geometric primitives that must be usable and comparable as-is.

TODO:
Explain the proposal as if it was already included in the engine and you were teaching it to another Bevy user. That generally means:

- Introducing new named concepts.
- Explaining the feature, ideally through simple examples of solutions to concrete problems.
- Explaining how Bevy users should *think* about the feature, and how it should impact the way they use Bevy. It should explain the impact as concretely as possible.
- If applicable, provide sample error messages, deprecation warnings, or migration guidance.
- If applicable, explain how this feature compares to similar existing features, and in what situations the user would use each one.

## Reference-level explanation

### `bevy_geom::Shape2d`

These types only exist in 2d space: their dimensions and location are only defined in `x` and `y` unlike their 3d counterparts.

- `Point`: type alias of Vec2
- `Direction`: Vec2 that is guaranteed to be normalized through its getter/setter

#### Axis

Line with infinite length on the x/y plane.


```rust
struct Axis { point: Point, normal: Direction }
```

#### Line

- `Line`: (start: Point, end: Point) line bounded by two points
- `Arc`: (start: Point, end: Point, radius_origin: Point) segment of a circle

```rust
struct Circle` { origin: Point, radius: f32 }
```
- `Triangle`
- `AABBCentered` origin and half-extents
- `AabbExtents` minimum and maximum extents
- `OBB` origin, orthonormal basis, and half-extents

### `bevy_geom::Shape3d`

These types are fully defined in 3d space.

- `Point`: type alias of Vec3
- `Direction`: Vec3 that is guaranteed to be normalized through its getter/setter
- `Axis`
- `Line`
- `Plane`
- `Quad`
- `Sphere`
- `Cylinder`
- `Capsule`
- `Torus`
- `Cone`
- `Frustum`: defined with 6 planes
- `AabbCentered`
- `AabbExtents`
- `OBB`

### Bounding Boxes

This section is based off of prototyping work done in [bevy_mod_bounding](https://github.com/aevyrie/bevy_mod_bounding).

Because bounding boxes are fully defined in world space, this leads to the natural question of how they are kept in sync with their parent.

### Frustum Culling

This section is based off of prototyping work done in [bevy_frustum_culling](https://github.com/aevyrie/bevy_frustum_culling).

### Ray Casting

This section is based off of prototyping work done in [bevy_mod_picking](https://github.com/aevyrie/bevy_mod_picking).

## Drawbacks

An argument could be made to use an external crate for this, however these types are so fundamental I think it's important that they are optimized for the engine's uses, and are not from a generalized solution.

This is also a technically simple addition that shouldn't present maintenance burden. The real challenge is upfront in ensuring the API is designed well, and the primitives are performant for their most common use cases. If anything, this furthers the argument for not using an external crate.

## Rationale and alternatives

### Lack of `Transform`s

Primitives are fully defined in space, and do not use `Transform` or `GlobalTransform`. This is an intentional decision.

It's unsurprisingly much simpler to use these types when the primitives are fully defined internally, but maybe somewhat surprisingly, more efficient.

#### Cache Efficiency
aevyrie marked this conversation as resolved.
Show resolved Hide resolved

- Some primitives such as AABB and Sphere don't need a rotation to be fully defined.
- By using a `GlobalTransform`, not only is this an unused Quat that fills the cache line, it would also cause redundant change detection on rotations.
- This is especially important for AABBs and Spheres, because they are fundamental to collision detection and BV(H), and as such need to be as efficient as possible.
- I still haven't found a case where you would use a `Primitive3d` without needing this positional information that fully defines the primitive in space. If this holds true, it means that storing the positional data inside the primitive is _not_ a waste of cache, which is normally why you would want to separate the transform into a separate component.

#### CPU Efficiency
aevyrie marked this conversation as resolved.
Show resolved Hide resolved

- Storing the primitive's positional information internally serves as a form of memoization.
- Because you need the primitive to be fully defined in world space to run useful operations, this means that with a `GlobalTransform` you would need to apply the transform to the primitive every time you need to use it.
- By applying this transformation only once (e.g. during transform propagation), we only need to do this computation a single time.

#### Ergonomics
aevyrie marked this conversation as resolved.
Show resolved Hide resolved

- As I've already mentioned a few times, primitives need to be fully defined in world space to do anything useful with them.
- By making the primitive components fully defined and standalone, computing operations is as simple as: `primitive1.some_function(primitive_2)`, instead of also having query and pass in 2 `GlobalTransform`s in the correct order.

#### Use with Transforms
aevyrie marked this conversation as resolved.
Show resolved Hide resolved

- For use cases such as oriented bounding boxes, a primitive should be defined relative to its parent.
- In this case, the primitive would still be fully defined internally, but we would need to include primitive updates analogous to the transform propagation system.
- For example, a bounding sphere entity would be a child of a mesh, with a `Sphere` primitive and a `Transform`. On updates to the parent's `GlobalTransform`, the bounding sphere's `Transform` component would be used to update the `Sphere`'s position and radius by applying the scale and translation to a unit sphere. This could be applied to all primitives, with the update system being optimized for each primitive.

- What other designs have been considered and what is the rationale for not choosing them?
- What is the impact of not doing this?
- Why is this important to implement as a feature of Bevy itself, rather than an ecosystem crate?

## \[Optional\] Prior art
aevyrie marked this conversation as resolved.
Show resolved Hide resolved

Unity `PrimitiveObjects`: https://docs.unity3d.com/Manual/PrimitiveObjects.html
Godot `PrimitiveMesh`: https://docs.godotengine.org/en/stable/classes/class_primitivemesh.html#class-primitivemesh

These examples intermingle primitive geometry with the meshes themselves. This RFC makes these distinct.

aevyrie marked this conversation as resolved.
Show resolved Hide resolved

## Unresolved questions

aevyrie marked this conversation as resolved.
Show resolved Hide resolved
- What parts of the design do you expect to resolve through the RFC process before this gets merged?
- What parts of the design do you expect to resolve through the implementation of this feature before the feature PR is merged?

### Out of Scope

- Value types, e.g. float vs. fixed is out of scope. This RFC is focused on the core geometry types and is intended to use Bevy's common rendering value types such as `f32`.

## Future possibilities
aevyrie marked this conversation as resolved.
Show resolved Hide resolved

- Bounding boxes
- Collisions
- Frustum Culling
- Debug Rendering