# Curve/Hair Data Structure
## Goal
* Define a data structure that can be used for all kinds of curves.
* Decide how to integrate it in Blender.
* Decide how to deal with `Text` and `Surface` objects.
Also see https://developer.blender.org/T94193.
## Naming
* Challenges for finding a good name:
* Name requires two levels of plurality:
* Levels:
* Single Spline
* Multiple Splines that form a "curve"
* Multiple curves
* `Curve` exists already in DNA and in the ui.
* Renaming the existing `Curve` struct is probably not worth the effort.
* So a different name is needed, at least for the internal data structure.
* User level name:
* Ideally there would just be a "Curve" object type (including for hair).
* The difficulty is that we will probably have two different object types, which both represent curves (at least during a transistion period).
* Calling both types "Curve Objects" is confusing, especially if they have different features.
* There can still be a hair edit mode that is available on curve objects.
* Similar to how there is edit and sculpt mode for meshes.
* Possible Names:
* Single word names that could refer to a list of splines:
* Hair
* Curve
* Spline
* Strand
* Grass
* Fiber
* String
* Cord
* Maybe it's reasonable to have a two-word-name to solve problem of having two levels of plurality.
* Possible suffixes that can be used with the names above.
* Group
* Set
* s (as in `CurveS` or `SplineS`)
* Doesn't really solve the plural-problem.
* How to name a variable that contains multiple `Curves`?
* Should individual curves now be called `Spline` or `Curve`?
* Batch
* Collection
* Array
* Bundle
* Cluster
* Pack
* List
* Sequence
* If the new type is supposed to be called `Curve` later on, maybe it should have `Curve` in the name now already, to avoid introducing new terminology.
* `NewCurve`
* `Curve` (and [rename](https://developer.blender.org/P2673) existing `Curve` to `LegacyCurve`)
* Unclear if it is feasible to repurpose an existing ID struct name like this.
* `NCurve` (`N` for `New`)
## Data Structure
* Basic structure conceptually:
* A curve has an ordered list of splines.
* A spline has an ordered list of points.
* A spline can have zero, one or more points.
* Two main approaches:
* Store data for each spline separately or store data for multiple splines together.
* Given that we want to support large amounts of hair (many splines), continuous arrays that contain data for multiple splines is probably the only viable option.
* General data structure should follow the approach used by `Hair` in `DNA_hair_types.h`.
* Attribute Domains:
* Point:
* Different value for every control point.
* Can be interpolated along a spline segment.
* Spline:
* Different value for every spline.
* Optional domains:
* Segment:
* Segment is the part between two control points.
* Segment Corner:
* Two values for every segment, one for the left and one for the right point.
* Similar to Face Corner attributes.
* Useful especially for uvs on cyclic splines.
* Both segment domains are a bit more complex than the other ones, because their domain size changes when splines become (non-)cyclic.
* At least when we don't want to store unnecessary values for non-cyclic splines.
* For example, one could store segment data on the point domain, but then there would be an additional unused value.
* Furthermore, segment corner attributes could be stored as two separate point attributes.
* The memory overhead could be very large when there are very many very short splines (as is common for hair).
* Built-in Attributes:
* Obligatory:
* `position` on points (`float3`)
* `handle_left`, `handle_right` on points (`float3`)
* Only available when `type` is `bezier`.
* Optional:
* `cyclic` on splines (`bool`)
* Default: `false`.
* `type` on splines (`enum`, `uint8`)
* Default: `poly`.
* Values: `poly`, `bezier`, `nurbs`, `catmull-rom`
* `radius` on points (`float`)
* Default: tbd.
* Probably zero, or it should be an obligatory attribute.
* `resolution` on splines (`int`)
* Default: zero?
* Available even on poly splines?
* `id` on points (`int`, later maybe some bigger integer)
* Default: index.
* `spline_id` on splines (`int`, later maybe some bigger integer)
* Default: index.
* `tilt` on points (`float`)
* Default: 0.
* `handle_type_left`, `handle_type_right` on points (`enum`, `int8`)
* Default: `free`.
* Values: `free`, `auto`, `vector`, `align`.
* Only available when `type` is `bezier`.
* `knots_mode` on splines (`enum`, `int8`)
* Default: `normal`
* Values: `normal`, `end_point`, `bezier`.
* Making the knot vector available directly is probably preferrable for proper NURB spline support
* `normal_mode` (`enum`, `int8`)
* Default: `minimum_twist`
* Values: `minimum_twist`, `custom`
* See [these](https://devtalk.blender.org/t/2021-12-6-2021-12-10-geometry-nodes-sub-module-meetings/21859) meeting notes about custom normals on splines.
* `up` on points (`float3`)
* Default `(0, 0, 1)`.
* Used with normal calculation.
* Maybe mapping information, see `HairMapping`.
* Unclear whether this really should be a built-in attribute or whether it should just be a naming convention.
* There seem to be many ways two encode a position on a mesh.
* Instead of the poly index, one could also use an id.
* Instead of uv coordinates, one could use barycentric coordinates on the tesselated triangles.
* Maybe we could introduce a new more generic `Surface Hook` that is implementation defined.
* Experimented with it while working on particle nodes: https://devtalk.blender.org/t/particle-nodes-ui/8808/319
* It's quite useful to have a concept or a "location on a surface" without worrying too much about its implementation.
* Arbitrary fields could be sampled at such a location.
* This also simplifies e.g. the raycast node a lot.
* Concerns with storing point attribute for multiple splines in a continuous array:
* Operations like adding or removing a point require possibly expensive array operations.
* In practice we probably have to iterate over all points anyway after such a change.
* The much more common case is to process all splines/points at the same time.
* Shouldn't optimize the case that happens 1% of the times at the cost of the other 99%.
* If it really becomes a problem, we could think about splitting up a single long array into multiple shorter ones, each of which may contain multiple splines.
* This optimization isn't really worth it (yet).
* Runtime/Derived data:
* Positions, tangent, normal, ... of evaluated points (which take resolution into account).
* Conversion to Poly Splines:
* Renderers and exporters might require poly splines when they can't work with e.g. bezier splines directly.
* There should be an easy way to get all splines as poly splines through rna.
* Maybe similar to `Object.to_mesh`.
## Possible Steps
Assuming we use the name `NCurve`. Still needs to be decided.
1. Add new `NCurve` id struct (no corresponding object type yet).
* Could rename `Hair` to `NCurve`.
1. Change geometry nodes to use `NCurve` instead of `CurveEval`.
1. Add object type for `NCurve` as experimental feature.
1. Port curve edit mode from `Curve` to `NCurve`.
1. Add versioning to convert all "normal" curves to `NCurve`.
1. Add data blocks for `TextGeometry` (`Text` is used already) and `Surface`.
1. Add versioning to convert remaining `Curve` to text and surface objects.
1. Remove `Curve` data block and object.
1. Remove `NCurve` from experimental feature set.
## Questions
* Under what circumstances can render engines benefit from rendering curves directly instead of a mesh generated from a curve?
* Do we already need a new object type in 3.1 or is it enough to be able to import the data into a `GeometrySet`?
* Can a catmul-rom spline be cyclic?
* How does grease pencil fit into this?