Implement LUTs color grading using .cube files? #1436
-
I've looked at using LUTs as color filters a few times, but I've never been able to find a workable solution with Skia. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
Unfortunately there is not out of the box support for this and you would have to write you own implementation from .cube to SkColorFilter. Shader Toy offers examples of LUT (https://www.shadertoy.com/view/wtKSWw) which can "easily" be converted to Skia runtime effects. I hope this helps. I love to learn more about this topic, if you have information about it. |
Beta Was this translation helpful? Give feedback.
-
Here how I achieved using shaders by providing LUTs (512x512)px file as .png instead of .cube, maybe help someone. Declarative implementation const paint = Skia.Paint();
const source = Skia.RuntimeEffect.Make(`
uniform shader image;
uniform shader luts;
half4 main(float2 xy) {
vec4 color = image.eval(xy);
int r = int(color.r * 255.0 / 4);
int g = int(color.g * 255.0 / 4);
int b = int(color.b * 255.0 / 4);
float lutX = float(int(mod(float(b), 8.0)) * 64 + r);
float lutY = float(int((b / 8) * 64 + g));
vec4 lutsColor = luts.eval(float2(lutX, lutY));
return lutsColor;
}
`)!;
export default function Picture() {
const luts = useImage(require('./assets/luts.png'));
const photo = useImage(require('./assets/photo.png'));
return (
<View style={{flex: 1}}>
<Canvas style={{flex: 1}}>
<Group>
<Fill />
<Shader source={source} uniforms={{}}>
<ImageShader
fit="none"
image={luts}
rect={{ x: 0, y: 0, width: 512, height: 512 }}
/>
<ImageShader
fit="contain"
image={photo}
rect={{
x: 0,
y: 0,
width: layout.width,
height: layout.height,
}}
/>
</Shader>
</Group>
</Canvas>
</View>
);
} Imperative implementation const paint = Skia.Paint();
const source = Skia.RuntimeEffect.Make(`
uniform shader image;
uniform shader luts;
half4 main(float2 xy) {
vec4 color = image.eval(xy);
int r = int(color.r * 255.0 / 4);
int g = int(color.g * 255.0 / 4);
int b = int(color.b * 255.0 / 4);
float lutX = float(int(mod(float(b), 8.0)) * 64 + r);
float lutY = float(int((b / 8) * 64 + g));
vec4 lutsColor = luts.eval(float2(lutX, lutY));
return lutsColor;
}
`)!;
export default function Picture() {
const luts = useImage(require('./assets/luts.png'));
const photo = useImage(require('./assets/photo.png'));
const onDraw = useDrawCallback(
(canvas, drawing) => {
if (photo && luts) {
const photoRects = fitRects(
'contain',
rect(0, 0, photo.width(), photo.height()),
rect(0, 0, drawing.width, drawing.height),
);
const photoM3 = Skia.Matrix();
const photoTransform = rect2rect(photoRects.src, photoRects.dst);
photoM3.translate(
photoTransform[0].translateX,
photoTransform[1].translateY,
);
photoM3.scale(photoTransform[2].scaleX, photoTransform[3].scaleY);
const photoShader = photo.makeShaderCubic(
TileMode.Decal,
TileMode.Decal,
0,
0,
photoM3,
);
const lutsShader = luts.makeShaderOptions(
TileMode.Clamp,
TileMode.Clamp,
FilterMode.Nearest,
MipmapMode.None,
Skia.Matrix(),
);
const shader = source.makeShaderWithChildren(
processUniforms(source, {}),
[photoShader, lutsShader],
Skia.Matrix(),
);
canvas.drawPaint(paint);
}
},
[luts, photo],
);
return (
<View style={{flex: 1}}>
<SkiaView style={{flex: 1}} onDraw={onDraw} />
</View>
);
} |
Beta Was this translation helpful? Give feedback.
Here how I achieved using shaders by providing LUTs (512x512)px file as .png instead of .cube, maybe help someone.
Declarative implementation