Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/release-content/release-notes/ring_primitive.md
7223 views
---
title: Ring primitives authors: ["@tigregalis", "@lynn-lumen"] pull_requests: [21446]
---

Ring / hollow shapes

Rings of 2d primitives (bottom row)

Extrusions of rings of extrudable primitives (front row)

There is a new generic primitive Ring, which takes as input any Primitive2d, with two instances of that primitive shape: the outer and the inner (or hollow). A Ring here is what an Annulus is to a Circle. This allows us to have (or at least approximate - more on that later) "hollow" shapes or "outlines".

// construct the `Ring` from an outer and inner shape let capsule_ring = Ring::new(Capsule2d::new(50.0, 100.0), Capsule2d::new(45.0, 100.0)); let hexagon_ring = Ring::new(RegularPolygon::new(50.0, 6), RegularPolygon::new(45.0, 6)); // note vertex count must match // or, from a shape and a thickness for any types that implement `Inset` let capsule_ring = Ring::from_primitive_and_thickness(Capsule2d::new(50.0, 100.0), 5.0); let hexagon_ring = Ring::from_primitive_and_thickness(RegularPolygon::new(50.0, 6), 5.0); // or, from the `ToRing` trait for any types that implement `Inset` let capsule_ring = Capsule2d::new(50.0, 100.0).to_ring(5.0); let hexagon_ring = RegularPolygon::new(50.0, 6).to_ring(5.0);

How it works

The mesh for a RingMeshBuilder is constructed by concatenating the vertices of the outer and inner meshes, then walking the perimeter to join corresponding vertices like so:

Vertices around a pentagon ring

# outer vertices, then inner vertices positions = [ 0 1 2 3 4 0' 1' 2' 3' 4' ] # pairs of triangles indices = [ 0 1 0' 0' 1 1' 1 2 1' 1' 2 2' 2 3 2' 2' 3 3' 3 4 3' 3' 4 4' 4 0 4' 4' 0 0' ]

Examples of generated meshes:

Mesh for a pentagon ring

Mesh for a heart ring

Extrusions

A Ring for a type that is Extrudable is also Extrudable.

let extrusion = Extrusion::new(RegularPolygon::new(1.0, 5).to_ring(0.2));

Mesh for an extruded pentagon ring

Mesh for an extruded heart ring

Inset shapes

Some shapes can be "inset", that is, we can produce a smaller shape where the lines/curves/vertices are equidistant from the outer shape's when they share the same origin. This is represented by the Inset trait. Inset shapes give us nice "outlines" when combined with Ring, so for these shapes we provide a ToRing method that takes an inset distance.

The implementation of Inset can be unintuitive - have a look at the source at crates/bevy_math/src/primitives/inset.rs. For example, the inset CircularSegment in our implementation is actually constructed by shortening the radius and the angle.

Some shapes can't be represented by an inset: Ellipse for example doesn't implement Inset, because concentric ellipses do not have parallel lines.

Concentric ellipses

If the ellipse is not a circle, the inset shape is not actually an ellipse (although it may look like one) but can also be a lens-like shape. The following image shows an ellipse in white and all points at a constant distance from that ellipse in blue. Neither of the blue shapes is an ellipse.

An ellipse in white and its parallel lines in blue

For the sake of flexibility, however, we don't require Ring shapes to be Inset.

Limitations

It's assumed that the inner and outer meshes have the same number of vertices.

It's currently assumed the vertex positions are well ordered (i.e. walking around the perimeter, without zig-zagging), otherwise it will result in incorrect geometries.

The outer_shape must contain the inner_shape for the generated meshes to be accurate. If there are vertices in the inner_shape that escape the outer_shape (for example, if the inner_shape is in fact larger), it may result in incorrect geometries.

Because the origin of the generated mesh matters when constructing a Ring, some "outline" shapes can't currently be easily represented.