Saltallica Posted January 20, 2018 Share Posted January 20, 2018 Hi there - I'm going down a rabbit hole trying to implement a color grading / LUT shader for PIXI. Color grading is where you can you use a sprite as a lookup table to quickly transform one set of colors to another - this is handy for applying realtime contrast and color adjustments. I'm using this as a reference: https://www.defold.com/tutorials/grading/ I've created a filter/shader using the code in the link above: var ColorGradingShader = function(LUTSprite) { var my = this; var code = ` precision lowp float; uniform vec4 filterArea; varying vec2 vTextureCoord; uniform sampler2D uSampler; uniform sampler2D lut; #define MAXCOLOR 15.0 #define COLORS 16.0 #define WIDTH 256.0 #define HEIGHT 16.0 void main() { vec4 px = texture2D(uSampler, vTextureCoord.xy); float cell = px.b * MAXCOLOR; float cell_l = floor(cell); float cell_h = ceil(cell); float half_px_x = 0.5 / WIDTH; float half_px_y = 0.5 / HEIGHT; float r_offset = half_px_x + px.r / COLORS * (MAXCOLOR / COLORS); float g_offset = half_px_y + px.g * (MAXCOLOR / COLORS); vec2 lut_pos_l = vec2(cell_l / COLORS + r_offset, g_offset); vec2 lut_pos_h = vec2(cell_h / COLORS + r_offset, g_offset); vec4 graded_color_l = texture2D(lut, lut_pos_l); vec4 graded_color_h = texture2D(lut, lut_pos_h); vec4 graded_color = mix(graded_color_l, graded_color_h, fract(cell)); gl_FragColor = graded_color; } `; PIXI.Filter.call(my, null, code); my.uniforms.lut = LUTSprite.texture; } ColorGradingShader.prototype = Object.create(PIXI.Filter.prototype); ColorGradingShader.prototype.constructor = ColorGradingShader; export default ColorGradingShader; I then add this to my top level container: //relevant code from a wrapping class this.colorGradingSprite = new PIXI.Sprite.fromImage('/img/lut16.png'); this.pixiContainer.filters = [ this.colorGradingFilter ]; When using any LUT image, including the default without any color adjustments: I go from this: to this: I'm assuming there are some adjustments necessary to either the shader code, or how the lut sprite itself is being loaded - I have no clue.. Any help would be greatly appreciated! And for those curious, here's my end goal: Thanks, Sean jonforum and ivan.popelyshev 2 Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted January 20, 2018 Share Posted January 20, 2018 Code looks fine. Please provide more details. Quote Link to comment Share on other sites More sharing options...
Saltallica Posted January 20, 2018 Author Share Posted January 20, 2018 Thanks for reviewing, what more can I provide? Using Pixi 4.6.2... Running under latest Chrome... here's the vertex and fragments shaders as passed to gl: precision lowp float; uniform vec4 filterArea; varying vec2 vTextureCoord; uniform sampler2D uSampler; uniform sampler2D lut; #define MAXCOLOR 15.0 #define COLORS 16.0 #define WIDTH 256.0 #define HEIGHT 16.0 void main() { vec4 px = texture2D(uSampler, vTextureCoord.xy); float cell = px.b * MAXCOLOR; float cell_l = floor(cell); float cell_h = ceil(cell); float half_px_x = 0.5 / WIDTH; float half_px_y = 0.5 / HEIGHT; float r_offset = half_px_x + px.r / COLORS * (MAXCOLOR / COLORS); float g_offset = half_px_y + px.g * (MAXCOLOR / COLORS); vec2 lut_pos_l = vec2(cell_l / COLORS + r_offset, g_offset); vec2 lut_pos_h = vec2(cell_h / COLORS + r_offset, g_offset); vec4 graded_color_l = texture2D(lut, lut_pos_l); vec4 graded_color_h = texture2D(lut, lut_pos_h); vec4 graded_color = mix(graded_color_l, graded_color_h, fract(cell)); gl_FragColor = graded_color; } precision highp float; attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; uniform mat3 projectionMatrix; uniform mat3 filterMatrix; varying vec2 vTextureCoord; varying vec2 vFilterCoord; void main(void){ gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); vFilterCoord = ( filterMatrix * vec3( aTextureCoord, 1.0) ).xy; vTextureCoord = aTextureCoord ; } Anything else you are looking for? Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted January 20, 2018 Share Posted January 20, 2018 Yep, complete example, published on https://jsfiddle.net ir in codepen. Or a zip file, but that'll make it harder for me, a bit Quote Link to comment Share on other sites More sharing options...
Saltallica Posted January 20, 2018 Author Share Posted January 20, 2018 (edited) Here you go: https://jsfiddle.net/ycdvehcf/3/ Not the full game obviously, but you can see the shader being toggled on and off. Thanks so much for your help! Edited January 20, 2018 by Saltallica tweaked fiddle Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted January 20, 2018 Share Posted January 20, 2018 my.uniforms.lut = LUTSprite.texture; //new code LUTSprite.texture.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST; LUTSprite.texture.baseTexture.mipmap = false; I adjusted the filtering, at least its consistent now. Quote Link to comment Share on other sites More sharing options...
Saltallica Posted January 20, 2018 Author Share Posted January 20, 2018 :: giant thumbs up emoji :: Didn't consider mipmapping causing issues I do notice the that the LUT sprite itself, when the filter is applied, looks like it's flipping upside down. So that leads me to think it could be one of two things (maybe?) The math for the shader needs be adjusted to flip the Y axis Flipping the LUT image PNG upside down might work? Thanks for looking in to this! Quote Link to comment Share on other sites More sharing options...
Saltallica Posted January 21, 2018 Author Share Posted January 21, 2018 Flipping the LUT image did the trick! Here's a working example: https://jsfiddle.net/ycdvehcf/4/ Also, changing the scaleMode to PIXI.SCALE_MODES.LINEAR keeps color banding from occurring For anyone else who stumbles on to this post - use this as your base LUT image: Ivan, thanks for pointing me in the right direction! Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted January 21, 2018 Share Posted January 21, 2018 I forgot about flipping Y. Congratulations! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.