1
$\begingroup$

For materials pertaining to hair strands, Cycles gives us a Hair Info node with a scalar output called Intercept, whose value will be 0 at the root and 1 at the tip, irrespective of how long the hair strand actually is (in Blender units, e.g. meters).

Knowing where we are along a hair strand, we can achieve visual effects such as banding along each hair. But (by the use of vertex groups for density, kink, and length) I also wish to bring about a smooth transition from hairless to full-crop —e.g. along the nape of a character’s neck— and this will result in a range of hair lengths that can span an order of magnitude.

If we lack information on the actual length of a hair strand, any banding algorithm that relies on Intercept and works well for full-length strands will necessarily give a compressed and visually dissatisfying result on the shortest hairs:

Subtle banding of hair with wide range of lengths requires knowledge of actual hair length.

To compensate, algorithmically, we need the ability to read the actual length of the strand being rendered. Actual length information is, of course, available somewhere inside Blender before the Cycles rendering is invoked. Is there any way for a materials developer to read that information, in Blender 2.79 or 2.80?

Or, at the very least, is there a way to read the vertex weight of a vertex group (such as: the one that is modifying hair length)?

$\endgroup$
1
$\begingroup$

Alright, here is a provisional solution, as evidenced by this image:

enter image description here (compare with my original, above).

A satisfactory solution would make use of each hair strand’s actual length at render time. This length depends on many factors, including:

  1. The hair particle’s initial velocity (normal and tangent).
  2. The influence of gravity, if any.
  3. Serious kink, notably Spiral.
  4. Added randomness.
  5. Surprisingly, the damping factor.
  6. The vertex group for length control, if any.

So, the product of intercept times length control is proportional, only approximately, to the hair strand’s actual length, but this is what I use for the image above, and it is the reason why I call this a provisional solution.

Unfortunately, vertex weights are not yet (September 2018) available to the Cycles material developer; not through the Attribute node, not through OSL, and not even through some clever driver expression: so says Grand Guru Brecht Van Lommel, here.
Thus, my provisional —and clumsy— solution, suggested by Brecht himself, is to copy the length control information over to a Vertex Color layer, which is, oddly enough, accessible via the Cycles Attribute node.

Here is a quick Python hack to achieve said copy:

#Given: active object with active vertex group and active vertex color layer
#
#Does: Copies vertex weights into red channel of vertex color layer, leaves rest untouched.
#
#© Tom Telos 2018, submitted freely to interested users, for experimental purposes only.
#
import bpy 

bpy.ops.object.mode_set(mode = 'OBJECT') 
ObA = bpy.context.active_object
if ObA == None : raise RuntimeError("No active object")
else : print( "Active object" , ObA.name , "found." )

VgA = ObA.vertex_groups.active 
if VgA == None : raise RuntimeError("No active vertex group")
else : print( ObA.name , "act vx gp " , VgA.name , " found." )

VcA = ObA.data.vertex_colors.active
if VcA == None : raise RuntimeError("No active vertex color layer")
else : print( ObA.name , "act vx colors " , VcA.name , " found." )

for loop in ObA.data.loops : #Crazy, but this works.
    iV = loop.vertex_index
    iL = loop.index
    try :  #fails if vertex not in vg
        VcA.data[iL].color[0] = VgA.weight(iV) #weight() not [] !
    except: continue

It is in lieu of Varkenvarken’s much more sophisticated addon which, unfortunately, does not work for me with recent builds of Blender 2.79, ostensibly because of a Python version mismatch, but, more likely because, in recent Blender 2.79 builds, the number of vertex color “channels” has been increased from 3 to 4.

My hack is simply paste-and-run, and assumes that there is an active object with an active vertex group and an active vertex color layer. For each vertex in the active vertex group, it copies its weight to the red channel of the color layer. That’s all. It does not modify the vertex color of any vertex not present in the vertex group.

P.S. Brecht Van Lommel, here, confirms that, as of September 2018, there is no user-level access to actual hair length.

$\endgroup$
0
$\begingroup$

You can find the vertex weight in the "N" properties panel when - in edit mode - you select a vertex that has at least some weight relative to a vertex group.

enter image description here

$\endgroup$
  • $\begingroup$ Thank you. Yes. But, how do I refer to the weight, in a particular vertex group, of the vertex closest to the root of the hair strand being rendered? How can we refer to that, in a Cycles nodes diagram, or in an OSL script, or, possibly, in a driver? $\endgroup$ – Tom Telos Sep 13 '18 at 20:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.