colour-hdri icon indicating copy to clipboard operation
colour-hdri copied to clipboard

Implement support for "Piece-wise Power Curves" tonemapping operator.

Open KelSolaar opened this issue 7 years ago • 1 comments

References

  • http://filmicworlds.com/blog/filmic-tonemapping-with-piecewise-power-curves/
  • https://www.desmos.com/calculator/12vlon6rpu
  • https://colab.research.google.com/drive/1YKOF_uYi7zL-ihrENXUJOC2r47QNSRAo?usp=sharing

KelSolaar avatar May 27 '17 05:05 KelSolaar

We should create a new colour_hdri.tonemapping_operator_piecewise_power_curves global tonemapping operator in the colour.tonemapping.global_operators.operators module.

It would be great to update the Jupyter Notebook example if possible.

The implementation should be straightforward given the code from John Habble:

void FilmicToneCurve::CalcDirectParamsFromUser(CurveParamsDirect & dstParams, const CurveParamsUser & srcParams)
{
	dstParams = CurveParamsDirect();

	float toeStrength = srcParams.m_toeStrength;
	float toeLength = srcParams.m_toeLength;
	float shoulderStrength = srcParams.m_shoulderStrength;
	float shoulderLength = srcParams.m_shoulderLength;

	float shoulderAngle = srcParams.m_shoulderAngle;
	float gamma = srcParams.m_gamma;

	// This is not actually the display gamma. It's just a UI space to avoid having to 
	// enter small numbers for the input.
	float perceptualGamma = 2.2f;

	// constraints
	{
		toeLength = Saturate(toeLength);
		toeStrength = Saturate(toeStrength);
		shoulderAngle = Saturate(shoulderAngle);
		shoulderLength = Saturate(shoulderLength);

		shoulderStrength = MaxFloat(0.0f,shoulderStrength);
	}

	// apply base params
	{
		// toe goes from 0 to 0.5
		float x0 = toeLength * .5f;
		float y0 = (1.0f - toeStrength) * x0; // lerp from 0 to x0

		float remainingY = 1.0f - y0;

		float initialW = x0 + remainingY;

		float y1_offset = (1.0f - shoulderLength) * remainingY;
		float x1 = x0 + y1_offset;
		float y1 = y0 + y1_offset;

		// filmic shoulder strength is in F stops
		float extraW = exp2f(shoulderStrength)-1.0f;

		float W = initialW + extraW;

		// to adjust the perceptual gamma space, apply power
		dstParams.m_x0 = powf(x0,perceptualGamma);
		dstParams.m_y0 = powf(y0,perceptualGamma);
		dstParams.m_x1 = powf(x1,perceptualGamma);
		dstParams.m_y1 = powf(y1,perceptualGamma);
		dstParams.m_W = W;

		// bake the linear to gamma space conversion
		dstParams.m_gamma = gamma;
	}

	dstParams.m_overshootX = (dstParams.m_W * 2.0f) * shoulderAngle * shoulderStrength;
	dstParams.m_overshootY = 0.5f * shoulderAngle * shoulderStrength;
}

KelSolaar avatar Oct 01 '19 08:10 KelSolaar