Przeglądaj źródła

[unity] Tint Black support via uv2,uv3.

pharan 8 lat temu
rodzic
commit
75ab281817

+ 5 - 2
spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs

@@ -43,12 +43,12 @@ namespace Spine.Unity.Editor {
 		protected static bool advancedFoldout;
 		protected static bool showBoneNames, showPaths, showShapes, showConstraints = true;
 
-		protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, separatorSlotNames, frontFacing, zSpacing, pmaVertexColors, clearStateOnDisable;
+		protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, separatorSlotNames, frontFacing, zSpacing, pmaVertexColors, clearStateOnDisable, tintBlack;
 		protected SpineInspectorUtility.SerializedSortingProperties sortingProperties;
 		protected bool isInspectingPrefab;
 
 		protected GUIContent SkeletonDataAssetLabel, SkeletonUtilityButtonContent;
-		protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, MeshesLabel, ImmubleTrianglesLabel;
+		protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, MeshesLabel, ImmubleTrianglesLabel, TintBlackLabel;
 		protected GUIContent NormalsLabel, TangentsLabel;
 		const string ReloadButtonLabel = "Reload";
 
@@ -83,6 +83,7 @@ namespace Spine.Unity.Editor {
 			ZSpacingLabel = new GUIContent("Z Spacing", "A value other than 0 adds a space between each rendered attachment to prevent Z Fighting when using shaders that read or write to the depth buffer. Large values may cause unwanted parallax and spaces depending on camera setup.");
 			NormalsLabel = new GUIContent("Add Normals", "Use this if your shader requires vertex normals. A more efficient solution for 2D setups is to modify the shader to assume a single normal value for the whole mesh.");
 			TangentsLabel = new GUIContent("Solve Tangents", "Calculates the tangents per frame. Use this if you are using lit shaders (usually with normal maps) that require vertex tangents.");
+			TintBlackLabel = new GUIContent("Tint Black", "Adds black tint vertex data to the mesh as UV2 and UV3. Black tinting requires that the shader interpret UV2 and UV3 as black tint colors for this effect to work. You may also use the default [Spine/Skeleton Tint Black] shader.\n\nIf you only need to tint the whole skeleton and not individual parts, the [Spine/Skeleton Tint] shader is recommended for better efficiency and changing/animating the _Black material property via MaterialPropertyBlock.");
 
 			var so = this.serializedObject;
 			skeletonDataAsset = so.FindProperty("skeletonDataAsset");
@@ -93,6 +94,7 @@ namespace Spine.Unity.Editor {
 			immutableTriangles = so.FindProperty("immutableTriangles");
 			pmaVertexColors = so.FindProperty("pmaVertexColors");
 			clearStateOnDisable = so.FindProperty("clearStateOnDisable");
+			tintBlack = so.FindProperty("tintBlack");
 
 			separatorSlotNames = so.FindProperty("separatorSlotNames");
 			separatorSlotNames.isExpanded = true;
@@ -237,6 +239,7 @@ namespace Spine.Unity.Editor {
 							// Optimization options
 							EditorGUILayout.PropertyField(meshes, MeshesLabel);
 							EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel);
+							EditorGUILayout.PropertyField(tintBlack, TintBlackLabel);
 							EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel);
 							EditorGUILayout.Space();
 						}

+ 51 - 0
spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs

@@ -39,6 +39,8 @@ namespace Spine.Unity.MeshGeneration {
 		public bool AddNormals { get { return addNormals; } set { addNormals = value; } }
 		protected bool addTangents;
 		public bool AddTangents { get { return addTangents; } set { addTangents = value; } }
+		protected bool addBlackTint;
+		public bool AddBlackTint { get { return addBlackTint; } set { addBlackTint = value; } }
 		#endregion
 
 		protected float[] attachmentVertexBuffer = new float[8];
@@ -52,6 +54,8 @@ namespace Spine.Unity.MeshGeneration {
 		protected Vector4[] meshTangents;
 		protected Vector2[] tempTanBuffer;
 
+		protected Vector2[] uv2, uv3; // Black tint
+
 		public void TryAddNormalsTo (Mesh mesh, int targetVertexCount) {
 			#if SPINE_OPTIONAL_NORMALS
 			if (addNormals) {
@@ -88,6 +92,19 @@ namespace Spine.Unity.MeshGeneration {
 			return verticesWasResized;
 		}
 
+		public static bool EnsureSize (int targetVertexCount, ref Vector2[] buffer) {
+			Vector2[] buff = buffer;
+			bool verticesWasResized = (buffer == null || targetVertexCount > buffer.Length);
+			if (verticesWasResized) {
+				buffer = new Vector2[targetVertexCount];
+			} else {
+				Vector3 zero = Vector3.zero;
+				for (int i = targetVertexCount, n = buff.Length; i < n; i++)
+					buff[i] = zero;
+			}
+			return verticesWasResized;
+		}
+
 		public static bool EnsureTriangleBuffersSize (ExposedList<SubmeshTriangleBuffer> submeshBuffers, int targetSubmeshCount, SubmeshInstruction[] instructionItems) {
 			bool submeshBuffersWasResized = submeshBuffers.Count < targetSubmeshCount;
 			if (submeshBuffersWasResized) {
@@ -98,6 +115,40 @@ namespace Spine.Unity.MeshGeneration {
 			return submeshBuffersWasResized;
 		}
 
+		public static void FillBlackUVs (Skeleton skeleton, int startSlot, int endSlot, Vector2[] uv2, Vector2[] uv3, int vertexIndex, bool renderMeshes = true) {
+			var skeletonDrawOrderItems = skeleton.DrawOrder.Items;
+			Vector2 rg, b2;
+			int vi = vertexIndex;
+			b2.y = 1f;
+
+			// drawOrder[endSlot] is excluded
+			for (int slotIndex = startSlot; slotIndex < endSlot; slotIndex++) {
+				var slot = skeletonDrawOrderItems[slotIndex];
+				var attachment = slot.attachment;
+
+				rg.x = slot.r2; //r
+				rg.y = slot.g2; //g
+				b2.x = slot.b2; //b
+
+				var regionAttachment = attachment as RegionAttachment;
+				if (regionAttachment != null) {
+					uv2[vi] = rg; uv2[vi + 1] = rg; uv2[vi + 2] = rg; uv2[vi + 3] = rg;
+					uv3[vi] = b2; uv3[vi + 1] = b2; uv3[vi + 2] = b2; uv3[vi + 3] = b2;
+					vi += 4;
+				} else if (renderMeshes) {
+					var meshAttachment = attachment as MeshAttachment;
+					if (meshAttachment != null) {
+						int meshVertexCount = meshAttachment.worldVerticesLength;
+						for (int iii = 0; iii < meshVertexCount; iii += 2) {
+							uv2[vi] = rg;
+							uv3[vi] = b2;
+							vi++;
+						}
+					}
+				}
+			}
+		}
+
 		/// <summary>Fills Unity vertex data buffers with verts from the Spine Skeleton.</summary>
 		/// <param name="skeleton">Spine.Skeleton source of the drawOrder array</param>
 		/// <param name="startSlot">Slot index of the first slot.</param>

+ 11 - 0
spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs

@@ -74,6 +74,11 @@ namespace Spine.Unity.MeshGeneration {
 
 			// STEP 2 : Ensure buffers are the correct size
 			ArraysMeshGenerator.EnsureSize(totalVertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32);
+			if (addBlackTint) {
+				ArraysMeshGenerator.EnsureSize(totalVertexCount, ref this.uv2);
+				ArraysMeshGenerator.EnsureSize(totalVertexCount, ref this.uv3);
+			}
+
 			this.triangles = this.triangles ?? new int[totalTriangleCount];
 				
 			// STEP 3 : Update vertex buffer
@@ -92,6 +97,7 @@ namespace Spine.Unity.MeshGeneration {
 				meshBoundsMax.z = zFauxHalfThickness * scale;
 
 				int vertexIndex = 0;
+				if (addBlackTint) ArraysMeshGenerator.FillBlackUVs(skeleton, 0, drawOrderCount, this.uv2, this.uv3, vertexIndex);
 				ArraysMeshGenerator.FillVerts(skeleton, 0, drawOrderCount, this.ZSpacing, this.PremultiplyVertexColors, this.meshVertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
 
 				// Apply scale to vertices
@@ -116,6 +122,11 @@ namespace Spine.Unity.MeshGeneration {
 			mesh.uv = meshUVs;
 			mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
 			mesh.triangles = triangles;
+			if (addBlackTint) {
+				mesh.uv2 = this.uv2;
+				mesh.uv3 = this.uv3;
+			}
+
 			TryAddNormalsTo(mesh, totalVertexCount);
 
 			if (addTangents) { 

+ 9 - 2
spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs

@@ -69,6 +69,10 @@ namespace Spine.Unity.MeshGeneration {
 			// STEP 1: Ensure correct buffer sizes.
 			bool vertBufferResized = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32); 
 			bool submeshBuffersResized = ArraysMeshGenerator.EnsureTriangleBuffersSize(submeshBuffers, submeshCount, currentInstructionsItems);
+			if (addBlackTint) {
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv2);
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv3);
+			}
 
 			// STEP 2: Update buffers based on Skeleton.
 
@@ -109,6 +113,7 @@ namespace Spine.Unity.MeshGeneration {
 					var ca = skeletonDrawOrderItems[i].attachment;
 					if (ca != null) workingAttachments.Add(ca); // Includes BoundingBoxes. This is ok.
 				}
+				if (addBlackTint) ArraysMeshGenerator.FillBlackUVs(skeleton, startSlot, endSlot, this.uv2, this.uv3, vertexIndex);
 				ArraysMeshGenerator.FillVerts(skeleton, startSlot, endSlot, zSpacing, this.PremultiplyVertexColors, this.meshVertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
 			}
 
@@ -135,13 +140,15 @@ namespace Spine.Unity.MeshGeneration {
 					meshVertices[i].y *= scale;
 					//meshVertices[i].z *= scale;
 				}
-					
 			}
 
 			// STEP 3: Assign the buffers into the Mesh.
 			smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, workingAttachments, currentInstructions);
 			mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
-
+			if (addBlackTint) {
+				mesh.uv2 = this.uv2;
+				mesh.uv3 = this.uv3;
+			}
 
 			if (structureDoesntMatch) {
 				// Push new triangles if doesn't match.

+ 11 - 0
spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs

@@ -160,6 +160,11 @@ namespace Spine.Unity.MeshGeneration {
 			bool vertBufferResized = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32);
 			Vector3[] vertices = this.meshVertices;
 
+			if (addBlackTint) {
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv2);
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv3);
+			}
+
 			// STEP 2: Update buffers based on Skeleton.
 			float zSpacing = this.ZSpacing;
 			Vector3 meshBoundsMin;
@@ -190,7 +195,9 @@ namespace Spine.Unity.MeshGeneration {
 				int start = submeshInstruction.startSlot;
 				int end = submeshInstruction.endSlot;
 				var skeleton = submeshInstruction.skeleton;
+				if (addBlackTint) ArraysMeshGenerator.FillBlackUVs(skeleton, start, end, this.uv2, this.uv3, vertexIndex);
 				ArraysMeshGenerator.FillVerts(skeleton, start, end, zSpacing, this.PremultiplyVertexColors, vertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
+
 				if (structureDoesntMatch) {
 					var currentBuffer = submeshBuffers.Items[submeshIndex];
 					bool isLastSubmesh = (submeshIndex == submeshCount - 1);
@@ -207,6 +214,10 @@ namespace Spine.Unity.MeshGeneration {
 
 			// STEP 3: Assign the buffers into the Mesh.
 			smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, meshInstructions);
+			if (addBlackTint) {
+				mesh.uv2 = this.uv2;
+				mesh.uv3 = this.uv3;
+			}
 			mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
 
 			if (structureDoesntMatch) {

+ 1 - 0
spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs

@@ -43,5 +43,6 @@ namespace Spine.Unity.MeshGeneration {
 
 		bool AddNormals { get; set; }
 		bool AddTangents { get; set; }
+		bool AddBlackTint { get; set; }
 	}
 }

+ 2 - 0
spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs

@@ -47,6 +47,7 @@ namespace Spine.Unity.MeshGeneration {
 		bool PremultiplyVertexColors { get; set; }
 		bool AddNormals { get; set; }
 		bool AddTangents { get; set; }
+		bool AddBlackTint { get; set; }
 	}
 
 	// ISubmeshSetMeshGenerator
@@ -62,6 +63,7 @@ namespace Spine.Unity.MeshGeneration {
 		bool PremultiplyVertexColors { get; set; }
 		bool AddNormals { get; set; }
 		bool AddTangents { get; set; }
+		bool AddBlackTint { get; set; }
 	}
 
 	/// <summary>Primarily a collection of Submesh Instructions. This constitutes instructions for how to construct a mesh containing submeshes.</summary>

+ 3 - 1
spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs

@@ -44,8 +44,8 @@ namespace Spine.Unity.Editor {
 	public class SkeletonGraphicInspector : UnityEditor.Editor {
 		SerializedProperty material_, color_;
 		SerializedProperty skeletonDataAsset_, initialSkinName_;
-		SerializedProperty startingAnimation_, startingLoop_, timeScale_, freeze_, unscaledTime_;
 	#if !PREUNITY_5_2
+		SerializedProperty startingAnimation_, startingLoop_, timeScale_, freeze_, unscaledTime_, tintBlack_;
 		SerializedProperty raycastTarget_;
 
 		SkeletonGraphic thisSkeletonGraphic;
@@ -62,6 +62,7 @@ namespace Spine.Unity.Editor {
 			// SkeletonRenderer
 			skeletonDataAsset_ = so.FindProperty("skeletonDataAsset");
 			initialSkinName_ = so.FindProperty("initialSkinName");
+			//tintBlack_ = so.FindProperty("tintBlack");
 
 			// SkeletonAnimation
 			startingAnimation_ = so.FindProperty("startingAnimation");
@@ -87,6 +88,7 @@ namespace Spine.Unity.Editor {
 
 			EditorGUILayout.Space();
 			EditorGUILayout.PropertyField(initialSkinName_);
+			//EditorGUILayout.PropertyField(tintBlack_);
 			EditorGUILayout.Space();
 			EditorGUILayout.LabelField("Animation", EditorStyles.boldLabel);
 			EditorGUILayout.PropertyField(startingAnimation_);

+ 2 - 0
spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs

@@ -50,6 +50,7 @@ namespace Spine.Unity {
 		public float timeScale = 1f;
 		public bool freeze;
 		public bool unscaledTime;
+		//public bool tintBlack = false;
 
 		#if UNITY_EDITOR
 		protected override void OnValidate () {
@@ -180,6 +181,7 @@ namespace Spine.Unity {
 
 			this.skeleton = new Skeleton(skeletonData);
 			this.spineMeshGenerator = new Spine.Unity.MeshGeneration.ArraysSimpleMeshGenerator(); // You can switch this out with any other implementer of Spine.Unity.MeshGeneration.ISimpleMeshGenerator
+			//this.spineMeshGenerator.AddBlackTint = this.tintBlack;
 			this.spineMeshGenerator.PremultiplyVertexColors = true;
 
 			// Set the initial Skin and Animation

+ 106 - 0
spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader

@@ -0,0 +1,106 @@
+// Spine/Skeleton Tint Black
+// - Two color tint
+// - UV2 and UV3 as Black Tint color.
+// - Final black tint is (UV black data and _Black/"Black Point")
+// - unlit
+// - Premultiplied alpha blending
+// - No depth, no backface culling, no fog.
+
+Shader "Spine/Skeleton Tint Black" {
+	Properties {
+		_Color ("Tint Color", Color) = (1,1,1,1)
+		_Black ("Black Point", Color) = (0,0,0,0)
+		[NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {}
+		_Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1
+	}
+
+	SubShader {
+		Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
+		LOD 100
+
+		Fog { Mode Off }
+		Cull Off
+		ZWrite Off
+		Blend One OneMinusSrcAlpha
+		Lighting Off
+
+		Pass {
+			CGPROGRAM
+			#pragma vertex vert
+			#pragma fragment frag
+			#include "UnityCG.cginc"
+			uniform sampler2D _MainTex;
+			uniform float4 _Color;
+			uniform float4 _Black;
+
+			struct VertexInput {
+				float4 vertex : POSITION;
+				float2 uv : TEXCOORD0;
+				float2 uv1 : TEXCOORD1;
+				float2 uv2 : TEXCOORD2;
+				float4 vertexColor : COLOR;
+			};
+
+			struct VertexOutput {
+				float4 pos : SV_POSITION;
+				float2 uv : TEXCOORD0;
+				float2 uv1 : TEXCOORD1;
+				float2 uv2 : TEXCOORD2;
+				float4 vertexColor : COLOR;
+			};
+
+			VertexOutput vert (VertexInput v) {
+				VertexOutput o;
+				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
+				o.uv = v.uv;
+				o.vertexColor = v.vertexColor * float4(_Color.rgb * _Color.a, _Color.a); // Combine a PMA version of _Color with vertexColor.
+				o.uv1 = v.uv1;
+				o.uv2 = v.uv2;
+				return o;
+			}
+
+			float4 frag (VertexOutput i) : COLOR {
+				float4 texColor = tex2D(_MainTex, i.uv);
+				return (texColor * i.vertexColor) + float4(((1-texColor.rgb) * texColor.a * (_Black.rgb + float3(i.uv1.r, i.uv1.g, i.uv2.r))), 1);
+			}
+			ENDCG
+		}
+
+		Pass {
+			Name "Caster"
+			Tags { "LightMode"="ShadowCaster" }
+			Offset 1, 1
+
+			ZWrite On
+			ZTest LEqual
+
+			CGPROGRAM
+			#pragma vertex vert
+			#pragma fragment frag
+			#pragma multi_compile_shadowcaster
+			#pragma fragmentoption ARB_precision_hint_fastest
+			#include "UnityCG.cginc"
+			struct v2f { 
+				V2F_SHADOW_CASTER;
+				float2 uv : TEXCOORD1;
+			};
+
+			v2f vert (appdata_base v) {
+				v2f o;
+				TRANSFER_SHADOW_CASTER(o)
+				o.uv = v.texcoord;
+				return o;
+			}
+
+			uniform sampler2D _MainTex;
+			uniform fixed _Cutoff;
+
+			float4 frag (v2f i) : COLOR {
+				fixed4 texcol = tex2D(_MainTex, i.uv);
+				clip(texcol.a - _Cutoff);
+				SHADOW_CASTER_FRAGMENT(i)
+			}
+			ENDCG
+		}
+	}
+}

+ 7 - 0
spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: deee23ab4aa38564ead2ac05e112c169
+ShaderImporter:
+  defaultTextures: []
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 19 - 0
spine-unity/Assets/spine-unity/SkeletonRenderer.cs

@@ -65,6 +65,7 @@ namespace Spine.Unity {
 		public bool renderMeshes = true, immutableTriangles;
 		public bool pmaVertexColors = true;
 		public bool clearStateOnDisable = false;
+		public bool tintBlack = false;
 
 		#if SPINE_OPTIONAL_NORMALS
 		public bool calculateNormals;
@@ -131,6 +132,10 @@ namespace Spine.Unity {
 		Vector3[] vertices;
 		Color32[] colors;
 		Vector2[] uvs;
+
+		Vector2[] uv2;
+		Vector2[] uv3;
+
 		#if SPINE_OPTIONAL_NORMALS
 		Vector3[] normals;
 		#endif
@@ -423,6 +428,10 @@ namespace Spine.Unity {
 			// STEP 2. Update vertex buffer based on verts from the attachments.  ============================================================
 			// Uses values that were also stored in workingInstruction.
 			bool vertexCountIncreased = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.vertices, ref this.uvs, ref this.colors);
+			if (tintBlack) {
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv2);
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv3);
+			}
 			#if SPINE_OPTIONAL_NORMALS
 			if (vertexCountIncreased && calculateNormals) {
 				Vector3[] localNormals = this.normals = new Vector3[vertexCount];
@@ -452,9 +461,14 @@ namespace Spine.Unity {
 				}
 			}
 			int vertexIndex = 0;
+
+			if (tintBlack)
+				ArraysMeshGenerator.FillBlackUVs(skeleton, 0, drawOrderCount, this.uv2, this.uv3, vertexIndex, renderMeshes); // This needs to be called before FillVerts so we have the correct vertexIndex argument.
+
 			ArraysMeshGenerator.FillVerts(skeleton, 0, drawOrderCount, this.zSpacing, pmaVertexColors, this.vertices, this.uvs, this.colors, ref vertexIndex, ref tempVertices, ref meshBoundsMin, ref meshBoundsMax, renderMeshes);
 
 
+
 			// Step 3. Move the mesh data into a UnityEngine.Mesh ============================================================
 			var currentSmartMesh = doubleBufferedMesh.GetNext();	// Double-buffer for performance.
 			var currentMesh = currentSmartMesh.mesh;
@@ -463,6 +477,11 @@ namespace Spine.Unity {
 			currentMesh.uv = uvs;
 			currentMesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
 
+			if (tintBlack) {
+				currentMesh.uv2 = this.uv2;
+				currentMesh.uv3 = this.uv3;
+			}
+
 			var currentSmartMeshInstructionUsed = currentSmartMesh.instructionUsed;
 			#if SPINE_OPTIONAL_NORMALS
 			if (calculateNormals && currentSmartMeshInstructionUsed.vertexCount < vertexCount)