Alright, here is a provisional solution, as evidenced by this image:
(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:
- The hair particle’s initial velocity (normal and tangent).
- The influence of gravity, if any.
- Serious kink, notably Spiral.
- Added randomness.
- Surprisingly, the damping factor.
- 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.
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 = VgA.weight(iV) #weight() not  !
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.