mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-14 02:58:44 +08:00
SpineRenderSeparator
This commit is contained in:
parent
5538c0adde
commit
0687826542
@ -30,7 +30,6 @@
|
||||
*****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
@ -40,9 +39,7 @@ public class SkeletonRendererInspector : Editor {
|
||||
|
||||
protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, submeshSeparators, front, zSpacing;
|
||||
|
||||
private static MethodInfo EditorGUILayoutSortingLayerField;
|
||||
protected SerializedObject rendererSerializedObject;
|
||||
protected SerializedProperty sortingLayerIDProperty;
|
||||
protected SpineInspectorUtility.SerializedSortingProperties sortingProperties;
|
||||
|
||||
protected virtual void OnEnable () {
|
||||
SpineEditorUtilities.ConfirmInitialization();
|
||||
@ -56,11 +53,8 @@ public class SkeletonRendererInspector : Editor {
|
||||
front = serializedObject.FindProperty("frontFacing");
|
||||
zSpacing = serializedObject.FindProperty("zSpacing");
|
||||
|
||||
if(EditorGUILayoutSortingLayerField == null)
|
||||
EditorGUILayoutSortingLayerField = typeof(EditorGUILayout).GetMethod("SortingLayerField", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(GUIContent), typeof(SerializedProperty), typeof(GUIStyle) }, null);
|
||||
|
||||
rendererSerializedObject = new SerializedObject(((SkeletonRenderer)target).GetComponent<Renderer>());
|
||||
sortingLayerIDProperty = rendererSerializedObject.FindProperty("m_SortingLayerID");
|
||||
var renderer = ((SkeletonRenderer)target).GetComponent<Renderer>();
|
||||
sortingProperties = new SpineInspectorUtility.SerializedSortingProperties(renderer);
|
||||
}
|
||||
|
||||
protected virtual void DrawInspectorGUI () {
|
||||
@ -107,23 +101,7 @@ public class SkeletonRendererInspector : Editor {
|
||||
|
||||
// Sorting Layers
|
||||
{
|
||||
var renderer = component.GetComponent<Renderer>();
|
||||
if(renderer != null) {
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
if(EditorGUILayoutSortingLayerField != null && sortingLayerIDProperty != null) {
|
||||
EditorGUILayoutSortingLayerField.Invoke(null, new object[] { new GUIContent("Sorting Layer"), sortingLayerIDProperty, EditorStyles.popup } );
|
||||
} else {
|
||||
renderer.sortingLayerID = EditorGUILayout.IntField("Sorting Layer ID", renderer.sortingLayerID);
|
||||
}
|
||||
|
||||
renderer.sortingOrder = EditorGUILayout.IntField("Order in Layer", renderer.sortingOrder);
|
||||
|
||||
if(EditorGUI.EndChangeCheck()) {
|
||||
rendererSerializedObject.ApplyModifiedProperties();
|
||||
EditorUtility.SetDirty(renderer);
|
||||
}
|
||||
}
|
||||
SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true);
|
||||
}
|
||||
|
||||
// More Render Options...
|
||||
|
||||
@ -0,0 +1,92 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes Software License
|
||||
* Version 2.3
|
||||
*
|
||||
* Copyright (c) 2013-2015, Esoteric Software
|
||||
* All rights reserved.
|
||||
*
|
||||
* You are granted a perpetual, non-exclusive, non-sublicensable and
|
||||
* non-transferable license to use, install, execute and perform the Spine
|
||||
* Runtimes Software (the "Software") and derivative works solely for personal
|
||||
* or internal use. Without the written permission of Esoteric Software (see
|
||||
* Section 2 of the Spine Software License Agreement), you may not (a) modify,
|
||||
* translate, adapt or otherwise create derivative works, improvements of the
|
||||
* Software or develop new applications using the Software or (b) remove,
|
||||
* delete, alter or obscure any trademarks or any copyright, trademark, patent
|
||||
* or other intellectual property or proprietary rights notices on or in the
|
||||
* Software, including any copy thereof. Redistributions in binary or source
|
||||
* form must include this license and terms.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEditor;
|
||||
using System.Reflection;
|
||||
|
||||
public static class SpineInspectorUtility {
|
||||
|
||||
#region Sorting Layer Field Helpers
|
||||
static readonly GUIContent SortingLayerLabel = new GUIContent("Sorting Layer");
|
||||
static readonly GUIContent OrderInLayerLabel = new GUIContent("Order in Layer");
|
||||
|
||||
static MethodInfo m_SortingLayerFieldMethod;
|
||||
static MethodInfo SortingLayerFieldMethod {
|
||||
get {
|
||||
if (m_SortingLayerFieldMethod == null)
|
||||
m_SortingLayerFieldMethod = typeof(EditorGUILayout).GetMethod("SortingLayerField", BindingFlags.Static | BindingFlags.NonPublic, null, new System.Type[] { typeof(GUIContent), typeof(SerializedProperty), typeof(GUIStyle) }, null);
|
||||
|
||||
return m_SortingLayerFieldMethod;
|
||||
}
|
||||
}
|
||||
|
||||
public struct SerializedSortingProperties {
|
||||
public SerializedObject renderer;
|
||||
public SerializedProperty sortingLayerID;
|
||||
public SerializedProperty sortingOrder;
|
||||
|
||||
public SerializedSortingProperties (Renderer r) {
|
||||
renderer = new SerializedObject(r);
|
||||
sortingLayerID = renderer.FindProperty("m_SortingLayerID");
|
||||
sortingOrder = renderer.FindProperty("m_SortingOrder");
|
||||
}
|
||||
|
||||
public void ApplyModifiedProperties () {
|
||||
renderer.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SortingPropertyFields (SerializedSortingProperties prop, bool applyModifiedProperties) {
|
||||
if (applyModifiedProperties) {
|
||||
EditorGUI.BeginChangeCheck();
|
||||
SortingPropertyFields(prop.sortingLayerID, prop.sortingOrder);
|
||||
if(EditorGUI.EndChangeCheck()) {
|
||||
prop.ApplyModifiedProperties();
|
||||
EditorUtility.SetDirty(prop.renderer.targetObject);
|
||||
}
|
||||
} else {
|
||||
SortingPropertyFields(prop.sortingLayerID, prop.sortingOrder);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SortingPropertyFields (SerializedProperty m_SortingLayerID, SerializedProperty m_SortingOrder) {
|
||||
if (SpineInspectorUtility.SortingLayerFieldMethod != null && m_SortingLayerID != null) {
|
||||
SpineInspectorUtility.SortingLayerFieldMethod.Invoke(null, new object[] { SortingLayerLabel, m_SortingLayerID, EditorStyles.popup } );
|
||||
} else {
|
||||
EditorGUILayout.PropertyField(m_SortingLayerID);
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(m_SortingOrder, OrderInLayerLabel);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@ -1,8 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67418e462bd4dc24e8c234b92f1d4d9b
|
||||
guid: 663715b5714e2db499192c8d91ef1f86
|
||||
timeCreated: 1457404957
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,15 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Spine.Unity {
|
||||
public class DoubleBuffered<T> where T : new() {
|
||||
readonly T a = new T();
|
||||
readonly T b = new T();
|
||||
bool usingA;
|
||||
|
||||
public T GetNext () {
|
||||
usingA = !usingA;
|
||||
return usingA ? a : b;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08b76da7751523448a87e528c48a5399
|
||||
timeCreated: 1457396939
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce7d323baddaa244c8f9f45b38b68193
|
||||
folderAsset: yes
|
||||
timeCreated: 1457398522
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,315 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Spine.Unity {
|
||||
public class ArraysSingleSubmeshGenerator : ISingleSubmeshGenerator {
|
||||
|
||||
public float zSpacing = 0f;
|
||||
|
||||
bool premultiplyVertexColors = true;
|
||||
public bool PremultiplyVertexColors { get { return this.premultiplyVertexColors; } set { this.premultiplyVertexColors = value; } }
|
||||
|
||||
public Mesh GenerateMesh (SubmeshInstruction instruction) {
|
||||
float zSpacing = this.zSpacing;
|
||||
float[] attVertBuffer = this.attachmentVertexBuffer;
|
||||
Vector2[] uvs = this.meshUVs;
|
||||
Color32[] colors32 = this.meshColors32;
|
||||
Color32 color;
|
||||
var attachmentList = this.attachmentListBuffer;
|
||||
attachmentList.Clear();
|
||||
|
||||
// Ensure correct buffer sizes.
|
||||
Vector3[] vertices = this.meshVertices;
|
||||
|
||||
int instructionVertexCount = instruction.vertexCount;
|
||||
bool newVertices = vertices == null || instructionVertexCount > vertices.Length;
|
||||
if (newVertices) {
|
||||
this.meshVertices = vertices = new Vector3[instructionVertexCount];
|
||||
this.meshColors32 = colors32 = new Color32[instructionVertexCount];
|
||||
this.meshUVs = uvs = new Vector2[instructionVertexCount];
|
||||
} else {
|
||||
var zero = Vector3.zero;
|
||||
for (int i = instructionVertexCount, n = this.meshVertices.Length; i < n; i++)
|
||||
vertices[i] = zero;
|
||||
}
|
||||
|
||||
Vector3 meshBoundsMin;
|
||||
Vector3 meshBoundsMax;
|
||||
|
||||
int attachmentCount = instruction.endSlot - instruction.startSlot;
|
||||
|
||||
// Initial values for manual Mesh Bounds calculation
|
||||
if (attachmentCount <= 0) {
|
||||
meshBoundsMin = new Vector3(0, 0, 0);
|
||||
meshBoundsMax = new Vector3(0, 0, 0);
|
||||
} else {
|
||||
meshBoundsMin.x = int.MaxValue;
|
||||
meshBoundsMin.y = int.MaxValue;
|
||||
meshBoundsMax.x = int.MinValue;
|
||||
meshBoundsMax.y = int.MinValue;
|
||||
|
||||
if (zSpacing > 0f) {
|
||||
meshBoundsMin.z = 0f;
|
||||
meshBoundsMax.z = zSpacing * (attachmentCount - 1);
|
||||
} else {
|
||||
meshBoundsMin.z = zSpacing * (attachmentCount - 1);
|
||||
meshBoundsMax.z = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
int vertexIndex = 0;
|
||||
var skeleton = instruction.skeleton;
|
||||
var skeletonDrawOrderItems = skeleton.DrawOrder.Items;
|
||||
float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b;
|
||||
|
||||
// Push verts in this submesh
|
||||
for (int slotIndex = instruction.startSlot, endSlot = instruction.endSlot; slotIndex < endSlot; slotIndex++) {
|
||||
var slot = skeletonDrawOrderItems[slotIndex];
|
||||
var attachment = slot.attachment;
|
||||
float z = slotIndex * zSpacing;
|
||||
|
||||
var regionAttachment = attachment as RegionAttachment;
|
||||
if (regionAttachment != null) {
|
||||
attachmentList.Add(attachment);
|
||||
regionAttachment.ComputeWorldVertices(slot.bone, attVertBuffer);
|
||||
|
||||
float x1 = attVertBuffer[RegionAttachment.X1], y1 = attVertBuffer[RegionAttachment.Y1];
|
||||
float x2 = attVertBuffer[RegionAttachment.X2], y2 = attVertBuffer[RegionAttachment.Y2];
|
||||
float x3 = attVertBuffer[RegionAttachment.X3], y3 = attVertBuffer[RegionAttachment.Y3];
|
||||
float x4 = attVertBuffer[RegionAttachment.X4], y4 = attVertBuffer[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;
|
||||
|
||||
color.a = (byte)(a * slot.a * regionAttachment.a);
|
||||
if (this.premultiplyVertexColors) {
|
||||
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);
|
||||
} else {
|
||||
color.r = (byte)(r * slot.r * regionAttachment.r); color.g = (byte)(g * slot.g * regionAttachment.g); color.b = (byte)(b * slot.b * regionAttachment.b);
|
||||
}
|
||||
if (slot.data.blendMode == BlendMode.additive) color.a = 0;
|
||||
colors32[vertexIndex] = color; colors32[vertexIndex + 1] = color; colors32[vertexIndex + 2] = color; colors32[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 {
|
||||
var meshAttachment = attachment as MeshAttachment;
|
||||
if (meshAttachment != null) {
|
||||
attachmentList.Add(attachment);
|
||||
int meshVertexCount = meshAttachment.vertices.Length;
|
||||
if (attVertBuffer.Length < meshVertexCount) this.attachmentVertexBuffer = attVertBuffer = new float[meshVertexCount];
|
||||
meshAttachment.ComputeWorldVertices(slot, attVertBuffer);
|
||||
|
||||
color.a = (byte)(a * slot.a * meshAttachment.a);
|
||||
if (this.premultiplyVertexColors) {
|
||||
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);
|
||||
} else {
|
||||
color.r = (byte)(r * slot.r * meshAttachment.r);
|
||||
color.g = (byte)(g * slot.g * meshAttachment.g);
|
||||
color.b = (byte)(b * slot.b * meshAttachment.b);
|
||||
}
|
||||
if (slot.data.blendMode == BlendMode.additive) color.a = 0;
|
||||
|
||||
float[] attachmentUVs = meshAttachment.uvs;
|
||||
for (int iii = 0; iii < meshVertexCount; iii += 2) {
|
||||
float x = attVertBuffer[iii], y = attVertBuffer[iii + 1];
|
||||
vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z;
|
||||
colors32[vertexIndex] = color; uvs[vertexIndex].x = attachmentUVs[iii]; uvs[vertexIndex].y = attachmentUVs[iii + 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;
|
||||
|
||||
vertexIndex++;
|
||||
}
|
||||
} else {
|
||||
var weightedMeshAttachment = attachment as WeightedMeshAttachment;
|
||||
if (weightedMeshAttachment != null) {
|
||||
attachmentList.Add(attachment);
|
||||
int meshVertexCount = weightedMeshAttachment.uvs.Length;
|
||||
if (attVertBuffer.Length < meshVertexCount) this.attachmentVertexBuffer = attVertBuffer = new float[meshVertexCount];
|
||||
weightedMeshAttachment.ComputeWorldVertices(slot, attVertBuffer);
|
||||
|
||||
color.a = (byte)(a * slot.a * weightedMeshAttachment.a);
|
||||
if (this.premultiplyVertexColors) {
|
||||
color.r = (byte)(r * slot.r * weightedMeshAttachment.r * color.a);
|
||||
color.g = (byte)(g * slot.g * weightedMeshAttachment.g * color.a);
|
||||
color.b = (byte)(b * slot.b * weightedMeshAttachment.b * color.a);
|
||||
} else {
|
||||
color.r = (byte)(r * slot.r * weightedMeshAttachment.r);
|
||||
color.g = (byte)(g * slot.g * weightedMeshAttachment.g);
|
||||
color.b = (byte)(b * slot.b * weightedMeshAttachment.b);
|
||||
}
|
||||
if (slot.data.blendMode == BlendMode.additive) color.a = 0;
|
||||
|
||||
float[] attachmentUVs = weightedMeshAttachment.uvs;
|
||||
for (int iii = 0; iii < meshVertexCount; iii += 2) {
|
||||
float x = attVertBuffer[iii], y = attVertBuffer[iii + 1];
|
||||
vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z;
|
||||
colors32[vertexIndex] = color;
|
||||
uvs[vertexIndex].x = attachmentUVs[iii]; uvs[vertexIndex].y = attachmentUVs[iii + 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;
|
||||
|
||||
vertexIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var smartMesh = this.doubleBufferedSmartMesh.GetNext();
|
||||
var mesh = smartMesh.mesh;
|
||||
|
||||
bool structureDoesntMatch = newVertices || smartMesh.StructureDoesntMatch(attachmentList, instruction);
|
||||
|
||||
// Push triangles in this submesh
|
||||
if (structureDoesntMatch) {
|
||||
mesh.Clear();
|
||||
|
||||
int triangleCount = instruction.triangleCount;
|
||||
|
||||
int[] thisTriangles = this.triangles;
|
||||
if (triangles == null || triangles.Length < triangleCount) {
|
||||
this.triangles = thisTriangles = new int[triangleCount];
|
||||
} else if (triangles.Length > triangleCount) {
|
||||
for (int i = triangleCount; i < triangles.Length; i++)
|
||||
thisTriangles[i] = 0;
|
||||
}
|
||||
|
||||
// Iterate through submesh slots and store the triangles.
|
||||
int triangleIndex = 0;
|
||||
int afv = 0; // attachment first vertex, for single submesh, don't use instructions.firstVertexIndex
|
||||
|
||||
for (int i = instruction.startSlot, n = instruction.endSlot; i < n; i++) {
|
||||
var attachment = skeletonDrawOrderItems[i].attachment;
|
||||
|
||||
if (attachment is RegionAttachment) {
|
||||
thisTriangles[triangleIndex] = afv; thisTriangles[triangleIndex + 1] = afv + 2; thisTriangles[triangleIndex + 2] = afv + 1;
|
||||
thisTriangles[triangleIndex + 3] = afv + 2; thisTriangles[triangleIndex + 4] = afv + 3; thisTriangles[triangleIndex + 5] = afv + 1;
|
||||
|
||||
triangleIndex += 6;
|
||||
afv += 4;
|
||||
} else {
|
||||
int[] attachmentTriangles;
|
||||
int attachmentVertexCount;
|
||||
var meshAttachment = attachment as MeshAttachment;
|
||||
if (meshAttachment != null) {
|
||||
attachmentVertexCount = meshAttachment.vertices.Length >> 1; // length/2
|
||||
attachmentTriangles = meshAttachment.triangles;
|
||||
} else {
|
||||
var weightedMeshAttachment = attachment as WeightedMeshAttachment;
|
||||
if (weightedMeshAttachment != null) {
|
||||
attachmentVertexCount = weightedMeshAttachment.uvs.Length >> 1; // length/2
|
||||
attachmentTriangles = weightedMeshAttachment.triangles;
|
||||
} else
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++)
|
||||
thisTriangles[triangleIndex] = afv + attachmentTriangles[ii];
|
||||
|
||||
afv += attachmentVertexCount;
|
||||
}
|
||||
} // Done adding current submesh triangles
|
||||
}
|
||||
|
||||
Vector3 meshBoundsExtents = (meshBoundsMax - meshBoundsMin);
|
||||
Vector3 meshCenter = meshBoundsMin + meshBoundsExtents * 0.5f;
|
||||
|
||||
smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, attachmentList, instruction);
|
||||
mesh.bounds = new Bounds(meshCenter, meshBoundsExtents);
|
||||
|
||||
if (structureDoesntMatch) {
|
||||
mesh.triangles = triangles;
|
||||
}
|
||||
|
||||
return smartMesh.mesh;
|
||||
}
|
||||
|
||||
readonly DoubleBuffered<ArraysSingleSubmeshGenerator.SmartMesh> doubleBufferedSmartMesh = new DoubleBuffered<SmartMesh>();
|
||||
readonly ExposedList<Attachment> attachmentListBuffer = new ExposedList<Attachment>();
|
||||
|
||||
float[] attachmentVertexBuffer = new float[8];
|
||||
Vector3[] meshVertices;
|
||||
Color32[] meshColors32;
|
||||
Vector2[] meshUVs;
|
||||
int[] triangles;
|
||||
|
||||
class SmartMesh {
|
||||
public readonly Mesh mesh = SpineMesh.NewMesh();
|
||||
SubmeshInstruction instructionsUsed;
|
||||
readonly ExposedList<Attachment> attachmentsUsed = new ExposedList<Attachment>();
|
||||
|
||||
public void Set (Vector3[] verts, Vector2[] uvs, Color32[] colors, ExposedList<Attachment> attachmentList, SubmeshInstruction instructions) {
|
||||
mesh.vertices = verts;
|
||||
mesh.uv = uvs;
|
||||
mesh.colors32 = colors;
|
||||
instructionsUsed = instructions;
|
||||
|
||||
attachmentsUsed.Clear();
|
||||
attachmentsUsed.GrowIfNeeded(attachmentList.Capacity);
|
||||
attachmentsUsed.Count = attachmentList.Count;
|
||||
attachmentList.CopyTo(attachmentsUsed.Items);
|
||||
}
|
||||
|
||||
public bool StructureDoesntMatch (ExposedList<Attachment> attachmentList, SubmeshInstruction instructions) {
|
||||
// Check each submesh instructions for equal arrangement.
|
||||
var thisInstructions = instructionsUsed;
|
||||
if (
|
||||
instructions.skeleton != thisInstructions.skeleton ||
|
||||
instructions.material.GetInstanceID() != thisInstructions.material.GetInstanceID() ||
|
||||
instructions.startSlot != thisInstructions.startSlot ||
|
||||
instructions.endSlot != thisInstructions.endSlot ||
|
||||
instructions.triangleCount != thisInstructions.triangleCount ||
|
||||
instructions.vertexCount != thisInstructions.vertexCount
|
||||
) return true;
|
||||
//Debug.Log("structure matched");
|
||||
|
||||
// Check count inequality.
|
||||
if (attachmentList.Count != this.attachmentsUsed.Count) return true;
|
||||
var attachmentsPassed = attachmentList.Items;
|
||||
var myAttachments = this.attachmentsUsed.Items;
|
||||
for (int i = 0, n = attachmentsUsed.Count; i < n; i++)
|
||||
if (attachmentsPassed[i] != myAttachments[i]) return true;
|
||||
|
||||
//Debug.Log("attachments matched");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8bde87b725a537d4d9ff09a3ec7da8b5
|
||||
timeCreated: 1456493071
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -15,7 +15,7 @@ public class ArraysSubmeshedMeshGenerator : Spine.Unity.ISubmeshedMeshGenerator
|
||||
|
||||
public float zSpacing = 0f;
|
||||
|
||||
public SubmeshedMeshInstructions GenerateInstructions (Skeleton skeleton) {
|
||||
public SubmeshedMeshInstruction GenerateInstruction (Skeleton skeleton) {
|
||||
if (skeleton == null) throw new System.ArgumentNullException("skeleton");
|
||||
|
||||
// Count vertices and submesh triangles.
|
||||
@ -33,9 +33,9 @@ public class ArraysSubmeshedMeshGenerator : Spine.Unity.ISubmeshedMeshGenerator
|
||||
int separatorCount = separators.Count;
|
||||
|
||||
var instructionList = this.currentInstructions.submeshInstructions;
|
||||
instructionList.Clear();
|
||||
instructionList.Clear(false);
|
||||
|
||||
currentInstructions.attachmentList.Clear();
|
||||
currentInstructions.attachmentList.Clear(false);
|
||||
|
||||
for (int i = 0; i < drawOrderCount; i++) {
|
||||
var slot = drawOrderItems[i];
|
||||
@ -70,11 +70,10 @@ public class ArraysSubmeshedMeshGenerator : Spine.Unity.ISubmeshedMeshGenerator
|
||||
|
||||
// Populate submesh when material changes. (or when forced to separate by a submeshSeparator)
|
||||
if (( runningVertexCount > 0 && lastMaterial.GetInstanceID() != attachmentMaterial.GetInstanceID() ) ||
|
||||
//if (( lastMaterial != null && lastMaterial.GetInstanceID() != attachmentMaterial.GetInstanceID() ) ||
|
||||
( separatorCount > 0 && separators.Contains(slot) )) {
|
||||
|
||||
instructionList.Add(
|
||||
new SubmeshInstructions {
|
||||
new SubmeshInstruction {
|
||||
skeleton = skeleton,
|
||||
material = lastMaterial,
|
||||
triangleCount = submeshTriangleCount,
|
||||
@ -101,7 +100,7 @@ public class ArraysSubmeshedMeshGenerator : Spine.Unity.ISubmeshedMeshGenerator
|
||||
}
|
||||
|
||||
instructionList.Add(
|
||||
new SubmeshInstructions {
|
||||
new SubmeshInstruction {
|
||||
skeleton = skeleton,
|
||||
material = lastMaterial,
|
||||
triangleCount = submeshTriangleCount,
|
||||
@ -116,7 +115,7 @@ public class ArraysSubmeshedMeshGenerator : Spine.Unity.ISubmeshedMeshGenerator
|
||||
return currentInstructions;
|
||||
}
|
||||
|
||||
public SubmeshedMesh GenerateMesh (SubmeshedMeshInstructions meshInstructions) {
|
||||
public SubmeshedMesh GenerateMesh (SubmeshedMeshInstruction meshInstructions) {
|
||||
var smartMesh = doubleBufferedSmartMesh.GetNextMesh();
|
||||
var mesh = smartMesh.mesh;
|
||||
|
||||
@ -406,7 +405,7 @@ public class ArraysSubmeshedMeshGenerator : Spine.Unity.ISubmeshedMeshGenerator
|
||||
|
||||
#region Internals
|
||||
readonly DoubleBufferedSmartMesh doubleBufferedSmartMesh = new DoubleBufferedSmartMesh();
|
||||
readonly SubmeshedMeshInstructions currentInstructions = new SubmeshedMeshInstructions();
|
||||
readonly SubmeshedMeshInstruction currentInstructions = new SubmeshedMeshInstruction();
|
||||
|
||||
float[] attachmentVertexBuffer = new float[8];
|
||||
Vector3[] meshVertices;
|
||||
@ -442,39 +441,35 @@ public class ArraysSubmeshedMeshGenerator : Spine.Unity.ISubmeshedMeshGenerator
|
||||
class SmartMesh {
|
||||
public readonly Mesh mesh = SpineMesh.NewMesh();
|
||||
readonly ExposedList<Attachment> attachmentsUsed = new ExposedList<Attachment>();
|
||||
readonly ExposedList<SubmeshInstructions> instructionsUsed = new ExposedList<SubmeshInstructions>();
|
||||
readonly ExposedList<SubmeshInstruction> instructionsUsed = new ExposedList<SubmeshInstruction>();
|
||||
|
||||
public void Set (Vector3[] verts, Vector2[] uvs, Color32[] colors, SubmeshedMeshInstructions instructions) {
|
||||
public void Set (Vector3[] verts, Vector2[] uvs, Color32[] colors, SubmeshedMeshInstruction instruction) {
|
||||
mesh.vertices = verts;
|
||||
mesh.uv = uvs;
|
||||
mesh.colors32 = colors;
|
||||
|
||||
attachmentsUsed.Clear();
|
||||
attachmentsUsed.GrowIfNeeded(instructions.attachmentList.Capacity);
|
||||
attachmentsUsed.Count = instructions.attachmentList.Count;
|
||||
instructions.attachmentList.CopyTo(attachmentsUsed.Items);
|
||||
attachmentsUsed.Clear(false);
|
||||
attachmentsUsed.GrowIfNeeded(instruction.attachmentList.Capacity);
|
||||
attachmentsUsed.Count = instruction.attachmentList.Count;
|
||||
instruction.attachmentList.CopyTo(attachmentsUsed.Items);
|
||||
|
||||
instructionsUsed.Clear();
|
||||
instructionsUsed.GrowIfNeeded(instructions.submeshInstructions.Capacity);
|
||||
instructionsUsed.Count = instructions.submeshInstructions.Count;
|
||||
instructions.submeshInstructions.CopyTo(instructionsUsed.Items);
|
||||
instructionsUsed.Clear(false);
|
||||
instructionsUsed.GrowIfNeeded(instruction.submeshInstructions.Capacity);
|
||||
instructionsUsed.Count = instruction.submeshInstructions.Count;
|
||||
instruction.submeshInstructions.CopyTo(instructionsUsed.Items);
|
||||
}
|
||||
|
||||
public bool StructureDoesntMatch (SubmeshedMeshInstructions instructions) {
|
||||
public bool StructureDoesntMatch (SubmeshedMeshInstruction instructions) {
|
||||
// Check count inequality.
|
||||
if (instructions.attachmentList.Count != this.attachmentsUsed.Count) return true;
|
||||
if (instructions.submeshInstructions.Count != this.instructionsUsed.Count) return true;
|
||||
|
||||
//Debug.Log("broadphase matched");
|
||||
|
||||
// Check each attachment.
|
||||
var attachmentsPassed = instructions.attachmentList.Items;
|
||||
var myAttachments = this.attachmentsUsed.Items;
|
||||
for (int i = 0, n = attachmentsUsed.Count; i < n; i++)
|
||||
if (attachmentsPassed[i] != myAttachments[i]) return true;
|
||||
|
||||
//Debug.Log("attachments matched");
|
||||
|
||||
// Check each submesh for equal arrangement.
|
||||
var instructionListItems = instructions.submeshInstructions.Items;
|
||||
var myInstructions = this.instructionsUsed.Items;
|
||||
@ -482,7 +477,6 @@ public class ArraysSubmeshedMeshGenerator : Spine.Unity.ISubmeshedMeshGenerator
|
||||
var lhs = instructionListItems[i];
|
||||
var rhs = myInstructions[i];
|
||||
if (
|
||||
lhs.skeleton != rhs.skeleton ||
|
||||
lhs.material.GetInstanceID() != rhs.material.GetInstanceID() ||
|
||||
lhs.startSlot != rhs.startSlot ||
|
||||
lhs.endSlot != rhs.endSlot ||
|
||||
@ -5,18 +5,18 @@ namespace Spine.Unity {
|
||||
public interface ISubmeshedMeshGenerator {
|
||||
/// <summary>Generates instructions for how to generate the submeshed mesh based on the given state of the
|
||||
/// skeleton. The returned instructions can be used to generate a whole submeshed mesh or individual submeshes.</summary>
|
||||
SubmeshedMeshInstructions GenerateInstructions (Skeleton skeleton);
|
||||
SubmeshedMeshInstruction GenerateInstruction (Skeleton skeleton);
|
||||
|
||||
/// <summary>Returns a SubmeshedMesh (a mesh and a material array coupled in a struct).
|
||||
/// Call GenerateInstructions to get the SubmeshedMeshInstructions to pass into this.</summary>
|
||||
SubmeshedMesh GenerateMesh (SubmeshedMeshInstructions wholeMeshInstruction);
|
||||
SubmeshedMesh GenerateMesh (SubmeshedMeshInstruction wholeMeshInstruction);
|
||||
|
||||
/// <summary>A list of slots that mark the end of a submesh. The slot after it will be the start of a new submesh.</summary>
|
||||
List<Slot> Separators { get; }
|
||||
}
|
||||
|
||||
public interface ISingleSubmeshGenerator {
|
||||
void FillMesh (SubmeshInstructions instructions, Mesh meshToFill);
|
||||
Mesh GenerateMesh (SubmeshInstruction instruction);
|
||||
}
|
||||
|
||||
/// <summary>A Submeshed mesh is a return type so the mesh with
|
||||
@ -31,8 +31,8 @@ namespace Spine.Unity {
|
||||
}
|
||||
|
||||
/// <summary>Primarily a collection of Submesh Instructions. This constitutes instructions for how to construct a mesh containing submeshes.</summary>
|
||||
public class SubmeshedMeshInstructions {
|
||||
public readonly ExposedList<SubmeshInstructions> submeshInstructions = new ExposedList<SubmeshInstructions>();
|
||||
public class SubmeshedMeshInstruction {
|
||||
public readonly ExposedList<SubmeshInstruction> submeshInstructions = new ExposedList<SubmeshInstruction>();
|
||||
public readonly ExposedList<Attachment> attachmentList = new ExposedList<Attachment>();
|
||||
public int vertexCount = -1;
|
||||
|
||||
@ -52,7 +52,7 @@ namespace Spine.Unity {
|
||||
}
|
||||
|
||||
/// <summary>Instructions for how to generate a mesh or submesh out of a range of slots in a given skeleton.</summary>
|
||||
public struct SubmeshInstructions {
|
||||
public struct SubmeshInstruction {
|
||||
public Skeleton skeleton;
|
||||
public int startSlot;
|
||||
public int endSlot;
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a361f5ac799a5149b340f9e20da27d1
|
||||
folderAsset: yes
|
||||
timeCreated: 1457405502
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 211465c9f045fd142abe552a6ffdc799
|
||||
folderAsset: yes
|
||||
timeCreated: 1457405813
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,36 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEditor;
|
||||
using Spine.Unity;
|
||||
|
||||
[CustomEditor(typeof(SpineRenderSeparator))]
|
||||
public class SpineRenderSeparatorInspector : Editor {
|
||||
|
||||
SpineRenderSeparator component;
|
||||
|
||||
void OnEnable () {
|
||||
component = target as SpineRenderSeparator;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI () {
|
||||
base.OnInspectorGUI();
|
||||
if (GUILayout.Button("Destroy Submesh Renderers")) {
|
||||
if (EditorUtility.DisplayDialog("Destroy Submesh Renderers", "Do you really want to destroy all the SubmeshRenderer GameObjects in the list?", "Destroy", "Cancel")) {
|
||||
|
||||
for (int i = 0; i < component.submeshRenderers.Count; i++) {
|
||||
Debug.LogFormat("Destroying {0}", component.submeshRenderers[i].gameObject.name);
|
||||
DestroyImmediate(component.submeshRenderers[i].gameObject);
|
||||
}
|
||||
|
||||
component.submeshRenderers.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Add SubmeshRenderer")) {
|
||||
int index = component.submeshRenderers.Count;
|
||||
var smr = SubmeshRenderer.NewSubmeshRendererGameObject(component.transform, index.ToString());
|
||||
component.submeshRenderers.Add(smr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8742ee1d54c9954d95c9e6508806ac2
|
||||
timeCreated: 1457405832
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,63 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Spine.Unity;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class SpineRenderSeparator : MonoBehaviour {
|
||||
[SerializeField]
|
||||
protected SkeletonRenderer skeletonRenderer;
|
||||
public SkeletonRenderer SkeletonRenderer {
|
||||
get { return skeletonRenderer; }
|
||||
set {
|
||||
if (skeletonRenderer != null)
|
||||
skeletonRenderer.GenerateMeshOverride -= SeparatelyRenderSubmeshes;
|
||||
skeletonRenderer = value;
|
||||
}
|
||||
}
|
||||
|
||||
MeshRenderer masterMeshRenderer;
|
||||
|
||||
public List<Spine.Unity.SubmeshRenderer> submeshRenderers = new List<SubmeshRenderer>();
|
||||
public bool propagateMaterialPropertyBlock = false;
|
||||
|
||||
void OnEnable () {
|
||||
if (skeletonRenderer == null) return;
|
||||
if (block == null) block = new MaterialPropertyBlock();
|
||||
masterMeshRenderer = skeletonRenderer.GetComponent<MeshRenderer>();
|
||||
masterMeshRenderer.enabled = false;
|
||||
skeletonRenderer.GenerateMeshOverride -= SeparatelyRenderSubmeshes;
|
||||
skeletonRenderer.GenerateMeshOverride += SeparatelyRenderSubmeshes;
|
||||
}
|
||||
|
||||
void OnDisable () {
|
||||
if (skeletonRenderer == null) return;
|
||||
|
||||
masterMeshRenderer.enabled = true;
|
||||
skeletonRenderer.GenerateMeshOverride -= SeparatelyRenderSubmeshes;
|
||||
|
||||
foreach (var s in submeshRenderers)
|
||||
s.ClearMesh();
|
||||
}
|
||||
|
||||
MaterialPropertyBlock block;
|
||||
|
||||
void SeparatelyRenderSubmeshes (SkeletonRenderer.SmartMesh.Instruction instruction) {
|
||||
var submeshInstructions = instruction.submeshInstructions;
|
||||
var submeshInstructionsItems = submeshInstructions.Items;
|
||||
for (int i = 0; i < instruction.submeshInstructions.Count; i++) {
|
||||
if (i >= submeshRenderers.Count) return;
|
||||
var submeshRenderer = submeshRenderers[i];
|
||||
submeshRenderer.RenderSubmesh(submeshInstructionsItems[i]);
|
||||
|
||||
if (propagateMaterialPropertyBlock) {
|
||||
masterMeshRenderer.GetPropertyBlock(block);
|
||||
submeshRenderer.SetPropertyBlock(block);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c70a5b35f6ff2541aed8e8346b7e4d5
|
||||
timeCreated: 1457405791
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 792af191c395561459cc0cc03a517ae8
|
||||
folderAsset: yes
|
||||
timeCreated: 1457401769
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5eec1664658bb4344909619707652674
|
||||
folderAsset: yes
|
||||
timeCreated: 1457405608
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,22 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEditor;
|
||||
using Spine.Unity;
|
||||
|
||||
[CustomEditor(typeof(SubmeshRenderer))]
|
||||
public class SubmeshRendererInspector : Editor {
|
||||
|
||||
SpineInspectorUtility.SerializedSortingProperties sortingProperties;
|
||||
SubmeshRenderer component;
|
||||
|
||||
void OnEnable () {
|
||||
component = target as SubmeshRenderer;
|
||||
sortingProperties = new SpineInspectorUtility.SerializedSortingProperties(component.GetComponent<MeshRenderer>());
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI () {
|
||||
DrawDefaultInspector();
|
||||
SpineInspectorUtility.SortingPropertyFields(sortingProperties, true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15418e02758268b488e9ab86f805330c
|
||||
timeCreated: 1457407060
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,63 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Spine.Unity {
|
||||
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
|
||||
public class SubmeshRenderer : MonoBehaviour {
|
||||
ISingleSubmeshGenerator meshGenerator;
|
||||
public ISingleSubmeshGenerator MeshGenerator {
|
||||
get {
|
||||
LazyIntialize();
|
||||
return meshGenerator;
|
||||
}
|
||||
}
|
||||
|
||||
MeshRenderer meshRenderer;
|
||||
public MeshRenderer MeshRenderer {
|
||||
get {
|
||||
LazyIntialize();
|
||||
return meshRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
MeshFilter meshFilter;
|
||||
public MeshFilter MeshFilter {
|
||||
get {
|
||||
LazyIntialize();
|
||||
return meshFilter;
|
||||
}
|
||||
}
|
||||
|
||||
void LazyIntialize () {
|
||||
if (meshGenerator != null) return;
|
||||
meshGenerator = new ArraysSingleSubmeshGenerator(); // swap this out with your custom ISingleSubmeshGenerator code.
|
||||
meshFilter = GetComponent<MeshFilter>();
|
||||
meshRenderer = GetComponent<MeshRenderer>();
|
||||
}
|
||||
|
||||
public void ClearMesh () {
|
||||
meshFilter.sharedMesh = null;
|
||||
}
|
||||
|
||||
public void RenderSubmesh (SubmeshInstruction instruction) {
|
||||
LazyIntialize();
|
||||
meshRenderer.sharedMaterial = instruction.material;
|
||||
meshFilter.sharedMesh = meshGenerator.GenerateMesh(instruction);
|
||||
}
|
||||
|
||||
public void SetPropertyBlock (MaterialPropertyBlock block) {
|
||||
LazyIntialize();
|
||||
meshRenderer.SetPropertyBlock(block);
|
||||
}
|
||||
|
||||
public static SubmeshRenderer NewSubmeshRendererGameObject (Transform parent, string name) {
|
||||
var go = new GameObject(name, typeof(MeshFilter), typeof(MeshRenderer));
|
||||
go.transform.SetParent(parent, false);
|
||||
var returnComponent = go.AddComponent<SubmeshRenderer>();
|
||||
|
||||
return returnComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5273e5c60bd84a44db5a4e8f3252eef0
|
||||
timeCreated: 1457396525
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -32,6 +32,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Spine;
|
||||
using Spine.Unity;
|
||||
|
||||
/// <summary>Renders a skeleton.</summary>
|
||||
[ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent]
|
||||
@ -52,11 +53,15 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
|
||||
// Submesh Separation
|
||||
[SpineSlot] public string[] submeshSeparators = new string[0];
|
||||
[HideInInspector] public List<Slot> submeshSeparatorSlots = new List<Slot>();
|
||||
[System.NonSerialized] public List<Slot> submeshSeparatorSlots = new List<Slot>();
|
||||
|
||||
// Custom Slot Material
|
||||
[System.NonSerialized] private readonly Dictionary<Slot, Material> customSlotMaterials = new Dictionary<Slot, Material>();
|
||||
[System.NonSerialized] readonly Dictionary<Slot, Material> customSlotMaterials = new Dictionary<Slot, Material>();
|
||||
public Dictionary<Slot, Material> CustomSlotMaterials { get { return customSlotMaterials; } }
|
||||
|
||||
// Custom Mesh Generation Override
|
||||
public delegate void InstructionDelegate (SkeletonRenderer.SmartMesh.Instruction instruction);
|
||||
public event InstructionDelegate GenerateMeshOverride;
|
||||
#endregion
|
||||
|
||||
[System.NonSerialized] public bool valid;
|
||||
@ -65,7 +70,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
MeshRenderer meshRenderer;
|
||||
MeshFilter meshFilter;
|
||||
|
||||
DoubleBufferedSmartMesh doubleBufferedMesh;
|
||||
Spine.Unity.DoubleBuffered<SkeletonRenderer.SmartMesh> doubleBufferedMesh;
|
||||
readonly SmartMesh.Instruction currentInstructions = new SmartMesh.Instruction();
|
||||
readonly ExposedList<SubmeshTriangleBuffer> submeshes = new ExposedList<SubmeshTriangleBuffer>();
|
||||
|
||||
@ -80,8 +85,6 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
Vector3[] normals;
|
||||
Vector4[] tangents;
|
||||
|
||||
SkeletonUtilitySubmeshRenderer[] submeshRenderers;
|
||||
|
||||
#region Runtime Instantiation
|
||||
public static T NewSpineGameObject<T> (SkeletonDataAsset skeletonDataAsset) where T : SkeletonRenderer {
|
||||
return SkeletonRenderer.AddSpineComponent<T>(new GameObject("New Spine GameObject"), skeletonDataAsset);
|
||||
@ -140,7 +143,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
|
||||
meshFilter = GetComponent<MeshFilter>();
|
||||
meshRenderer = GetComponent<MeshRenderer>();
|
||||
doubleBufferedMesh = new DoubleBufferedSmartMesh();
|
||||
doubleBufferedMesh = new DoubleBuffered<SmartMesh>();
|
||||
vertices = new Vector3[0];
|
||||
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
@ -152,23 +155,17 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
submeshSeparatorSlots.Add(skeleton.FindSlot(submeshSeparators[i]));
|
||||
}
|
||||
|
||||
CollectSubmeshRenderers();
|
||||
|
||||
LateUpdate();
|
||||
|
||||
if (OnRebuild != null)
|
||||
OnRebuild(this);
|
||||
}
|
||||
|
||||
public void CollectSubmeshRenderers () {
|
||||
submeshRenderers = GetComponentsInChildren<SkeletonUtilitySubmeshRenderer>();
|
||||
}
|
||||
|
||||
public virtual void LateUpdate () {
|
||||
if (!valid)
|
||||
return;
|
||||
|
||||
if (!meshRenderer.enabled && submeshRenderers.Length == 0)
|
||||
if (!meshRenderer.enabled && GenerateMeshOverride == null)
|
||||
return;
|
||||
|
||||
// Step 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes.
|
||||
@ -202,6 +199,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
bool isCustomMaterialsPopulated = customSlotMaterials.Count > 0;
|
||||
|
||||
int vertexCount = 0;
|
||||
int submeshVertexCount = 0;
|
||||
int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0;
|
||||
Material lastMaterial = null;
|
||||
for (int i = 0; i < drawOrderCount; i++) {
|
||||
@ -261,16 +259,19 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
(submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) {
|
||||
|
||||
workingSubmeshInstructions.Add(
|
||||
new SmartMesh.Instruction.SubmeshInstruction {
|
||||
new Spine.Unity.SubmeshInstruction {
|
||||
skeleton = this.skeleton,
|
||||
material = lastMaterial,
|
||||
startSlot = submeshStartSlotIndex,
|
||||
endSlot = i,
|
||||
triangleCount = submeshTriangleCount,
|
||||
firstVertex = submeshFirstVertex,
|
||||
firstVertexIndex = submeshFirstVertex,
|
||||
vertexCount = submeshVertexCount
|
||||
}
|
||||
);
|
||||
|
||||
submeshTriangleCount = 0;
|
||||
submeshVertexCount = 0;
|
||||
submeshFirstVertex = vertexCount;
|
||||
submeshStartSlotIndex = i;
|
||||
}
|
||||
@ -278,15 +279,18 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
|
||||
submeshTriangleCount += attachmentTriangleCount;
|
||||
vertexCount += attachmentVertexCount;
|
||||
submeshVertexCount += attachmentVertexCount;
|
||||
}
|
||||
|
||||
workingSubmeshInstructions.Add(
|
||||
new SmartMesh.Instruction.SubmeshInstruction {
|
||||
new Spine.Unity.SubmeshInstruction {
|
||||
skeleton = this.skeleton,
|
||||
material = lastMaterial,
|
||||
startSlot = submeshStartSlotIndex,
|
||||
endSlot = drawOrderCount,
|
||||
triangleCount = submeshTriangleCount,
|
||||
firstVertex = submeshFirstVertex,
|
||||
firstVertexIndex = submeshFirstVertex,
|
||||
vertexCount = submeshVertexCount
|
||||
}
|
||||
);
|
||||
|
||||
@ -294,6 +298,10 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
workingInstruction.immutableTriangles = this.immutableTriangles;
|
||||
workingInstruction.frontFacing = this.frontFacing;
|
||||
|
||||
if (GenerateMeshOverride != null) {
|
||||
GenerateMeshOverride(workingInstruction);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2. Update vertex buffer based on verts from the attachments.
|
||||
// Uses values that were also stored in workingInstruction.
|
||||
@ -509,7 +517,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
}
|
||||
|
||||
// Step 3. Move the mesh data into a UnityEngine.Mesh
|
||||
var currentSmartMesh = doubleBufferedMesh.GetNextMesh(); // Double-buffer for performance.
|
||||
var currentSmartMesh = doubleBufferedMesh.GetNext(); // Double-buffer for performance.
|
||||
var currentMesh = currentSmartMesh.mesh;
|
||||
|
||||
currentMesh.vertices = vertices;
|
||||
@ -590,20 +598,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
|
||||
|
||||
// Step 5. Miscellaneous
|
||||
// Submesh Renderers
|
||||
if (submeshRenderers.Length > 0) {
|
||||
var thisSharedMaterials = this.sharedMaterials;
|
||||
for (int i = 0; i < submeshRenderers.Length; i++) {
|
||||
SkeletonUtilitySubmeshRenderer submeshRenderer = submeshRenderers[i];
|
||||
if (submeshRenderer.submeshIndex < thisSharedMaterials.Length) {
|
||||
submeshRenderer.SetMesh(meshRenderer, currentMesh, thisSharedMaterials[submeshRenderer.submeshIndex]);
|
||||
} else {
|
||||
submeshRenderer.GetComponent<Renderer>().enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add stuff here if you want
|
||||
}
|
||||
|
||||
static bool CheckIfMustUpdateMeshStructure (SmartMesh.Instruction a, SmartMesh.Instruction b) {
|
||||
@ -613,6 +608,9 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if (a.vertexCount != b.vertexCount)
|
||||
return true;
|
||||
|
||||
if (a.immutableTriangles != b.immutableTriangles)
|
||||
return true;
|
||||
|
||||
@ -652,22 +650,25 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
var submeshA = submeshInstructionsItemsA[i];
|
||||
var submeshB = submeshInstructionsItemsB[i];
|
||||
|
||||
if (!(submeshA.startSlot == submeshB.startSlot &&
|
||||
if (!(
|
||||
submeshA.vertexCount == submeshB.vertexCount &&
|
||||
submeshA.startSlot == submeshB.startSlot &&
|
||||
submeshA.endSlot == submeshB.endSlot &&
|
||||
submeshA.triangleCount == submeshB.triangleCount &&
|
||||
submeshA.firstVertex == submeshB.firstVertex))
|
||||
submeshA.firstVertexIndex == submeshB.firstVertexIndex
|
||||
))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetSubmesh (int submeshIndex, SmartMesh.Instruction.SubmeshInstruction submeshInstructions, ExposedList<bool> flipStates, bool isLastSubmesh) {
|
||||
void SetSubmesh (int submeshIndex, Spine.Unity.SubmeshInstruction submeshInstructions, ExposedList<bool> flipStates, bool isLastSubmesh) {
|
||||
SubmeshTriangleBuffer currentSubmesh = submeshes.Items[submeshIndex];
|
||||
int[] triangles = currentSubmesh.triangles;
|
||||
|
||||
int triangleCount = submeshInstructions.triangleCount;
|
||||
int firstVertex = submeshInstructions.firstVertex;
|
||||
int firstVertex = submeshInstructions.firstVertexIndex;
|
||||
|
||||
int trianglesCapacity = triangles.Length;
|
||||
if (isLastSubmesh && trianglesCapacity > triangleCount) {
|
||||
@ -787,19 +788,8 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
}
|
||||
#endif
|
||||
|
||||
class DoubleBufferedSmartMesh {
|
||||
readonly SmartMesh mesh1 = new SmartMesh();
|
||||
readonly SmartMesh mesh2 = new SmartMesh();
|
||||
bool usingMesh1;
|
||||
|
||||
public SmartMesh GetNextMesh () {
|
||||
usingMesh1 = !usingMesh1;
|
||||
return usingMesh1 ? mesh1 : mesh2;
|
||||
}
|
||||
}
|
||||
|
||||
///<summary>This is a Mesh that also stores the instructions SkeletonRenderer generated for it.</summary>
|
||||
class SmartMesh {
|
||||
public class SmartMesh {
|
||||
public Mesh mesh = Spine.Unity.SpineMesh.NewMesh();
|
||||
public SmartMesh.Instruction instructionUsed = new SmartMesh.Instruction();
|
||||
|
||||
@ -809,11 +799,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
public int vertexCount = -1;
|
||||
public readonly ExposedList<Attachment> attachments = new ExposedList<Attachment>();
|
||||
public readonly ExposedList<bool> attachmentFlips = new ExposedList<bool>();
|
||||
public readonly ExposedList<SubmeshInstruction> submeshInstructions = new ExposedList<SubmeshInstruction>();
|
||||
public struct SubmeshInstruction {
|
||||
public Material material;
|
||||
public int firstVertex, startSlot, endSlot, triangleCount;
|
||||
}
|
||||
public readonly ExposedList<Spine.Unity.SubmeshInstruction> submeshInstructions = new ExposedList<Spine.Unity.SubmeshInstruction>();
|
||||
|
||||
public void Clear () {
|
||||
this.attachments.Clear(false);
|
||||
@ -824,7 +810,6 @@ public class SkeletonRenderer : MonoBehaviour {
|
||||
public void Set (Instruction other) {
|
||||
this.immutableTriangles = other.immutableTriangles;
|
||||
this.frontFacing = other.frontFacing;
|
||||
//this.requiresUpdate = other.requiresUpdate;
|
||||
this.vertexCount = other.vertexCount;
|
||||
|
||||
this.attachments.Clear(false);
|
||||
|
||||
@ -35,9 +35,7 @@ public class SkeletonUtilityInspector : Editor {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
typeof(EditorGUIUtility).InvokeMember("SetIconForObject", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic, null, null, new object[2] {
|
||||
utilityBone.gameObject,
|
||||
icon
|
||||
@ -170,8 +168,9 @@ public class SkeletonUtilityInspector : Editor {
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
if (GUILayout.Button(new GUIContent("Spawn Submeshes", SpineEditorUtilities.Icons.subMeshRenderer), GUILayout.Width(150), GUILayout.Height(24)))
|
||||
skeletonUtility.SpawnSubRenderers(true);
|
||||
// if (GUILayout.Button(new GUIContent("Spawn Submeshes", SpineEditorUtilities.Icons.subMeshRenderer), GUILayout.Width(150), GUILayout.Height(24)))
|
||||
// skeletonUtility.SpawnSubRenderers(true);
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
@ -1,79 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes Software License
|
||||
* Version 2.3
|
||||
*
|
||||
* Copyright (c) 2013-2015, Esoteric Software
|
||||
* All rights reserved.
|
||||
*
|
||||
* You are granted a perpetual, non-exclusive, non-sublicensable and
|
||||
* non-transferable license to use, install, execute and perform the Spine
|
||||
* Runtimes Software (the "Software") and derivative works solely for personal
|
||||
* or internal use. Without the written permission of Esoteric Software (see
|
||||
* Section 2 of the Spine Software License Agreement), you may not (a) modify,
|
||||
* translate, adapt or otherwise create derivative works, improvements of the
|
||||
* Software or develop new applications using the Software or (b) remove,
|
||||
* delete, alter or obscure any trademarks or any copyright, trademark, patent
|
||||
* or other intellectual property or proprietary rights notices on or in the
|
||||
* Software, including any copy thereof. Redistributions in binary or source
|
||||
* form must include this license and terms.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
[CustomEditor(typeof(SkeletonUtilitySubmeshRenderer))]
|
||||
public class SkeletonUtilitySubmeshRendererInspector : Editor {
|
||||
|
||||
private static MethodInfo EditorGUILayoutSortingLayerField;
|
||||
protected SerializedObject rendererSerializedObject;
|
||||
protected SerializedProperty sortingLayerIDProperty;
|
||||
|
||||
SkeletonUtilitySubmeshRenderer component;
|
||||
|
||||
void OnEnable () {
|
||||
component = (SkeletonUtilitySubmeshRenderer)target;
|
||||
|
||||
if (EditorGUILayoutSortingLayerField == null)
|
||||
EditorGUILayoutSortingLayerField = typeof(EditorGUILayout).GetMethod("SortingLayerField", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(GUIContent), typeof(SerializedProperty), typeof(GUIStyle) }, null);
|
||||
|
||||
rendererSerializedObject = new SerializedObject(((SkeletonUtilitySubmeshRenderer)target).GetComponent<Renderer>());
|
||||
sortingLayerIDProperty = rendererSerializedObject.FindProperty("m_SortingLayerID");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI () {
|
||||
// Sorting Layers
|
||||
{
|
||||
var renderer = component.GetComponent<Renderer>();
|
||||
if (renderer != null) {
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
if (EditorGUILayoutSortingLayerField != null && sortingLayerIDProperty != null) {
|
||||
EditorGUILayoutSortingLayerField.Invoke(null, new object[] { new GUIContent("Sorting Layer"), sortingLayerIDProperty, EditorStyles.popup });
|
||||
} else {
|
||||
renderer.sortingLayerID = EditorGUILayout.IntField("Sorting Layer ID", renderer.sortingLayerID);
|
||||
}
|
||||
|
||||
renderer.sortingOrder = EditorGUILayout.IntField("Order in Layer", renderer.sortingOrder);
|
||||
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
rendererSerializedObject.ApplyModifiedProperties();
|
||||
EditorUtility.SetDirty(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -381,24 +381,4 @@ public class SkeletonUtility : MonoBehaviour {
|
||||
return go;
|
||||
}
|
||||
|
||||
public void SpawnSubRenderers (bool disablePrimaryRenderer) {
|
||||
int submeshCount = GetComponent<MeshFilter>().sharedMesh.subMeshCount;
|
||||
|
||||
for (int i = 0; i < submeshCount; i++) {
|
||||
GameObject go = new GameObject("Submesh " + i, typeof(MeshFilter), typeof(MeshRenderer));
|
||||
go.transform.parent = transform;
|
||||
go.transform.localPosition = Vector3.zero;
|
||||
go.transform.localRotation = Quaternion.identity;
|
||||
go.transform.localScale = Vector3.one;
|
||||
|
||||
SkeletonUtilitySubmeshRenderer s = go.AddComponent<SkeletonUtilitySubmeshRenderer>();
|
||||
s.GetComponent<Renderer>().sortingOrder = i * 10;
|
||||
s.submeshIndex = i;
|
||||
}
|
||||
|
||||
skeletonRenderer.CollectSubmeshRenderers();
|
||||
|
||||
if (disablePrimaryRenderer)
|
||||
GetComponent<Renderer>().enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes Software License
|
||||
* Version 2.3
|
||||
*
|
||||
* Copyright (c) 2013-2015, Esoteric Software
|
||||
* All rights reserved.
|
||||
*
|
||||
* You are granted a perpetual, non-exclusive, non-sublicensable and
|
||||
* non-transferable license to use, install, execute and perform the Spine
|
||||
* Runtimes Software (the "Software") and derivative works solely for personal
|
||||
* or internal use. Without the written permission of Esoteric Software (see
|
||||
* Section 2 of the Spine Software License Agreement), you may not (a) modify,
|
||||
* translate, adapt or otherwise create derivative works, improvements of the
|
||||
* Software or develop new applications using the Software or (b) remove,
|
||||
* delete, alter or obscure any trademarks or any copyright, trademark, patent
|
||||
* or other intellectual property or proprietary rights notices on or in the
|
||||
* Software, including any copy thereof. Redistributions in binary or source
|
||||
* form must include this license and terms.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class SkeletonUtilitySubmeshRenderer : MonoBehaviour {
|
||||
[System.NonSerialized]
|
||||
public Mesh mesh;
|
||||
public int submeshIndex = 0;
|
||||
public Material hiddenPassMaterial;
|
||||
Renderer cachedRenderer;
|
||||
MeshFilter filter;
|
||||
Material[] sharedMaterials;
|
||||
|
||||
void Awake () {
|
||||
cachedRenderer = GetComponent<Renderer>();
|
||||
filter = GetComponent<MeshFilter>();
|
||||
sharedMaterials = new Material[0];
|
||||
}
|
||||
|
||||
public void SetMesh (Renderer parentRenderer, Mesh mesh, Material mat) {
|
||||
if (cachedRenderer == null)
|
||||
return;
|
||||
|
||||
cachedRenderer.enabled = true;
|
||||
filter.sharedMesh = mesh;
|
||||
if (cachedRenderer.sharedMaterials.Length != parentRenderer.sharedMaterials.Length) {
|
||||
sharedMaterials = parentRenderer.sharedMaterials;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sharedMaterials.Length; i++) {
|
||||
if (i == submeshIndex)
|
||||
sharedMaterials[i] = mat;
|
||||
else
|
||||
sharedMaterials[i] = hiddenPassMaterial;
|
||||
}
|
||||
|
||||
cachedRenderer.sharedMaterials = sharedMaterials;
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7820c1c2b0e52c6408de899d6939996e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- parentRenderer: {instanceID: 0}
|
||||
- mesh: {instanceID: 0}
|
||||
- hiddenPassMaterial: {fileID: 2100000, guid: 43227e5adadc6f24bb4bf74b92a56fb4,
|
||||
type: 2}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
x
Reference in New Issue
Block a user