wde_renderer/assets/meshes/
capsule.rs1use bevy::math::Vec3;
2use wde_wgpu::vertex::Vertex;
3
4use crate::assets::{Mesh, MeshBbox};
5
6pub struct CapsuleMeshConfig {
7 pub radius: f32,
8 pub height: f32,
9 pub segments: u32,
10 pub rings: u32
11}
12impl Default for CapsuleMeshConfig {
13 fn default() -> Self {
14 Self {
15 radius: 0.5,
16 height: 2.0,
17 segments: 16,
18 rings: 8
19 }
20 }
21}
22
23pub struct CapsuleMesh;
24impl CapsuleMesh {
25 pub fn from(label: &str, config: CapsuleMeshConfig) -> Mesh {
37 let (radius, height, segments, rings) =
38 (config.radius, config.height, config.segments, config.rings);
39
40 let segments = segments.max(3);
41 let rings = rings.max(1);
42
43 let cylinder_height = (height - 2.0 * radius).max(0.0);
45 let half_cylinder_height = cylinder_height / 2.0;
46
47 let mut vertices = Vec::new();
48 let mut indices = Vec::new();
49
50 for ring in 0..=rings {
52 let phi = std::f32::consts::PI * 0.5 * (ring as f32) / (rings as f32);
53 let y = radius * phi.cos() + half_cylinder_height;
54 let ring_radius = radius * phi.sin();
55
56 for segment in 0..=segments {
57 let theta = 2.0 * std::f32::consts::PI * (segment as f32) / (segments as f32);
58 let x = ring_radius * theta.cos();
59 let z = ring_radius * theta.sin();
60
61 let normal_x = x;
63 let normal_y = radius * phi.cos();
64 let normal_z = z;
65 let normal_length =
66 (normal_x * normal_x + normal_y * normal_y + normal_z * normal_z).sqrt();
67
68 let u = (segment as f32) / (segments as f32);
70 let v = 1.0 - (ring as f32) / (rings as f32) * 0.25; vertices.push(Vertex {
73 position: [x, y, z],
74 normal: [
75 normal_x / normal_length,
76 normal_y / normal_length,
77 normal_z / normal_length
78 ],
79 uv: [u, v],
80 tangent: [0.0, 0.0, 0.0, 0.0]
81 });
82 }
83 }
84
85 for ring in 0..=1 {
87 let y = if ring == 0 {
88 half_cylinder_height
89 } else {
90 -half_cylinder_height
91 };
92
93 for segment in 0..=segments {
94 let theta = 2.0 * std::f32::consts::PI * (segment as f32) / (segments as f32);
95 let x = radius * theta.cos();
96 let z = radius * theta.sin();
97
98 let normal_x = theta.cos();
100 let normal_z = theta.sin();
101
102 let u = (segment as f32) / (segments as f32);
104 let v = 0.75 - (ring as f32) * 0.5; vertices.push(Vertex {
107 position: [x, y, z],
108 normal: [normal_x, 0.0, normal_z],
109 uv: [u, v],
110 tangent: [0.0, 0.0, 0.0, 0.0]
111 });
112 }
113 }
114
115 for ring in 0..=rings {
117 let phi = std::f32::consts::PI * 0.5 * (ring as f32) / (rings as f32);
118 let y = -radius * phi.cos() - half_cylinder_height;
119 let ring_radius = radius * phi.sin();
120
121 for segment in 0..=segments {
122 let theta = 2.0 * std::f32::consts::PI * (segment as f32) / (segments as f32);
123 let x = ring_radius * theta.cos();
124 let z = ring_radius * theta.sin();
125
126 let normal_x = x;
128 let normal_y = -radius * phi.cos();
129 let normal_z = z;
130 let normal_length =
131 (normal_x * normal_x + normal_y * normal_y + normal_z * normal_z).sqrt();
132
133 let u = (segment as f32) / (segments as f32);
135 let v = 0.25 - (ring as f32) / (rings as f32) * 0.25; vertices.push(Vertex {
138 position: [x, y, z],
139 normal: [
140 normal_x / normal_length,
141 normal_y / normal_length,
142 normal_z / normal_length
143 ],
144 uv: [u, v],
145 tangent: [0.0, 0.0, 0.0, 0.0]
146 });
147 }
148 }
149
150 let mut vertex_offset = 0u32;
152 for ring in 0..rings {
153 for segment in 0..segments {
154 let current = vertex_offset + ring * (segments + 1) + segment;
155 let next = current + segments + 1;
156
157 indices.push(current);
158 indices.push(next);
159 indices.push(current + 1);
160
161 indices.push(current + 1);
162 indices.push(next);
163 indices.push(next + 1);
164 }
165 }
166
167 vertex_offset += (rings + 1) * (segments + 1);
169 for segment in 0..segments {
170 let current = vertex_offset + segment;
171 let next = current + segments + 1;
172
173 indices.push(current);
174 indices.push(next);
175 indices.push(current + 1);
176
177 indices.push(current + 1);
178 indices.push(next);
179 indices.push(next + 1);
180 }
181
182 vertex_offset += 2 * (segments + 1);
184 for ring in 0..rings {
185 for segment in 0..segments {
186 let current = vertex_offset + ring * (segments + 1) + segment;
187 let next = current + segments + 1;
188
189 indices.push(current);
190 indices.push(next);
191 indices.push(current + 1);
192
193 indices.push(current + 1);
194 indices.push(next);
195 indices.push(next + 1);
196 }
197 }
198
199 let half_height = height / 2.0;
201 let bounding_box = MeshBbox {
202 min: Vec3::new(-radius, -half_height, -radius),
203 max: Vec3::new(radius, half_height, radius)
204 };
205
206 Mesh {
207 label: label.to_string(),
208 vertices,
209 indices,
210 bbox: bounding_box,
211 use_ssbo: false
212 }
213 }
214}