Loading Look up table into post-effect shader for a limited pallet effect

I am attempting to load a look up table (in the format of a png) into my shader to allow for a limited pallet effect. However, I get this error:

The texture is being loaded by the javascript portion of the code, but I don’t think it’s being passed to the shader code correctly.

Shader [Shader Id 0 Untitled] requires texture sampler [uLUTTexture] which has not been set, while rendering [PixelateEffect | Pass:RenderPassQuad | drawQuadWithShader | QuadRender]

This is my fragment shader code (there is irrelevant code around it because I was messing with some of the contrast of the output, along with a pixelize shader).

fshader: [
            (graphicsDevice.webgl2) ? ("#version 300 es\n\n" + pc.shaderChunks.gles3PS) : "",
            "precision " + graphicsDevice.precision + " float;",
            pc.shaderChunks.screenDepthPS,
            "",
            "varying vec2 vUv0;",
            "",
            "uniform vec2 uResolution;",
            "uniform sampler2D uColorBuffer;",
            "uniform float uAmount;",
            "uniform float uLowContrast;",
            "uniform float uHighContrast;",
            "uniform sampler2D uLUTTexture;", //this is the LUT 
            "",
            "void main() {",
            "    highp vec2 uv = vUv0; // variable_vertex.xy; // interpolated at pixel's center",
            "",
            "   vec2 pixelateDxy = uAmount / uResolution;",
            "   vec2 pixelateCoord = pixelateDxy * floor( uv / pixelateDxy );",
            "    vec4 color = texture2D(uColorBuffer, pixelateCoord);",
            "float brightness = dot(color.rgb, vec3(0.299, 0.587, 0.114));",
            "vec4 newColor = vec4(0);",
            " if (brightness > 0.4 && brightness < 0.6){",
            " color = clamp(color * uLowContrast,0.0,1.0);",    
            "} else if (brightness > 0.75 && brightness < 1.0) {",
            "color = clamp(color * uHighContrast,0.0,1.0);",
             "} else {",
            "color = color;}",
            // THIS IS THE LUT CODE 
            "float index = floor(color.b * (16.0 - 1.0));",
            "float lutY = (index + 0.5) / 16.0;",
            "vec2 lutUV = vec2(color.r, lutY);",
            "vec3 lutColor = texture2D(uLUTTexture,lutUV).rgb;",
            "   gl_FragColor = vec4(lutColor,1.0);",
            // END OF LUT CODE
            "}"
        ].join("\n")
    });

Here is how I load the image to use for the LUT into the shader (I cut out some irrelevant code):

Pixelate.attributes.add('textureAsset', {
    type: 'asset'
});

Pixelate.prototype.initialize = function () {

    this.effect = new PixelateEffect(this.app.graphicsDevice);
    this.effect.amount = this.amount;
    this.effect.lowContrast = this.lowContrast;
    this.effect.highContrast = this.highContrast;

    this.lutTexture = new pc.Texture(this.app.graphicsDevice, {
    format: pc.PIXELFORMAT_R8_G8_B8_A8,
    mipmaps: false
    });

    // const asset = new pc.Asset("lutTexture", "texture", { url: "path/to/lut.png" });
    this.app.assets.add(this.textureAsset);
    this.app.assets.load(this.textureAsset);

    this.textureAsset.ready(() => {
        console.log("ready");
       this.lutTexture= this.textureAsset.resource;
       console.log(this.lutTexture);
    this.lutTexture.setSource(this.textureAsset.resource);
    });

Here is my project as well. Thanks!

you need something like this

this.app. graphicsDevice .scope.resolve('uLUTTexture').setValue(this.lutTexture);

I have something similar in the script:

Object.assign(PixelateEffect.prototype, {
    render: function (inputTarget, outputTarget, rect) {

        var device = this.device;
        var scope = device.scope;

        scope.resolve("uResolution").setValue([device.width, device.height]);
        scope.resolve("uAmount").setValue(this.amount);
        scope.resolve("uLowContrast").setValue(this.lowContrast);
        scope.resolve("uHighContrast").setValue(this.highContrast);
        scope.resolve("uColorBuffer").setValue(inputTarget.colorBuffer);
        scope.resolve("uLUTTexture").setValue(this.lutTexture); // <-- here


        pc.drawFullscreenQuad(device, outputTarget, this.vertexBuffer, this.shader, rect);
    }
});

Doesn’t help though.

1 Like

I tried running your example in the debug mode, and I do not get the error you mentioned about the missing sampler.

I had multiple shaders on the camera because I was messing around with different effects, I accidentally left the wrong one on (that works). Now the non-working one with this error is enabled.

your texture is undefined.

oh I see, I forgot to set it under this.effect.lutTexture, Thanks!

got it working!

1 Like