GroomComponent Cards & Lumen SurfaceCache

Hello,

We have noticed that when using the GroomComponent and set the hair mode to Cards, the surface cache is yellow (invalid). The corresponding hair Card mesh that we use, when dragged in the Editor on its own, has correct surface cache (and radiosity probes around it), so my first guess was that the CardRepresentationData was not being initialised correctly int he GroomComponent Card codepath.

I did some digging and I have the following in the FHairStrandsSceneProxy constructor:

FHairStrandsSceneProxy(UGroomComponent* Component)
.....
{
    // Build card approximation
    if (CardRepresentationData)
    {
       delete CardRepresentationData;
       CardRepresentationData = nullptr;
    }
 
    UpdateVisibleInLumenScene();
    
    CardRepresentationData = new FCardRepresentationData;
    FMeshCardsBuildData& CardData = CardRepresentationData->MeshCardsBuildData;
 
    CardData.Bounds = Component->GetLocalBounds().GetBox();
    CardData.bMostlyTwoSided = true;
 
    MeshCardRepresentation::SetCardsFromBounds(CardData);
}
 
...
 
virtual const FCardRepresentationData* GetMeshCardRepresentation() const override
{
    return CardRepresentationData;
}

It’s basically doing what the SkeletalMeshSceneProxy does and to some extent it works, at least the surface cache is no longer yellow. However, it’s pink (no coverage), which is also wrong if we compare it to the static mesh itself.

I can verify that the codepath where it updates Lumen in LumenMeshCards.cpp and LumenSceneRendering.cpp (UpdateSurfaceCachePrimitives() ) is considering the newly added card representation for the hair cards and it’s not earlying out anywhere.

Also, I understand that the GroomComponent grabs all the StaticMesh vertex & index data and stores it internally without directly referencing the original StaticMesh anymore (correct me if I am wrong).

My question is, is there a solution in progress for this and / or do you have any other suggestions for us? I am happy to try and give you a repro project if needed.

Best regards

Pantelis Lekakis

Lead Programmer, Firesprite

Steps to Reproduce
If you use the hair GroomComponent with Cards, just visualise the Lumen surface card and it will be yellow (invalid).

This is with HWRT enabled.

Hi Pantelis,

Having spoken with the developers, we have not encountered this issue ourselves yet, so this is the first time someone has brought it up. I do have two options for you at this point:

  1. Your attempts to fix the Groom component are on track, so I encourage you to continue addressing this issue and submitting a pull request for us to review. You could take a Renderdoc/Pix capture and check if the hair card geometry is being allocated for Lumen and being rendered. If that is the case, there might be a scheduling issue or some missing logic on the CPU that we can then further discuss.
  2. If you feel like this is too big a task, please send me the repro project that you have available, and we can file a ticket to have the team look into adding a proper fix to the engine. I can’t say exactly when they will address this issue, but I can escalate it depending on your project needs.

Please let me know how you would like to proceed.

Cheers,

Tim

There are some cvars related to adjusting the lighting around hair thickness if you use screen traces (see r.Lumen.Reflections.HairStrands.ScreenTrace, r.Lumen.ScreenProbeGather.ScreenTraces.HairBias, etc.) inside LumenScreenProbeTracing::TraceScreenProbes, which might be helpful to you. However, these do not modify any settings in the HWRT code path, which is also located in the function above. I cannot say how helpful tweaking these settings will be, since there is still more to be done in that code path, and you are also seeing this issue with non-hair geometry. Unfortunately, that is the best answer I have for you at this time. If you require further clarification, please let me know, and I’ll do my best to provide an answer.

I did find something in regards to the Hair shading model which makes the *direct* lighting (during hit lighting) appear black.

Although I’m not sure if this thread is the right place to put it, it feels relevant, so here is my fix:

FDeferredLightData GetRayTracingDeferredLightData(
 
	int LightIndex,
 
	bool bIndirectLighting,
 
	inout uint OutLightType,
 
	inout uint OutLightMissShaderIndex)
 
{
 
	FDeferredLightData LightData = (FDeferredLightData)0;
 
	FRTLightingData RayTracingLightData = RaytracingLightGridData.SceneLights[LightIndex];
 
 ...
 
 // Init transmission data:
 
 LightData.HairTransmittance = InitHairTransmittanceData();
 
 ...
 
}

Hi Pantelis,

Is this change related to the previous conversation we had about some parts of the Groom pipeline not working? Additionally, please specify the changes you made and provide the rationale behind them. Typically, we prefer people to submit fixes via pull requests on GitHub. However, if you can briefly describe what you changed and why, we can look into integrating it directly.

Thank you Tim, I will be looking into this further.

Perhaps it’s a hair thickness issue, are you aware of any settings that could help? We see similar issues with very thin (and one sided) walls.