From 75ab2818174298c863842f9cdcc3f42b725945af Mon Sep 17 00:00:00 2001 From: pharan Date: Mon, 27 Feb 2017 00:41:11 +0800 Subject: [PATCH] [unity] Tint Black support via uv2,uv3. --- .../Editor/SkeletonRendererInspector.cs | 7 +- .../Arrays/ArraysMeshGenerator.cs | 51 +++++++++ .../Arrays/ArraysSimpleMeshGenerator.cs | 11 ++ .../Arrays/ArraysSubmeshSetMeshGenerator.cs | 11 +- .../Arrays/ArraysSubmeshedMeshGenerator.cs | 11 ++ .../Mesh Generation/ISimpleMeshGenerator.cs | 1 + .../ISubmeshedMeshGenerator.cs | 2 + .../Editor/SkeletonGraphicInspector.cs | 4 +- .../SkeletonGraphic/SkeletonGraphic.cs | 2 + .../Shaders/Skeleton TintBlack.shader | 106 ++++++++++++++++++ .../Shaders/Skeleton TintBlack.shader.meta | 7 ++ .../Assets/spine-unity/SkeletonRenderer.cs | 19 ++++ 12 files changed, 227 insertions(+), 5 deletions(-) create mode 100644 spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader create mode 100644 spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader.meta diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs index c72e03421..6021648bc 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs +++ b/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(); } diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs index 7d807def9..d40973c7a 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs +++ b/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 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++; + } + } + } + } + } + /// Fills Unity vertex data buffers with verts from the Spine Skeleton. /// Spine.Skeleton source of the drawOrder array /// Slot index of the first slot. diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs index 0e9ead5d1..e4d9de211 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs +++ b/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) { diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs index 9c0e6e11a..90f60d8b5 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs +++ b/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. diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs index 691d2e3be..dc7e3f43b 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs +++ b/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) { diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs index 815964115..fc440cc5f 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs +++ b/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; } } } diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs index 988dac63b..dda27ccec 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs +++ b/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; } } /// Primarily a collection of Submesh Instructions. This constitutes instructions for how to construct a mesh containing submeshes. diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs index c312eef3f..e888b936f 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs +++ b/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_); diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs index 4e41e20d3..1e2854e01 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs +++ b/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 diff --git a/spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader b/spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader new file mode 100644 index 000000000..12008abc5 --- /dev/null +++ b/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 + } + } +} diff --git a/spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader.meta b/spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader.meta new file mode 100644 index 000000000..2801fe0de --- /dev/null +++ b/spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: deee23ab4aa38564ead2ac05e112c169 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs index 88e96e635..64e477cd5 100644 --- a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs +++ b/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)