Groom group desc exposing to sequencer

Hello,

Regarding the groom shading problem ([Case [Content removed] we have some workarounds, but one needs some expertise from your side we think.

The HairShadowDensity from the groom Groups Desc helps a lot. Having a low value like 0.05 - 0.1 flatten the hair, helps match the art style and hide the shading problem a bit. The problem is, the group desc don’t seems editable dynamically. It is not only the shadow density actually, even the width and scales would need tweaking for close up for example.

We found out that the Group Desc is editable. But it seems necessary to compile / construct the component to send those data to the render thread. Meaning it’s impossible to have a per shot value.

Correct me if I’m wrong but it seems needed to call UpdateHairGroupsDescAndInvalidateRenderState(); in the groom component to properly send the update.

Would this be the way to make those attributes sequencer-editable and working correctly ?

What can be the consequences of having it refreshing frequently? (per-shot)

Thanks !

Maxime

[Attachment Removed]

Hello,

If I recall correctly you need to attribute interp for making an attribute editable in the sequencer. You can follow the pattern used by HairLengthScale I believe.

/Charles.

[Attachment Removed]

Hello,

Exposing and linking array data with Sequencer can break easily. Debugging quickly, it looks like the Sequencer parameter binding does not manager to recompute the data writting offset correctly.

I wonder if the simplest wouldn’t be to go through a BP instead. In a BP you can access/control all the fields of the hair desc, and set them as you want to. Here is an example of a BP where I set the hair length and the shadow density of the groups 0/1. This requires to hook it to some event like OnTick and to PIE while running the sequencer.

[Image Removed] [Image Removed]In order to transfer the data from gamethread to renderthread, you need this snippet as well within the function

void UGroomComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
	....
	
	TArray<FHairGroupDesc> CopyGroupDesc;
	{
		const uint32 GroupCount = GetGroupCount();
		CopyGroupDesc.Reserve(GroupCount);
		for (uint32 GroupIndex = 0; GroupIndex < GroupCount; ++GroupIndex)
		{
			CopyGroupDesc.Add(GetGroomGroupsDesc(GroomAsset, this, GroupIndex));
		}
	}
 
	ENQUEUE_RENDER_COMMAND(FHairStrandsTick_GroupDesc)(
	[Id,  LocalHairGroupInstances, CopyGroupDesc](FRHICommandListImmediate& RHICmdList)
	{
		uint32 GroupIndex = 0;
		for (const TRefCountPtr<FHairGroupInstance>& Instance : LocalHairGroupInstances)
		{
			Instance->Strands.Modifier = CopyGroupDesc[GroupIndex];
			++GroupIndex;
		}
	});
}

/Charles.

[Attachment Removed]

Hi,

You have a couple of options with varying results. Sequencer has a repeater event if you want to try run an event per frame. You can also expose that variable to cinematics and try and change things in the consturction script. Then set sequencer to re-run construction per frame.

[Image Removed]You can find some documentation here: https://dev.epicgames.com/documentation/unreal\-engine/cinematic\-event\-track\-in\-unreal\-engine?lang\=en\-US

Cheers,

/Charles.

[Attachment Removed]

Hello !

Thanks for the reply.

Yes, we did follow the pattern of HairLengthScale and we have something very similar working.

But we found out a few bugs that happens even to HairLengthScale, where the sequencer overrides do not have effect anymore.

The setup is as follow:

  • In the level, there is a Groom Actor where the groom asset is set to None (to mimick what we do in our workflow).
  • A level sequence is referencing this actor, set its groom asset, modify its HairLengthScale.
    • There are 2 groups in the groom asset, so 2 tracks modifying the attribute.
  • A parent sequence contains the sequence above.

At first, modifying the attribute works correctly, setting it to 0 correctly make the groom disappear.

A small bug occurs though, it seems only one of the track is actually controlling the groom length, and its controlling it for all groups instead of the group it comes from.

Then, if we go out of the sequence’s range and go back in, now the attributes do not work anymore.

If we save the sequence though, it seems to refresh it. But it breaks again when out of range.

Attached is a small repro project with the setup mentioned above.

Do you have any idea of what could be the issue ?

Is some update trigger missing somewhere ?

Thanks !

Maxime

[Attachment Removed]

Here is the repro project.

[Attachment Removed]

Hello Charles !

Thanks for this ! I’ll try it.

Indeed we thought about the BP way, but it was not working either, I guess because it missed your tick function.

Is the tick the only option ?

Could this be a function we can call only when the values actually change ? Based on setter functions for example.

Would this be enough and more efficient ? Or would the tick method be equivalent in performance ?

Thanks !

Maxime

[Attachment Removed]