subdiv_kernels/options.rs
1/// Rule for sharp/crease/corner vertices. Currently only the OpenSubdiv/DeRose
2/// rule-transition behavior is available.
3#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5#[non_exhaustive]
6pub enum CornerRule {
7 /// OpenSubdiv / DeRose rule-transition behavior.
8 #[default]
9 OpenSubdivDeRose,
10}
11
12/// Edge sharpness propagation policy.
13#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub enum CreaseComputationMethod {
16 /// Integer decrement style.
17 #[default]
18 Uniform,
19
20 /// Chaikin-inspired smoothing style.
21 Chaikin,
22}
23
24/// Triangle handling mode for Catmull-Clark on triangle faces.
25#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27pub enum TriangleSubdivisionRule {
28 /// Catmull-Clark triangle rule.
29 #[default]
30 CatmullClark,
31
32 /// Smooth-triangle variant.
33 SmoothTriangles,
34}
35
36/// Boundary interpolation policy for positional evaluation.
37#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
39pub enum BoundaryInterpolation {
40 /// No boundary-specific handling.
41 Natural,
42
43 /// Interpolate boundary edges only.
44 #[default]
45 EdgesOnly,
46
47 /// Interpolate boundary edges and pin corners.
48 EdgesAndCorners,
49}
50
51/// Face-varying (per-corner, seam-capable) interpolation policy, mirroring
52/// OpenSubdiv's `Sdc::Options::FVarLinearInterpolation` spectrum from fully
53/// linear to fully smooth.
54#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56pub enum FaceVaryingInterpolation {
57 /// Linear interpolation everywhere (OSD `FVAR_LINEAR_ALL`); the old
58 /// RenderMan `facevarying` class.
59 Linear,
60
61 /// Smooth interior, linear only at face-varying corners
62 /// (OSD `FVAR_LINEAR_CORNERS_ONLY`).
63 SmoothWithLinearCorners,
64
65 /// Smooth interior, linear along face-varying boundaries/seams
66 /// (OSD `FVAR_LINEAR_BOUNDARIES`). The common default for UV channels:
67 /// smooth within an island, pinned at island seams.
68 #[default]
69 SmoothWithLinearBoundaries,
70
71 /// Smooth subdivision rules everywhere, with seams as smooth boundary
72 /// curves (OSD `FVAR_LINEAR_NONE`); the old RenderMan `facevertex` class.
73 Smooth,
74}
75
76// ── New API types ──────────────────────────────────────────────────────
77
78/// Which subdivision scheme to apply.
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
80#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
81pub enum Scheme {
82 /// Catmull–Clark: quad-based, the film/VFX standard. Accepts any polygons;
83 /// every refined face is a quad.
84 CatmullClark,
85 /// Loop: for triangle meshes. Triangles in, triangles out.
86 Loop,
87 /// √3 (Kobbelt): for triangle meshes. Adds fewer triangles per step than
88 /// Loop and reorients them each level.
89 Sqrt3,
90 /// Doo–Sabin: corner-cutting; produces a new face around each original
91 /// vertex, edge, and face.
92 DooSabin,
93}
94
95/// Scheme-level options that define subdivision behavior.
96///
97/// These are set once when creating a [`Refiner`](crate::Refiner) and
98/// apply to all refinement calls on that refiner.
99#[derive(Debug, Clone, Copy, PartialEq)]
100#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
101pub struct SchemeOptions {
102 /// Sharp-vertex rule selection.
103 pub corner_rule: CornerRule,
104
105 /// Crease propagation mode.
106 pub crease_computation: CreaseComputationMethod,
107
108 /// Positional boundary mode.
109 pub boundary_interpolation: BoundaryInterpolation,
110
111 /// Triangle handling mode (CC only).
112 pub triangle_subdivision_rule: TriangleSubdivisionRule,
113
114 /// Whether to promote vertices with 3+ sharp incident edges.
115 pub auto_corner: bool,
116
117 /// Whether crease values are normalized per level.
118 pub crease_normalize: bool,
119
120 /// Whether corner values are normalized per level.
121 pub corner_normalize: bool,
122}
123
124impl Default for SchemeOptions {
125 fn default() -> Self {
126 Self {
127 corner_rule: CornerRule::default(),
128 crease_computation: CreaseComputationMethod::default(),
129 boundary_interpolation: BoundaryInterpolation::default(),
130 triangle_subdivision_rule: TriangleSubdivisionRule::default(),
131 auto_corner: false,
132 crease_normalize: false,
133 corner_normalize: false,
134 }
135 }
136}
137
138use core::num::NonZeroU8;
139
140/// Per-call refinement parameters.
141#[derive(Debug, Clone, PartialEq)]
142#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
143pub struct UniformRefine {
144 /// Number of uniform refinement levels. Must be at least 1.
145 pub levels: NonZeroU8,
146
147 /// Optional face selection mask. When `Some`, only selected faces are refined.
148 pub selected_faces: Option<Vec<bool>>,
149
150 /// Crease weight applied at selection boundaries.
151 pub selection_boundary_crease: f32,
152
153 /// Track the refined vertices lying along each input edge.
154 ///
155 /// When enabled, the refinement result fills in its `edge_polylines`:
156 /// for every input edge, the refined vertex indices on it, in order.
157 pub edge_polylines: bool,
158}
159
160impl Default for UniformRefine {
161 fn default() -> Self {
162 Self {
163 // SAFETY: 1 is non-zero.
164 levels: NonZeroU8::new(1).unwrap(),
165 selected_faces: None,
166 selection_boundary_crease: 0.0,
167 edge_polylines: false,
168 }
169 }
170}
171
172impl From<NonZeroU8> for UniformRefine {
173 fn from(levels: NonZeroU8) -> Self {
174 Self {
175 levels,
176 ..Self::default()
177 }
178 }
179}