Rotate tangent on FRichCurve

Hello,
I’m trying to obtain an inversed U curve in editor.

I can create a FRichCurve modifiable in editor with the following:

// -----\/----- height curve
    FKeyHandle h1;
    FKeyHandle h2;
    FKeyHandle h3;
 
 
    // create keyhandles to manipulate keys
    h1 = FKeyHandle();
    h2 = FKeyHandle();
    h3 = FKeyHandle();
 
    // add keys to the graph
    CustomStepSpeedCurve.EditorCurveData.AddKey(0.f, 0.f, true, h1);
    CustomStepSpeedCurve.EditorCurveData.AddKey(0.5f, 0.5f, true, h2);
    CustomStepSpeedCurve.EditorCurveData.AddKey(1.f, 0.f, true, h3);
 
    // interp
    CustomStepSpeedCurve.EditorCurveData.SetKeyTangentMode(h1, ERichCurveTangentMode::RCTM_Auto);
    CustomStepSpeedCurve.EditorCurveData.SetKeyTangentMode(h2, ERichCurveTangentMode::RCTM_Auto);
    CustomStepSpeedCurve.EditorCurveData.SetKeyTangentMode(h3, ERichCurveTangentMode::RCTM_Auto);
 
    CustomStepSpeedCurve.EditorCurveData.SetKeyInterpMode(h1, ERichCurveInterpMode::RCIM_Cubic);
    CustomStepSpeedCurve.EditorCurveData.SetKeyInterpMode(h2, ERichCurveInterpMode::RCIM_Cubic);
    CustomStepSpeedCurve.EditorCurveData.SetKeyInterpMode(h3, ERichCurveInterpMode::RCIM_Cubic);

However what this gives me is the following:

What I’m trying to reach is the following:

Is there a way to programmatically “rotate” the tangent as you would in editor by moving the yellow line?

Thank you in advance,
r.

1 Like

Yes, set a different KeyTangentMode for the first vertex, and configure the tangent parameters as you need them.

This is what I’m missing, I don’t know how to set them. Do you have any pointers?

First: You don’t define the key handles ahead of time – they are returned by AddKey(). It’s “handle” as in “code pointer to thing” not “handle” as in “artist movable tangent.”

Second: The best way I’ve found is to read using the Keys member, and update using SetKeys()

	FKeyHandle h1, h2;
	h1 = TheCurve.AddKey(0.f, 0.f, true);
	h2 = TheCurve.AddKey(1.f, 0.1f, true);
	auto keys = TheCurve.Keys; // make a copy
	keys[0].ArriveTangent = -1.0f;
	keys[0].LeaveTangent = 1.0f;
	keys[0].InterpMode = ERichCurveInterpMode::RCIM_Cubic;
	keys[0].TangentMode = ERichCurveTangentMode::RCTM_Break;
	TheCurve.SetKeys(keys); // update and broadcast to listeners

Thank you for yourt time. Unfortunately, this possibly works with FRichCurve, but not with the version that allows editing from the Editor (FRuntimeFloatCurve):

	FKeyHandle h1, h2, h3;
	h1 = CustomStepHeightCurve.EditorCurveData.AddKey(0.f, 0.f, true);
	h2 = CustomStepHeightCurve.EditorCurveData.AddKey(0.5f, 1.f, true);
	h2 = CustomStepHeightCurve.EditorCurveData.AddKey(1.f, 0.f, true);

	// make a copy
	auto HeightKeys = CustomStepHeightCurve.EditorCurveData.Keys;

	HeightKeys[0].ArriveTangent = 2.8878f;
	HeightKeys[0].LeaveTangent = 2.8878f;
	HeightKeys[0].InterpMode = ERichCurveInterpMode::RCIM_Cubic;
	HeightKeys[0].TangentMode = ERichCurveTangentMode::RCTM_Auto;

	HeightKeys[1].ArriveTangent = 0.f;
	HeightKeys[1].LeaveTangent = 0.f;
	HeightKeys[1].InterpMode = ERichCurveInterpMode::RCIM_Cubic;
	HeightKeys[1].TangentMode = ERichCurveTangentMode::RCTM_Auto;

	HeightKeys[2].ArriveTangent = -2.8878f;
	HeightKeys[2].LeaveTangent = -2.8878f;
	HeightKeys[2].InterpMode = ERichCurveInterpMode::RCIM_Cubic;
	HeightKeys[2].TangentMode = ERichCurveTangentMode::RCTM_Auto;

	// save in curve
	CustomStepHeightCurve.EditorCurveData.SetKeys(HeightKeys);

This results in an empty curve:

image

Also, if you don’t define the handlers ahead of time you get some other tangent issues.

That’s not how the handles work. The handles are identifiers for the internal objects. A handle object that’s uninitialized doesn’t have any special powers. The fact that you have a variable in your program named h1 doesn’t matter – the value returned by AddKey() is the value you need to use to reference that particular key for that particular curve.
They’re essentially just integers.

struct FKeyHandle
{
	ENGINE_API FKeyHandle();
[...]
private:
	uint32 Index;
};

The index makes no sense outside of the context of the curve itself. (The curve actually has a map from “index” value to actual-key-index, which is why it’s a “Handle” and not just a raw index.)

If you’re having “other issues,” then perhaps those are a clue to what’s actually not working as expected in your code?

Calling SetKeys() calls AutoSetTangents() which updates the tangents for keys with the TangentMode set to RCTM_Auto, so if you want to keep the specified values, set the mode to RCTM_Break. Like my code suggested.

No idea why the editor doesn’t pick up the keys.

The “other issues” are tangents not being used for all the keys when you define them as you suggest (= as return values only). I understand what you’re saying, but if you tried it yourself you would see that the tangents are not kept for all keys unless you declare them explicitly.

Thanks for your help, maybe this has to do with the fact that I’m using those curves from a custom animation BP node, which seems to have some special treatment by the compiler…?

I think the tangents are being overridden because you’re specifying RCTM_Auto and not RCTM_Break. That’s what RTCM_Auto does – it overrides the tangents you specify with “auto computed” values.