1#[cfg(feature = "render")]
4use ranim_render::extract::{Extract, ExtractContext};
5
6use ranim_core::{
7 color::{self, AlphaColor, Srgb},
8 components::rgba::Rgba,
9 glam::DVec3,
10 traits::{ApplyTransform, FillColor, Interpolatable, Opacity},
11};
12
13use crate::mesh::MeshItem;
14
15use super::{compute_smooth_normals, generate_grid_indices};
16
17fn colorscale_lookup(colorscale: &[(AlphaColor<Srgb>, f64)], value: f64) -> AlphaColor<Srgb> {
19 if colorscale.is_empty() {
20 return color::palette::css::WHITE.with_alpha(1.0);
21 }
22 if value <= colorscale[0].1 {
23 return colorscale[0].0;
24 }
25 if value >= colorscale[colorscale.len() - 1].1 {
26 return colorscale[colorscale.len() - 1].0;
27 }
28 for i in 0..colorscale.len() - 1 {
29 let (c0, v0) = colorscale[i];
30 let (c1, v1) = colorscale[i + 1];
31 if value >= v0 && value <= v1 {
32 let t = ((value - v0) / (v1 - v0)) as f32;
33 let [r0, g0, b0, a0] = c0.components;
34 let [r1, g1, b1, a1] = c1.components;
35 return AlphaColor::new([
36 r0 + (r1 - r0) * t,
37 g0 + (g1 - g0) * t,
38 b0 + (b1 - b0) * t,
39 a0 + (a1 - a0) * t,
40 ]);
41 }
42 }
43 colorscale[colorscale.len() - 1].0
44}
45
46#[derive(Debug, Clone, PartialEq)]
59pub struct Surface {
60 pub vertices: Vec<DVec3>,
62 pub vertex_colors: Vec<AlphaColor<Srgb>>,
64 pub vertex_normals: Vec<DVec3>,
66 pub triangle_indices: Vec<u32>,
68 pub resolution: (u32, u32),
70}
71
72impl Surface {
73 pub fn from_uv_func(
78 uv_func: impl Fn(f64, f64) -> DVec3,
79 u_range: (f64, f64),
80 v_range: (f64, f64),
81 resolution: (u32, u32),
82 ) -> Self {
83 let (nu, nv) = resolution;
84 assert!(nu >= 2 && nv >= 2, "resolution must be >= (2, 2)");
85
86 let mut points = Vec::with_capacity((nu * nv) as usize);
87 for i in 0..nu {
88 let u = u_range.0 + (u_range.1 - u_range.0) * (i as f64 / (nu - 1) as f64);
89 for j in 0..nv {
90 let v = v_range.0 + (v_range.1 - v_range.0) * (j as f64 / (nv - 1) as f64);
91 points.push(uv_func(u, v));
92 }
93 }
94
95 let triangle_indices = generate_grid_indices(nu, nv);
96
97 let vertex_colors = vec![color::palette::css::BLUE.with_alpha(1.0); points.len()];
98 let vertex_normals = vec![DVec3::ZERO; points.len()];
99 Self {
100 vertices: points,
101 triangle_indices,
102 resolution,
103 vertex_colors,
104 vertex_normals,
105 }
106 }
107
108 pub fn with_vertex_colors(mut self, colors: Vec<AlphaColor<Srgb>>) -> Self {
110 self.vertex_colors = colors;
111 self
112 }
113
114 pub fn with_fill_by_z(mut self, colorscale: &[(AlphaColor<Srgb>, f64)]) -> Self {
119 let colors = self
120 .vertices
121 .iter()
122 .map(|p| colorscale_lookup(colorscale, p.z))
123 .collect();
124 self.vertex_colors = colors;
125 self
126 }
127
128 pub fn with_smooth_normals(mut self) -> Self {
130 self.update_smooth_normals();
131 self
132 }
133 pub fn update_smooth_normals(&mut self) -> &mut Self {
135 self.vertex_normals = compute_smooth_normals(&self.vertices, &self.triangle_indices);
136 self
137 }
138}
139
140impl Interpolatable for Surface {
141 fn lerp(&self, target: &Self, t: f64) -> Self {
142 Self {
143 vertices: self.vertices.lerp(&target.vertices, t),
144 triangle_indices: if t < 0.5 {
146 self.triangle_indices.clone()
147 } else {
148 target.triangle_indices.clone()
149 },
150 resolution: if t < 0.5 {
151 self.resolution
152 } else {
153 target.resolution
154 },
155 vertex_colors: self.vertex_colors.lerp(&target.vertex_colors, t),
156 vertex_normals: self.vertex_normals.lerp(&target.vertex_normals, t),
157 }
158 }
159}
160
161impl FillColor for Surface {
162 fn fill_color(&self) -> AlphaColor<Srgb> {
163 let Rgba(rgba) = self
165 .vertex_colors
166 .first()
167 .cloned()
168 .map(Rgba::from)
169 .unwrap_or_default();
170 AlphaColor::new([rgba.x, rgba.y, rgba.z, rgba.w])
171 }
172
173 fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
174 self.vertex_colors.fill(color);
175 self
176 }
177
178 fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
179 self.vertex_colors
180 .iter_mut()
181 .for_each(|x| *x = x.with_alpha(opacity));
182 self
183 }
184}
185
186impl Opacity for Surface {
187 fn set_opacity(&mut self, opacity: f32) -> &mut Self {
188 self.set_fill_opacity(opacity)
189 }
190}
191
192impl From<Surface> for MeshItem {
193 fn from(value: Surface) -> Self {
194 MeshItem {
195 points: value.vertices.into(),
196 triangle_indices: value.triangle_indices,
197 vertex_colors: value
198 .vertex_colors
199 .into_iter()
200 .map(Rgba::from)
201 .collect::<Vec<_>>()
202 .into(),
203 vertex_normals: value.vertex_normals.into(),
204 }
205 }
206}
207
208#[cfg(feature = "render")]
209impl Extract for Surface {
210 fn extract(&self, ctx: &mut ExtractContext<'_>) {
211 MeshItem::from(self.clone()).extract(ctx);
212 }
213}
214
215impl<G: Into<ranim_core::glam::DAffine3>> ApplyTransform<G> for Surface {
216 fn apply(&mut self, transform: G) -> &mut Self {
217 let transform = transform.into();
218 self.vertices.apply(transform);
219 if transform.matrix3.determinant().abs() > 1e-12 {
220 let normal_matrix = transform.matrix3.inverse().transpose();
221 self.vertex_normals.iter_mut().for_each(|normal| {
222 if let Some(unit) = (normal_matrix * *normal).try_normalize() {
223 *normal = unit;
224 }
225 });
226 }
227 self
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234 use ranim_core::glam::dvec3;
235
236 #[test]
237 fn test_flat_surface() {
238 let surface =
239 Surface::from_uv_func(|u, v| dvec3(u, v, 0.0), (0.0, 1.0), (0.0, 1.0), (3, 3));
240 assert_eq!(surface.vertices.len(), 9);
241 assert_eq!(surface.triangle_indices.len(), 24);
242 let mesh = MeshItem::from(surface.clone());
243 assert_eq!(mesh.points.len(), surface.vertices.len());
244 assert_eq!(mesh.triangle_indices, surface.triangle_indices);
245
246 assert_eq!(surface.vertices[0], dvec3(0.0, 0.0, 0.0));
248 assert_eq!(surface.vertices[2], dvec3(0.0, 1.0, 0.0));
249 assert_eq!(surface.vertices[6], dvec3(1.0, 0.0, 0.0));
250 assert_eq!(surface.vertices[8], dvec3(1.0, 1.0, 0.0));
251 }
252
253 #[test]
254 fn test_surface_interpolation() {
255 let a = Surface::from_uv_func(|u, v| dvec3(u, v, 0.0), (0.0, 1.0), (0.0, 1.0), (2, 2));
256 let b = Surface::from_uv_func(|u, v| dvec3(u, v, 1.0), (0.0, 1.0), (0.0, 1.0), (2, 2));
257 let mid = a.lerp(&b, 0.5);
258 for p in &mid.vertices {
260 assert!((p.z - 0.5).abs() < 1e-10);
261 }
262 }
263}