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//! ![Freestyle Sculpt Demo](https://raw.githubusercontent.com/Synphonyte/freestyle-sculpt/refs/heads/main/docs/freestyle-demo.webp)
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}