Skip to content

Instantly share code, notes, and snippets.

@rafaskb
Last active April 5, 2023 22:20
Show Gist options
  • Save rafaskb/e779e70e58da42dbd68ae1aeb022c46e to your computer and use it in GitHub Desktop.
Save rafaskb/e779e70e58da42dbd68ae1aeb022c46e to your computer and use it in GitHub Desktop.
Look-up Table shader for gdx-vfx. It takes an image where each line consists of a color mapping, and the shader is able to take two indices and mix them.
package com.grashers.core.utilities.vfx.effects;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.crashinvaders.vfx.VfxRenderContext;
import com.crashinvaders.vfx.effects.ChainVfxEffect;
import com.crashinvaders.vfx.effects.ShaderVfxEffect;
import com.crashinvaders.vfx.framebuffer.VfxFrameBuffer;
import com.crashinvaders.vfx.framebuffer.VfxPingPongWrapper;
import com.crashinvaders.vfx.gl.VfxGLUtils;
public class LutEffect extends ShaderVfxEffect implements ChainVfxEffect {
private static final String TEXTURE0 = "u_texture0";
private static final String TEXTURE1 = "u_texture1";
private static final String INTENSITY = "u_intensity";
private static final String INDEX1 = "u_index1";
private static final String INDEX2 = "u_index2";
private static final String INDEX_OFFSET = "u_indexOffset";
private static final String STEP = "u_step";
private static final String STEP_OFFSET = "u_stepOffset";
private Texture texture;
private float intensity = 1f;
private int index1 = -1;
private int index2 = -1;
private float step = 0;
private float stepOffset = 0;
private float indexOffset = 0;
public LutEffect(Texture texture) {
super(VfxGLUtils.compileShader(
Gdx.files.classpath("gdxvfx/shaders/screenspace.vert"),
Gdx.files.internal("__________path/to/your/lut.frag"))); // FIXME
setTexture(texture);
rebind();
}
@Override
public void rebind() {
program.bind();
setUniform(TEXTURE0, TEXTURE_HANDLE0);
setUniform(TEXTURE1, TEXTURE_HANDLE1);
setUniform(INTENSITY, intensity);
setUniform(INDEX1, index1);
setUniform(INDEX2, index2);
setUniform(INDEX_OFFSET, indexOffset);
setUniform(STEP, step);
setUniform(STEP_OFFSET, stepOffset);
}
@Override
public void render(VfxRenderContext context, VfxPingPongWrapper buffers) {
render(context, buffers.getSrcBuffer(), buffers.getDstBuffer());
}
public void render(VfxRenderContext context, VfxFrameBuffer src, VfxFrameBuffer dst) {
// Bind src buffer's texture as a primary one.
src.getTexture().bind(TEXTURE_HANDLE0);
texture.bind(TEXTURE_HANDLE1);
// Apply shader effect and render result to dst buffer.
renderShader(context, dst);
}
public Texture getTexture() {
return texture;
}
public void setTexture(Texture texture) {
this.texture = texture;
setUniform(TEXTURE1, TEXTURE_HANDLE1);
this.step = 1f / (float) texture.getHeight();
this.stepOffset = this.step / 2f; // center texel
setUniform(STEP, step);
setUniform(STEP_OFFSET, stepOffset);
}
public float getIntensity() {
return intensity;
}
public void setIntensity(float intensity) {
this.intensity = intensity;
setUniform(INTENSITY, intensity);
}
public int getIndex1() {
return index1;
}
public void setIndex1(int index1) {
this.index1 = index1;
setUniform(INDEX1, index1);
}
public int getIndex2() {
return index2;
}
public void setIndex2(int index2) {
this.index2 = index2;
setUniform(INDEX2, index2);
}
public float getIndexOffset() {
return indexOffset;
}
public void setIndexOffset(float indexOffset) {
this.indexOffset = indexOffset;
setUniform(INDEX_OFFSET, indexOffset);
}
}
@rafaskb
Copy link
Author

rafaskb commented Apr 5, 2023

lut.frag

#ifdef GL_ES
#define PRECISION mediump
precision PRECISION float;
#else
#define PRECISION
#endif

uniform PRECISION sampler2D u_texture0;
uniform PRECISION sampler2D u_texture1;

varying vec2 v_texCoords;
uniform float u_intensity;
uniform int u_index1;
uniform int u_index2;
uniform float u_indexOffset;
uniform float u_step;
uniform float u_stepOffset;

vec3 lookup(vec3 color) {
    vec3 curveColorA;
    vec3 curveColorB;

    float idxA = float(u_index1) * u_step + u_stepOffset;
    float idxB = float(u_index2) * u_step + u_stepOffset;

    curveColorA.r = texture2D(u_texture1, vec2(color.r, idxA)).r;
    curveColorA.g = texture2D(u_texture1, vec2(color.g, idxA)).g;
    curveColorA.b = texture2D(u_texture1, vec2(color.b, idxA)).b;

    curveColorB.r = texture2D(u_texture1, vec2(color.r, idxB)).r;
    curveColorB.g = texture2D(u_texture1, vec2(color.g, idxB)).g;
    curveColorB.b = texture2D(u_texture1, vec2(color.b, idxB)).b;

    return mix(color, mix(curveColorA, curveColorB, u_indexOffset), u_intensity);
}

void main() {
    vec3 rgb = texture2D(u_texture0, v_texCoords).xyz;
    gl_FragColor = vec4(lookup(rgb), 1);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment