freestyle_sculpt/lib.rs
1//! This is a pure Rust implementation of Freestyle Sculpting, a real-time dynamic topology sculpting algorithm.
2//!
3//! It is based on the paper [Freestyle: Sculpting meshes with self-adaptive topology](https://inria.hal.science/inria-00606516/document) by Lucian Stanculescu, Raphaƫlle Chaine, Marie-Paule Cani. This is the same algorithm that is used by the Dyntopo sculpting mode in Blender.
4//!
5//! 
6//!
7//! Please check out the [bevy-basic-sculpt example](https://github.com/Synphonyte/freestyle-sculpt/tree/main/examples/bevy-basic-sculpt) to see how it can be used in an interactive application.
8//!
9//! ## Limitations
10//!
11//! At the moment it doesn't support topology genus changes, i.e. no splitting or merging of different parts of the mesh.
12//!
13//! ## Optional Cargo features
14//!
15//! - `rerun`: Enables recording of the mesh graph and the different algorithms to [Rerun](https://rerun.io/) for visualization.
16//! - `bevy`: Enables integration with the [Bevy](https://bevyengine.org/) game engine.
17//!
18//! ## Customize sculpting
19//!
20//! To implement a custom deformation field, you can create a struct that implements the [`DeformationField`] trait. Have a look
21//! at the existing deformation fields in the [`deformation`] module for inspiration.
22//!
23//! If you want to implement a custom selection strategy, you can create a struct that implements the [`MeshSelector`] trait. Have a look
24//! at the existing selection strategies in the [`selectors`] module for inspiration.
25
26use itertools::Itertools;
27use mesh_graph::MeshGraph;
28use parry3d::utils::median;
29
30///Deformation fields to do the vertex manipulation
31pub mod deformation;
32mod integrations;
33/// Ray casting onto mesh graphs
34pub mod ray;
35/// Selection strategies to decide which vertices to deform
36pub mod selectors;
37
38/// Defines all the necessary parameters for sculpting operations.
39#[derive(Debug, Clone, Copy)]
40#[cfg_attr(feature = "bevy", derive(bevy::prelude::Resource))]
41#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
42pub struct SculptParams {
43 pub max_move_dist_squared: f32,
44 pub min_edge_length_squared: f32,
45 pub max_edge_length_squared: f32,
46}
47
48impl SculptParams {
49 /// Creates a new instance of `SculptParams` with the specified maximum edge length.
50 ///
51 /// All other parameters are calculated based on the maximum edge length.
52 pub const fn new(max_edge_length: f32) -> Self {
53 let max_edge_length_squared = max_edge_length * max_edge_length;
54
55 Self {
56 max_move_dist_squared: max_edge_length_squared * 0.11,
57 min_edge_length_squared: max_edge_length_squared * 0.24,
58 max_edge_length_squared,
59 }
60 }
61
62 pub fn from_mesh_graph(mesh_graph: &MeshGraph, min_edge_length: f32) -> Self {
63 let edge_length = median(
64 &mut mesh_graph
65 .halfedges
66 .values()
67 .map(|he| he.length(mesh_graph))
68 .collect_vec(),
69 );
70
71 Self::new((edge_length * 1.5).max(min_edge_length))
72 }
73}