Curve Support in Geometry Nodes #86243

Closed
opened 2021-03-03 22:38:18 +01:00 by Hans Goudey · 27 comments
Member

Background

Currently, "curve data" in Blender actually refers to two or three different kinds of data:

  • Bezier / NURBS / Poly Path The curve spline itself, before any mesh data is generated. However, note that the segments of a curve are also generated data. The control points are the interactive data.
  • Surface This is a different object type, but it's quite similar to the other two types above, with a separation between the input data (control points and edges) and the generated surface. In general this design document won't discuss "Surface" data.
  • Mesh This data is generated by a combination of the original curve data and some values, like the bevel size and its resolution. Currently this is stored as a DispList in Blender, but to the user it is basically mesh data.

Because of this ambiguity, the most important thing to figure out is at which level to apply operations, similar to the existing "Apply on Spline" toggle on the curve modifier stack.

  • It's possible to imagine a few different "position" domains on a curve: the control points, points on the calculated spline, and points on any generated mesh data.
  • In any case, if generated data like the bevel geometry or the smoothed curve is written to, the curve must be converted to a mesh.

A conversion from curve to mesh changes what kind of operations are possible on the input data, so conversion from curve to mesh is an important step in the node tree.

  • The conversion is made simpler by the flexibility of geometry sets; a curve object can evaluate to mesh data in a nodes modifier (or theoretically even the other way around).
  • If any mesh modifiers are used before the nodes modifier on a curve object, the input geometry to the nodes modifier will only contain a mesh.

Most settings in the curve object data panel in the property editor describe how to evaluate the curve. However, generally the curve is actually evaluated somewhere inside the modifier stack-- just before the first "Generate" modifier that needs a mesh input. Generalizing evaluation to nodes brings up some issues because of the increased flexibility. Shouldn't the settings for the "Curve to Mesh" operation be closer to the operation itself? There are a few options:

  • Don't store the settings at all, instead provide them as inputs whenever they are needed for an operation on the curve. This is tempting because it feels low-level, but it might require repeating many of these settings for use in different operations.
    • The node can be added with versioning to existing curve objects, or it could be implicit if necessary.
    • This the "everything nodes" solution, visible, flexible, potentially low-level.
    • The utility of the settings in the property editor curve tab is not clear with this solution.
  • Since the options are stored in the curve, they could simply be controlled by a "Set Curve Info" node in the tree. A "Curve to Mesh" node then wouldn't have any settings, it would just use the settings already in the curve.
    • The settings in the property editor can be stored in the curve, so they are still useful.
    • Harder to control conversion settings in the node tree.
  • It may be possible to combine the two options above somehow. For example, the spline could be implicitly calculated as part of the curve, but a mesh surface like a beveled curve or a filled 2D curve could require a node.
    • The spline resolution would then be stored in the curve data, like it is currently. However, that does conflict with the resolution data stored per-spline.
    • The conversion to mesh using the settings in the property editor could happen implicitly after modifiers if there is any curve data left.

Conclusions

  • The curve geometry component control points use the existing "Point" domain instead of a new "Control Point" domain.
    • The point domain should be write-able without converting the curve to a mesh.
    • Leverage the differences between curves and meshes and actually treat the curve differently than a mesh.
  • A "Convert to Mesh" node is needed to access the evaluated data with attributes.
    • Making the evaluated spline available before conversion may be useful, but that mix of evaluated and original data might be a problem.
    • It's possible we would want this conversion to be implicit, but since you lose the ability to
  • Curves have two domains, spline and points. The built-in attributes:
    Name Domain Type Notes
    Length Spline Float Read-only
    Shade Smooth Spline Boolean
    Cyclic Spline Boolean
    Radius Point Float
    Tilt Point Float Range starts at 0, evaluated data.
    Weight Point Float NURBS only
    Position Point Vector
    Normal Point Vector Read-only
  • If there is still curve data left at the end of the modifier evaluation (including nodes modifiers), it will be implicitly converted to a mesh for display, just like how curves already work in Blender.

Node Mockups

While there are many opportunities to expand functionality when curves can be handled with nodes, these mockups focus on exposing existing functionality.

Node Notes
image.png This is mostly just like the current curve geometry settings. The bevel radius is also influenced by the radius attribute.
image.png Curve offset could even be a separate node, and even controlled by an attribute. This would not be essential for an initial version though.
image.png The settings in the "Start and End Mapping" can become a separate node, because they're useful even when you don't want to generate geometry from a curve.
image.png The drop-down can let you choose to use a distance between points or a total number of sampled points.
image.png The selection is a boolean attribute in the spline domain.
image.png The selection is a boolean attribute in the point domain.
image.png 2D curves are an important special case that are important to support. That may require some further thinking though.
image.png The curve profile widget can be a quick way to input a bezier spline, at first specifically for use with the bevel modifier, or with curve bevel.
image.png This deformation node could easily support every geometry component type (including curves!)

Implementation Details

The current curve data structures are confusing and not very suited to be used in this context, and improving them is on the radar of the modeling module anyway. Improved C++ data structures could significantly ease the process of implementing these features.

With these data structures, a few operations would be necessary as a minimum:

  • Conversion from curve DNA structs to these data structures.
  • Evaluation of the structures (calculate spline, bevel geometry), with a Mesh result.

Some of the data stored below depends on decisions made in the previous sections.

enum class BezierHandleType {
Free,
Auto,
Vector,
Align,
};
struct ControlPoint {
float3 position;
float radius;
float tilt;
};
struct ControlPointBezier : ControlPoint {
float3 handle_position_a;
float3 handle_position_b;
BezierHandleType handle_type_a;
BezierHandleType handle_type_b;
};
struct ControlPointNURBS : ControlPoint {
float weight;
};
enum class SplineType {
Bezier,
Poly,
NURBS,
};
struct Spline {
SplineType type;
};
struct SplineBezier : Spline {
Vector<ControlPointBezier> control_points;
int32_t flag; /* Cyclic, smooth. */
int32_t resolution_u;
int32_t resolution_v;
};
struct SplineNURBS : Spline {
Vector<ControlPointNURBS> control_points;
int32_t flag; /* Cyclic, smooth. */
int32_t resolution_u;
int32_t resolution_v;
uint8_t order;
};
/* Proposed name to be different from DNA type. */
struct EditCurve {
Vector<Spline> splines;
AttributeStorage attributes;
int32_t flag; /* 2D. */

/* Attributes. */
CustomData *control_point_data;
CustomData *spline_data;


/* Then maybe whatever caches are necessary, etc. */
Vector<float3> evaluated_spline_cache;

};
## Background Currently, "curve data" in Blender actually refers to two or three different kinds of data: - **Bezier / NURBS / Poly Path** The curve spline itself, before any mesh data is generated. However, note that the segments of a curve are also generated data. The control points are the interactive data. - **Surface** This is a different object type, but it's quite similar to the other two types above, with a separation between the input data (control points and edges) and the generated surface. In general this design document won't discuss "Surface" data. - **Mesh** This data is generated by a combination of the original curve data and some values, like the bevel size and its resolution. Currently this is stored as a `DispList` in Blender, but to the user it is basically mesh data. Because of this ambiguity, the most important thing to figure out is at which level to apply operations, similar to the existing "Apply on Spline" toggle on the curve modifier stack. - It's possible to imagine a few different "position" domains on a curve: the control points, points on the calculated spline, and points on any generated mesh data. - In any case, if generated data like the bevel geometry or the smoothed curve is written to, the curve must be converted to a mesh. A conversion from curve to mesh changes what kind of operations are possible on the input data, so conversion from curve to mesh is an important step in the node tree. - The conversion is made simpler by the flexibility of geometry sets; a curve object can evaluate to mesh data in a nodes modifier (or theoretically even the other way around). - If any mesh modifiers are used before the nodes modifier on a curve object, the input geometry to the nodes modifier will only contain a mesh. Most settings in the curve object data panel in the property editor describe how to evaluate the curve. However, generally the curve is actually evaluated somewhere inside the modifier stack-- just before the first "Generate" modifier that needs a mesh input. Generalizing evaluation to nodes brings up some issues because of the increased flexibility. Shouldn't the settings for the "Curve to Mesh" operation be closer to the operation itself? There are a few options: - Don't store the settings at all, instead provide them as inputs whenever they are needed for an operation on the curve. This is tempting because it feels low-level, but it might require repeating many of these settings for use in different operations. - The node can be added with versioning to existing curve objects, or it could be implicit if necessary. - This the "everything nodes" solution, visible, flexible, potentially low-level. - The utility of the settings in the property editor curve tab is not clear with this solution. - Since the options are stored in the curve, they could simply be controlled by a "Set Curve Info" node in the tree. A "Curve to Mesh" node then wouldn't have any settings, it would just use the settings already in the curve. - The settings in the property editor can be stored in the curve, so they are still useful. - Harder to control conversion settings in the node tree. - It may be possible to combine the two options above somehow. For example, the spline could be implicitly calculated as part of the curve, but a mesh surface like a beveled curve or a filled 2D curve could require a node. - The spline resolution would then be stored in the curve data, like it is currently. However, that does conflict with the resolution data stored per-spline. - The conversion to mesh using the settings in the property editor could happen implicitly after modifiers if there is any curve data left. ## Conclusions - The curve geometry component control points use the existing "Point" domain instead of a new "Control Point" domain. - The point domain should be write-able without converting the curve to a mesh. - Leverage the differences between curves and meshes and actually treat the curve differently than a mesh. - A "Convert to Mesh" node is needed to access the evaluated data with attributes. - Making the evaluated spline available before conversion may be useful, but that mix of evaluated and original data might be a problem. - It's possible we would want this conversion to be implicit, but since you lose the ability to - Curves have two domains, spline and points. The built-in attributes: | **Name** | **Domain** | **Type** | **Notes** | | -- | -- | -- | -- | | Length | Spline | Float | Read-only | | Shade Smooth | Spline | Boolean | | | Cyclic | Spline | Boolean | | | Radius | Point | Float | | | Tilt | Point | Float | Range starts at 0, evaluated data. | | Weight | Point | Float | NURBS only | | Position | Point | Vector | | | Normal | Point | Vector | Read-only | - If there is still curve data left at the end of the modifier evaluation (including nodes modifiers), it will be implicitly converted to a mesh for display, just like how curves already work in Blender. ## Node Mockups While there are many opportunities to expand functionality when curves can be handled with nodes, these mockups focus on exposing existing functionality. | **Node** | **Notes** | | -- | -- | | ![image.png](https://archive.blender.org/developer/F9863453/image.png) | This is mostly just like the current curve geometry settings. The bevel radius is also influenced by the `radius` attribute. | | ![image.png](https://archive.blender.org/developer/F9863475/image.png) | Curve offset could even be a separate node, and even controlled by an attribute. This would not be essential for an initial version though. | | ![image.png](https://archive.blender.org/developer/F9863456/image.png) | The settings in the "Start and End Mapping" can become a separate node, because they're useful even when you don't want to generate geometry from a curve. | | ![image.png](https://archive.blender.org/developer/F9863464/image.png) | The drop-down can let you choose to use a distance between points or a total number of sampled points. | | ![image.png](https://archive.blender.org/developer/F9863466/image.png) | The selection is a boolean attribute in the spline domain. | | ![image.png](https://archive.blender.org/developer/F9863468/image.png) | The selection is a boolean attribute in the point domain. | | ![image.png](https://archive.blender.org/developer/F9863487/image.png) | 2D curves are an important special case that are important to support. That may require some further thinking though. | | ![image.png](https://archive.blender.org/developer/F9863572/image.png) | The curve profile widget can be a quick way to input a bezier spline, at first specifically for use with the bevel modifier, or with curve bevel. | | ![image.png](https://archive.blender.org/developer/F9904822/image.png) | This deformation node could easily support every geometry component type (including curves!) ## Implementation Details The current curve data structures are confusing and not very suited to be used in this context, and improving them is on the radar of the modeling module anyway. Improved C++ data structures could significantly ease the process of implementing these features. With these data structures, a few operations would be necessary as a minimum: - Conversion from curve DNA structs to these data structures. - Evaluation of the structures (calculate spline, bevel geometry), with a `Mesh` result. Some of the data stored below depends on decisions made in the previous sections. ``` enum class BezierHandleType { Free, Auto, Vector, Align, }; ``` ``` struct ControlPoint { float3 position; float radius; float tilt; }; ``` ``` struct ControlPointBezier : ControlPoint { float3 handle_position_a; float3 handle_position_b; BezierHandleType handle_type_a; BezierHandleType handle_type_b; }; ``` ``` struct ControlPointNURBS : ControlPoint { float weight; }; ``` ``` enum class SplineType { Bezier, Poly, NURBS, }; ``` ``` struct Spline { SplineType type; }; ``` ``` struct SplineBezier : Spline { Vector<ControlPointBezier> control_points; int32_t flag; /* Cyclic, smooth. */ int32_t resolution_u; int32_t resolution_v; }; ``` ``` struct SplineNURBS : Spline { Vector<ControlPointNURBS> control_points; int32_t flag; /* Cyclic, smooth. */ int32_t resolution_u; int32_t resolution_v; uint8_t order; }; ``` ``` /* Proposed name to be different from DNA type. */ struct EditCurve { Vector<Spline> splines; AttributeStorage attributes; int32_t flag; /* 2D. */ /* Attributes. */ CustomData *control_point_data; CustomData *spline_data; /* Then maybe whatever caches are necessary, etc. */ Vector<float3> evaluated_spline_cache; }; ```
Author
Member

Changed status from 'Needs Triage' to: 'Confirmed'

Changed status from 'Needs Triage' to: 'Confirmed'
Author
Member

Added subscriber: @HooglyBoogly

Added subscriber: @HooglyBoogly
Contributor

Added subscriber: @KenzieMac130

Added subscriber: @KenzieMac130

Added subscriber: @MiroHorvath

Added subscriber: @MiroHorvath

Added subscriber: @GeorgiaPacific

Added subscriber: @GeorgiaPacific

Added subscriber: @RC12

Added subscriber: @RC12
Contributor

Could it be possible to version all of the "Geometry" features of the curve over to the modifier stack so all that is left is explicitly related to defining the shape and base sampling of the curve? I remember when I changed some things about the curve to default to filled it had a knock-on-effect on text as well and I was a little surprised. The curve/surface/text object just feels kind of an odd duck since they can be mutated into each-other by changing the data-block and It kind of feels like the differences mainly come from how the curve data is edited or skinned.

Could it be possible to version all of the "Geometry" features of the curve over to the modifier stack so all that is left is explicitly related to defining the shape and base sampling of the curve? I remember when I changed some things about the curve to default to filled it had a knock-on-effect on text as well and I was a little surprised. The curve/surface/text object just feels kind of an odd duck since they can be mutated into each-other by changing the data-block and It kind of feels like the differences mainly come from how the curve data is edited or skinned.

Added subscriber: @xrogueleaderx

Added subscriber: @xrogueleaderx
Author
Member

@KenzieMac130 I'm not sure I completely understand your point, but the input to the nodes modifier would be the curve data generated by the text object in this case.

Also, this proposal doesn't include surface objects, but I imagine that would be a natural addition later on. Best to take these things step by step for now.

It is a bit odd with the special cases for editing and skinning curves. 2D curves are also the same data, just with a toggle changed. Actually, I wonder if it makes sense to separate 2D curves further, I'm not sure.

@KenzieMac130 I'm not sure I completely understand your point, but the input to the nodes modifier would be the curve data generated by the text object in this case. Also, this proposal doesn't include surface objects, but I imagine that would be a natural addition later on. Best to take these things step by step for now. It is a bit odd with the special cases for editing and skinning curves. 2D curves are also the same data, just with a toggle changed. Actually, I wonder if it makes sense to separate 2D curves further, I'm not sure.
Contributor

Since I wasn't the clearest (probably even in my own mind) I was suggesting that since the different types of curve objects seem to share that functionality that there could be a way to break apart the curve types into how they are edited and how they are skinned. With how different (layers?) of edit types could be stacked in the curve data while how they generate geometry could be moved entirely into modifier space. This is since I have seen quite a few people in their workflows doing things like converting text objects into curves in order to achieve things like a neon tube effect when really what they are after is a different method of skinning but have to give up their preferred way of editing. But now that I think more about it that does introduce problems as well so this was probably just a false bit of connecting dots on my end.
However it does make sense that 2D curves should be their own "type" as well as they offer both changes in skinning as well as editing.

Since I wasn't the clearest (probably even in my own mind) I was suggesting that since the different types of curve objects seem to share that functionality that there could be a way to break apart the curve types into how they are edited and how they are skinned. With how different (layers?) of edit types could be stacked in the curve data while how they generate geometry could be moved entirely into modifier space. This is since I have seen quite a few people in their workflows doing things like converting text objects into curves in order to achieve things like a neon tube effect when really what they are after is a different method of skinning but have to give up their preferred way of editing. But now that I think more about it that does introduce problems as well so this was probably just a false bit of connecting dots on my end. However it does make sense that 2D curves should be their own "type" as well as they offer both changes in skinning as well as editing.
Hans Goudey self-assigned this 2021-03-05 22:20:50 +01:00

Added subscriber: @roman-13

Added subscriber: @roman-13

@HooglyBoogly Will it be possible to copy objects along a curve? Now it is quite problematic to do this.

@HooglyBoogly Will it be possible to copy objects along a curve? Now it is quite problematic to do this.
Author
Member

Suren! One simple solution would be a sample curve node and then a point instance node.

Suren! One simple solution would be a sample curve node and then a point instance node.

Added subscriber: @dfelinto

Added subscriber: @dfelinto

Some comments:

  • Shouldn't "Sample Curve" simply be called "Curve to Points"?
  • 2D Curves need indeed to be properly considered. In Blender they are simply curves with the Z=0.0. Any downside on not treating them any special?
  • Curve Profile is creating curves without a lot of the information one may expect. What is the use of this? If this is intended as a primitive node then we would need origin/length/... or similar no?
Some comments: * Shouldn't "Sample Curve" simply be called "Curve to Points"? * 2D Curves need indeed to be properly considered. In Blender they are simply curves with the Z=0.0. Any downside on not treating them any special? * Curve Profile is creating curves without a lot of the information one may expect. What is the use of this? If this is intended as a primitive node then we would need origin/length/... or similar no?
Author
Member

Thanks for the comments!

  • Shouldn't "Sample Curve" simply be called "Curve to Points"?

I think that would be misleading, because the result of this node is still a curve. The original idea for this came from #86090. Using "Curve" instead of "Geometry" for the socket names will help a lot, I forgot to do that in the mockups.

  • 2D Curves need indeed to be properly considered. In Blender they are simply curves with the Z=0.0. Any downside on not treating them any special?

Right, clarifying their status a bit would make sense, and I agree they could be treated specially. I just wasn't sure exactly what that would mean in the context of this proposal. Any ideas?

  • Curve Profile is creating curves without a lot of the information one may expect. What is the use of this? If this is intended as a primitive node then we would need origin/length/... or similar no?

Right, the initial use case is as an input to the bevel node. As a primitive node it might need those options though, I'm not sure. It's always possible to just use a transform node after anyway.

Thanks for the comments! > * Shouldn't "Sample Curve" simply be called "Curve to Points"? I think that would be misleading, because the result of this node is still a curve. The original idea for this came from #86090. Using "Curve" instead of "Geometry" for the socket names will help a lot, I forgot to do that in the mockups. > * 2D Curves need indeed to be properly considered. In Blender they are simply curves with the Z=0.0. Any downside on not treating them any special? Right, clarifying their status a bit would make sense, and I agree they could be treated specially. I just wasn't sure exactly what that would mean in the context of this proposal. Any ideas? > * Curve Profile is creating curves without a lot of the information one may expect. What is the use of this? If this is intended as a primitive node then we would need origin/length/... or similar no? Right, the initial use case is as an input to the bevel node. As a primitive node it might need those options though, I'm not sure. It's always possible to just use a transform node after anyway.

Added subscriber: @AmanKumar-2

Added subscriber: @AmanKumar-2

Is the curve support available in any of the current experimental branches for testing?

Is the curve support available in any of the current experimental branches for testing?
Author
Member

In #86243#1126776, @AmanKumar-2 wrote:
Is the curve support available in any of the current experimental branches for testing?

No, this is just a design task for now. We would need to allocate time to actually implement this.

> In #86243#1126776, @AmanKumar-2 wrote: > Is the curve support available in any of the current experimental branches for testing? No, this is just a design task for now. We would need to allocate time to actually implement this.

Added subscriber: @Erindale

Added subscriber: @Erindale
Author
Member

Changed status from 'Confirmed' to: 'Resolved'

Changed status from 'Confirmed' to: 'Resolved'
Author
Member

Since at least the basics of the design are agreed upon, I moved it to the wiki. https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes

Since at least the basics of the design are agreed upon, I moved it to the wiki. https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes

Added subscriber: @jmargaud

Added subscriber: @jmargaud

Added subscriber: @roo20

Added subscriber: @roo20

Removed subscriber: @roo20

Removed subscriber: @roo20

Added subscriber: @DuarteRamos

Added subscriber: @DuarteRamos

Added subscriber: @Syscrusher

Added subscriber: @Syscrusher
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
14 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#86243
No description provided.