RenderSeparator update.

This commit is contained in:
pharan 2016-03-24 00:35:19 +08:00
parent 9254e18801
commit 46ee116ee3
6 changed files with 114 additions and 101 deletions

View File

@ -119,7 +119,7 @@ namespace Spine.Unity.MeshGeneration {
startSlot = submeshStartSlotIndex,
endSlot = i,
firstVertexIndex = submeshFirstVertex,
separatedBySlot = separatedBySlot
forceSeparate = separatedBySlot
}
);
@ -147,7 +147,7 @@ namespace Spine.Unity.MeshGeneration {
startSlot = submeshStartSlotIndex,
endSlot = drawOrderCount,
firstVertexIndex = submeshFirstVertex,
separatedBySlot = false
forceSeparate = false
}
);

View File

@ -51,7 +51,7 @@ namespace Spine.Unity.MeshGeneration {
// Vertex index offset. Used by submesh generation if part of a bigger mesh.
public int firstVertexIndex;
public bool separatedBySlot;
public bool forceSeparate;
/// <summary>The number of slots in this SubmeshInstruction's range. Not necessarily the number of attachments.</summary>
public int SlotCount { get { return endSlot - startSlot; } }

View File

@ -36,10 +36,10 @@ using UnityEngine;
using UnityEditor;
using Spine;
namespace Spine.Unity {
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonGraphic))]
public class SkeletonGraphicInspector : Editor {
public class SkeletonGraphicInspector : UnityEditor.Editor {
SerializedProperty material_, color_;
SerializedProperty skeletonDataAsset_, initialSkinName_;
SerializedProperty startingAnimation_, startingLoop_, timeScale_, freeze_;
@ -133,7 +133,7 @@ namespace Spine.Unity {
}
}
[MenuItem("GameObject/Spine/SkeletonGraphic (UnityUI)", false, 10)]
[MenuItem("GameObject/Spine/SkeletonGraphic (UnityUI)", false, 15)]
static public void SkeletonGraphicCreateMenuItem () {
var parentGameObject = Selection.activeObject as GameObject;
var parentTransform = parentGameObject == null ? null : parentGameObject.GetComponent<RectTransform>();
@ -149,7 +149,7 @@ namespace Spine.Unity {
EditorGUIUtility.PingObject(Selection.activeObject);
}
[MenuItem("Assets/Spine/Instantiate (UnityUI)", false, 10)]
[MenuItem("Assets/Spine/Instantiate (UnityUI)", false, 20)]
static void InstantiateSkeletonGraphic () {
Object[] arr = Selection.objects;
foreach (Object o in arr) {
@ -161,7 +161,7 @@ namespace Spine.Unity {
}
}
[MenuItem("Assets/Spine/Instantiate (UnityUI)", true, 10)]
[MenuItem("Assets/Spine/Instantiate (UnityUI)", true, 20)]
static bool ValidateInstantiateSkeletonGraphic () {
Object[] arr = Selection.objects;

View File

@ -3,17 +3,19 @@ using System.Collections;
using UnityEditor;
using Spine.Unity;
[CustomEditor(typeof(SkeletonPartsRenderer))]
public class SkeletonRenderPartInspector : Editor {
SpineInspectorUtility.SerializedSortingProperties sortingProperties;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonPartsRenderer))]
public class SkeletonRenderPartInspector : UnityEditor.Editor {
SpineInspectorUtility.SerializedSortingProperties sortingProperties;
void OnEnable () {
var component = target as Component;
sortingProperties = new SpineInspectorUtility.SerializedSortingProperties(component.GetComponent<MeshRenderer>());
void OnEnable () {
sortingProperties = new SpineInspectorUtility.SerializedSortingProperties((target as Component).GetComponent<MeshRenderer>());
}
public override void OnInspectorGUI () {
DrawDefaultInspector();
SpineInspectorUtility.SortingPropertyFields(sortingProperties, true);
}
}
public override void OnInspectorGUI () {
DrawDefaultInspector();
SpineInspectorUtility.SortingPropertyFields(sortingProperties, true);
}
}

View File

@ -1,20 +1,22 @@
using UnityEngine;
using UnityEditor;
namespace Spine.Unity {
using Spine.Unity;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonRenderSeparator))]
public class SkeletonRenderSeparatorInspector : Editor {
public class SkeletonRenderSeparatorInspector : UnityEditor.Editor {
SkeletonRenderSeparator component;
// Properties
SerializedProperty skeletonRenderer_, copyPropertyBlock_, copyMeshRendererFlags_, partsRenderers_;
static bool partsRenderersExpanded = false;
// For separator field.
SerializedObject skeletonRendererSerializedObject;
SerializedProperty separatorNamesProp;
bool separatorExpanded = true;
System.Func<int, string, string, string> Plural = SpineInspectorUtility.Pluralize;
static bool skeletonRendererExpanded = true;
void OnEnable () {
if (component == null)
@ -23,14 +25,28 @@ namespace Spine.Unity {
skeletonRenderer_ = serializedObject.FindProperty("skeletonRenderer");
copyPropertyBlock_ = serializedObject.FindProperty("copyPropertyBlock");
copyMeshRendererFlags_ = serializedObject.FindProperty("copyMeshRendererFlags");
var partsRenderers = component.partsRenderers;
partsRenderers_ = serializedObject.FindProperty("partsRenderers");
partsRenderers_.isExpanded = true;
partsRenderers_.isExpanded = partsRenderersExpanded || // last state
partsRenderers.Contains(null) || // null items found
partsRenderers.Count < 1 || // no parts renderers
(skeletonRenderer_.objectReferenceValue != null && SkeletonRendererSeparatorCount + 1 > partsRenderers.Count); // not enough parts renderers
}
int SkeletonRendererSeparatorCount {
get {
if (Application.isPlaying) {
return component.SkeletonRenderer.separatorSlots.Count;
} else {
return separatorNamesProp == null ? 0 : separatorNamesProp.arraySize;
}
}
}
public override void OnInspectorGUI () {
// TODO: Add Undo support
var componentRenderers = component.partsRenderers;
int separatorCount = 0;
int totalParts;
bool componentEnabled = component.enabled;
@ -42,6 +58,7 @@ namespace Spine.Unity {
EditorGUILayout.PropertyField(copyPropertyBlock_);
EditorGUILayout.PropertyField(copyMeshRendererFlags_);
// SkeletonRenderer Box
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
// Fancy SkeletonRenderer foldout reference field
{
@ -52,14 +69,15 @@ namespace Spine.Unity {
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
if (component.SkeletonRenderer != null) {
separatorExpanded = EditorGUI.Foldout(foldoutSkeletonRendererRect, separatorExpanded, "");
skeletonRendererExpanded = EditorGUI.Foldout(foldoutSkeletonRendererRect, skeletonRendererExpanded, "");
}
EditorGUI.indentLevel--;
}
int separatorCount = 0;
EditorGUI.BeginChangeCheck();
if (component.SkeletonRenderer != null) {
// SubmeshSeparators from SkeletonRenderer
// Separators from SkeletonRenderer
{
bool skeletonRendererMismatch = skeletonRendererSerializedObject != null && skeletonRendererSerializedObject.targetObject != component.SkeletonRenderer;
if (separatorNamesProp == null || skeletonRendererMismatch) {
@ -71,21 +89,16 @@ namespace Spine.Unity {
}
if (separatorNamesProp != null) {
if (separatorExpanded) {
if (skeletonRendererExpanded) {
EditorGUI.indentLevel++;
SkeletonRendererInspector.SeparatorsField(separatorNamesProp);
EditorGUI.indentLevel--;
}
if (Application.isPlaying)
separatorCount = component.SkeletonRenderer.separatorSlots.Count;
else
separatorCount = separatorNamesProp.arraySize;
separatorCount = this.SkeletonRendererSeparatorCount;
}
}
if (separatorCount == 0) {
if (SkeletonRendererSeparatorCount == 0) {
EditorGUILayout.HelpBox("Separators are empty. Change the size to 1 and choose a slot if you want the render to be separated.", MessageType.Info);
}
}
@ -93,8 +106,8 @@ namespace Spine.Unity {
skeletonRendererSerializedObject.ApplyModifiedProperties();
totalParts = separatorCount + 1;
var counterStyle = separatorExpanded ? EditorStyles.label : EditorStyles.miniLabel;
EditorGUILayout.LabelField(string.Format("{0}: separates into {1}.", Plural(separatorCount, "separator", "separators"), Plural(totalParts, "part", "parts") ), counterStyle);
var counterStyle = skeletonRendererExpanded ? EditorStyles.label : EditorStyles.miniLabel;
EditorGUILayout.LabelField(string.Format("{0}: separates into {1}.", SpineInspectorUtility.Pluralize(separatorCount, "separator", "separators"), SpineInspectorUtility.Pluralize(totalParts, "part", "parts") ), counterStyle);
}
// Parts renderers
@ -103,6 +116,11 @@ namespace Spine.Unity {
EditorGUILayout.PropertyField(this.partsRenderers_, true);
EditorGUI.indentLevel--;
// Null items warning
bool nullItemsFound = componentRenderers.Contains(null);
if (nullItemsFound)
EditorGUILayout.HelpBox("Some items in the parts renderers list are null and may cause problems.\n\nYou can right-click on that element and choose 'Delete Array Element' to remove it.", MessageType.Warning);
// (Button) Match Separators count
if (separatorNamesProp != null) {
int currentRenderers = 0;
@ -110,39 +128,40 @@ namespace Spine.Unity {
if (r != null)
currentRenderers++;
}
int extraRenderersNeeded = totalParts - currentRenderers;
if (component.enabled && component.SkeletonRenderer != null && extraRenderersNeeded > 0) {
EditorGUILayout.HelpBox(string.Format("Insufficient parts renderers. Some parts will not be rendered."), MessageType.Warning);
string addMissingLabel = string.Format("Add the missing renderer{1} ({0}) ", extraRenderersNeeded, SpineInspectorUtility.PluralThenS(extraRenderersNeeded));
//var addMissingContentButtonContent = new GUIContent("Add", GUIUtility.)
if (GUILayout.Button(addMissingLabel, GUILayout.Height(40f))) {
AddPartsRenderer(extraRenderersNeeded);
DetectOrphanedPartsRenderers(component);
}
}
}
using (new EditorGUILayout.HorizontalScope()) {
// (Button) Destroy Renderers button
if (componentRenderers.Count > 0) {
if (GUILayout.Button("Clear Parts Renderers")) {
// Do you really want to destroy all?
if (EditorUtility.DisplayDialog("Destroy Renderers", "Do you really want to destroy all the Parts Renderer GameObjects in the list? (Undo will not work.)", "Destroy", "Cancel")) {
foreach (var r in componentRenderers) {
if (r != null)
DestroyImmediate(r.gameObject, allowDestroyingAssets: false);
if (partsRenderers_.isExpanded != partsRenderersExpanded) partsRenderersExpanded = partsRenderers_.isExpanded;
if (partsRenderers_.isExpanded) {
using (new EditorGUILayout.HorizontalScope()) {
// (Button) Destroy Renderers button
if (componentRenderers.Count > 0) {
if (GUILayout.Button("Clear Parts Renderers")) {
// Do you really want to destroy all?
if (EditorUtility.DisplayDialog("Destroy Renderers", "Do you really want to destroy all the Parts Renderer GameObjects in the list? (Undo will not work.)", "Destroy", "Cancel")) {
foreach (var r in componentRenderers) {
if (r != null)
DestroyImmediate(r.gameObject, allowDestroyingAssets: false);
}
componentRenderers.Clear();
// Do you also want to destroy orphans? (You monster.)
DetectOrphanedPartsRenderers(component);
}
componentRenderers.Clear();
// Do you also want to destroy orphans? (You monster.)
DetectOrphanedPartsRenderers(component);
}
}
}
// (Button) Add Part Renderer button
if (GUILayout.Button("Add (1) Parts Renderer"))
AddPartsRenderer(1);
// (Button) Add Part Renderer button
if (GUILayout.Button("Add Parts Renderer"))
AddPartsRenderer(1);
}
}
}
@ -151,7 +170,7 @@ namespace Spine.Unity {
public void AddPartsRenderer (int count) {
var componentRenderers = component.partsRenderers;
bool emptyFound = componentRenderers.Exists(x => x == null);
bool emptyFound = componentRenderers.Contains(null);
if (emptyFound) {
bool userClearEntries = EditorUtility.DisplayDialog("Empty entries found", "Null entries found. Do you want to remove null entries before adding the new renderer? ", "Clear Empty Entries", "Don't Clear");
if (userClearEntries) componentRenderers.RemoveAll(x => x == null);
@ -164,20 +183,17 @@ namespace Spine.Unity {
EditorGUIUtility.PingObject(smr);
// increment renderer sorting order.
if (index != 0) {
var prev = componentRenderers[index - 1];
if (prev != null) {
var prevMeshRenderer = prev.GetComponent<MeshRenderer>();
var currentMeshRenderer = smr.GetComponent<MeshRenderer>();
if (prevMeshRenderer != null && currentMeshRenderer != null) {
int prevSortingLayer = prevMeshRenderer.sortingLayerID;
int prevSortingOrder = prevMeshRenderer.sortingOrder;
if (index == 0) continue;
var prev = componentRenderers[index - 1]; if (prev == null) continue;
currentMeshRenderer.sortingLayerID = prevSortingLayer;
currentMeshRenderer.sortingOrder = prevSortingOrder + SkeletonRenderSeparator.DefaultSortingOrderIncrement;
}
}
}
var prevMeshRenderer = prev.GetComponent<MeshRenderer>();
var currentMeshRenderer = smr.GetComponent<MeshRenderer>();
if (prevMeshRenderer == null || currentMeshRenderer == null) continue;
int prevSortingLayer = prevMeshRenderer.sortingLayerID;
int prevSortingOrder = prevMeshRenderer.sortingOrder;
currentMeshRenderer.sortingLayerID = prevSortingLayer;
currentMeshRenderer.sortingOrder = prevSortingOrder + SkeletonRenderSeparator.DefaultSortingOrderIncrement;
}
}
@ -188,9 +204,8 @@ namespace Spine.Unity {
var orphans = new System.Collections.Generic.List<SkeletonPartsRenderer>();
foreach (var r in children) {
if (!component.partsRenderers.Contains(r)) {
if (!component.partsRenderers.Contains(r))
orphans.Add(r);
}
}
if (orphans.Count > 0) {
@ -202,7 +217,6 @@ namespace Spine.Unity {
}
}
#region SkeletonRenderer Context Menu Item
[MenuItem ("CONTEXT/SkeletonRenderer/Add Skeleton Render Separator")]
static void AddRenderSeparatorComponent (MenuCommand cmd) {

View File

@ -5,8 +5,8 @@ using Spine.Unity;
namespace Spine.Unity {
[HelpURL("")]
[ExecuteInEditMode]
[HelpURL("https://github.com/pharan/spine-unity-docs/blob/master/SkeletonRenderSeparator.md")]
public class SkeletonRenderSeparator : MonoBehaviour {
public const int DefaultSortingOrderIncrement = 5;
@ -17,7 +17,7 @@ namespace Spine.Unity {
get { return skeletonRenderer; }
set {
if (skeletonRenderer != null)
skeletonRenderer.GenerateMeshOverride -= SeparateSkeletonRender;
skeletonRenderer.GenerateMeshOverride -= HandleRender;
skeletonRenderer = value;
this.enabled = false; // Disable if nulled.
@ -26,6 +26,7 @@ namespace Spine.Unity {
MeshRenderer mainMeshRenderer;
public bool copyPropertyBlock = false;
[Tooltip("Copies MeshRenderer flags into ")]
public bool copyMeshRendererFlags = false;
public List<Spine.Unity.SkeletonPartsRenderer> partsRenderers = new List<SkeletonPartsRenderer>();
@ -42,13 +43,28 @@ namespace Spine.Unity {
if (block == null) block = new MaterialPropertyBlock();
mainMeshRenderer = skeletonRenderer.GetComponent<MeshRenderer>();
skeletonRenderer.GenerateMeshOverride -= SeparateSkeletonRender;
skeletonRenderer.GenerateMeshOverride += SeparateSkeletonRender;
skeletonRenderer.GenerateMeshOverride -= HandleRender;
skeletonRenderer.GenerateMeshOverride += HandleRender;
if (copyMeshRendererFlags) {
bool useLightProbes = mainMeshRenderer.useLightProbes;
bool receiveShadows = mainMeshRenderer.receiveShadows;
for (int i = 0; i < partsRenderers.Count; i++) {
var currentRenderer = partsRenderers[i];
if (currentRenderer == null) continue; // skip null items.
var mr = currentRenderer.MeshRenderer;
mr.useLightProbes = useLightProbes;
mr.receiveShadows = receiveShadows;
}
}
}
void OnDisable () {
if (skeletonRenderer == null) return;
skeletonRenderer.GenerateMeshOverride -= SeparateSkeletonRender;
skeletonRenderer.GenerateMeshOverride -= HandleRender;
#if UNITY_EDITOR
skeletonRenderer.LateUpdate();
@ -60,7 +76,7 @@ namespace Spine.Unity {
MaterialPropertyBlock block;
void SeparateSkeletonRender (SkeletonRenderer.SmartMesh.Instruction instruction) {
void HandleRender (SkeletonRenderer.SmartMesh.Instruction instruction) {
int rendererCount = partsRenderers.Count;
if (rendererCount <= 0) return;
@ -75,24 +91,11 @@ namespace Spine.Unity {
var currentRenderer = partsRenderers[rendererIndex];
bool skeletonRendererCalculateNormals = skeletonRenderer.calculateNormals;
bool useLightProbes = false;
bool receiveShadows = false;
if (copyMeshRendererFlags) {
useLightProbes = mainMeshRenderer.useLightProbes;
receiveShadows = mainMeshRenderer.receiveShadows;
}
for (int i = 0, start = 0; i <= lastSubmeshInstruction; i++) {
if (submeshInstructionsItems[i].separatedBySlot) {
if (submeshInstructionsItems[i].forceSeparate) {
currentRenderer.RenderParts(instruction.submeshInstructions, start, i + 1);
currentRenderer.MeshGenerator.GenerateNormals = skeletonRendererCalculateNormals;
if (copyMeshRendererFlags) {
var mr = currentRenderer.MeshRenderer;
mr.useLightProbes = useLightProbes;
mr.receiveShadows = receiveShadows;
}
if (copyPropertyBlock)
currentRenderer.SetPropertyBlock(block);
@ -107,19 +110,13 @@ namespace Spine.Unity {
} else if (i == lastSubmeshInstruction) {
currentRenderer.RenderParts(instruction.submeshInstructions, start, i + 1);
currentRenderer.MeshGenerator.GenerateNormals = skeletonRendererCalculateNormals;
if (copyMeshRendererFlags) {
var mr = currentRenderer.MeshRenderer;
mr.useLightProbes = useLightProbes;
mr.receiveShadows = receiveShadows;
}
if (copyPropertyBlock)
currentRenderer.SetPropertyBlock(block);
rendererIndex++;
}
}
// Too many renderers. Clear the rest.
// If too many renderers. Clear the rest.
rendererIndex++;
if (rendererIndex < rendererCount - 1) {
for (int i = rendererIndex; i < rendererCount; i++) {
currentRenderer = partsRenderers[i];