mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 07:14:55 +08:00
[unity] SkeletonRenderer Update (Tangents, MeshGeneration) (#646)
This commit is contained in:
parent
b564ad4503
commit
77c4cdc1e4
@ -30,7 +30,6 @@
|
||||
*****************************************************************************/
|
||||
#define NO_PREFAB_MESH
|
||||
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
@ -65,23 +64,24 @@ namespace Spine.Unity.Editor {
|
||||
}
|
||||
|
||||
protected virtual void DrawInspectorGUI () {
|
||||
// JOHN: todo: support multiediting.
|
||||
SkeletonRenderer component = (SkeletonRenderer)target;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PropertyField(skeletonDataAsset);
|
||||
const string ReloadButtonLabel = "Reload";
|
||||
float reloadWidth = GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20;
|
||||
if (GUILayout.Button(ReloadButtonLabel, GUILayout.Width(reloadWidth))) {
|
||||
if (component.skeletonDataAsset != null) {
|
||||
foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) {
|
||||
if (aa != null)
|
||||
aa.Reset();
|
||||
using (new EditorGUILayout.HorizontalScope()) {
|
||||
EditorGUILayout.PropertyField(skeletonDataAsset);
|
||||
const string ReloadButtonLabel = "Reload";
|
||||
float reloadWidth = GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20;
|
||||
if (GUILayout.Button(ReloadButtonLabel, GUILayout.Width(reloadWidth))) {
|
||||
if (component.skeletonDataAsset != null) {
|
||||
foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) {
|
||||
if (aa != null)
|
||||
aa.Reset();
|
||||
}
|
||||
component.skeletonDataAsset.Reset();
|
||||
}
|
||||
component.skeletonDataAsset.Reset();
|
||||
component.Initialize(true);
|
||||
}
|
||||
component.Initialize(true);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (!component.valid) {
|
||||
component.Initialize(true);
|
||||
@ -100,10 +100,10 @@ namespace Spine.Unity.Editor {
|
||||
|
||||
// Initial skin name.
|
||||
{
|
||||
String[] skins = new String[component.skeleton.Data.Skins.Count];
|
||||
string[] skins = new string[component.skeleton.Data.Skins.Count];
|
||||
int skinIndex = 0;
|
||||
for (int i = 0; i < skins.Length; i++) {
|
||||
String skinNameString = component.skeleton.Data.Skins.Items[i].Name;
|
||||
string skinNameString = component.skeleton.Data.Skins.Items[i].Name;
|
||||
skins[i] = skinNameString;
|
||||
if (skinNameString == initialSkinName.stringValue)
|
||||
skinIndex = i;
|
||||
@ -115,40 +115,33 @@ namespace Spine.Unity.Editor {
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Sorting Layers
|
||||
{
|
||||
SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true);
|
||||
}
|
||||
SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true);
|
||||
|
||||
// More Render Options...
|
||||
{
|
||||
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
|
||||
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
|
||||
EditorGUI.indentLevel++;
|
||||
advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced");
|
||||
if (advancedFoldout) {
|
||||
EditorGUI.indentLevel++;
|
||||
advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced");
|
||||
if (advancedFoldout) {
|
||||
EditorGUI.indentLevel++;
|
||||
SeparatorsField(separatorSlotNames);
|
||||
EditorGUILayout.PropertyField(meshes,
|
||||
new GUIContent("Render Mesh Attachments", "Disable to optimize rendering for skeletons that don't use Mesh Attachments"));
|
||||
EditorGUILayout.PropertyField(immutableTriangles,
|
||||
new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility"));
|
||||
EditorGUILayout.Space();
|
||||
SeparatorsField(separatorSlotNames);
|
||||
EditorGUILayout.PropertyField(meshes,
|
||||
new GUIContent("Render MeshAttachments", "Disable to optimize rendering for skeletons that don't use Mesh Attachments"));
|
||||
EditorGUILayout.PropertyField(immutableTriangles,
|
||||
new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility"));
|
||||
EditorGUILayout.Space();
|
||||
|
||||
const float MinZSpacing = -0.1f;
|
||||
const float MaxZSpacing = 0f;
|
||||
EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing);
|
||||
const float MinZSpacing = -0.1f;
|
||||
const float MaxZSpacing = 0f;
|
||||
EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing);
|
||||
|
||||
// Optional fields. May be disabled in SkeletonRenderer.
|
||||
if (normals != null) {
|
||||
EditorGUILayout.PropertyField(normals);
|
||||
EditorGUILayout.PropertyField(tangents);
|
||||
}
|
||||
if (frontFacing != null)
|
||||
EditorGUILayout.PropertyField(frontFacing);
|
||||
// Optional fields. May be disabled in SkeletonRenderer.
|
||||
if (normals != null) EditorGUILayout.PropertyField(normals, new GUIContent("Add Normals"));
|
||||
if (tangents != null) EditorGUILayout.PropertyField(tangents, new GUIContent("Solve Tangents"));
|
||||
if (frontFacing != null) EditorGUILayout.PropertyField(frontFacing);
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,7 +155,7 @@ namespace Spine.Unity.Editor {
|
||||
}
|
||||
|
||||
override public void OnInspectorGUI () {
|
||||
serializedObject.Update();
|
||||
//serializedObject.Update();
|
||||
DrawInspectorGUI();
|
||||
if (serializedObject.ApplyModifiedProperties() ||
|
||||
(UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed")
|
||||
|
||||
@ -34,8 +34,11 @@ using UnityEngine;
|
||||
namespace Spine.Unity.MeshGeneration {
|
||||
public class ArraysMeshGenerator {
|
||||
#region Settings
|
||||
protected bool premultiplyVertexColors = true;
|
||||
public bool PremultiplyVertexColors { get { return this.premultiplyVertexColors; } set { this.premultiplyVertexColors = value; } }
|
||||
public bool PremultiplyVertexColors { get; set; }
|
||||
protected bool addNormals;
|
||||
public bool AddNormals { get { return addNormals; } set { addNormals = value; } }
|
||||
protected bool addTangents { get; set; }
|
||||
public bool AddTangents { get { return addTangents; } set { addTangents = value; } }
|
||||
#endregion
|
||||
|
||||
protected float[] attachmentVertexBuffer = new float[8];
|
||||
@ -43,25 +46,22 @@ namespace Spine.Unity.MeshGeneration {
|
||||
protected Color32[] meshColors32;
|
||||
protected Vector2[] meshUVs;
|
||||
|
||||
|
||||
protected bool generateNormals = false;
|
||||
public bool GenerateNormals {
|
||||
get { return generateNormals; }
|
||||
set { generateNormals = value; }
|
||||
}
|
||||
|
||||
Vector3[] meshNormals;
|
||||
#if SPINE_OPTIONAL_NORMALS
|
||||
protected Vector3[] meshNormals;
|
||||
#endif
|
||||
protected Vector4[] meshTangents;
|
||||
protected Vector2[] tempTanBuffer;
|
||||
|
||||
public void TryAddNormalsTo (Mesh mesh, int targetVertexCount) {
|
||||
#if SPINE_OPTIONAL_NORMALS
|
||||
if (generateNormals) {
|
||||
bool verticesWasResized = this.meshNormals == null || targetVertexCount > meshNormals.Length;
|
||||
if (addNormals) {
|
||||
bool verticesWasResized = this.meshNormals == null || meshNormals.Length < targetVertexCount;
|
||||
if (verticesWasResized) {
|
||||
this.meshNormals = new Vector3[targetVertexCount];
|
||||
Vector3 normal = new Vector3(0, 0, -1);
|
||||
Vector3 fixedNormal = new Vector3(0, 0, -1f);
|
||||
Vector3[] normals = this.meshNormals;
|
||||
for (int i = 0; i < targetVertexCount; i++)
|
||||
normals[i] = normal;
|
||||
normals[i] = fixedNormal;
|
||||
}
|
||||
|
||||
mesh.normals = this.meshNormals;
|
||||
@ -69,7 +69,8 @@ namespace Spine.Unity.MeshGeneration {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Ensures the sizes of the passed array references. If they are not the correct size, a new array will be assigned to the references.</summary>
|
||||
/// <returns><c>true</c>, if a resize occurred, <c>false</c> otherwise.</returns>
|
||||
public static bool EnsureSize (int targetVertexCount, ref Vector3[] vertices, ref Vector2[] uvs, ref Color32[] colors) {
|
||||
Vector3[] verts = vertices;
|
||||
bool verticesWasResized = verts == null || targetVertexCount > verts.Length;
|
||||
@ -97,12 +98,10 @@ namespace Spine.Unity.MeshGeneration {
|
||||
return submeshBuffersWasResized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills vertex arrays.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="endSlot">The index bounding the slot list. endSlot - 1 is the last slot to be added.</param>
|
||||
/// <param name="endSlot">The index bounding the slot list. [endSlot - 1] is the last slot to be added.</param>
|
||||
/// <param name="zSpacing">Spacing along the z-axis between attachments.</param>
|
||||
/// <param name="pmaColors">If set to <c>true</c>, vertex colors will be premultiplied. This will also enable additive.</param>
|
||||
/// <param name="verts">Vertex positions array. </param>
|
||||
@ -112,7 +111,8 @@ namespace Spine.Unity.MeshGeneration {
|
||||
/// <param name="tempVertBuffer">A temporary vertex position buffer for attachment position values.</param>
|
||||
/// <param name="boundsMin">Reference to the running calculated minimum bounds.</param>
|
||||
/// <param name="boundsMax">Reference to the running calculated maximum bounds.</param>
|
||||
public static void FillVerts (Skeleton skeleton, int startSlot, int endSlot, float zSpacing, bool pmaColors, Vector3[] verts, Vector2[] uvs, Color32[] colors, ref int vertexIndex, ref float[] tempVertBuffer, ref Vector3 boundsMin, ref Vector3 boundsMax) {
|
||||
/// <param name = "renderMeshes">Include MeshAttachments. If false, it will ignore MeshAttachments.</param>
|
||||
public static void FillVerts (Skeleton skeleton, int startSlot, int endSlot, float zSpacing, bool pmaColors, Vector3[] verts, Vector2[] uvs, Color32[] colors, ref int vertexIndex, ref float[] tempVertBuffer, ref Vector3 boundsMin, ref Vector3 boundsMax, bool renderMeshes = true) {
|
||||
Color32 color;
|
||||
var skeletonDrawOrderItems = skeleton.DrawOrder.Items;
|
||||
float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b;
|
||||
@ -183,7 +183,7 @@ namespace Spine.Unity.MeshGeneration {
|
||||
else if (y4 > bmax.y) bmax.y = y4;
|
||||
|
||||
vi += 4;
|
||||
} else {
|
||||
} else if (renderMeshes) {
|
||||
var meshAttachment = attachment as MeshAttachment;
|
||||
if (meshAttachment != null) {
|
||||
int meshVertexCount = meshAttachment.worldVerticesLength;
|
||||
@ -229,22 +229,18 @@ namespace Spine.Unity.MeshGeneration {
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Fills a submesh triangle buffer array.
|
||||
/// </summary>
|
||||
/// <summary>Fills a submesh triangle buffer array.</summary>
|
||||
/// <param name="skeleton">Spine.Skeleton source of draw order slots.</param>
|
||||
/// <param name="triangleCount">The target triangle count.</param>
|
||||
/// <param name="firstVertex">First vertex of this submesh.</param>
|
||||
/// <param name="startSlot">Start slot.</param>
|
||||
/// <param name="endSlot">End slot.</param>
|
||||
/// <param name="triangleBuffer">The triangle buffer array to be filled. This reference will be replaced in case the triangle values don't fit.</param>
|
||||
/// <param name="bufferTriangleCount">The current triangle count of the submesh buffer. This is not always equal to triangleBuffer.Length because for last submeshes, length may be larger than needed.</param>
|
||||
/// <param name="isLastSubmesh">If set to <c>true</c>, the triangle buffer is allowed to be larger than needed.</param>
|
||||
public static void FillTriangles (Skeleton skeleton, int triangleCount, int firstVertex, int startSlot, int endSlot, ref int[] triangleBuffer, bool isLastSubmesh) {
|
||||
public static void FillTriangles (ref int[] triangleBuffer, Skeleton skeleton, int triangleCount, int firstVertex, int startSlot, int endSlot, bool isLastSubmesh) {
|
||||
int trianglesCapacity = triangleBuffer.Length;
|
||||
var tris = triangleBuffer;
|
||||
int[] tris = triangleBuffer;
|
||||
|
||||
// Ensure triangleBuffer size.
|
||||
if (isLastSubmesh) {
|
||||
if (trianglesCapacity > triangleCount) {
|
||||
for (int i = triangleCount; i < trianglesCapacity; i++)
|
||||
@ -256,45 +252,170 @@ namespace Spine.Unity.MeshGeneration {
|
||||
triangleBuffer = tris = new int[triangleCount];
|
||||
}
|
||||
|
||||
// Iterate through submesh slots and store the triangles.
|
||||
int triangleIndex = 0;
|
||||
int afv = firstVertex; // attachment first vertex
|
||||
var skeletonDrawOrderItems = skeleton.drawOrder.Items;
|
||||
for (int i = startSlot, n = endSlot; i < n; i++) {
|
||||
for (int i = startSlot, n = endSlot, ti = 0, afv = firstVertex; i < n; i++) {
|
||||
var attachment = skeletonDrawOrderItems[i].attachment;
|
||||
|
||||
// RegionAttachment
|
||||
if (attachment is RegionAttachment) {
|
||||
tris[triangleIndex] = afv; tris[triangleIndex + 1] = afv + 2; tris[triangleIndex + 2] = afv + 1;
|
||||
tris[triangleIndex + 3] = afv + 2; tris[triangleIndex + 4] = afv + 3; tris[triangleIndex + 5] = afv + 1;
|
||||
triangleIndex += 6;
|
||||
tris[ti] = afv;
|
||||
tris[ti + 1] = afv + 2;
|
||||
tris[ti + 2] = afv + 1;
|
||||
tris[ti + 3] = afv + 2;
|
||||
tris[ti + 4] = afv + 3;
|
||||
tris[ti + 5] = afv + 1;
|
||||
ti += 6;
|
||||
afv += 4;
|
||||
} else {
|
||||
int[] attachmentTriangles;
|
||||
int attachmentVertexCount;
|
||||
var meshAttachment = attachment as MeshAttachment;
|
||||
if (meshAttachment != null) {
|
||||
attachmentVertexCount = meshAttachment.worldVerticesLength >> 1; // length/2
|
||||
attachmentTriangles = meshAttachment.triangles;
|
||||
for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++)
|
||||
tris[triangleIndex] = afv + attachmentTriangles[ii];
|
||||
|
||||
afv += attachmentVertexCount;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} // Done adding current submesh triangles
|
||||
|
||||
// MeshAttachment
|
||||
var meshAttachment = attachment as MeshAttachment;
|
||||
if (meshAttachment != null) {
|
||||
int[] attachmentTriangles = meshAttachment.triangles;
|
||||
for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, ti++)
|
||||
tris[ti] = afv + attachmentTriangles[ii];
|
||||
|
||||
afv += meshAttachment.worldVerticesLength >> 1; // length/2;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void FillTrianglesQuads (ref int[] triangleBuffer, ref int storedTriangleCount, ref int storedFirstVertex, int instructionsFirstVertex, int instructionTriangleCount, bool isLastSubmesh) {
|
||||
int trianglesCapacity = triangleBuffer.Length;
|
||||
|
||||
if (isLastSubmesh && trianglesCapacity > instructionTriangleCount) {
|
||||
for (int i = instructionTriangleCount; i < trianglesCapacity; i++)
|
||||
triangleBuffer[i] = 0;
|
||||
storedTriangleCount = instructionTriangleCount;
|
||||
} else if (trianglesCapacity != instructionTriangleCount) {
|
||||
triangleBuffer = new int[instructionTriangleCount];
|
||||
storedTriangleCount = 0;
|
||||
}
|
||||
|
||||
// Use stored quad triangles if possible.
|
||||
int[] tris = triangleBuffer;
|
||||
if (storedFirstVertex != instructionsFirstVertex || storedTriangleCount < instructionTriangleCount) { //|| storedTriangleCount == 0
|
||||
storedTriangleCount = instructionTriangleCount;
|
||||
storedFirstVertex = instructionsFirstVertex;
|
||||
int afv = instructionsFirstVertex; // attachment first vertex
|
||||
for (int ti = 0; ti < instructionTriangleCount; ti += 6, afv += 4) {
|
||||
tris[ti] = afv;
|
||||
tris[ti + 1] = afv + 2;
|
||||
tris[ti + 2] = afv + 1;
|
||||
tris[ti + 3] = afv + 2;
|
||||
tris[ti + 4] = afv + 3;
|
||||
tris[ti + 5] = afv + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates a UnityEngine.Bounds struct from minimum and maximum value vectors.</summary>
|
||||
public static Bounds ToBounds (Vector3 boundsMin, Vector3 boundsMax) {
|
||||
Vector3 size = (boundsMax - boundsMin);
|
||||
Vector3 center = boundsMin + size * 0.5f;
|
||||
return new Bounds(center, size);
|
||||
}
|
||||
|
||||
#region TangentSolver2D
|
||||
// Thanks to contributions from forum user ToddRivers
|
||||
|
||||
/// <summary>Step 1 of solving tangents. Ensure you have buffers of the correct size.</summary>
|
||||
/// <param name="tangentBuffer">Eventual Vector4[] tangent buffer to assign to Mesh.tangents.</param>
|
||||
/// <param name="tempTanBuffer">Temporary Vector2 buffer for calculating directions.</param>
|
||||
/// <param name="vertexCount">Number of vertices that require tangents (or the size of the vertex array)</param>
|
||||
public static void SolveTangents2DEnsureSize (ref Vector4[] tangentBuffer, ref Vector2[] tempTanBuffer, int vertexCount) {
|
||||
if (tangentBuffer == null || tangentBuffer.Length < vertexCount)
|
||||
tangentBuffer = new Vector4[vertexCount];
|
||||
|
||||
if (tempTanBuffer == null || tempTanBuffer.Length < vertexCount * 2)
|
||||
tempTanBuffer = new Vector2[vertexCount * 2]; // two arrays in one.
|
||||
}
|
||||
|
||||
/// <summary>Step 2 of solving tangents. Fills (part of) a temporary tangent-solution buffer based on the vertices and uvs defined by a submesh's triangle buffer. Only needs to be called once for single-submesh meshes.</summary>
|
||||
/// <param name="tempTanBuffer">A temporary Vector3[] for calculating tangents.</param>
|
||||
/// <param name="vertices">The mesh's current vertex position buffer.</param>
|
||||
/// <param name="triangles">The mesh's current triangles buffer.</param>
|
||||
/// <param name="uvs">The mesh's current uvs buffer.</param>
|
||||
/// <param name="vertexCount">Number of vertices that require tangents (or the size of the vertex array)</param>
|
||||
/// <param name = "triangleCount">The number of triangle indexes in the triangle array to be used.</param>
|
||||
public static void SolveTangents2DTriangles (Vector2[] tempTanBuffer, int[] triangles, int triangleCount, Vector3[] vertices, Vector2[] uvs, int vertexCount) {
|
||||
Vector2 sdir;
|
||||
Vector2 tdir;
|
||||
for (int t = 0; t < triangleCount; t += 3) {
|
||||
int i1 = triangles[t + 0];
|
||||
int i2 = triangles[t + 1];
|
||||
int i3 = triangles[t + 2];
|
||||
|
||||
Vector3 v1 = vertices[i1];
|
||||
Vector3 v2 = vertices[i2];
|
||||
Vector3 v3 = vertices[i3];
|
||||
|
||||
Vector2 w1 = uvs[i1];
|
||||
Vector2 w2 = uvs[i2];
|
||||
Vector2 w3 = uvs[i3];
|
||||
|
||||
float x1 = v2.x - v1.x;
|
||||
float x2 = v3.x - v1.x;
|
||||
float y1 = v2.y - v1.y;
|
||||
float y2 = v3.y - v1.y;
|
||||
|
||||
float s1 = w2.x - w1.x;
|
||||
float s2 = w3.x - w1.x;
|
||||
float t1 = w2.y - w1.y;
|
||||
float t2 = w3.y - w1.y;
|
||||
|
||||
float div = s1 * t2 - s2 * t1;
|
||||
float r = (div == 0f) ? 0f : 1f / div;
|
||||
|
||||
sdir.x = (t2 * x1 - t1 * x2) * r;
|
||||
sdir.y = (t2 * y1 - t1 * y2) * r;
|
||||
tempTanBuffer[i1] = tempTanBuffer[i2] = tempTanBuffer[i3] = sdir;
|
||||
|
||||
tdir.x = (s1 * x2 - s2 * x1) * r;
|
||||
tdir.y = (s1 * y2 - s2 * y1) * r;
|
||||
tempTanBuffer[vertexCount + i1] = tempTanBuffer[vertexCount + i2] = tempTanBuffer[vertexCount + i3] = tdir;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Step 3 of solving tangents. Fills a Vector4[] tangents array according to values calculated in step 2.</summary>
|
||||
/// <param name="tangents">A Vector4[] that will eventually be used to set Mesh.tangents</param>
|
||||
/// <param name="tempTanBuffer">A temporary Vector3[] for calculating tangents.</param>
|
||||
/// <param name="vertexCount">Number of vertices that require tangents (or the size of the vertex array)</param>
|
||||
public static void SolveTangents2DBuffer (Vector4[] tangents, Vector2[] tempTanBuffer, int vertexCount) {
|
||||
|
||||
Vector4 tangent;
|
||||
tangent.z = 0;
|
||||
for (int i = 0; i < vertexCount; ++i) {
|
||||
Vector2 t = tempTanBuffer[i];
|
||||
|
||||
// t.Normalize() (aggressively inlined). Even better if offloaded to GPU via vertex shader.
|
||||
float magnitude = Mathf.Sqrt(t.x * t.x + t.y * t.y);
|
||||
if (magnitude > 1E-05) {
|
||||
float reciprocalMagnitude = 1f/magnitude;
|
||||
t.x *= reciprocalMagnitude;
|
||||
t.y *= reciprocalMagnitude;
|
||||
}
|
||||
|
||||
Vector2 t2 = tempTanBuffer[vertexCount + i];
|
||||
tangent.x = t.x;
|
||||
tangent.y = t.y;
|
||||
//tangent.z = 0;
|
||||
tangent.w = (t.y * t2.x > t.x * t2.y) ? 1 : -1; // 2D direction calculation. Used for binormals.
|
||||
tangents[i] = tangent;
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SubmeshTriangleBuffer
|
||||
public class SubmeshTriangleBuffer {
|
||||
public int[] triangles;
|
||||
//public int triangleCount;
|
||||
public int triangleCount; // for last/single submeshes with potentially zeroed triangles.
|
||||
public int firstVertex = -1; // for !renderMeshes.
|
||||
|
||||
public SubmeshTriangleBuffer () { }
|
||||
|
||||
public SubmeshTriangleBuffer (int triangleCount) {
|
||||
triangles = new int[triangleCount];
|
||||
|
||||
@ -34,18 +34,15 @@ namespace Spine.Unity.MeshGeneration {
|
||||
public class ArraysSimpleMeshGenerator : ArraysMeshGenerator, ISimpleMeshGenerator {
|
||||
#region Settings
|
||||
protected float scale = 1f;
|
||||
public float Scale {
|
||||
get { return scale; }
|
||||
set { scale = value; }
|
||||
}
|
||||
public float Scale { get { return scale; } set { scale = value; } }
|
||||
public float ZSpacing { get; set; }
|
||||
#endregion
|
||||
|
||||
private Mesh lastGeneratedMesh;
|
||||
protected Mesh lastGeneratedMesh;
|
||||
public Mesh LastGeneratedMesh { get { return lastGeneratedMesh; } }
|
||||
|
||||
readonly DoubleBufferedMesh doubleBufferedMesh = new DoubleBufferedMesh();
|
||||
int[] triangles;
|
||||
int triangleBufferCount;
|
||||
|
||||
public Mesh GenerateMesh (Skeleton skeleton) {
|
||||
int totalVertexCount = 0; // size of vertex arrays
|
||||
@ -80,7 +77,6 @@ namespace Spine.Unity.MeshGeneration {
|
||||
this.triangles = this.triangles ?? new int[totalTriangleCount];
|
||||
|
||||
// STEP 3 : Update vertex buffer
|
||||
const float zSpacing = 0;
|
||||
const float zFauxHalfThickness = 0.01f; // Somehow needs this thickness for bounds to work properly in some cases (eg, Unity UI clipping)
|
||||
Vector3 meshBoundsMin;
|
||||
Vector3 meshBoundsMax;
|
||||
@ -96,7 +92,7 @@ namespace Spine.Unity.MeshGeneration {
|
||||
meshBoundsMax.z = zFauxHalfThickness * scale;
|
||||
|
||||
int vertexIndex = 0;
|
||||
ArraysMeshGenerator.FillVerts(skeleton, 0, drawOrderCount, zSpacing, this.premultiplyVertexColors, this.meshVertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
|
||||
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
|
||||
meshBoundsMax.x *= scale; meshBoundsMax.y *= scale;
|
||||
@ -111,7 +107,7 @@ namespace Spine.Unity.MeshGeneration {
|
||||
}
|
||||
|
||||
// Step 4 : Update Triangles buffer
|
||||
ArraysMeshGenerator.FillTriangles(skeleton, totalTriangleCount, 0, 0, drawOrderCount, ref this.triangles, true);
|
||||
ArraysMeshGenerator.FillTriangles(ref this.triangles, skeleton, totalTriangleCount, 0, 0, drawOrderCount, true);
|
||||
|
||||
// Step 5 : Update Mesh with buffers
|
||||
var mesh = doubleBufferedMesh.GetNextMesh();
|
||||
@ -120,6 +116,13 @@ namespace Spine.Unity.MeshGeneration {
|
||||
mesh.uv = meshUVs;
|
||||
mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
|
||||
mesh.triangles = triangles;
|
||||
TryAddNormalsTo(mesh, totalVertexCount);
|
||||
|
||||
if (addTangents) {
|
||||
SolveTangents2DEnsureSize(ref this.meshTangents, ref this.tempTanBuffer, totalVertexCount);
|
||||
SolveTangents2DTriangles(this.tempTanBuffer, triangles, totalTriangleCount, meshVertices, meshUVs, totalVertexCount);
|
||||
SolveTangents2DBuffer(this.meshTangents, this.tempTanBuffer, totalVertexCount);
|
||||
}
|
||||
|
||||
lastGeneratedMesh = mesh;
|
||||
return mesh;
|
||||
|
||||
@ -28,13 +28,12 @@
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
#define SPINE_OPTIONAL_NORMALS
|
||||
using UnityEngine;
|
||||
|
||||
namespace Spine.Unity.MeshGeneration {
|
||||
public class ArraysSubmeshSetMeshGenerator : ArraysMeshGenerator, ISubmeshSetMeshGenerator {
|
||||
#region Settings
|
||||
public float zSpacing = 0f;
|
||||
public float ZSpacing { get; set; }
|
||||
#endregion
|
||||
|
||||
readonly DoubleBuffered<SmartMesh> doubleBufferedSmartMesh = new DoubleBuffered<SmartMesh>();
|
||||
@ -69,7 +68,7 @@ namespace Spine.Unity.MeshGeneration {
|
||||
// Initial values for manual Mesh Bounds calculation
|
||||
Vector3 meshBoundsMin;
|
||||
Vector3 meshBoundsMax;
|
||||
float zSpacing = this.zSpacing;
|
||||
float zSpacing = this.ZSpacing;
|
||||
if (vertexCount <= 0) {
|
||||
meshBoundsMin = new Vector3(0, 0, 0);
|
||||
meshBoundsMax = new Vector3(0, 0, 0);
|
||||
@ -103,7 +102,7 @@ namespace Spine.Unity.MeshGeneration {
|
||||
var ca = skeletonDrawOrderItems[i].attachment;
|
||||
if (ca != null) workingAttachments.Add(ca); // Includes BoundingBoxes. This is ok.
|
||||
}
|
||||
ArraysMeshGenerator.FillVerts(skeleton, startSlot, endSlot, zSpacing, this.premultiplyVertexColors, this.meshVertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
|
||||
ArraysMeshGenerator.FillVerts(skeleton, startSlot, endSlot, zSpacing, this.PremultiplyVertexColors, this.meshVertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
|
||||
}
|
||||
|
||||
bool structureDoesntMatch = vertBufferResized || submeshBuffersResized || smartMesh.StructureDoesntMatch(workingAttachments, currentInstructions);
|
||||
@ -112,7 +111,9 @@ namespace Spine.Unity.MeshGeneration {
|
||||
if (structureDoesntMatch) {
|
||||
var currentBuffer = submeshBuffers.Items[submeshIndex];
|
||||
bool isLastSubmesh = (submeshIndex == submeshCount - 1);
|
||||
ArraysMeshGenerator.FillTriangles(currentInstruction.skeleton, currentInstruction.triangleCount, currentInstruction.firstVertexIndex, currentInstruction.startSlot, currentInstruction.endSlot, ref currentBuffer.triangles, isLastSubmesh);
|
||||
ArraysMeshGenerator.FillTriangles(ref currentBuffer.triangles, currentInstruction.skeleton, currentInstruction.triangleCount, currentInstruction.firstVertexIndex, currentInstruction.startSlot, currentInstruction.endSlot, isLastSubmesh);
|
||||
currentBuffer.triangleCount = currentInstruction.triangleCount;
|
||||
currentBuffer.firstVertex = currentInstruction.firstVertexIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,15 +125,26 @@ namespace Spine.Unity.MeshGeneration {
|
||||
// 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 SPINE_OPTIONAL_NORMALS
|
||||
this.TryAddNormalsTo(mesh, vertexCount);
|
||||
#endif
|
||||
|
||||
|
||||
if (structureDoesntMatch) {
|
||||
// Push new triangles if doesn't match.
|
||||
mesh.subMeshCount = submeshCount;
|
||||
for (int i = 0; i < submeshCount; i++)
|
||||
mesh.SetTriangles(submeshBuffers.Items[i].triangles, i);
|
||||
|
||||
this.TryAddNormalsTo(mesh, vertexCount);
|
||||
}
|
||||
|
||||
if (addTangents) {
|
||||
SolveTangents2DEnsureSize(ref this.meshTangents, ref this.tempTanBuffer, vertexCount);
|
||||
|
||||
for (int i = 0, n = submeshCount; i < n; i++) {
|
||||
var submesh = submeshBuffers.Items[i];
|
||||
SolveTangents2DTriangles(this.tempTanBuffer, submesh.triangles, submesh.triangleCount, meshVertices, meshUVs, vertexCount);
|
||||
}
|
||||
|
||||
SolveTangents2DBuffer(this.meshTangents, this.tempTanBuffer, vertexCount);
|
||||
}
|
||||
|
||||
return new MeshAndMaterials(smartMesh.mesh, sharedMaterials);
|
||||
|
||||
@ -28,7 +28,6 @@
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
//#define SPINE_OPTIONAL_NORMALS
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
@ -42,11 +41,9 @@ namespace Spine.Unity.MeshGeneration {
|
||||
readonly List<Slot> separators = new List<Slot>();
|
||||
public List<Slot> Separators { get { return this.separators; } }
|
||||
|
||||
public float zSpacing = 0f;
|
||||
#if SPINE_OPTIONAL_NORMALS
|
||||
public bool generateNormals;
|
||||
public bool generateTangents;
|
||||
#endif
|
||||
#region Settings
|
||||
public float ZSpacing { get; set; }
|
||||
#endregion
|
||||
|
||||
readonly DoubleBuffered<SmartMesh> doubleBufferedSmartMesh = new DoubleBuffered<SmartMesh>();
|
||||
readonly SubmeshedMeshInstruction currentInstructions = new SubmeshedMeshInstruction();
|
||||
@ -158,12 +155,13 @@ namespace Spine.Unity.MeshGeneration {
|
||||
var instructionList = meshInstructions.submeshInstructions;
|
||||
|
||||
// STEP 1: Ensure correct buffer sizes.
|
||||
int vertexCount = meshInstructions.vertexCount;
|
||||
bool submeshBuffersResized = ArraysMeshGenerator.EnsureTriangleBuffersSize(submeshBuffers, submeshCount, instructionList.Items);
|
||||
bool vertBufferResized = ArraysMeshGenerator.EnsureSize(meshInstructions.vertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32);
|
||||
bool vertBufferResized = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32);
|
||||
Vector3[] vertices = this.meshVertices;
|
||||
|
||||
// STEP 2: Update buffers based on Skeleton.
|
||||
float zSpacing = this.zSpacing;
|
||||
float zSpacing = this.ZSpacing;
|
||||
Vector3 meshBoundsMin;
|
||||
Vector3 meshBoundsMax;
|
||||
int attachmentCount = meshInstructions.attachmentList.Count;
|
||||
@ -192,11 +190,13 @@ namespace Spine.Unity.MeshGeneration {
|
||||
int start = submeshInstruction.startSlot;
|
||||
int end = submeshInstruction.endSlot;
|
||||
var skeleton = submeshInstruction.skeleton;
|
||||
ArraysMeshGenerator.FillVerts(skeleton, start, end, zSpacing, this.premultiplyVertexColors, vertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
|
||||
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);
|
||||
ArraysMeshGenerator.FillTriangles(skeleton, submeshInstruction.triangleCount, submeshInstruction.firstVertexIndex, start, end, ref currentBuffer.triangles, isLastSubmesh);
|
||||
ArraysMeshGenerator.FillTriangles(ref currentBuffer.triangles, skeleton, submeshInstruction.triangleCount, submeshInstruction.firstVertexIndex, start, end, isLastSubmesh);
|
||||
currentBuffer.triangleCount = submeshInstruction.triangleCount;
|
||||
currentBuffer.firstVertex = submeshInstruction.firstVertexIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,24 +215,16 @@ namespace Spine.Unity.MeshGeneration {
|
||||
for (int i = 0; i < submeshCount; i++)
|
||||
mesh.SetTriangles(submeshBuffers.Items[i].triangles, i);
|
||||
|
||||
#if SPINE_OPTIONAL_NORMALS
|
||||
if (generateNormals) {
|
||||
int vertexCount = meshInstructions.vertexCount;
|
||||
Vector3[] normals = new Vector3[vertexCount];
|
||||
Vector3 normal = new Vector3(0, 0, -1);
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
normals[i] = normal;
|
||||
mesh.normals = normals;
|
||||
TryAddNormalsTo(mesh, vertexCount);
|
||||
}
|
||||
|
||||
if (generateTangents) {
|
||||
Vector4[] tangents = new Vector4[vertexCount];
|
||||
Vector4 tangent = new Vector4(1, 0, 0, -1);
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
tangents[i] = tangent;
|
||||
mesh.tangents = tangents;
|
||||
}
|
||||
if (addTangents) {
|
||||
SolveTangents2DEnsureSize(ref this.meshTangents, ref this.tempTanBuffer, vertexCount);
|
||||
for (int i = 0, n = submeshCount; i < n; i++) {
|
||||
var submesh = submeshBuffers.Items[i];
|
||||
SolveTangents2DTriangles(this.tempTanBuffer, submesh.triangles, submesh.triangleCount, meshVertices, meshUVs, vertexCount);
|
||||
}
|
||||
#endif
|
||||
SolveTangents2DBuffer(this.meshTangents, this.tempTanBuffer, vertexCount);
|
||||
}
|
||||
|
||||
return new MeshAndMaterials(smartMesh.mesh, sharedMaterials);
|
||||
|
||||
@ -4,8 +4,13 @@
|
||||
// The Scale property allows generated mesh to match external systems like Canvas referencePixelsPerUnit
|
||||
|
||||
public interface ISimpleMeshGenerator {
|
||||
float Scale { set; }
|
||||
UnityEngine.Mesh GenerateMesh (Spine.Skeleton skeleton);
|
||||
UnityEngine.Mesh LastGeneratedMesh { get; }
|
||||
|
||||
float Scale { set; }
|
||||
float ZSpacing { get; set; }
|
||||
|
||||
bool AddNormals { get; set; }
|
||||
bool AddTangents { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,10 @@ namespace Spine.Unity.MeshGeneration {
|
||||
SubmeshedMeshInstruction GenerateInstruction (Skeleton skeleton);
|
||||
MeshAndMaterials GenerateMesh (SubmeshedMeshInstruction wholeMeshInstruction);
|
||||
List<Slot> Separators { get; }
|
||||
|
||||
float ZSpacing { get; set; }
|
||||
bool AddNormals { get; set; }
|
||||
bool AddTangents { get; set; }
|
||||
}
|
||||
|
||||
// ISubmeshSetMeshGenerator
|
||||
@ -22,7 +26,10 @@ namespace Spine.Unity.MeshGeneration {
|
||||
// Step 4: Put the Mesh in MeshFilter. Put the Materials in MeshRenderer.sharedMaterials.
|
||||
public interface ISubmeshSetMeshGenerator {
|
||||
MeshAndMaterials GenerateMesh (ExposedList<SubmeshInstruction> instructions, int startSubmesh, int endSubmesh);
|
||||
bool GenerateNormals { get; set; }
|
||||
|
||||
float ZSpacing { get; set; }
|
||||
bool AddNormals { get; set; }
|
||||
bool AddTangents { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Primarily a collection of Submesh Instructions. This constitutes instructions for how to construct a mesh containing submeshes.</summary>
|
||||
|
||||
@ -69,7 +69,7 @@ namespace Spine.Unity.Modules {
|
||||
|
||||
void OnEnable () {
|
||||
if (skeletonRenderer == null) return;
|
||||
if (block == null) block = new MaterialPropertyBlock();
|
||||
if (copiedBlock == null) copiedBlock = new MaterialPropertyBlock();
|
||||
mainMeshRenderer = skeletonRenderer.GetComponent<MeshRenderer>();
|
||||
|
||||
skeletonRenderer.GenerateMeshOverride -= HandleRender;
|
||||
@ -103,7 +103,7 @@ namespace Spine.Unity.Modules {
|
||||
s.ClearMesh();
|
||||
}
|
||||
|
||||
MaterialPropertyBlock block;
|
||||
MaterialPropertyBlock copiedBlock;
|
||||
|
||||
void HandleRender (SkeletonRenderer.SmartMesh.Instruction instruction) {
|
||||
int rendererCount = partsRenderers.Count;
|
||||
@ -112,21 +112,27 @@ namespace Spine.Unity.Modules {
|
||||
int rendererIndex = 0;
|
||||
|
||||
if (copyPropertyBlock)
|
||||
mainMeshRenderer.GetPropertyBlock(block);
|
||||
mainMeshRenderer.GetPropertyBlock(copiedBlock);
|
||||
|
||||
var submeshInstructions = instruction.submeshInstructions;
|
||||
var submeshInstructionsItems = submeshInstructions.Items;
|
||||
int lastSubmeshInstruction = submeshInstructions.Count - 1;
|
||||
|
||||
var currentRenderer = partsRenderers[rendererIndex];
|
||||
bool useNormals = skeletonRenderer.calculateNormals;
|
||||
bool addNormals = skeletonRenderer.calculateNormals;
|
||||
bool addTangents = skeletonRenderer.calculateTangents;
|
||||
|
||||
for (int si = 0, start = 0; si <= lastSubmeshInstruction; si++) {
|
||||
if (submeshInstructionsItems[si].forceSeparate || si == lastSubmeshInstruction) {
|
||||
currentRenderer.RenderParts(instruction.submeshInstructions, start, si + 1);
|
||||
currentRenderer.MeshGenerator.GenerateNormals = useNormals;
|
||||
// Apply properties
|
||||
var meshGenerator = currentRenderer.MeshGenerator;
|
||||
meshGenerator.AddNormals = addNormals;
|
||||
meshGenerator.AddTangents = addTangents;
|
||||
if (copyPropertyBlock)
|
||||
currentRenderer.SetPropertyBlock(block);
|
||||
currentRenderer.SetPropertyBlock(copiedBlock);
|
||||
|
||||
// Render
|
||||
currentRenderer.RenderParts(instruction.submeshInstructions, start, si + 1);
|
||||
|
||||
start = si + 1;
|
||||
rendererIndex++;
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
SkeletonRenderSeparator
|
||||
=======================
|
||||
|
||||
Dependencies:
|
||||
- SkeletonPartsRenderer uses the `ArraysMeshGenerator` class in `Spine.Unity.MeshGeneration`
|
||||
- It requires `SPINE_OPTIONAL_RENDEROVERRIDE` to be #defined in `SkeletonRenderer.cs`.
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0e413eeb00eabc46bde6dbd7aaaa76c
|
||||
timeCreated: 1469110129
|
||||
licenseType: Free
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -28,9 +28,12 @@
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
#define SPINE_OPTIONAL_NORMALS
|
||||
|
||||
#define SPINE_OPTIONAL_RENDEROVERRIDE
|
||||
#define SPINE_OPTIONAL_MATERIALOVERRIDE
|
||||
#define SPINE_OPTIONAL_NORMALS
|
||||
#define SPINE_OPTIONAL_SOLVETANGENTS
|
||||
|
||||
//#define SPINE_OPTIONAL_FRONTFACING
|
||||
//#define SPINE_OPTIONAL_SUBMESHRENDERER // Deprecated
|
||||
|
||||
@ -62,8 +65,12 @@ namespace Spine.Unity {
|
||||
public float zSpacing;
|
||||
public bool renderMeshes = true, immutableTriangles;
|
||||
public bool pmaVertexColors = true;
|
||||
|
||||
#if SPINE_OPTIONAL_NORMALS
|
||||
public bool calculateNormals, calculateTangents;
|
||||
public bool calculateNormals;
|
||||
#endif
|
||||
#if SPINE_OPTIONAL_SOLVETANGENTS
|
||||
public bool calculateTangents;
|
||||
#endif
|
||||
#if SPINE_OPTIONAL_FRONTFACING
|
||||
public bool frontFacing;
|
||||
@ -115,7 +122,7 @@ namespace Spine.Unity {
|
||||
|
||||
Spine.Unity.DoubleBuffered<SkeletonRenderer.SmartMesh> doubleBufferedMesh;
|
||||
readonly SmartMesh.Instruction currentInstructions = new SmartMesh.Instruction();
|
||||
readonly ExposedList<SubmeshTriangleBuffer> submeshes = new ExposedList<SubmeshTriangleBuffer>();
|
||||
readonly ExposedList<ArraysMeshGenerator.SubmeshTriangleBuffer> submeshes = new ExposedList<ArraysMeshGenerator.SubmeshTriangleBuffer>();
|
||||
readonly ExposedList<Material> submeshMaterials = new ExposedList<Material>();
|
||||
Material[] sharedMaterials = new Material[0];
|
||||
float[] tempVertices = new float[8];
|
||||
@ -124,7 +131,10 @@ namespace Spine.Unity {
|
||||
Vector2[] uvs;
|
||||
#if SPINE_OPTIONAL_NORMALS
|
||||
Vector3[] normals;
|
||||
#endif
|
||||
#if SPINE_OPTIONAL_SOLVETANGENTS
|
||||
Vector4[] tangents;
|
||||
Vector2[] tempTanBuffer;
|
||||
#endif
|
||||
|
||||
#region Runtime Instantiation
|
||||
@ -189,7 +199,7 @@ namespace Spine.Unity {
|
||||
vertices = new Vector3[0];
|
||||
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
if (initialSkinName != null && initialSkinName.Length > 0 && initialSkinName != "default")
|
||||
if (!string.IsNullOrEmpty(initialSkinName) && initialSkinName != "default")
|
||||
skeleton.SetSkin(initialSkinName);
|
||||
|
||||
separatorSlots.Clear();
|
||||
@ -211,27 +221,18 @@ namespace Spine.Unity {
|
||||
return;
|
||||
|
||||
if (
|
||||
(
|
||||
!meshRenderer.enabled
|
||||
|
||||
)
|
||||
(!meshRenderer.enabled)
|
||||
#if SPINE_OPTIONAL_RENDEROVERRIDE
|
||||
&& this.generateMeshOverride == null
|
||||
#endif
|
||||
|
||||
#if SPINE_OPTIONAL_SUBMESHRENDERER
|
||||
&& submeshRenderers.Length > 0
|
||||
#endif
|
||||
|
||||
)
|
||||
return;
|
||||
|
||||
|
||||
|
||||
|
||||
// STEP 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes.
|
||||
|
||||
// This method caches several .Items arrays.
|
||||
// Never mutate their overlying ExposedList objects.
|
||||
// STEP 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes. ============================================================
|
||||
ExposedList<Slot> drawOrder = skeleton.drawOrder;
|
||||
var drawOrderItems = drawOrder.Items;
|
||||
int drawOrderCount = drawOrder.Count;
|
||||
@ -267,7 +268,6 @@ namespace Spine.Unity {
|
||||
for (int i = 0; i < drawOrderCount; i++) {
|
||||
Slot slot = drawOrderItems[i];
|
||||
Attachment attachment = slot.attachment;
|
||||
|
||||
workingAttachmentsItems[i] = attachment;
|
||||
|
||||
#if SPINE_OPTIONAL_FRONTFACING
|
||||
@ -357,7 +357,8 @@ namespace Spine.Unity {
|
||||
workingInstruction.frontFacing = this.frontFacing;
|
||||
#endif
|
||||
|
||||
// STEP 1.9. Post-process workingInstructions.
|
||||
|
||||
// STEP 1.9. Post-process workingInstructions. ============================================================
|
||||
|
||||
#if SPINE_OPTIONAL_MATERIALOVERRIDE
|
||||
// Material overrides are done here so they can be applied per submesh instead of per slot
|
||||
@ -374,7 +375,6 @@ namespace Spine.Unity {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SPINE_OPTIONAL_RENDEROVERRIDE
|
||||
if (this.generateMeshOverride != null) {
|
||||
this.generateMeshOverride(workingInstruction);
|
||||
@ -382,50 +382,22 @@ namespace Spine.Unity {
|
||||
}
|
||||
#endif
|
||||
|
||||
// STEP 2. Update vertex buffer based on verts from the attachments.
|
||||
|
||||
// STEP 2. Update vertex buffer based on verts from the attachments. ============================================================
|
||||
// Uses values that were also stored in workingInstruction.
|
||||
Vector3[] vertices = this.vertices;
|
||||
bool vertexCountIncreased = vertexCount > vertices.Length;
|
||||
|
||||
if (vertexCountIncreased) {
|
||||
this.vertices = vertices = new Vector3[vertexCount];
|
||||
this.colors = new Color32[vertexCount];
|
||||
this.uvs = new Vector2[vertexCount];
|
||||
|
||||
#if SPINE_OPTIONAL_NORMALS
|
||||
if (calculateNormals) {
|
||||
Vector3[] localNormals = this.normals = new Vector3[vertexCount];
|
||||
Vector3 normal = new Vector3(0, 0, -1);
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
localNormals[i] = normal;
|
||||
}
|
||||
|
||||
// For dynamic tangent calculation, you can remove the tangent-filling logic and add tangent calculation logic below.
|
||||
if (calculateTangents) {
|
||||
Vector4[] localTangents = this.tangents = new Vector4[vertexCount];
|
||||
Vector4 tangent = new Vector4(1, 0, 0, -1);
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
localTangents[i] = tangent;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
Vector3 zero = Vector3.zero;
|
||||
for (int i = vertexCount, n = vertices.Length; i < n; i++)
|
||||
vertices[i] = zero;
|
||||
bool vertexCountIncreased = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.vertices, ref this.uvs, ref this.colors);
|
||||
#if SPINE_OPTIONAL_NORMALS
|
||||
if (vertexCountIncreased && calculateNormals) {
|
||||
Vector3[] localNormals = this.normals = new Vector3[vertexCount];
|
||||
Vector3 normal = new Vector3(0, 0, -1);
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
localNormals[i] = normal;
|
||||
}
|
||||
|
||||
float zSpacing = this.zSpacing;
|
||||
float[] tempVertices = this.tempVertices;
|
||||
Vector2[] uvs = this.uvs;
|
||||
Color32[] colors = this.colors;
|
||||
int vertexIndex = 0;
|
||||
bool pmaVertexColors = this.pmaVertexColors;
|
||||
Color32 color;
|
||||
float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b;
|
||||
#endif
|
||||
|
||||
Vector3 meshBoundsMin;
|
||||
Vector3 meshBoundsMax;
|
||||
if (vertexCount == 0) {
|
||||
if (vertexCount <= 0) {
|
||||
meshBoundsMin = new Vector3(0, 0, 0);
|
||||
meshBoundsMax = new Vector3(0, 0, 0);
|
||||
} else {
|
||||
@ -433,6 +405,7 @@ namespace Spine.Unity {
|
||||
meshBoundsMin.y = int.MaxValue;
|
||||
meshBoundsMax.x = int.MinValue;
|
||||
meshBoundsMax.y = int.MinValue;
|
||||
|
||||
if (zSpacing > 0f) {
|
||||
meshBoundsMin.z = 0f;
|
||||
meshBoundsMax.z = zSpacing * (drawOrderCount - 1);
|
||||
@ -440,192 +413,60 @@ namespace Spine.Unity {
|
||||
meshBoundsMin.z = zSpacing * (drawOrderCount - 1);
|
||||
meshBoundsMax.z = 0f;
|
||||
}
|
||||
int i = 0;
|
||||
do {
|
||||
Slot slot = drawOrderItems[i];
|
||||
Attachment attachment = slot.attachment;
|
||||
RegionAttachment regionAttachment = attachment as RegionAttachment;
|
||||
if (regionAttachment != null) {
|
||||
regionAttachment.ComputeWorldVertices(slot.bone, tempVertices);
|
||||
|
||||
float z = i * zSpacing;
|
||||
float x1 = tempVertices[RegionAttachment.X1], y1 = tempVertices[RegionAttachment.Y1];
|
||||
float x2 = tempVertices[RegionAttachment.X2], y2 = tempVertices[RegionAttachment.Y2];
|
||||
float x3 = tempVertices[RegionAttachment.X3], y3 = tempVertices[RegionAttachment.Y3];
|
||||
float x4 = tempVertices[RegionAttachment.X4], y4 = tempVertices[RegionAttachment.Y4];
|
||||
vertices[vertexIndex].x = x1;
|
||||
vertices[vertexIndex].y = y1;
|
||||
vertices[vertexIndex].z = z;
|
||||
vertices[vertexIndex + 1].x = x4;
|
||||
vertices[vertexIndex + 1].y = y4;
|
||||
vertices[vertexIndex + 1].z = z;
|
||||
vertices[vertexIndex + 2].x = x2;
|
||||
vertices[vertexIndex + 2].y = y2;
|
||||
vertices[vertexIndex + 2].z = z;
|
||||
vertices[vertexIndex + 3].x = x3;
|
||||
vertices[vertexIndex + 3].y = y3;
|
||||
vertices[vertexIndex + 3].z = z;
|
||||
|
||||
if (pmaVertexColors) {
|
||||
color.a = (byte)(a * slot.a * regionAttachment.a);
|
||||
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;
|
||||
} else {
|
||||
color.a = (byte)(a * slot.a * regionAttachment.a);
|
||||
color.r = (byte)(r * slot.r * regionAttachment.r * 255);
|
||||
color.g = (byte)(g * slot.g * regionAttachment.g * 255);
|
||||
color.b = (byte)(b * slot.b * regionAttachment.b * 255);
|
||||
}
|
||||
|
||||
colors[vertexIndex] = color;
|
||||
colors[vertexIndex + 1] = color;
|
||||
colors[vertexIndex + 2] = color;
|
||||
colors[vertexIndex + 3] = color;
|
||||
|
||||
float[] regionUVs = regionAttachment.uvs;
|
||||
uvs[vertexIndex].x = regionUVs[RegionAttachment.X1];
|
||||
uvs[vertexIndex].y = regionUVs[RegionAttachment.Y1];
|
||||
uvs[vertexIndex + 1].x = regionUVs[RegionAttachment.X4];
|
||||
uvs[vertexIndex + 1].y = regionUVs[RegionAttachment.Y4];
|
||||
uvs[vertexIndex + 2].x = regionUVs[RegionAttachment.X2];
|
||||
uvs[vertexIndex + 2].y = regionUVs[RegionAttachment.Y2];
|
||||
uvs[vertexIndex + 3].x = regionUVs[RegionAttachment.X3];
|
||||
uvs[vertexIndex + 3].y = regionUVs[RegionAttachment.Y3];
|
||||
|
||||
// Calculate min/max X
|
||||
if (x1 < meshBoundsMin.x)
|
||||
meshBoundsMin.x = x1;
|
||||
else if (x1 > meshBoundsMax.x)
|
||||
meshBoundsMax.x = x1;
|
||||
if (x2 < meshBoundsMin.x)
|
||||
meshBoundsMin.x = x2;
|
||||
else if (x2 > meshBoundsMax.x)
|
||||
meshBoundsMax.x = x2;
|
||||
if (x3 < meshBoundsMin.x)
|
||||
meshBoundsMin.x = x3;
|
||||
else if (x3 > meshBoundsMax.x)
|
||||
meshBoundsMax.x = x3;
|
||||
if (x4 < meshBoundsMin.x)
|
||||
meshBoundsMin.x = x4;
|
||||
else if (x4 > meshBoundsMax.x)
|
||||
meshBoundsMax.x = x4;
|
||||
|
||||
// Calculate min/max Y
|
||||
if (y1 < meshBoundsMin.y)
|
||||
meshBoundsMin.y = y1;
|
||||
else if (y1 > meshBoundsMax.y)
|
||||
meshBoundsMax.y = y1;
|
||||
if (y2 < meshBoundsMin.y)
|
||||
meshBoundsMin.y = y2;
|
||||
else if (y2 > meshBoundsMax.y)
|
||||
meshBoundsMax.y = y2;
|
||||
if (y3 < meshBoundsMin.y)
|
||||
meshBoundsMin.y = y3;
|
||||
else if (y3 > meshBoundsMax.y)
|
||||
meshBoundsMax.y = y3;
|
||||
if (y4 < meshBoundsMin.y)
|
||||
meshBoundsMin.y = y4;
|
||||
else if (y4 > meshBoundsMax.y)
|
||||
meshBoundsMax.y = y4;
|
||||
|
||||
vertexIndex += 4;
|
||||
} else {
|
||||
if (!renderMeshes)
|
||||
continue;
|
||||
MeshAttachment meshAttachment = attachment as MeshAttachment;
|
||||
if (meshAttachment != null) {
|
||||
int meshVertexCount = meshAttachment.worldVerticesLength;
|
||||
if (tempVertices.Length < meshVertexCount)
|
||||
this.tempVertices = tempVertices = new float[meshVertexCount];
|
||||
meshAttachment.ComputeWorldVertices(slot, tempVertices);
|
||||
|
||||
if (pmaVertexColors) {
|
||||
color.a = (byte)(a * slot.a * meshAttachment.a);
|
||||
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;
|
||||
} else {
|
||||
color.a = (byte)(a * slot.a * meshAttachment.a);
|
||||
color.r = (byte)(r * slot.r * meshAttachment.r * 255);
|
||||
color.g = (byte)(g * slot.g * meshAttachment.g * 255);
|
||||
color.b = (byte)(b * slot.b * meshAttachment.b * 255);
|
||||
}
|
||||
|
||||
float[] meshUVs = meshAttachment.uvs;
|
||||
float z = i * zSpacing;
|
||||
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
|
||||
float x = tempVertices[ii], y = tempVertices[ii + 1];
|
||||
vertices[vertexIndex].x = x;
|
||||
vertices[vertexIndex].y = y;
|
||||
vertices[vertexIndex].z = z;
|
||||
colors[vertexIndex] = color;
|
||||
uvs[vertexIndex].x = meshUVs[ii];
|
||||
uvs[vertexIndex].y = meshUVs[ii + 1];
|
||||
|
||||
if (x < meshBoundsMin.x)
|
||||
meshBoundsMin.x = x;
|
||||
else if (x > meshBoundsMax.x)
|
||||
meshBoundsMax.x = x;
|
||||
if (y < meshBoundsMin.y)
|
||||
meshBoundsMin.y = y;
|
||||
else if (y > meshBoundsMax.y)
|
||||
meshBoundsMax.y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (++i < drawOrderCount);
|
||||
}
|
||||
int vertexIndex = 0;
|
||||
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
|
||||
|
||||
// Step 3. Move the mesh data into a UnityEngine.Mesh ============================================================
|
||||
var currentSmartMesh = doubleBufferedMesh.GetNext(); // Double-buffer for performance.
|
||||
var currentMesh = currentSmartMesh.mesh;
|
||||
|
||||
currentMesh.vertices = vertices;
|
||||
currentMesh.vertices = this.vertices;
|
||||
currentMesh.colors32 = colors;
|
||||
currentMesh.uv = uvs;
|
||||
|
||||
Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin;
|
||||
Vector3 meshBoundsCenter = meshBoundsMin + meshBoundsExtents * 0.5f;
|
||||
currentMesh.bounds = new Bounds(meshBoundsCenter, meshBoundsExtents);
|
||||
currentMesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
|
||||
|
||||
var currentSmartMeshInstructionUsed = currentSmartMesh.instructionUsed;
|
||||
#if SPINE_OPTIONAL_NORMALS
|
||||
if (currentSmartMeshInstructionUsed.vertexCount < vertexCount) {
|
||||
if (calculateNormals)
|
||||
currentMesh.normals = normals;
|
||||
|
||||
// For dynamic calculated tangents, this needs to be moved out of the vertexCount check block when replacing the logic, also ensuring the size.
|
||||
if (calculateTangents)
|
||||
currentMesh.tangents = this.tangents;
|
||||
}
|
||||
if (calculateNormals && currentSmartMeshInstructionUsed.vertexCount < vertexCount)
|
||||
currentMesh.normals = normals;
|
||||
#endif
|
||||
|
||||
// Check if the triangles should also be updated.
|
||||
// This thorough structure check is cheaper than updating triangles every frame.
|
||||
bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(workingInstruction, currentSmartMeshInstructionUsed);
|
||||
int submeshCount = workingSubmeshInstructions.Count;
|
||||
if (mustUpdateMeshStructure) {
|
||||
var thisSubmeshMaterials = this.submeshMaterials;
|
||||
thisSubmeshMaterials.Clear(false);
|
||||
|
||||
int submeshCount = workingSubmeshInstructions.Count;
|
||||
int oldSubmeshCount = submeshes.Count;
|
||||
|
||||
submeshes.Capacity = submeshCount;
|
||||
for (int i = oldSubmeshCount; i < submeshCount; i++)
|
||||
submeshes.Items[i] = new SubmeshTriangleBuffer();
|
||||
submeshes.Items[i] = new ArraysMeshGenerator.SubmeshTriangleBuffer(workingSubmeshInstructions.Items[i].triangleCount);
|
||||
|
||||
var mutableTriangles = !workingInstruction.immutableTriangles;
|
||||
for (int i = 0, last = submeshCount - 1; i < submeshCount; i++) {
|
||||
var submeshInstruction = workingSubmeshInstructions.Items[i];
|
||||
if (mutableTriangles || i >= oldSubmeshCount)
|
||||
SetSubmesh(i, submeshInstruction,
|
||||
#if SPINE_OPTIONAL_FRONTFACING
|
||||
currentInstructions.attachmentFlips,
|
||||
#endif
|
||||
i == last);
|
||||
|
||||
if (mutableTriangles || i >= oldSubmeshCount) {
|
||||
|
||||
#if !SPINE_OPTIONAL_FRONTFACING
|
||||
var currentSubmesh = submeshes.Items[i];
|
||||
int instructionTriangleCount = submeshInstruction.triangleCount;
|
||||
if (renderMeshes) {
|
||||
ArraysMeshGenerator.FillTriangles(ref currentSubmesh.triangles, skeleton, instructionTriangleCount, submeshInstruction.firstVertexIndex, submeshInstruction.startSlot, submeshInstruction.endSlot, (i == last));
|
||||
currentSubmesh.triangleCount = instructionTriangleCount;
|
||||
} else {
|
||||
ArraysMeshGenerator.FillTrianglesQuads(ref currentSubmesh.triangles, ref currentSubmesh.triangleCount, ref currentSubmesh.firstVertex, submeshInstruction.firstVertexIndex, instructionTriangleCount, (i == last));
|
||||
}
|
||||
#else
|
||||
SetSubmesh(i, submeshInstruction, currentInstructions.attachmentFlips, i == last);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
thisSubmeshMaterials.Add(submeshInstruction.material);
|
||||
}
|
||||
|
||||
@ -635,12 +476,24 @@ namespace Spine.Unity {
|
||||
currentMesh.SetTriangles(submeshes.Items[i].triangles, i);
|
||||
}
|
||||
|
||||
#if SPINE_OPTIONAL_SOLVETANGENTS
|
||||
if (calculateTangents) {
|
||||
ArraysMeshGenerator.SolveTangents2DEnsureSize(ref this.tangents, ref this.tempTanBuffer, vertices.Length);
|
||||
for (int i = 0; i < submeshCount; i++) {
|
||||
var submesh = submeshes.Items[i];
|
||||
ArraysMeshGenerator.SolveTangents2DTriangles(this.tempTanBuffer, submesh.triangles, submesh.triangleCount, this.vertices, this.uvs, vertexCount);
|
||||
}
|
||||
ArraysMeshGenerator.SolveTangents2DBuffer(this.tangents, this.tempTanBuffer, vertexCount);
|
||||
currentMesh.tangents = this.tangents;
|
||||
}
|
||||
#endif
|
||||
|
||||
// CheckIfMustUpdateMaterialArray (last pushed materials vs currently parsed materials)
|
||||
// Needs to check against the Working Submesh Instructions Materials instead of the cached submeshMaterials.
|
||||
{
|
||||
var lastPushedMaterials = this.sharedMaterials;
|
||||
bool mustUpdateRendererMaterials = mustUpdateMeshStructure ||
|
||||
(lastPushedMaterials.Length != workingSubmeshInstructions.Count);
|
||||
(lastPushedMaterials.Length != submeshCount);
|
||||
|
||||
if (!mustUpdateRendererMaterials) {
|
||||
var workingSubmeshInstructionsItems = workingSubmeshInstructions.Items;
|
||||
@ -662,14 +515,12 @@ namespace Spine.Unity {
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4. The UnityEngine.Mesh is ready. Set it as the MeshFilter's mesh. Store the instructions used for that mesh.
|
||||
|
||||
// Step 4. The UnityEngine.Mesh is ready. Set it as the MeshFilter's mesh. Store the instructions used for that mesh. ============================================================
|
||||
meshFilter.sharedMesh = currentMesh;
|
||||
currentSmartMesh.instructionUsed.Set(workingInstruction);
|
||||
|
||||
|
||||
// Step 5. Miscellaneous
|
||||
// Add stuff here if you want
|
||||
|
||||
#if SPINE_OPTIONAL_SUBMESHRENDERER
|
||||
if (submeshRenderers.Length > 0) {
|
||||
for (int i = 0; i < submeshRenderers.Length; i++) {
|
||||
@ -748,10 +599,7 @@ namespace Spine.Unity {
|
||||
|
||||
#if SPINE_OPTIONAL_FRONTFACING
|
||||
void SetSubmesh (int submeshIndex, Spine.Unity.MeshGeneration.SubmeshInstruction submeshInstructions, ExposedList<bool> flipStates, bool isLastSubmesh) {
|
||||
#else
|
||||
void SetSubmesh (int submeshIndex, Spine.Unity.MeshGeneration.SubmeshInstruction submeshInstructions, bool isLastSubmesh) {
|
||||
#endif
|
||||
SubmeshTriangleBuffer currentSubmesh = submeshes.Items[submeshIndex];
|
||||
var currentSubmesh = submeshes.Items[submeshIndex];
|
||||
int[] triangles = currentSubmesh.triangles;
|
||||
|
||||
int triangleCount = submeshInstructions.triangleCount;
|
||||
@ -770,12 +618,8 @@ namespace Spine.Unity {
|
||||
currentSubmesh.triangles = triangles = new int[triangleCount];
|
||||
currentSubmesh.triangleCount = 0;
|
||||
}
|
||||
|
||||
#if SPINE_OPTIONAL_FRONTFACING
|
||||
|
||||
if (!this.renderMeshes && !this.frontFacing) {
|
||||
#else
|
||||
if (!this.renderMeshes) {
|
||||
#endif
|
||||
// Use stored triangles if possible.
|
||||
if (currentSubmesh.firstVertex != firstVertex || currentSubmesh.triangleCount < triangleCount) { //|| currentSubmesh.triangleCount == 0
|
||||
currentSubmesh.triangleCount = triangleCount;
|
||||
@ -792,20 +636,14 @@ namespace Spine.Unity {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// This method caches several .Items arrays.
|
||||
// Never mutate their overlying ExposedList objects.
|
||||
|
||||
#if SPINE_OPTIONAL_FRONTFACING
|
||||
|
||||
var flipStatesItems = flipStates.Items;
|
||||
#endif
|
||||
|
||||
// Iterate through all slots and store their triangles.
|
||||
var drawOrderItems = skeleton.DrawOrder.Items;
|
||||
int triangleIndex = 0; // Modified by loop
|
||||
for (int i = submeshInstructions.startSlot, n = submeshInstructions.endSlot; i < n; i++) {
|
||||
Attachment attachment = drawOrderItems[i].attachment;
|
||||
#if SPINE_OPTIONAL_FRONTFACING
|
||||
bool flip = frontFacing && flipStatesItems[i];
|
||||
|
||||
// Add RegionAttachment triangles
|
||||
@ -830,20 +668,6 @@ namespace Spine.Unity {
|
||||
firstVertex += 4;
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
if (attachment is RegionAttachment) {
|
||||
triangles[triangleIndex] = firstVertex;
|
||||
triangles[triangleIndex + 1] = firstVertex + 2;
|
||||
triangles[triangleIndex + 2] = firstVertex + 1;
|
||||
triangles[triangleIndex + 3] = firstVertex + 2;
|
||||
triangles[triangleIndex + 4] = firstVertex + 3;
|
||||
triangles[triangleIndex + 5] = firstVertex + 1;
|
||||
|
||||
triangleIndex += 6;
|
||||
firstVertex += 4;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Add (Weighted)MeshAttachment triangles
|
||||
int[] attachmentTriangles;
|
||||
@ -856,7 +680,6 @@ namespace Spine.Unity {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if SPINE_OPTIONAL_FRONTFACING
|
||||
if (flip) {
|
||||
for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) {
|
||||
triangles[triangleIndex + 2] = firstVertex + attachmentTriangles[ii];
|
||||
@ -868,14 +691,11 @@ namespace Spine.Unity {
|
||||
triangles[triangleIndex] = firstVertex + attachmentTriangles[ii];
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++)
|
||||
triangles[triangleIndex] = firstVertex + attachmentTriangles[ii];
|
||||
#endif
|
||||
|
||||
firstVertex += attachmentVertexCount;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnDrawGizmos () {
|
||||
@ -943,13 +763,5 @@ namespace Spine.Unity {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SubmeshTriangleBuffer {
|
||||
public int[] triangles = new int[0];
|
||||
|
||||
// These two fields are used when renderMeshes == false
|
||||
public int triangleCount;
|
||||
public int firstVertex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user