So, if I use a texture with pma applied, can I understand that if I use only Blend mode as One OneMinusSrcAlpha, there is nothing to adjust in the shader?
The part that sets the material parameter to use premultipliedAlpha when creating the skeleton mesh:
const skeletonMesh = new spine.threejs.SkeletonMesh(
skeletonData,
(materialParameters: THREE.ShaderMaterialParameters) => {
materialParameters.depthTest = true;
materialParameters.premultipliedAlpha = true;
materialParameters.blending = THREE.NormalBlending; // gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
}
);
Basic fragment shader for three.js provided by spine-ts:
uniform sampler2D map;
varying vec2 vUv;
varying vec4 vColor;
void main(void) {
gl_FragColor = texture2D(map, vUv)*vColor;
}
If I apply only these two things, I understand that there should be no problem, but setting it like this brings up the following screen.
https://d.pr/i/QlGUfH
If I add shader code(gl_FragColor.rgb *= gl_FragColor.a😉 to the next step, there will be a problem with black edges.
https://d.pr/i/a3ABKz
Can you give me some more advice? For the threejs code related to the blending setting, it is good to refer to the following.
https://github.com/mrdoob/three.js/blob/master/src/renderers/webgl/WebGLState.js#L590
I thought about relationship of the premultipliedAlpha setting between threejs and spine-runtime.
The premultipliedAlpha setting in threejs is possible at two points. One renderer and one material. The default is true for renderers and false for materials.
The behavior of setting premultipliedAlpha in threejs is not clear why, but if I set premultipliedAlpha = true on material, it will change itself to a blending (Src: One, Dst: OneMinusSrcAlpha) called NormalBlending, and if I use the default fragment shader of threejs, add this code(gl_FragColor.rgb * = gl_FragColor.a😉 to the shader automatically.
This seems to artificially mirror the alpha value in the fragment shader when the alpha value is not a shelved texture resource. I don't know what the advantage of this, because I don't have enough knowledge in graphics processing.
When thinking about extending this to the spine, the alpha value was already reflected when packing the resource in the spine, so in threejs, I finally understood that only the blending mode needs to be changed to Src: One and Dst: OneMinusSrcAlpha.
But when I do this, afterimages appear as follows. Are there any caveats when packing pma images?
https://d.pr/i/QlGUfH
Or am I misunderstanding? I want help.
I found a solution.
First of all, to confirm that there was no problem with pma packing, I ran the spine I packed in the player module of spine-ts and confirmed that there was no problem.
Looking at the source code of the spine-ts player module, I have confirmed that premultipliedAlpha = true is the default and internal one / one minus src alpha blending is running.
Then, I compared the differences between the player module and threejs module of spine-ts.
I saw in the player module that logic to pre-multiply the color rgb with the alpha value just before sending the color value to the fragment shader was added.
I added that code to the spine-ts threejs module and finally confirmed that it works.
The following is the relevant code part, and I added this code to the next line. (premultipliedAlpha was also added to the SkeletonMesh constructor.)
spine-runtimes/SkeletonMesh.ts at 3.8
if (this.premultipliedAlpha) {
color.r *= color.a;
color.g *= color.a;
color.b *= color.a;
}