Skip to content

Commit 72043fb

Browse files
committed
Optimized ColorGrading
1 parent da8af1c commit 72043fb

File tree

4 files changed

+200
-140
lines changed

4 files changed

+200
-140
lines changed

Cat/Includes/CatCommon.cginc

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,15 +309,16 @@ inline half1 EqualLuminance(half3 c) {
309309
return (c.r + c.g + c.b) / 3.0;
310310
}
311311

312-
inline half3 HsvToRgb(half3 hsv) {
312+
313+
inline half3 HSVtoRGB(half3 hsv) {
313314
const half h = hsv.x, s = hsv.y, v = hsv.z;
314315
half3 c = saturate(abs(frac(h + half3(3, 2, 1) / 3.0) - 0.5) * 6 - 1);
315316
c = c * s - s;
316317
c = c * v + v;
317318
return c;
318319
}
319320

320-
inline half3 RgbToHsv(half3 rgb) {
321+
inline half3 RGBtoHSV(half3 rgb) {
321322
const half EPSILON = 1e-3;
322323

323324
float v = MaxC(rgb);
@@ -335,7 +336,75 @@ inline half3 RgbToHsv(half3 rgb) {
335336

336337
return float3(h, s, v);
337338
}
338-
339+
340+
341+
inline half3 HSLtoRGB(half3 hsl) {
342+
const half h = hsl.x, s = hsl.y, l = hsl.z;
343+
half sat = s * (l < 0.5 ? l : 1-l);
344+
half3 c = saturate(abs(frac(h + half3(3, 2, 1) / 3.0) - 0.5) * 6 - 1);
345+
c = c * 2 - 1;
346+
c = c * sat + l;
347+
return c;
348+
//c = (2 * c - 1) * sat + l;
349+
350+
//half3 hsv = { h, 2 * sat / (l + sat), l + sat }
351+
//return HSVtoRGB(hsv);
352+
353+
//half C = s - s * abs(2 * l - 1);
354+
//half H_d = 6 * h;
355+
//half X_d = 1 - abs(H_d % 2 - 1);
356+
//half X = C * X_d;
357+
}
358+
359+
inline half3 RGBtoHSL(half3 rgb) {
360+
const half3 hsv = RGBtoHSV(rgb);
361+
const half h = hsv.x, sat = hsv.y, v = hsv.z;
362+
363+
half s = sat * v;
364+
half x = 2 * v - s;
365+
s = s / (x < 1 ? x : 2 - x);
366+
half l = x / 2;
367+
368+
return float3(h, s, l);
369+
}
370+
371+
372+
inline half3 HCVtoRGB(half3 hcv) {
373+
const half EPSILON = 1e-3;
374+
375+
const half h = hcv.x, c = hcv.y, v = hcv.z;
376+
377+
half3 C = saturate(abs(frac(h + half3(3, 2, 1) / 3.0) - 0.5) * 6 - 1);
378+
half s = saturate(c / max((v), EPSILON));
379+
C = C * s - s;
380+
C = C * v + v;
381+
//C = C * c - c + v;
382+
return C;
383+
}
384+
385+
inline half3 RGBtoHCV(half3 rgb) {
386+
const half EPSILON = 1e-3;
387+
388+
float v = MaxC(rgb);
389+
390+
//float3 rgbMax = rgb / max(v, EPSILON);
391+
392+
//float s = 1 - MinC(rgbMax);
393+
//float c = s * v;
394+
float c = (v - MinC(rgb));
395+
396+
//float3 rgbSat = (rgbMax-1) / max(s, EPSILON) + 1;
397+
//float3 rgbSat = (rgbMax-1) / max(c, EPSILON) * v + 1;
398+
float3 rgbSat = saturate((rgb - v) / max(c, EPSILON) + 1);
399+
400+
half r = rgbSat.x, g = rgbSat.y, b = rgbSat.z;
401+
//float h = -g*(1*r - 2) - b*(3*g - 4) - r*(5*b - 6);
402+
float h = (g-EPSILON > 0 ? 0 : (6 - 6*b) * r) - b * (g * (2 * r + 3) - r - 4) - g * (r - 2);
403+
h = frac(h / 6.0);
404+
405+
return float3(h, c, v);
406+
}
407+
339408

340409
inline float1 CompressBy(float1 value, float1 amplitude) {
341410
float1 invDenom = 1 / (1 + amplitude);

Cat/PostProcessing/CatColorGrading/CatColorGrading.cs

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public struct Settings {
4545
[Range(-1, 1)]
4646
public float highlights;
4747

48+
4849
//[Header("Tone Mapping")]
4950
//[Range(0, 1)]
5051
//public float strength;
@@ -112,6 +113,7 @@ static class PropertyIDs {
112113

113114
internal static readonly int Temperature_f = Shader.PropertyToID("_Temperature");
114115
internal static readonly int Tint_f = Shader.PropertyToID("_Tint");
116+
internal static readonly int ColorBalance_v = Shader.PropertyToID("_ColorBalance");
115117

116118
internal static readonly int BlackPoint_f = Shader.PropertyToID("_BlackPoint");
117119
internal static readonly int WhitePoint_f = Shader.PropertyToID("_WhitePoint");
@@ -127,16 +129,25 @@ override protected void UpdateMaterialPerFrame(Material material, Camera camera,
127129
}
128130

129131
override protected void UpdateMaterial(Material material, Camera camera, VectorInt2 cameraSize) {
130-
131-
material.SetFloat(PropertyIDs.Exposure_f, settings.exposure);
132-
material.SetFloat(PropertyIDs.Contrast_f, settings.contrast);
133-
material.SetFloat(PropertyIDs.Saturation_f, settings.saturation);
134-
135-
material.SetFloat(PropertyIDs.Temperature_f, settings.temperature);
136-
material.SetFloat(PropertyIDs.Tint_f, settings.tint);
137-
material.SetFloat(PropertyIDs.BlackPoint_f, settings.blackPoint);
138-
material.SetFloat(PropertyIDs.WhitePoint_f, settings.whitePoint);
132+
const float EPSILON = 1e-4f;
133+
var exposure = Mathf.Pow(2, settings.exposure);
134+
var contrast = Mathf.Max(EPSILON, settings.contrast + Mathf.Max(0, settings.contrast) * Mathf.Max(0, settings.contrast) + 1);
135+
var saturation = (settings.saturation + Mathf.Max(0, settings.saturation) * Mathf.Max(0, settings.saturation) + 1) / contrast;
136+
var temperature = settings.temperature;
137+
var tint = settings.tint;
138+
var blackPoint = 0 + settings.blackPoint * 0.25f;
139+
var whitePoint = 1 +settings. whitePoint * 0.25f;
140+
141+
material.SetFloat(PropertyIDs.Exposure_f, exposure);
142+
material.SetFloat(PropertyIDs.Contrast_f, contrast);
143+
material.SetFloat(PropertyIDs.Saturation_f, saturation);
139144

145+
//material.SetFloat(PropertyIDs.Temperature_f, settings.temperature);
146+
//material.SetFloat(PropertyIDs.Tint_f, settings.tint);
147+
material.SetVector(PropertyIDs.ColorBalance_v, CalculateColorBalance(settings.temperature, settings.tint));
148+
material.SetFloat(PropertyIDs.BlackPoint_f, blackPoint);
149+
material.SetFloat(PropertyIDs.WhitePoint_f, whitePoint);
150+
140151
material.SetVector(PropertyIDs.CurveParams_v, settings.GetCurveParams());
141152

142153
//material.SetFloat(PropertyIDs.Strength_f, settings.strength);
@@ -150,6 +161,54 @@ internal override void RenderImage(RenderTexture source, RenderTexture destinati
150161
public void OnValidate () {
151162
setMaterialDirty();
152163
}
164+
165+
// An analytical model of chromaticity of the standard illuminant, by Judd et al.
166+
// http://en.wikipedia.org/wiki/Standard_illuminant#Illuminant_series_D
167+
// Slightly modifed to adjust it with the D65 white point (x=0.31271, y=0.32902).
168+
float StandardIlluminantY(float x) {
169+
return 2.87f * x - 3 * x * x - 00.27509507f;
170+
}
171+
172+
readonly Matrix4x4 M_CAT02_XYZ_TO_LMS = new Matrix4x4() {
173+
m00 = 0.7328f, m01 = 0.4296f, m02 = -0.1624f, m03 = 0,
174+
m10 = -0.7036f, m11 = 1.6975f, m12 = 0.0061f, m13 = 0,
175+
m20 = 0.0030f, m21 = 0.0136f, m22 = 0.9834f, m23 = 0,
176+
m30 = 0 , m31 = 0 , m32 = 0 , m33 = 0
177+
// 0.7328 , 0.4296 , -0.1624 ,
178+
// -0.7036 , 1.6975 , 0.0061 ,
179+
// 0.0030 , 0.0136 , 0.9834
180+
};
181+
182+
Vector3 XYZtoLMS(Vector3 xyz) {
183+
return M_CAT02_XYZ_TO_LMS.MultiplyVector(xyz);
184+
}
185+
// CIE xy chromaticity to CAT02 LMS.
186+
// http://en.wikipedia.org/wiki/LMS_color_space#CAT02
187+
Vector3 XYtoLMS(float x, float y){
188+
var xyz = new Vector3(x / y, 1, (1 - x - y) / y);
189+
return XYZtoLMS(xyz);
190+
}
191+
192+
Vector3 CalculateColorBalance(float temperature, float tint) {
193+
// Range ~[-1.8;1.8] ; using higher ranges is unsafe
194+
float t1 = temperature / 0.55f;
195+
float t2 = tint / 0.55f;
196+
197+
// Get the CIE xy chromaticity of the reference white point.
198+
// Note: 0.31271 = x value on the D65 white point
199+
float x = 0.31271f - t1 * (t1 < 0 ? 0.1f : 0.05f);
200+
float y = StandardIlluminantY(x) + t2 * 0.05f;
201+
202+
// Calculate the coefficients in the LMS space.
203+
var w1 = new Vector3(0.949237f, 1.03542f, 1.08728f); // D65 white point
204+
var w2 = XYtoLMS(x, y);
205+
w2.Set(1/w2.x, 1/w2.y, 1/w2.z);
206+
w2.Scale(w1);
207+
return w2;
208+
}
209+
210+
211+
153212
}
154213

155214
}

Cat/PostProcessing/CatColorGrading/Resources/ACES.cginc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,12 @@ half3 ACES_to_ACEScc(half3 x)
250250
*/
251251
}
252252

253+
half3 ACES_to_ACEScc_optimized(half3 x) {
254+
x = clamp(x, 0.0, HALF_MAX);
255+
// x is clamped to [0, HALF_MAX], skip the <= 0 check
256+
return (log2(0.00001525878 + x) + 9.72) / 17.52;
257+
}
258+
253259
//
254260
// ACES Color Space Conversion - ACEScc to ACES
255261
//
@@ -278,6 +284,12 @@ half3 ACEScc_to_ACES(half3 x)
278284
);
279285
}
280286

287+
half3 ACEScc_to_ACES_optimized(half3 x) {
288+
x = clamp(x, -0.3584475374911926, 1.4679963120638975);
289+
// x is clamped so result is in [0, HALF_MAX], skip the <= and >= checks
290+
return exp2(x*17.52 - 9.72) - 0.00001525878;
291+
}
292+
281293
//
282294
// ACES Color Space Conversion - ACES to ACEScg
283295
//

0 commit comments

Comments
 (0)