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: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);
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;
}
`;
#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?)