1#![warn(missing_docs)]
84pub mod animation;
88pub mod cache;
89pub mod collision;
90pub mod compiled;
91mod crispy;
92pub mod eval;
93pub mod fidelity;
94pub mod interval;
95pub mod io;
96pub mod llm_schema;
97pub mod material;
98pub mod mesh;
99pub mod modifiers;
100pub mod morphology;
101pub mod neural;
102pub mod npr;
103pub mod operations;
104pub mod optimize;
105pub mod primitives;
106pub mod raycast;
107pub mod soa;
108pub mod tight_aabb;
109pub mod transforms;
110pub mod types;
111
112pub mod autodiff;
114pub mod constraint;
115pub mod diff;
116pub mod heatmap;
117pub mod incremental;
118pub mod measure;
119pub mod sdf2d;
120pub mod shell;
121pub mod validity;
122
123#[cfg(all(feature = "font", alice_font_bridge))]
126pub mod font_bridge;
127
128#[cfg(feature = "python")]
129pub mod python;
130
131#[cfg(feature = "godot")]
132pub mod godot;
133
134#[cfg(feature = "ffi")]
135pub mod ffi;
136
137#[cfg(feature = "codec")]
138pub mod codec_bridge;
139
140#[cfg(feature = "physics")]
141pub mod physics_bridge;
142
143#[cfg(feature = "physics")]
144pub mod sim_bridge;
145
146#[cfg(feature = "physics")]
147pub mod live_sdf;
148
149#[cfg(feature = "asp")]
150pub mod asp_bridge;
151
152#[cfg(feature = "sdf-cache")]
153pub mod cache_bridge;
154
155#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
156pub mod wasm;
157
158#[cfg(feature = "texture-fit")]
159pub mod texture;
160
161#[cfg(feature = "volume")]
162pub mod volume;
163
164#[cfg(feature = "svo")]
165pub mod svo;
166
167#[cfg(feature = "destruction")]
168pub mod destruction;
169
170#[cfg(feature = "terrain")]
171pub mod terrain;
172
173#[cfg(feature = "gi")]
174pub mod gi;
175
176pub const VERSION: &str = env!("CARGO_PKG_VERSION");
178
179pub use alice_det_math::SEMANTICS_ID;
189
190pub mod prelude {
192 pub use crate::animation::{
193 morph, AnimatedSdf, Interpolation, Keyframe, LoopMode, Timeline, Track,
194 };
195 pub use crate::autodiff::{
196 eval_hessian, eval_with_gradient, gaussian_curvature, mean_curvature, principal_curvatures,
197 Dual, Dual3,
198 };
199 #[cfg(feature = "codec")]
200 pub use crate::codec_bridge::{
201 compress_sdf, compression_ratio, decode_sdf_volume, decompress_sdf, encode_sdf_volume,
202 volume_stats, voxelize_sdf, voxelize_sdf_uniform, CompressResult, EncodeConfig, SdfVolume,
203 VolumeStats,
204 };
205 pub use crate::collision::{
206 compute_manifold, sdf_ccd, sdf_closest_point, sdf_collide, sdf_distance, sdf_overlap,
207 ContactManifold, SdfContact,
208 };
209 pub use crate::compiled::{
210 eval_compiled, eval_compiled_batch_simd, eval_compiled_batch_simd_parallel,
211 eval_compiled_batch_soa, eval_compiled_batch_soa_parallel, eval_compiled_bvh,
212 eval_compiled_distance_and_normal, eval_compiled_normal, eval_compiled_simd,
213 get_scene_aabb, AabbPacked, CompileError, CompiledSdf, CompiledSdfBvh, RefitError, Vec3x8,
214 };
215 pub use crate::constraint::{
216 Constraint, ConstraintKind, ConstraintSolver, ParamId, SolveResult,
217 };
218 #[cfg(feature = "destruction")]
219 pub use crate::destruction::{
220 carve, carve_batch, generate_debris, voronoi_fracture, CarveShape, ChunkMesh, DebrisConfig,
221 DebrisPiece, DestructionResult, FractureConfig, FracturePiece, MutableVoxelGrid,
222 };
223 pub use crate::diff::{
224 apply_patch, invert_patch, merge_patches, tree_diff, tree_hash, DiffError, DiffOp,
225 TreePatch,
226 };
227 pub use crate::eval::{
228 eval, eval_batch, eval_batch_parallel, eval_gradient, eval_grid, eval_material,
229 eval_normal, gradient, normal,
230 };
231 #[cfg(feature = "gi")]
232 pub use crate::gi::{
233 bake_irradiance_grid, cone_trace, direct_lighting, sky_color, trace_hemisphere,
234 BakeGiConfig, ConeTraceConfig, ConeTraceResult, DirectionalLight, IrradianceGrid,
235 IrradianceProbe, PointLight,
236 };
237 pub use crate::heatmap::{
238 generate_heatmap, heatmap_to_rgba, ColorMap, Heatmap, HeatmapConfig, SlicePlane,
239 };
240 pub use crate::incremental::{IncrementalError, InstructionSlot, ParamDependencyIndex};
241 pub use crate::io::{
242 export_alembic, export_fbx, export_glb, export_glb_bytes, export_gltf_json, export_nanite,
243 export_nanite_json, export_nanite_with_config, export_obj, export_usda, get_info,
244 import_fbx, import_glb, import_glb_bytes, import_obj, load, load_asdf, load_asdf_json,
245 save, save_asdf, save_asdf_json, AlembicConfig, FbxConfig, FbxFormat, FbxUpAxis,
246 GltfConfig, NaniteExportConfig, ObjConfig, UsdConfig, UsdUpAxis,
247 };
248 #[cfg(feature = "physics")]
249 pub use crate::live_sdf::{LiveMesh, LiveMeshConfig, LiveSdf};
250 pub use crate::material::{
251 material_lerp, Material, MaterialLibrary, StandardMaterials, TextureSlot,
252 };
253 pub use crate::measure::{
254 estimate_center_of_mass, estimate_surface_area, estimate_volume, AreaEstimate,
255 CenterOfMass, VolumeEstimate,
256 };
257 #[allow(deprecated)] pub use crate::mesh::point_cloud_to_sdf;
259 pub use crate::mesh::{
260 adaptive_marching_cubes,
262 apply_uvs,
263 compute_aabb,
264 compute_acmr,
265 compute_bounding_sphere,
266 compute_convex_hull,
267 compute_quality,
268 convex_decomposition,
269 decimate,
271 deduplicate_vertices,
272 detect_primitive,
273 dual_contouring,
275 dual_contouring_compiled,
276 extract_hermite,
277 generate_lightmap_uvs,
279 generate_lightmap_uvs_fast,
280 generate_lod_chain,
281 generate_lod_chain_decimated,
282 generate_nanite_mesh,
283 marching_cubes,
284 mesh_to_sdf,
285 mesh_to_sdf_exact,
286 optimize_vertex_cache,
288 primitives_to_csg,
289 sdf_to_mesh,
290 simplify_collision,
291 uv_unwrap,
293 validate_mesh,
294 AdaptiveConfig,
295 BoundingSphere,
296 CollisionAabb,
298 CollisionMesh,
299 ConvexDecomposition,
300 ConvexHull,
301 DecimateConfig,
302 DecimationLodConfig,
303 DualContouringConfig,
304 FittedPrimitive,
306 FittingConfig,
307 HermiteConfig,
308 HermitePoint,
310 LodChain,
312 LodConfig,
313 LodSelector,
314 MarchingCubesConfig,
315 Mesh,
316 MeshBvh,
317 MeshQuality,
318 MeshRepair,
319 MeshSdf,
320 MeshSignMode,
321 MeshToSdfConfig,
322 MeshToSdfStrategy,
323 MeshValidation,
325 NaniteCluster,
327 NaniteConfig,
328 NaniteMesh,
329 PointCloudSdf,
331 PointCloudSdfConfig,
332 Triangle,
333 UvChart,
334 UvUnwrapConfig,
335 UvUnwrapResult,
336 Vertex,
337 VhacdConfig,
339 };
340 #[cfg(feature = "gpu")]
341 pub use crate::mesh::{
342 gpu_marching_cubes, gpu_marching_cubes_from_shader, GpuMarchingCubesConfig,
343 };
344 pub use crate::modifiers::*;
345 pub use crate::npr::compiled_color::{
346 ColorOp, CompiledColorPipeline, NprBatchContext8, NprColorBatch8,
347 };
348 pub use crate::npr::composition::{bloom_toon, chromatic_offsets, vignette};
349 pub use crate::npr::distortion::{hand_drawn_jitter, line_boil, sketch_wobble};
350 pub use crate::npr::dsl::{NprColorContext, NprColorNode, PaletteSource};
351 pub use crate::npr::dsl_shader::{
352 transpile_npr_color_node, NprShaderContext, NprShaderSnippet,
353 };
354 pub use crate::npr::hatch::{cross_hatch, hatch_lines, paper_grain, pencil_shade};
355 pub use crate::npr::motion::{impact_flash, speed_line};
356 pub use crate::npr::noise::{
357 fbm, HashNoise, NoiseField, PerlinNoise, SimplexNoise, WorleyNoise,
358 };
359 pub use crate::npr::outline::{
360 composite_outline, curvature_outline, depth_step_outline, distance_field_outline,
361 distance_field_outline_soft,
362 };
363 pub use crate::npr::palette::{palette_gradient, season_palette, time_of_day};
364 pub use crate::npr::rim::{fresnel_rim, procedural_matcap, stylized_specular};
365 #[cfg(any(feature = "glsl", feature = "hlsl", feature = "gpu"))]
366 pub use crate::npr::scene_composer::SceneShaderBuilder;
367 pub use crate::npr::sdf_integration::{
368 curvature_outline_from_node, distance_outline_from_node, soft_toon_shade_from_node,
369 toon_shade_from_node,
370 };
371 pub use crate::npr::shader_glue::{
372 full_helpers_for, helpers_for, palette_helpers_for, ShaderLanguage, NPR_GLSL_HELPERS,
373 NPR_GLSL_PALETTE_HELPERS, NPR_HLSL_HELPERS, NPR_HLSL_PALETTE_HELPERS, NPR_WGSL_HELPERS,
374 NPR_WGSL_PALETTE_HELPERS,
375 };
376 pub use crate::npr::sky::{
377 distance_color_quantize, light_shaft_beam, puffy_cloud_layer, sky_gradient_bands, sun_disc,
378 };
379 pub use crate::npr::toon::{posterize_color, soft_toon_ramp, toon_ramp, two_tone};
380 pub use crate::npr::{NprColor, NprInput};
381 pub use crate::operations::*;
382 pub use crate::primitives::*;
383 pub use crate::raycast::{
384 ambient_occlusion, raycast, raycast_batch, raymarch, raymarch_with_config, soft_shadow,
385 RaymarchConfig, RaymarchResult,
386 };
387 pub use crate::sdf2d::{eval_2d, eval_2d_batch, eval_2d_normal, Sdf2dNode};
388 pub use crate::shell::{
389 eval_shell, eval_shell_batch, eval_shell_batch_parallel, eval_shell_compiled,
390 eval_shell_compiled_batch_parallel, eval_shell_gradient, shell_node, ShellConfig,
391 };
392 #[cfg(feature = "physics")]
393 pub use crate::sim_bridge::{attach_physics, simulate_sdf, SimulatedSdf};
394 #[cfg(all(feature = "physics", feature = "gpu"))]
395 pub use crate::sim_bridge::{gpu_mesh_with_physics, GpuPhysicsBundle};
396 pub use crate::soa::{SoADistances, SoAPoints};
397 #[cfg(feature = "svo")]
398 pub use crate::svo::{
399 build_svo, build_svo_compiled, linearize_svo, svo_nearest_surface, svo_query_point,
400 svo_ray_query, LinearizedSvo, SparseVoxelOctree, SvoBuildConfig, SvoChunk, SvoNode,
401 SvoRayHit, SvoStreamingCache,
402 };
403 #[cfg(all(feature = "terrain", feature = "image"))]
404 pub use crate::terrain::HeightmapImageConfig;
405 #[cfg(feature = "terrain")]
406 pub use crate::terrain::{
407 erode, generate_cave_sdf, terrain_sdf, CaveConfig, ClipmapLevel, ClipmapMesh,
408 ClipmapTerrain, ErosionConfig, Heightmap, SplatLayer, Splatmap, TerrainConfig,
409 };
410 pub use crate::transforms::*;
411 pub use crate::types::{Aabb, Hit, Ray, SdfCategory, SdfMetadata, SdfNode, SdfTree};
412 #[cfg(feature = "volume")]
413 pub use crate::volume::{
414 bake_volume, bake_volume_with_normals, export_dds_3d, export_raw, generate_mip_chain,
415 BakeChannels, BakeConfig, Volume3D, VoxelDistGrad,
416 };
417 pub use glam::{Quat, Vec3};
418}
419
420pub use cache::{
422 compute_cache_key, hash_sdf_node, CacheConfig, ChunkCoord, ChunkedCacheConfig,
423 ChunkedMeshCache, MeshCache, MeshCacheKey,
424};
425pub use eval::eval;
426pub use io::{load, save};
427pub use mesh::sdf_to_mesh;
428pub use types::{SdfNode, SdfTree};
429
430#[cfg(doctest)]
471struct RemovedIn5;
472
473#[cfg(test)]
474mod tests {
475 use super::prelude::*;
476
477 #[test]
478 fn test_basic_workflow() {
479 let shape = SdfNode::sphere(1.0).subtract(SdfNode::box3d(0.5, 0.5, 0.5));
481
482 let d = eval(&shape, Vec3::ZERO);
484 assert!(d > 0.0); let d_surface = eval(&shape, Vec3::new(1.0, 0.0, 0.0));
488 assert!(d_surface.abs() < 0.01);
489
490 let tree = SdfTree::new(shape);
492 assert!(tree.node_count() > 0);
493 }
494
495 #[test]
496 fn test_complex_tree() {
497 let shape = SdfNode::sphere(1.0)
498 .smooth_union(SdfNode::cylinder(0.5, 2.0), 0.2)
499 .subtract(SdfNode::box3d(0.5, 0.5, 0.5).repeat_infinite(1.0, 1.0, 1.0))
500 .twist(0.5)
501 .scale(2.0);
502
503 assert!(shape.node_count() >= 6);
504 }
505
506 #[test]
507 fn test_mesh_generation() {
508 let sphere = SdfNode::sphere(1.0);
509 let config = MarchingCubesConfig {
510 resolution: 8,
511 iso_level: 0.0,
512 compute_normals: true,
513 ..Default::default()
514 };
515
516 let mesh = sdf_to_mesh(&sphere, Vec3::splat(-2.0), Vec3::splat(2.0), &config);
517 assert!(mesh.vertex_count() > 0);
518 assert!(mesh.triangle_count() > 0);
519 }
520
521 #[test]
522 fn test_raymarching() {
523 let sphere = SdfNode::sphere(1.0);
524 let ray = Ray::new(Vec3::new(-5.0, 0.0, 0.0), Vec3::new(1.0, 0.0, 0.0));
525
526 let hit = raycast(&sphere, ray, 10.0);
527 assert!(hit.is_some());
528
529 let hit = hit.unwrap();
530 assert!((hit.distance - 4.0).abs() < 0.1);
531 }
532
533 #[test]
534 fn test_production_stress_high_res() {
535 let shape = SdfNode::sphere(1.0).smooth_union(SdfNode::box3d(0.5, 0.5, 0.5), 0.2);
537 let config = MarchingCubesConfig {
538 resolution: 64,
539 iso_level: 0.0,
540 compute_normals: true,
541 ..Default::default()
542 };
543 let mesh = sdf_to_mesh(&shape, Vec3::splat(-2.0), Vec3::splat(2.0), &config);
544
545 assert!(
547 mesh.vertex_count() > 1000,
548 "Expected >1000 vertices, got {}",
549 mesh.vertex_count()
550 );
551 assert!(
552 mesh.triangle_count() > 500,
553 "Expected >500 triangles, got {}",
554 mesh.triangle_count()
555 );
556 }
557
558 #[test]
559 fn test_production_multi_material_pipeline() {
560 let shape = SdfNode::sphere(1.0);
562 let config = MarchingCubesConfig {
563 resolution: 16,
564 iso_level: 0.0,
565 compute_normals: true,
566 ..Default::default()
567 };
568 let mut mesh = sdf_to_mesh(&shape, Vec3::splat(-2.0), Vec3::splat(2.0), &config);
569
570 let half = mesh.vertices.len() / 2;
572 for v in mesh.vertices[half..].iter_mut() {
573 v.material_id = 1;
574 }
575
576 let acmr_before = compute_acmr(&mesh, 32);
578 optimize_vertex_cache(&mut mesh);
579 let acmr_after = compute_acmr(&mesh, 32);
580 assert!(acmr_after <= acmr_before + 0.01);
581
582 let mut mat_lib = MaterialLibrary::new();
584 mat_lib.add(
585 Material::metal("Chrome", 0.9, 0.9, 0.9, 0.2)
586 .with_albedo_map("textures/chrome_albedo.png")
587 .with_normal_map("textures/chrome_normal.png"),
588 );
589
590 let path = std::env::temp_dir().join("alice_stress_multi_mat.glb");
592 export_glb(&mesh, &path, &GltfConfig::aaa(), Some(&mat_lib)).unwrap();
593
594 let bytes = std::fs::read(&path).unwrap();
595 assert!(bytes.len() > 100);
596 assert_eq!(&bytes[0..4], &0x46546C67u32.to_le_bytes());
598
599 std::fs::remove_file(&path).ok();
600 }
601
602 #[test]
603 fn test_production_collision_pipeline() {
604 let shape = SdfNode::sphere(1.0).subtract(SdfNode::box3d(0.5, 0.5, 0.5));
606 let config = MarchingCubesConfig {
607 resolution: 16,
608 iso_level: 0.0,
609 compute_normals: true,
610 ..Default::default()
611 };
612 let mesh = sdf_to_mesh(&shape, Vec3::splat(-2.0), Vec3::splat(2.0), &config);
613
614 let aabb = compute_aabb(&mesh);
616 assert!(aabb.contains(Vec3::new(0.5, 0.0, 0.0)));
617
618 let bs = compute_bounding_sphere(&mesh);
620 assert!(bs.radius > 0.5);
621
622 let hull = compute_convex_hull(&mesh);
624 assert!(hull.vertices.len() >= 4);
625 assert!(hull.indices.len() >= 12);
626
627 let simplified = simplify_collision(&mesh, 8);
629 assert!(simplified.vertices.len() < mesh.vertices.len());
630 }
631
632 #[test]
633 fn test_compiled_vs_interpreted() {
634 let shape = SdfNode::sphere(1.0)
636 .smooth_union(
637 SdfNode::cylinder(0.3, 1.5).rotate_euler(1.57, 0.0, 0.0),
638 0.2,
639 )
640 .subtract(SdfNode::box3d(0.4, 0.4, 0.4))
641 .translate(0.5, 0.0, 0.0);
642
643 let compiled = CompiledSdf::compile(&shape);
644
645 let test_points = [
647 Vec3::ZERO,
648 Vec3::new(1.0, 0.0, 0.0),
649 Vec3::new(0.5, 0.5, 0.5),
650 Vec3::new(-1.0, -1.0, -1.0),
651 Vec3::new(0.25, 0.25, 0.25),
652 Vec3::new(2.0, 0.0, 0.0),
653 ];
654
655 for p in test_points {
656 let d_interp = eval(&shape, p);
657 let d_compiled = eval_compiled(&compiled, p);
658 assert!(
659 (d_interp - d_compiled).abs() < 0.001,
660 "Mismatch at {:?}: interp={}, compiled={}",
661 p,
662 d_interp,
663 d_compiled
664 );
665 }
666 }
667}