6 float FilmicMapping::CurveSegment::eval(
const float x)
const {
7 float x0 = (x - offsetX) * scaleX;
13 y0 = expf(lnA + B * logf(x0));
16 return y0 * scaleY + offsetY;
22 DirectParams directParams;
23 this->getDirectParams(directParams, userParams);
24 this->
create(directParams);
28 const float normX = x * invW;
29 int index = (normX < x0) ? 0 : ((normX < x1) ? 1 : 2);
30 CurveSegment segment = segments[index];
31 return segment.eval(normX);
40 static void SolveAB(
float& lnA,
float& B,
float x0,
float y0,
float m) {
42 lnA = logf(y0) - B * logf(x0);
60 float ret = g * m * powf(m * x + b, g - 1.0f);
65 DirectParams params = srcParams;
69 invW = 1.0f / srcParams.W;
73 params.x0 /= srcParams.W;
74 params.x1 /= srcParams.W;
75 params.overshootX = srcParams.overshootX / srcParams.W;
78 float shoulderM = 0.0f;
83 float g = srcParams.gamma;
98 CurveSegment midSegment;
99 midSegment.offsetX = -(b / m);
100 midSegment.offsetY = 0.0f;
101 midSegment.scaleX = 1.0f;
102 midSegment.scaleY = 1.0f;
103 midSegment.lnA = g * logf(m);
106 segments[1] = midSegment;
112 params.y0 =
max(1e-5f, powf(params.y0, params.gamma));
113 params.y1 =
max(1e-5f, powf(params.y1, params.gamma));
115 params.overshootY = powf(1.0f + params.overshootY, params.gamma) - 1.0f;
125 CurveSegment toeSegment;
126 toeSegment.offsetX = 0;
127 toeSegment.offsetY = 0.0f;
128 toeSegment.scaleX = 1.0f;
129 toeSegment.scaleY = 1.0f;
131 SolveAB(toeSegment.lnA, toeSegment.B, params.x0, params.y0, toeM);
132 segments[0] = toeSegment;
138 CurveSegment shoulderSegment;
140 float x0 = (1.0f + params.overshootX) - params.x1;
141 float y0 = (1.0f + params.overshootY) - params.y1;
145 SolveAB(lnA, B, x0, y0, shoulderM);
147 shoulderSegment.offsetX = (1.0f + params.overshootX);
148 shoulderSegment.offsetY = (1.0f + params.overshootY);
150 shoulderSegment.scaleX = -1.0f;
151 shoulderSegment.scaleY = -1.0f;
152 shoulderSegment.lnA = lnA;
153 shoulderSegment.B = B;
155 segments[2] = shoulderSegment;
162 float scale = segments[2].eval(1.0f);
163 float invScale = 1.0f / scale;
165 segments[0].offsetY *= invScale;
166 segments[0].scaleY *= invScale;
168 segments[1].offsetY *= invScale;
169 segments[1].scaleY *= invScale;
171 segments[2].offsetY *= invScale;
172 segments[2].scaleY *= invScale;
176 void FilmicMapping::getDirectParams(DirectParams& dstParams,
const UserParams& srcParams) {
177 dstParams = DirectParams();
179 float toeStrength = srcParams.toeStrength;
180 float toeLength = srcParams.toeLength;
181 float shoulderStrength = srcParams.shoulderStrength;
182 float shoulderLength = srcParams.shoulderLength;
184 float shoulderAngle = srcParams.shoulderAngle;
185 float gamma = srcParams.gamma;
189 float perceptualGamma = 2.2f;
193 toeLength = powf(
clamp(toeLength, 0.f, 1.f), perceptualGamma);
194 toeStrength =
clamp(toeStrength, 0.f, 1.f);
195 shoulderAngle =
clamp(shoulderAngle, 0.f, 1.f);
196 shoulderLength =
max(1e-5f,
clamp(shoulderLength, 0.f, 1.f));
198 shoulderStrength =
max(0.0f, shoulderStrength);
204 float x0 = toeLength * .5f;
205 float y0 = (1.0f - toeStrength) * x0;
207 float remainingY = 1.0f - y0;
209 float initialW = x0 + remainingY;
211 float y1_offset = (1.0f - shoulderLength) * remainingY;
212 float x1 = x0 + y1_offset;
213 float y1 = y0 + y1_offset;
216 float extraW = exp2f(shoulderStrength) - 1.0f;
218 float W = initialW + extraW;
227 dstParams.gamma = gamma;
230 dstParams.overshootX = (dstParams.W * 2.0f) * shoulderAngle * shoulderStrength;
231 dstParams.overshootY = 0.5f * shoulderAngle * shoulderStrength;
float EvalDerivativeLinearGamma(float m, float b, float g, float x)
void AsSlopeIntercept(float &m, float &b, float x0, float x1, float y0, float y1)
constexpr INLINE T max(const T &f1, const T &f2)
constexpr INLINE T clamp(const T &f, const T &f1, const T &f2)
#define NAMESPACE_SPH_END
float operator()(const float x) const
void create(const UserParams &userParams)