0
\$\begingroup\$

I have a function Evaluate(), which is used to remap a noise value based on a curve/spline to make the noise more interesting. There are 3 inputs: the noise value to be remapped, the gradient of the noise, and the curve/spline. What I need help with is finding the new gradient.

// "noise" is in the range [0,1], and is the value form a noise function,
// "gradient" is the gradient of the noise function, 
// and "filter" has the heights of an animation curve in the interval [0,1]
private void Evaluate(ref float noise, ref float3 gradient, in UnsafeList<float> filter)
{
    int index = (int)(noise * (filter.Length - 1));
    
    float remap = filter[index]; // f(x)
    int h = index + 1 == filterResolution ? -1 : 1; // direction to evaluate the array
    float remaph = filter[index + h]; // f(x+h)
    gradient = (remaph - remap) / h * gradient; // curve derivative * noise derivative 
    noise = remap;
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ This is just the chain rule. To calculate it you'd need the derivative of your animation curve as another array, or partial differences computed from adjacent indices. \$\endgroup\$ Commented Jan 12, 2023 at 0:11

1 Answer 1

0
\$\begingroup\$

Chain rule says

$$\frac {d} {d x}f(g(x)) = f^\prime(g(x)) \cdot g^\prime(x) $$

In your case you have three functions to compose:

  • Your filter function \$f(i)\$ that you approximate stepwise
    (You may get better results if you use a piecewise linear or spline interpolation here, to avoid stairstep artifacts from the truncation. Below, we'll pretend it's a smooth function so the flat steps don't zero-out the gradient)

  • Your range remapping function \$r(i) = (\text{filter length} - 1)i\$

  • Your noise function \$n(x, y, z)\$

So we need to multiply three coefficients here:

$$\frac {\delta} {\delta x}f(r(n(x,y,z))) = f^\prime(r(n(x,y,z))) \cdot r^\prime(n(x, y, z)) \cdot \frac {\delta n(x,y,z)} {\delta x}$$

In code that could look like this:

private void Evaluate(ref float noise, ref float3 gradient, in UnsafeList<float> filter)
{
    int index = (int)(noise * (filter.Length - 1));

    float filtered = filter[index];

    int maxIndex = Mathf.Min(index + 1, filter.Length - 1);
    int minIndex = Mathf.Max(index - 1, 0);

    float approximateSlope = (filter[maxIndex] - filter[minIndex]) 
                             / (maxIndex - minIndex);

    //               f'                   r'                n'
    gradient = approximateSlope * (filter.Length - 1) * gradient;
    noise = filtered;
}
\$\endgroup\$
1
  • \$\begingroup\$ Thanks! it works perfectly! \$\endgroup\$ Commented Jan 12, 2023 at 18:13

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.