How can I set a UNiagaraDataInterfaceColorCurve from a color curve asset?

I’m experimenting with Niagara, hoping to make a damage numbers particle effect that will normally use an all white color curve scaled by a user parameter to indicate the severity of the damage, and when a critical hit occurs it will instead use a rainbow gradient color curve. I couldn’t find a way within Niagara module scripting to conditionally choose one color curve vs. another, and from what I’ve read this is because significant conditional branches have a heavy impact on code intended to run on the GPU (HLSL generated by Niagara).

Instead, I’m trying to set the color curve to use as a Niagara User parameter in C++ and then only the color scale vector changes based on whether or not the damage represents a critical hit (which can be achieved with the selector node). The problem I’m having is that the color curve User parameter is apparently not getting set properly; regardless of the curve I set it to in C++, the particle system uses the default value I provided in the Niagara particle editor for the color curve User parameter. If I unset the default, then the particles become transparent (presumably because the default color curve value is now all zeroes).

Here’s the color curve asset loading code:

FString ColorCurvePath = TEXT("/Game/Ryddelmyst_Assets/Textures/");
        if (IsCrit)
        {
            ColorCurvePath += TEXT("RainbowRoadColorCurve");
        }
        else
        {
            ColorCurvePath += TEXT("WhiteColorCurve");
        }
        UCurveLinearColor* ColorCurveAsset = LoadObject<UCurveLinearColor>
        (
            nullptr,
            *ColorCurvePath,
            nullptr,
            LOAD_None,
            nullptr
        );

I wasn’t 100% certain that UCurveLineraColor is the class I want to represent an asset created in the content browser via Right Click → Miscellaneous → Curve → CurveLinearColor, but it looks about right and gives the FRichCurve curve data that UNiagaraDataInterfaceColorCurve seems to want.

I’m trying to set the UNiagaraDataInterfaceColorCurve as follows:

UNiagaraDataInterface* DataInterfaceForDamageColorCurve = UNiagaraFunctionLibrary::GetDataInterface(UNiagaraDataInterface::StaticClass(), FloatingNumbersFX_Component, FName{ TEXT("DamageColorCurve") });
        if (DataInterfaceForDamageColorCurve)
        {
            if (const auto DataInterfaceColorCurve = Cast<UNiagaraDataInterfaceColorCurve>(DataInterfaceForDamageColorCurve))
            {
                DataInterfaceColorCurve->RedCurve = ColorCurveAsset->FloatCurves[0];
                DataInterfaceColorCurve->GreenCurve = ColorCurveAsset->FloatCurves[1];
                DataInterfaceColorCurve->BlueCurve = ColorCurveAsset->FloatCurves[2];
                DataInterfaceColorCurve->AlphaCurve = ColorCurveAsset->FloatCurves[3];
            }
        }

I’ve verified that the variable ColorCurveAsset is non-null after load and that its Keys[0].Value and Keys[0].Time match the asset configuration, so presumably the load operation succeeded. The question then is how should I actually set the color channel curves in the UNiagaraDataInterfaceColorCurve object? The best approach I could see from the API was to set each channel curve individually as seen above, which potentially doesn’t work since I’m seeing the default color curve value used at runtime.

A bit late but just stumbled over this. I had the same problem and looked a bit further into the API. In case you have UseLUT checked in the advanced section of your curve parameter (which it is by default i guess), simply add the following line after setting the curves to update it:

DataInterfaceColorCurve->UpdateLUT();

This did the trick for me!

Alternatively to have even less code try this:

if (UNiagaraDataInterfaceColorCurve* AsDataInterfaceColorCurve = Cast<UNiagaraDataInterfaceColorCurve>(DataInterface)){
    AsDataInterfaceColorCurve->CurveAsset = ColorCurveAsset;
    AsDataInterfaceColorCurve->SyncCurvesToAsset();
    AsDataInterfaceColorCurve->UpdateLUT();
}

Hope this helps.

I encontered the same problem, and UpdateLUT() do works, but it’s an editor only function, it only works in the UE editor play. When packaging, it will cause failure.

yeah UpdateLUT being editor only is the killer, it works in PIE then fails in a packaged build. swapping whole data interfaces at runtime was never really supported.

simpler approach that survives packaging: keep one color curve on the emitter and drive the tint through a user-exposed niagara color parameter instead, then set it from blueprint each time damage happens. white for normal hits scaled by severity, rainbow values on crit.

Expose Niagara Variables C++ & Blueprints, a Niagara variable plugin for Unreal Engine 5, exposes the parameter setters stock leaves out so you dont need custom module code for it: Expose Niagara Variables to Blueprint & C++ — Set Niagara Parameters at Runtime | Fab