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

Add segments to ExtrusionBuilder #13719

Merged
merged 2 commits into from
Jun 10, 2024
Merged
Changes from all commits
Commits
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
146 changes: 92 additions & 54 deletions crates/bevy_render/src/mesh/primitives/extrusion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ where
ExtrusionBuilder {
base_builder: self.base_shape.mesh(),
half_depth: self.half_depth,
segments: 1,
}
}
}
Expand All @@ -101,8 +102,9 @@ where
P: Primitive2d + Meshable,
P::Output: Extrudable,
{
base_builder: P::Output,
half_depth: f32,
pub base_builder: P::Output,
pub half_depth: f32,
pub segments: usize,
lynn-lumen marked this conversation as resolved.
Show resolved Hide resolved
}

impl<P> ExtrusionBuilder<P>
Expand All @@ -115,8 +117,16 @@ where
Self {
base_builder: base_shape.mesh(),
half_depth: depth / 2.,
segments: 1,
}
}

/// Sets the number of segments along the depth of the extrusion.
/// Must be greater than `0` for the geometry of the mantel to be generated.
pub fn segments(mut self, segments: usize) -> Self {
self.segments = segments;
self
}
}

impl ExtrusionBuilder<Circle> {
Expand Down Expand Up @@ -218,14 +228,19 @@ where
panic!("The base mesh did not have vertex positions");
};

debug_assert!(self.segments > 0);

let layers = self.segments + 1;
let layer_depth_delta = self.half_depth * 2.0 / self.segments as f32;

let perimeter = self.base_builder.perimeter();
let (vert_count, index_count) =
perimeter
.iter()
.fold((0, 0), |(verts, indices), perimeter| {
(
verts + 2 * perimeter.vertices_per_layer(),
indices + perimeter.indices_per_segment(),
verts + layers * perimeter.vertices_per_layer(),
indices + self.segments * perimeter.indices_per_segment(),
)
});
let mut positions = Vec::with_capacity(vert_count);
Expand Down Expand Up @@ -253,36 +268,37 @@ where
// Get the index of the next vertex added to the mantel.
let index = positions.len() as u32;

// Push the positions of the two indices and their equivalent points on the back face.
// This works, since the front face has already been moved to the correct depth.
positions.push(a);
positions.push(b);
positions.push([a[0], a[1], -a[2]]);
positions.push([b[0], b[1], -b[2]]);

// UVs for the mantel are between (0, 0.5) and (1, 1).
uvs.extend_from_slice(&[
[uv_x, 0.5],
[uv_x + uv_delta, 0.5],
[uv_x, 1.],
[uv_x + uv_delta, 1.],
]);
// Push the positions of the two indices and their equivalent points on each layer.
for i in 0..layers {
let i = i as f32;
let z = a[2] - layer_depth_delta * i;
positions.push([a[0], a[1], z]);
positions.push([b[0], b[1], z]);

// UVs for the mantel are between (0, 0.5) and (1, 1).
let uv_y = 0.5 + 0.5 * i / self.segments as f32;
uvs.push([uv_x, uv_y]);
uvs.push([uv_x + uv_delta, uv_y]);
}

// The normal is calculated to be the normal of the line segment connecting a and b.
let n = Vec3::from_array([b[1] - a[1], a[0] - b[0], 0.])
.normalize_or_zero()
.to_array();
normals.extend_from_slice(&[n; 4]);
normals.extend_from_slice(&vec![n; 2 * layers]);

// Add the indices for the vertices created above to the mesh.
indices.extend_from_slice(&[
index,
index + 2,
index + 1,
index + 1,
index + 2,
index + 3,
]);
for i in 0..self.segments as u32 {
let base_index = index + 2 * i;
indices.extend_from_slice(&[
base_index,
base_index + 2,
base_index + 1,
base_index + 1,
base_index + 2,
base_index + 3,
]);
}
}
}
PerimeterSegment::Smooth {
Expand All @@ -296,14 +312,22 @@ where
// we need to store the index of the first vertex that is part of this segment.
let base_index = positions.len() as u32;

// If there is a first vertex, we need to add it and its counterpart on the back face.
// If there is a first vertex, we need to add it and its counterparts on each layer.
// The normal is provided by `segment.first_normal`.
if let Some(i) = segment_indices.first() {
let p = cap_verts[*i as usize];
positions.push(p);
positions.push([p[0], p[1], -p[2]]);
uvs.extend_from_slice(&[[uv_start, 0.5], [uv_start, 1.]]);
normals.extend_from_slice(&[first_normal.extend(0.).to_array(); 2]);
for i in 0..layers {
let i = i as f32;
let z = p[2] - layer_depth_delta * i;
positions.push([p[0], p[1], z]);

let uv_y = 0.5 + 0.5 * i / self.segments as f32;
uvs.push([uv_start, uv_y]);
}
normals.extend_from_slice(&vec![
first_normal.extend(0.).to_array();
layers
]);
}

// For all points inbetween the first and last vertices, we can automatically compute the normals.
Expand All @@ -315,11 +339,15 @@ where
let b = cap_verts[segment_indices[i] as usize];
let c = cap_verts[segment_indices[i + 1] as usize];

// Add the current vertex and its counterpart on the backface
positions.push(b);
positions.push([b[0], b[1], -b[2]]);
// Add the current vertex and its counterparts on each layer.
for i in 0..layers {
let i = i as f32;
let z = b[2] - layer_depth_delta * i;
positions.push([b[0], b[1], z]);

uvs.extend_from_slice(&[[uv_x, 0.5], [uv_x, 1.]]);
let uv_y = 0.5 + 0.5 * i / self.segments as f32;
uvs.push([uv_x, uv_y]);
}

// The normal for the current vertices can be calculated based on the two neighbouring vertices.
// The normal is interpolated between the normals of the two line segments connecting the current vertex with its neighbours.
Expand All @@ -333,32 +361,42 @@ where
.extend(0.)
.to_array()
};
normals.extend_from_slice(&[n; 2]);
normals.extend_from_slice(&vec![n; layers]);
}

// If there is a last vertex, we need to add it and its counterpart on the back face.
// If there is a last vertex, we need to add it and its counterparts on each layer.
// The normal is provided by `segment.last_normal`.
if let Some(i) = segment_indices.last() {
let p = cap_verts[*i as usize];
positions.push(p);
positions.push([p[0], p[1], -p[2]]);
uvs.extend_from_slice(&[
[uv_start + uv_segment_delta, 0.5],
[uv_start + uv_segment_delta, 1.],
for i in 0..layers {
let i = i as f32;
let z = p[2] - layer_depth_delta * i;
positions.push([p[0], p[1], z]);

let uv_y = 0.5 + 0.5 * i / self.segments as f32;
uvs.push([uv_start + uv_segment_delta, uv_y]);
}
normals.extend_from_slice(&vec![
last_normal.extend(0.).to_array();
layers
]);
normals.extend_from_slice(&[last_normal.extend(0.).to_array(); 2]);
}

for i in 0..(segment_indices.len() as u32 - 1) {
let index = base_index + 2 * i;
indices.extend_from_slice(&[
index,
index + 1,
index + 2,
index + 2,
index + 1,
index + 3,
]);
let columns = segment_indices.len() as u32;
let segments = self.segments as u32;
let layers = segments + 1;
for s in 0..segments {
for column in 0..(columns - 1) {
let index = base_index + s + column * layers;
indices.extend_from_slice(&[
index,
index + 1,
index + layers,
index + layers,
index + 1,
index + layers + 1,
]);
}
}
}
}
Expand Down