I am looking at changing the runtime shader to a custom shader (indexed color per character at first then per slot later). It will just be a change to the fragment shader with a largish set of uniforms for just the fragment shader (static per pixel, so I do not need to set them on the vertices, like is done with tint.)
My thought right now is to copy and add to the two color tint shader defined in https://github.com/EsotericSoftware/spine-runtimes/blob/3.8/spine-ts/webgl/src/Shader.ts . I will then use setUniform3f to set the uniforms on a per character basis (they will be vec3 RGB values.) I may also look at using a second texture as a color table (which will still require a custom shader, but now I will also need to create and load the the color table texture and set the color table texture uniform.)
I am wondering if you have other suggestions, so that I don't need to change the spine-ts runtime source (so I can stay current with the runtime.)
I did a hack version of Shader.ts to test it out and it seems to work ok. My test shader is using a bunch of branching, but I may move to using a second 1D texture as a color lookup depending on perf bottlenecks.
I am still hoping for some suggestions on how to integrate this smoothly with the spine runtime, instead of myself changing the runtime (I might just create a new shader and add a PR, but I am not sure if it will get accepted to add a new index color shader. I would like to hear comments on that...) I guess I could add another class file which extends the spine shader class...
My changes:
(this is my draw code)
// Set palette in shader
const PALETTE_ENTRIES = 8;
if (tickCount%30 == 0)
{
for (let i=0;i<PALETTE_ENTRIES;i++)
{
let uniformName = 'color'+i;
this.shader.setUniform4f(uniformName, Math.random(), Math.random(), Math.random(), 1.0);
}
}
// Start the batch and tell the SkeletonRenderer to render the active skeleton.
this.batcher.begin(this.shader);
// Apply vertex effect
this.renderer.vertexEffect = null;
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
// Render
this.renderer.premultipliedAlpha = premultipliedAlpha;
this.renderer.draw(this.batcher, skeletonInstance.skeletonInfo.skeleton);
These are my changes to Shader.ts:
let fs = `
#ifdef GL_ES
#define LOWP lowp
precision mediump float;
#else
#define LOWP
#endif
varying LOWP vec4 v_light;
varying LOWP vec4 v_dark;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform vec4 color0;
uniform vec4 color1;
uniform vec4 color2;
uniform vec4 color3;
uniform vec4 color4;
uniform vec4 color5;
uniform vec4 color6;
uniform vec4 color7;
void main () {
vec4 texColor = texture2D(u_texture, v_texCoords);
int index = int(texColor.r * 7.0);
if (texColor.a == 0.0)
{
// transparent, ignore index
} else if (index == 0)
{
texColor = color0;
} else if (index == 1)
{
texColor = color1;
} else if (index == 2)
{
texColor = color2;
} else if (index == 3)
{
texColor = color3;
} else if (index == 4)
{
texColor = color4;
} else if (index == 5)
{
texColor = color5;
} else if (index == 6)
{
texColor = color6;
} else
{
texColor = color7;
}
gl_FragColor.a = texColor.a * v_light.a;
gl_FragColor.rgb = ((texColor.a - 1.0) * v_dark.a + 1.0 - texColor.rgb) * v_dark.rgb + texColor.rgb * v_light.rgb;
}
`;
Now I'm looking at changing the palette colors (fs uniforms) on a per slot basis and that's definitely more complicated. I see the dark/light colors are applied on a slot basis by adding them to the vertices, but I am definitely open to suggestions on the best way to apply the palette color uniforms (for the fragment shader) on a per slot basis (it looks like I might need to dig into the poly batcher and mesh classes?)