Page MenuHome

Hair object - Node types design
Confirmed, NormalPublicDESIGN

Assigned To
None
Authored By
Daniel Bystedt (dbystedt)
Jul 2 2020, 1:08 AM
Tokens
"Love" token, awarded by astrand130."Love" token, awarded by negativecitizen."Party Time" token, awarded by sam_vh."Love" token, awarded by Shimoon."Love" token, awarded by Schamph."Like" token, awarded by thomas_p."Love" token, awarded by Kronk."Love" token, awarded by andruxa696."Like" token, awarded by sharaths21312.

Description

IMPORTANT: Please note that this document is subject to change and will most likely not represent the final product of the new hair object in Blender

Hair object - Node types design


Reference links

Hair object - project description
https://developer.blender.org/T68981
Hair object design
https://developer.blender.org/T78606

Commissioner: @Daniel Bystedt (dbystedt) d.bystedt@gmail.com, https://www.artstation.com/dbystedt
Project leader: @Sebastián Barschkis (sebbas)
Project members: @Campbell Barton (campbellbarton), @Philipp Oeser (lichtwerk)

Thread on devtalk about scattering objects by BD3D (eg Instances)


NOTES

  • Please note that all mockups are rather simplified at the moment. For example the sphere in most images will never be a part of the actual hair curves geometry. Attributes are visualized with black/white color etc.
  • Sockets are colored by using @Jacques Lucke (JacquesLucke) simulation editor in the daily builds of blender as a reference. ---

NODE GRAPH - EXAMPLES

Example 1
Open image in new tab to view details


NODES - DATA FLOW

Node: Input
Type: Data flow

Input type (Upper drop down menu)

  • Guide curves
    • that exists in current hair object
  • Alembic
    • Read (potentially) animated curves from alembic. List from .abc in blender file
  • Object
    • Object that exists in blender file. Used for geo masking or instancing object per hair
  • Collection content
    • Objects that exists in a collection in the blender file. Used for scattering random objects on surface. Random object in collection used per hair “instance”
  • Collection
    • That exists in blender file. Used for scattering objects on surface. The result of the entire collection is used per hair "instance"

Example of input node where Input type = Alembic


Node: Delete
Type: Data flow

Deletes vertices if attribute value in socket Fac is higher than 0.5. Avoid "floating" hairs where the root is missing.

Note on Fac
Visualisation of input mask. In a node tree this is represented by nodes of course (for example image texture)


Node: Split
Type: Data flow

Splits hair curves into two separate "groups". A hair curve can only belong to one group or the other (i.e. avoid hair curves that are split from root to tip)

Note on Fac
Visualisation of input mask. In a node tree this is represented by nodes of course (for example image texture)


Node: Merge
Type: Data flow

merge two inputs of hair curves to one output. It would also be nice to allow merge for instanced geo


Node: Switch
Type: Data flow

Hair 1 or 2 is selected as hair output via drop down menu. This could just as well be a slider, radio button etc


Node: Hair curves output
Type: Data flow

hair curves output to viewport and render. Multiple outputs can exist in the node graph, but only one can be active (just like in the shader editor)

Node: Object output
Type: Data flow

Output node for instances (rocks, trees etc) and deformed instances (game hair, feathers).

IMPORTANT: I would love developer input regarding if this is the best way to handle instances and deformed instances. "Deformed instances" might not be the best term, but I hope you understand what I mean.


NODES - CREATE


Node: Scatter hair
Type: Create

Influence radius (float)
Controls of how wide radius the input hair controls the direction/interpolation of the output hair. It also scatter hair within the area of the input hair roots. Using this could turn the children=simple type of hair useless

Vertices (integer)
Vertex count per hair curves

Relax iteration (integer)
Relaxes the distrubution of root vertecies. In the current implementation of hair, the distribution is pretty uneven. Possibly skip input if it complicates coding (eg if sampling from texture etc is hard to implement)

Density (float)
Sets the density of the hair curves

Length (float)
Length shoud also be represented by an individual node. For simpler node networks it could be nice to have length included in the scatter hair node. Mostly because it's convenient.

Width (float)
Sets the width of the hair curves


Node: Resample
Type: Create

Vertex amount (upper drop down menu)

  • Count
    • Amount of vertices per hair curve is decided depending on the value in the variable Fac
  • Length
    • Amount of vertices per hair curve is decided depending on distance in object space between each vertex/sample. Distance is set in the variable Fac

Fac
Float value used for variable vertex amount. When vertex amount = Count, then round off to lower integer (eg floor(Fac))

Resample method
When upsampling a low res hair curve it is useful to have the result as a smooth curve.

  • Nurbs
  • Linear

Node: Instance
Type: Create

Instance node socket (left side)
Accepts input node with type

  • Object
  • Collection content
  • Collection

Deform

  • False: the instanced objects are not deformed
  • True: The instanced objects are deformed along the shape of each hair curve

Object up (1:st drop down menu)
Decides which axis (in object space) of the source object that should be treated as object up (pointing in the direction of the hair curve tip vertex)

  • +X
  • -X
  • +Y
  • -Y
  • +Z
  • -Z

Object front (2:nd drop down menu)
Decides which axis (in object space) of the source object that should be treated as object front.

Front aim vector (3:d drop down menu)
Decides which vector that "Object front" should aim.

  • Tangent (Cross product calculated from position of root vertex and second vertex)
  • +X
  • -X
  • +Y
  • -Y
  • +Z
  • -Z

Tilt

  • If Deform = True: Rotate per component (vertex) along axis of vector between root and tip hair vertex.
  • If Deform = False: Rotate per hair curve along axis of vector between root and tip hair vertex.
NOTE: The word "Tilt" is used, since it is already used for curves in Blender

Non deforming example. Instanced objects up vector are aligned from root to tip. Used for trees, rocks etc

Deforming example. Used for game hair, feathers etc


NODES - DEFORM


Node: Deform
Type: Create

Direction
Along the direction of the hair (per segment/vertex)

Normal
Inherited/Transfered from the growth mesh

Read more about transferred normals from growth mesh to guide curves here T78606: Hair object - design proposal


Node: Frizz
Type: Create


Node: Rotate
Type: Deform



Node: Curl
Type: Deform


Node: Length
Type: Deform

Cut/Extend
Cut = shorter, extend = grow along vector between last two vertices at the tip

Scale
Scale per hair from hair root vertex


Node: Clump
Type: Deform

Fac
Amount of clumping. The user can edit the attribute that is connected to this socket in order to clump more/less at the root/tip of the hair curves.

Frequency
The primarily clump frequencey/size

Fractal iterations (integer)
Creating smaller (recursive) clumps per clump so that clumping does not look as uniform


Node: Width
Type: Deform

Width is also controllable through the UI of the hair object (outside of node network) and act as a multiplier to the width inside of the node network. There should be separate width for viewport and render


Node: Shrinkwrap
Type: Deform

This node is very useful for creating the look of wet hair

Object
Shrinkwrap target. Collection or geometrical object. See the node Input in the data flow section

Fac
The amount/blend of whrinkwrap deform


Node: Smooth
Type: Deform

Smooth vector (upper drop down menu)

  • Hair tip vector
  • Normal vector

Curve length (lower drop down menu)

  • Keep length
  • Lock tip

Lower drop down menu

normal vector + keep length
In this example the vector that the hair smooths/conforms to is the normal direction from the growth mesh surface. The length of the original hair curve is kept as it is smoothed

Hair tip vector + lock tip
In this example the vector that the hair smooths/conforms to is the vector from the root to the tip of the hair curve (pre smooth). The length of the hair curve is shortened so that the tip of the hair stays in place.

Iterations (integer)
Smoothing iterations


Node: Simulation influence
Type: Deform?
IMPORTANT: Update after feedback from @Jacques Lucke (JacquesLucke). Feel free to give further feedback

Reference to a simulation network where the actual simulation happens. The simulation network simulates the hair and the new position per hair curve vertex is output from the right socket. It is useful to simulate a sparse set of hair curves and then use a scatter hair node after in order to generate more hair curves that are conformed to the shape of the sparse set of simulated hair curves.

Simulation network (top drop down menu)
Link to a node network with simulation setup


NODES - ATTRIBUTE

Attributes on hair objects are created in the hair object UI, much like vertex groups on mesh objects. Perhaps these attributes could be picked up during shading in the future? See T78606: Hair object - design proposal for more info


Node: Object weight transfer
Type: Attribute

Input weight (top drop down menu)
Gets value of vertex weight from input object(s). Useful for dynamic weights controlled by modifiers. Input can be a mesh object (see Input node in the *Data flow** section in this document.


Node: UV transfer
Type: Attribute

I've been thinking about how to solve multiple uv sets in conjunction with the generation of hair curves. This node is one solution and is rather flexible, since we can sample uv's from any object. Another route would be to decide that we only source the uv's from the growth mesh. Feel free to give input regarding what would be the easiest in terms of development/coding.


Node: Hair root proximity
Type: Attribute

The hair root proximity node is very useful when scattering ground vegetation with the Instance node. The root mask can be used to make sure that bushes should not grow close to trees for instance.

Radius
The radius in object space of the mask produced from each root vertex of the hair curves

Node: Attribute get
Type: Attribute

Whenever the user needs to remap an attribute (multiply, add, clamp etc) she/he can break out the attribute with an attribute get node, do operations and then use a attribute set node to write it to the hair curves later in the node graph


Node: Attribute set
Type: Attribute

Whenever the user needs to remap an attribute (multiply, add, clamp etc) she/he can break out the attribute with an attribute get node, do operations and then use a attribute set node to write it to the hair curves later in the node graph. Usually the attribute is used right after the node, so it's convenient with a ouput socket with Factor.


Node: Geometry intersection
Type: Attribute
NOTE: I will add further visual examples to how this works later

Position (Top drop down menu)

  • Inside
    • Masks the hair curve vertices that positioned inside of the geometry object.
  • Outside
    • Masks the hair curve vertices that positioned outside of the geometry object.

Hair component(Bottom drop down menu)

  • Root
    • For each hair curve: if hair curve root is positioned inside/outside (depending on the variable Position), all of the vertices per hair is masked
  • Vertex
    • For each hair curve: If a vertex is positioned inside/outside (depending on the variable Position), that vertex and all of the vertices with higher index number per hair curve ("child vertices") will get a value of 1 for the hair curve attribute that is specified in the node.


USEFUL NODES FROM THE SHADING EDITOR

Almost all nodes in the shading editor would be very useful for creating masks for hair. It would be nice to reuse so the functionality is instantly recognized by the user. I need input from developers such as @Sebastián Barschkis (sebbas) if it's even possible to use existing nodes from shading editor.

Shading editor nodes is evaluated after the hair is deformed and we will likely want to evaluate these nodes BEFORE the final deformation of the hair. This could cause issues and I'm not sure it's possible to work around it somehow. Seems tedious to rewrite so many nodes.

A lot of these nodes would require an object/geometry input socket in order to define the source (such as

  • Vertex Color
  • Attribute
  • Texture Coordinate

Event Timeline

Daniel Bystedt (dbystedt) changed the task status from Needs Triage to Confirmed.Jul 2 2020, 1:08 AM
Daniel Bystedt (dbystedt) created this task.
Daniel Bystedt (dbystedt) moved this task from Backlog to Long-Term on the Nodes & Physics board.

Hair simulation should be done in another node tree indeed. We have the Simulation data block now, that owns a simulation node tree, that will contain simulation nodes for particles and hair (and later hopefully other simulation types). At least that is my understanding.

It's good to see that the other nodes fit quite well into a data-flow-graph. So they have inputs, compute some stuff, and output new/modified stuff. I think those nodes should exist in the same node tree as mesh/volume/modifier nodes. We don't really have an agreed upon design for that yet. We might need a design-sprint for that at some point, similar to what we had for simulation nodes.

One thing that is not entirely clear yet is the relationship between meshes and hair:
Does your "Hair" socket include hair+mesh? If yes, what are Split and Merge doing to the mesh.
Does the hair object somehow reference a base mesh? Can individual strands reference different base meshes? Or maybe hair should only be loosely coupled to a mesh somehow.

Also what exactly is the pink socket labelled "Instance" and "Output". Is it a mesh, or any other object (including hair, volume, ...). How is it different from the black socket?

I'm not sure if the "Weight" node can work like that. It outputs a float and it is not clear whether it is a float per position, per vertex, per polygon, ... Alternatively, the node could take a mesh and hair as input and then transfer some weight attribute from the mesh over to the hair object.

The "Root Mask" problem has a similar problem, but the other way around.

Does the "Geometry Mask" node "select" a bunch of hairs (creates a "strand group" that contains these hairs) or create new hair object containing only the masked strands?

I'm using some of the general nodes (like Combine XYZ) from the shader editor in the simulation node editor as well. Those "function nodes" can be used in hair nodes as well. Nodes like "Hair Info", "UV Map", "Vertex Color", ... probably can't be use without changes, because they have the same problem as the "Weight" and "Root Mask" node: the domain of their output value is not clear. In the shader editor, all values are in the same domain conceptually (at a single point on a surface or inside a volume).

Thanks for the feedback @Jacques Lucke (JacquesLucke). Your questions are a really good reference for how I should make my design task more readable and clear. I'll start off by adressing your questions

Hair simulation should be done in another node tree indeed. We have the Simulation data block now, that owns a simulation node tree, that will contain simulation nodes for particles and hair (and later hopefully other simulation types). At least that is my understanding.

Sounds great. Then perhaps it's best to completely remove

  • Physics velocity
  • Damp
  • Gravity
  • Force fields

from the node and only keep the node tree dropdown?

It's good to see that the other nodes fit quite well into a data-flow-graph. So they have inputs, compute some stuff, and output new/modified stuff. I think those nodes should exist in the same node tree as mesh/volume/modifier nodes. We don't really have an agreed upon design for that yet. We might need a design-sprint for that at some point, similar to what we had for simulation nodes.

Great! I'm very open to changing design. I only care about getting the functionality from the nodes

One thing that is not entirely clear yet is the relationship between meshes and hair:
Does your "Hair" socket include hair+mesh? If yes, what are Split and Merge doing to the mesh.

The hair data (orange dots) that is passed through the node tree only contain hair geometry (i.e. vertices and edges). The sphere growth mesh is only used for visualisation in the node examples. Perhaps I should do a node connection mockup example somehow so that it becomes even more clear. The Split node only separates hair curves based pm an input mask.

Does the hair object somehow reference a base mesh? Can individual strands reference different base meshes? Or maybe hair should only be loosely coupled to a mesh somehow.

Yes, the hair object references a base mesh. My current idea is to set the growth mesh in the hair object properties UI. It felt easier for me to handle one growth mesh per hair object in cases where the user needs to temporary detatch hair for remodeling or changing growth mesh and then attaching the hair again. See growth mesh in the image below

Also what exactly is the pink socket labelled "Instance" and "Output". Is it a mesh, or any other object (including hair, volume, ...). How is it different from the black socket?

Instances are sourced from the *input* (data flow) node. It can reference

  • mesh objects
  • Entire collection
  • Collection content (e.g. random objects that belongs to a specific collection)

When I did the mockup I thought that perhaps I needed to define instances created in the hair object node tree with other colors, but I don't have any strong feeling about this. Perhaps it's better with black sockets? I guess they are sort of the same.

I'm not sure if the "Weight" node can work like that. It outputs a float and it is not clear whether it is a float per position, per vertex, per polygon, ... Alternatively, the node could take a mesh and hair as input and then transfer some weight attribute from the mesh over to the hair object.

It outputs a float value between 0-1 per hair curve vertex. The weight node sources the weight from an object via the input node (or multiple object if the input node contains a collection and each object has a weight with a matching weight name). Weights are stored as float values per vertices on the source object. Therefore there will need to be a "transfer process" where the weight from the object(s) vertices are transferred to the root per hair curve and then copied to the remaining vertices per hair curve. I'll try to add a visual example so it's a bit more clear.

The "Root Mask" problem has a similar problem, but the other way around.

It outputs a float value between 0-1 per hair curve vertex. I think that I need to do another visual example of this if my node mockup is not explanation enough. It's basically the same as the process of the weight node, but in this case the source geometry is a mesh containing each root vertex of the input hair mesh.

Does the "Geometry Mask" node "select" a bunch of hairs (creates a "strand group" that contains these hairs) or create new hair object containing only the masked strands?

Ah. My bad. The output socket should be a Faq (i.e. float value between 0-1 per hair curve vertex).
For example: very short and curly hair that ends up inside of a characters body can be masked and deformed so that they can displaced outside of the body (I did something like this in houdini a while back and found it really useful)

I'm using some of the general nodes (like Combine XYZ) from the shader editor in the simulation node editor as well. Those "function nodes" can be used in hair nodes as well. Nodes like "Hair Info", "UV Map", "Vertex Color", ... probably can't be use without changes, because they have the same problem as the "Weight" and "Root Mask" node: the domain of their output value is not clear. In the shader editor, all values are in the same domain conceptually (at a single point on a surface or inside a volume).

Yeah I suspected this. I hate to load a lot of work on developers, bit it would be amazing to have access to those nodes in the hair object node graph as well.

My only concern is to have once again the object/collection scattering tools in the middle of the hair tools.

It makes sense with the "deform along guide" option but i think it should have it's own part somewhere else and keep this only for hair grooming in my opinion.

My only concern is to have once again the object/collection scattering tools in the middle of the hair tools.

It makes sense with the "deform along guide" option but i think it should have it's own part somewhere else and keep this only for hair grooming in my opinion.

That is a valid point and I will take note. I would need input from the developers what would be the best option regarding how to handle instances. My main concern is to make sure instance scattering (rocks, trees etc) and instance deform (game hair, feathers) can be implemented at the same time as the new hair system so that users don't loose functionality.

For now I will continue with the current design for instances, but make adjustments once I get developer feedback regarding how to handle instances and deformed instances