Created
April 15, 2025 19:30
-
-
Save RJ/4db7c0c30cefa5634ccaa5d9b677cc75 to your computer and use it in GitHub Desktop.
bevy annular_sector
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use bevy::{ | |
asset::RenderAssetUsages, | |
prelude::*, | |
render::mesh::{Indices, PrimitiveTopology}, | |
}; | |
use std::f32::consts::FRAC_PI_2; | |
/// A builder for creating a [`Mesh`] with an [`Annulus`] shape. | |
pub struct AnnularSectorMeshBuilder { | |
/// The [`Annulus`] shape. | |
pub annulus: Annulus, | |
/// The number of vertices used in constructing each concentric circle of the annulus mesh. | |
/// The default is `32`. | |
pub resolution: u32, | |
/// Half the angle defining the arc of the annular sector. | |
/// It is created starting from `Vec2::Y`, extending by `half_angle` radians on either side. | |
pub half_angle: f32, | |
} | |
impl AnnularSectorMeshBuilder { | |
/// Create an [`AnnularSectorMeshBuilder`] with the given inner radius, outer radius, half angle, and angular vertex count. | |
#[inline] | |
pub fn new(inner_radius: f32, outer_radius: f32, half_angle: f32, resolution: u32) -> Self { | |
Self { | |
annulus: Annulus::new(inner_radius, outer_radius), | |
half_angle, | |
resolution, | |
} | |
} | |
/// Sets the number of vertices used in constructing the concentric circles of the annulus mesh. | |
#[inline] | |
pub fn resolution(mut self, resolution: u32) -> Self { | |
self.resolution = resolution; | |
self | |
} | |
} | |
impl MeshBuilder for AnnularSectorMeshBuilder { | |
fn build(&self) -> Mesh { | |
let inner_radius = self.annulus.inner_circle.radius; | |
let outer_radius = self.annulus.outer_circle.radius; | |
let resolution = self.resolution as usize; | |
let mut positions = Vec::with_capacity((resolution + 1) * 2); | |
let mut uvs = Vec::with_capacity((resolution + 1) * 2); | |
let normals = vec![[0.0, 0.0, 1.0]; (resolution + 1) * 2]; | |
let mut indices = Vec::with_capacity(resolution * 6); | |
// Angular range: we center around Vec2::Y (FRAC_PI_2) and extend by the half_angle on both sides. | |
let start_angle = FRAC_PI_2 - self.half_angle; | |
let end_angle = FRAC_PI_2 + self.half_angle; | |
let arc_extent = end_angle - start_angle; | |
let step = arc_extent / self.resolution as f32; | |
// Create vertices (each step creates an inner and an outer vertex). | |
for i in 0..=resolution { | |
// For a full circle we wrap the index to duplicate the first vertex at the end. | |
let theta = if self.half_angle == FRAC_PI_2 { | |
start_angle + ((i % resolution) as f32) * step | |
} else { | |
start_angle + i as f32 * step | |
}; | |
let (sin, cos) = ops::sin_cos(theta); | |
let inner_pos = [cos * inner_radius, sin * inner_radius, 0.0]; | |
let outer_pos = [cos * outer_radius, sin * outer_radius, 0.0]; | |
positions.push(inner_pos); | |
positions.push(outer_pos); | |
// The first UV direction is radial and the second is angular; | |
// i.e., a single UV rectangle is stretched around the annulus, with | |
// its top and bottom meeting as the circle closes. Lines of constant | |
// U map to circles, and lines of constant V map to radial line segments. | |
let inner_uv = [0., i as f32 / self.resolution as f32]; | |
let outer_uv = [1., i as f32 / self.resolution as f32]; | |
uvs.push(inner_uv); | |
uvs.push(outer_uv); | |
} | |
// Adjacent pairs of vertices form two triangles with each other; here, | |
// we are just making sure that they both have the right orientation, | |
// which is the CCW order of | |
// `inner_vertex` -> `outer_vertex` -> `next_outer` -> `next_inner` | |
for i in 0..self.resolution { | |
let inner_vertex = 2 * i; | |
let outer_vertex = 2 * i + 1; | |
let next_inner = inner_vertex + 2; | |
let next_outer = outer_vertex + 2; | |
indices.extend_from_slice(&[inner_vertex, outer_vertex, next_outer]); | |
indices.extend_from_slice(&[next_outer, next_inner, inner_vertex]); | |
} | |
Mesh::new( | |
PrimitiveTopology::TriangleList, | |
RenderAssetUsages::default(), | |
) | |
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) | |
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) | |
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) | |
.with_inserted_indices(Indices::U32(indices)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
not sure it'll get merged. bevyengine/bevy#17928