Implement LUT-based color-grading

3D LUT color grading. Maybe it's only necessary to only have the StringProperty like lensflare.
Todo: LUT size handling (resolution dependent), currently only 512x512 LUTS.
This commit is contained in:
Alexander Kleemann 2017-12-07 17:09:44 +01:00
parent d657f03cf8
commit 42b0aaaded
5 changed files with 59 additions and 0 deletions

View file

@ -20,6 +20,10 @@ uniform sampler2D gbuffer1;
uniform sampler2D lensTexture;
#endif
#ifdef _CLUT
uniform sampler2D lutTexture;
#endif
#ifdef _Hist
uniform sampler2D histogram;
#endif
@ -86,6 +90,38 @@ vec3 applyFog(vec3 rgb, float distance) {
}
#endif
vec4 LUTlookup(in vec4 textureColor, in sampler2D lookupTable) {
//Clamp to prevent weird results
textureColor = clamp(textureColor, 0.0, 1.0);
mediump float blueColor = textureColor.b * 63.0;
mediump vec2 quad1;
quad1.y = floor(floor(blueColor) / 8.0);
quad1.x = floor(blueColor) - (quad1.y * 8.0);
mediump vec2 quad2;
quad2.y = floor(ceil(blueColor) / 8.0);
quad2.x = ceil(blueColor) - (quad2.y * 8.0);
highp vec2 texelPosition1;
texelPosition1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
texelPosition1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
highp vec2 texelPosition2;
texelPosition2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
texelPosition2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
lowp vec4 newColor1 = texture(lookupTable, texelPosition1);
lowp vec4 newColor2 = texture(lookupTable, texelPosition2);
lowp vec4 colorGradedResult = mix(newColor1, newColor2, fract(blueColor));
return colorGradedResult;
}
float vignette() {
// vignetting from iq
// return 0.4 + 0.6 * pow(16.0 * texCoord.x * texCoord.y * (1.0 - texCoord.x) * (1.0 - texCoord.y), 0.2);
@ -323,4 +359,15 @@ void main() {
// const float compoLetterboxSize = 0.1;
fragColor.rgb *= 1.0 - step(0.5 - compoLetterboxSize, abs(0.5 - texCo.y));
#endif
//3D LUT Implementation from GPUGems 2 by Nvidia
//https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter24.html
#ifdef _CLUT
fragColor = LUTlookup(fragColor, lutTexture);
#endif
}

View file

@ -75,6 +75,11 @@
"name": "cameraProj",
"link": "_cameraPlaneProj",
"ifdef": ["_CFog", "_CDOF", "_CGlare"]
},
{
"name": "lutTexture",
"link": "_lutTexture",
"ifdef": ["_CLUT"]
}
],
"texture_params": [],

View file

@ -32,6 +32,9 @@ class Uniforms {
else if (tulink == "_lensTexture") {
return Scene.active.embedded.get('lenstexture.jpg');
}
else if (tulink == "_lutTexture") {
return Scene.active.embedded.get('luttexture.jpg');
}
else if (tulink == "_cloudsTexture") {
return Scene.active.embedded.get('cloudstexture.png');
}

View file

@ -326,6 +326,8 @@ def init_properties():
bpy.types.World.arm_fisheye = bpy.props.BoolProperty(name="Fish Eye", default=False, update=assets.invalidate_shader_cache)
bpy.types.World.arm_vignette = bpy.props.BoolProperty(name="Vignette", default=False, update=assets.invalidate_shader_cache)
bpy.types.World.arm_lensflare = bpy.props.BoolProperty(name="Lens Flare", default=False, update=assets.invalidate_shader_cache)
bpy.types.World.arm_lut = bpy.props.BoolProperty(name="LUT Lookup Table", default=False, update=assets.invalidate_shader_cache)
bpy.types.World.arm_lut_texture = bpy.props.StringProperty(name="LUT Texture", default="", update=assets.invalidate_shader_cache)
# Skin
bpy.types.World.arm_skin = EnumProperty(
items=[('GPU (Dual-Quat)', 'GPU (Dual-Quat)', 'GPU (Dual-Quat)'),

View file

@ -1125,6 +1125,8 @@ class ArmRenderPropsPanel(bpy.types.Panel):
layout.prop(wrd, 'arm_lensflare')
layout.prop(wrd, 'arm_autoexposure_strength')
layout.prop(wrd, 'arm_lens_texture')
layout.prop(wrd, 'arm_lut')
layout.prop(wrd, 'arm_lut_texture')
class ArmGenLodButton(bpy.types.Operator):
'''Automatically generate LoD levels'''