Browse Source

[unity] Fixed enabling `CanvasGroup Compatible` at Spine-SkeletonGraphic-TintBlack shader causing Additive blend mode not to work but instead hide the attachment completely. Now providing a `Canvas Group Tint Black` parameter a `SkeletonGraphic` Inspector in the `Advanced` section. Closes #1756.

Harald Csaszar 5 years ago
parent
commit
d43b7b0a9f

+ 1 - 0
CHANGELOG.md

@@ -239,6 +239,7 @@
   * Added a new `Spine/Outline/OutlineOnly-ZWrite` shader to provide correct outline-only rendering. Note: the shader requires two render passes and is therefore not compatible with URP. The `Spine Examples/Other Examples/Outline Shaders` example scene has been updated to demonstrate the new shader.
   * Added `OnMeshAndMaterialsUpdated` callback event to `SkeletonRenderSeparator` and `SkeletonPartsRenderer`. It is issued at the end of `LateUpdate`, before rendering.
   * Added `Root Motion Scale X/Y` parameters to `SkeletonRootMotionBase` subclasses (`SkeletonRootMotion` and `SkeletonMecanimRootMotion`). Also providing `AdjustRootMotionToDistance()` and other methods to allow for easy delta compensation. Delta compensation can be used to e.g. stretch a jump to a given distance. Root motion can be adjusted at the start of an animation or every frame via `skeletonRootMotion.AdjustRootMotionToDistance(targetPosition - transform.position, trackIndex);`.
+  * Now providing a `Canvas Group Tint Black` parameter a `SkeletonGraphic` Inspector in the `Advanced` section. Enable when using Additive blend mode at SkeletonGraphic under a CanvasGroup. Be sure to also have the parameter `CanvasGroup Compatible` enabled at the shader.
 
 * **Changes of default values**
   * `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`.

+ 20 - 6
spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs

@@ -68,6 +68,9 @@ namespace Spine.Unity {
 			[Header("Vertex Data")]
 			public bool pmaVertexColors;
 			public bool tintBlack;
+			[Tooltip("Enable when using Additive blend mode at SkeletonGraphic under a CanvasGroup. " +
+				"When enabled, Additive alpha value is stored at uv2.g instead of color.a to capture CanvasGroup modifying color.a.")]
+			public bool canvasGroupTintBlack;
 			public bool calculateTangents;
 			public bool addNormals;
 			public bool immutableTriangles;
@@ -493,6 +496,7 @@ namespace Spine.Unity {
 			#else
 			bool useClipping = settings.useClipping;
 			#endif
+			bool canvasGroupTintBlack = settings.tintBlack && settings.canvasGroupTintBlack;
 
 			if (useClipping) {
 				if (instruction.preActiveClippingSlotSource >= 0) {
@@ -556,12 +560,18 @@ namespace Spine.Unity {
 					}
 				}
 
+				float tintBlackAlpha = 1.0f;
 				if (pmaVertexColors) {
 					color.a = (byte)(skeletonA * slot.a * c.a * 255);
 					color.r = (byte)(skeletonR * slot.r * c.r * color.a);
 					color.g = (byte)(skeletonG * slot.g * c.g * color.a);
 					color.b = (byte)(skeletonB * slot.b * c.b * color.a);
-					if (slot.data.blendMode == BlendMode.Additive) color.a = 0;
+					if (slot.data.blendMode == BlendMode.Additive) {
+						if (canvasGroupTintBlack)
+							tintBlackAlpha = 0;
+						else
+							color.a = 0;
+					}
 				} else {
 					color.a = (byte)(skeletonA * slot.a * c.a * 255);
 					color.r = (byte)(skeletonR * slot.r * c.r * 255);
@@ -590,7 +600,7 @@ namespace Spine.Unity {
 							g2 *= alpha;
 							b2 *= alpha;
 						}
-						AddAttachmentTintBlack(r2, g2, b2, attachmentVertexCount);
+						AddAttachmentTintBlack(r2, g2, b2, tintBlackAlpha, attachmentVertexCount);
 					}
 
 					//AddAttachment(workingVerts, uvs, color, attachmentTriangleIndices, attachmentVertexCount, attachmentIndexCount, ref meshBoundsMin, ref meshBoundsMax, z);
@@ -694,6 +704,7 @@ namespace Spine.Unity {
 		// Use this faster method when no clipping is involved.
 		public void BuildMeshWithArrays (SkeletonRendererInstruction instruction, bool updateTriangles) {
 			var settings = this.settings;
+			bool canvasGroupTintBlack = settings.tintBlack && settings.canvasGroupTintBlack;
 			int totalVertexCount = instruction.rawVertexCount;
 
 			// Add data to vertex buffers
@@ -758,6 +769,7 @@ namespace Spine.Unity {
 						rg.x = slot.r2; //r
 						rg.y = slot.g2; //g
 						b2.x = slot.b2; //b
+						b2.y = 1.0f;
 
 						var regionAttachment = attachment as RegionAttachment;
 						if (regionAttachment != null) {
@@ -766,6 +778,7 @@ namespace Spine.Unity {
 								rg.x *= alpha;
 								rg.y *= alpha;
 								b2.x *= alpha;
+								b2.y = slot.data.blendMode == BlendMode.Additive ? 0 : alpha;
 							}
 							uv2i[vi] = rg; uv2i[vi + 1] = rg; uv2i[vi + 2] = rg; uv2i[vi + 3] = rg;
 							uv3i[vi] = b2; uv3i[vi + 1] = b2; uv3i[vi + 2] = b2; uv3i[vi + 3] = b2;
@@ -778,6 +791,7 @@ namespace Spine.Unity {
 									rg.x *= alpha;
 									rg.y *= alpha;
 									b2.x *= alpha;
+									b2.y = slot.data.blendMode == BlendMode.Additive ? 0 : alpha;
 								}
 								int meshVertexCount = meshAttachment.worldVerticesLength;
 								for (int iii = 0; iii < meshVertexCount; iii += 2) {
@@ -814,7 +828,7 @@ namespace Spine.Unity {
 							color.r = (byte)(r * slot.r * regionAttachment.r * color.a);
 							color.g = (byte)(g * slot.g * regionAttachment.g * color.a);
 							color.b = (byte)(b * slot.b * regionAttachment.b * color.a);
-							if (slot.data.blendMode == BlendMode.Additive) color.a = 0;
+							if (slot.data.blendMode == BlendMode.Additive && !canvasGroupTintBlack) color.a = 0;
 						} else {
 							color.a = (byte)(a * slot.a * regionAttachment.a * 255);
 							color.r = (byte)(r * slot.r * regionAttachment.r * 255);
@@ -861,7 +875,7 @@ namespace Spine.Unity {
 								color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
 								color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
 								color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
-								if (slot.data.blendMode == BlendMode.Additive) color.a = 0;
+								if (slot.data.blendMode == BlendMode.Additive && !canvasGroupTintBlack) color.a = 0;
 							} else {
 								color.a = (byte)(a * slot.a * meshAttachment.a * 255);
 								color.r = (byte)(r * slot.r * meshAttachment.r * 255);
@@ -985,9 +999,9 @@ namespace Spine.Unity {
 			meshBoundsThickness *= scale;
 		}
 
-		void AddAttachmentTintBlack (float r2, float g2, float b2, int vertexCount) {
+		void AddAttachmentTintBlack (float r2, float g2, float b2, float a, int vertexCount) {
 			var rg = new Vector2(r2, g2);
-			var bo = new Vector2(b2, 1f);
+			var bo = new Vector2(b2, a);
 
 			int ovc = vertexBuffer.Count;
 			int newVertexCount = ovc + vertexCount;

+ 12 - 5
spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/SkeletonGraphic/Spine-SkeletonGraphic-TintBlack.shader

@@ -89,7 +89,7 @@ Shader "Spine/SkeletonGraphic Tint Black"
 				float4 vertex   : SV_POSITION;
 				fixed4 color    : COLOR;
 				half2 texcoord  : TEXCOORD0;
-				float3 darkColor : TEXCOORD1;
+				float4 darkColor : TEXCOORD1;
 				float4 worldPosition : TEXCOORD2;
 				UNITY_VERTEX_OUTPUT_STEREO
 			};
@@ -110,7 +110,7 @@ Shader "Spine/SkeletonGraphic Tint Black"
 				OUT.texcoord = IN.texcoord;
 
 				OUT.color = IN.color * _Color;
-				OUT.darkColor = float3(IN.uv1.r, IN.uv1.g, IN.uv2.r);
+				OUT.darkColor = float4(IN.uv1.r, IN.uv1.g, IN.uv2.r, IN.uv2.g);
 				return OUT;
 			}
 
@@ -125,10 +125,17 @@ Shader "Spine/SkeletonGraphic Tint Black"
 				clip(texColor.a - 0.001);
 				#endif
 
-				float4 fragColor = fragTintedColor(texColor, _Black.rgb + IN.darkColor, IN.color, _Black.a);
+				float4 vertexColor = IN.color;
 			#ifdef _CANVAS_GROUP_COMPATIBLE
-				// CanvasGroup alpha sets vertex color alpha, but does not premultiply it to rgb components.
-				fragColor.rgb *= IN.color.a;
+				// CanvasGroup alpha multiplies existing vertex color alpha, but
+				// does not premultiply it to rgb components. This causes problems
+				// with additive blending (alpha = 0), which is why we store the
+				// alpha value in uv2.g (darkColor.a).
+				vertexColor.a = IN.darkColor.a;
+			#endif
+				float4 fragColor = fragTintedColor(texColor, _Black.rgb + IN.darkColor, vertexColor, _Black.a);
+			#ifdef _CANVAS_GROUP_COMPATIBLE
+				fragColor.rgba *= IN.color.a;
 			#endif
 				return fragColor;
 			}