mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-05 18:26:52 +08:00
[Unity] Fix material array incorrect persistence
This fixes a separate flickering bug. Reported in the forum here: http://esotericsoftware.com/forum/Weird-flicker-between-some-of-the-animations-5577 The solution was to compare `this.sharedMaterials` against the immediately-determined material array. Also included: Moved attachment and flip array checks outside of extra loops in CheckIfMustUpdateMeshStructure to prevent O(2n) behavior. Renamed some identifiers. "temp" is replaced with "working". The analogy is human brain's "working memory". Added some cached references within the method's stack (where their members are frequently accessed). Added comments for easy update, in preparation for incoming changes in Spine v3.
This commit is contained in:
parent
6778a039c6
commit
205e0dc5ad
@ -39,39 +39,46 @@ using Spine;
|
|||||||
public class SkeletonRenderer : MonoBehaviour {
|
public class SkeletonRenderer : MonoBehaviour {
|
||||||
|
|
||||||
public delegate void SkeletonRendererDelegate (SkeletonRenderer skeletonRenderer);
|
public delegate void SkeletonRendererDelegate (SkeletonRenderer skeletonRenderer);
|
||||||
|
|
||||||
public SkeletonRendererDelegate OnReset;
|
public SkeletonRendererDelegate OnReset;
|
||||||
[System.NonSerialized]
|
|
||||||
public bool valid;
|
|
||||||
[System.NonSerialized]
|
|
||||||
public Skeleton skeleton;
|
|
||||||
public SkeletonDataAsset skeletonDataAsset;
|
public SkeletonDataAsset skeletonDataAsset;
|
||||||
public String initialSkinName;
|
public String initialSkinName;
|
||||||
|
|
||||||
|
#region Advanced
|
||||||
public bool calculateNormals, calculateTangents;
|
public bool calculateNormals, calculateTangents;
|
||||||
public float zSpacing;
|
public float zSpacing;
|
||||||
public bool renderMeshes = true, immutableTriangles;
|
public bool renderMeshes = true, immutableTriangles;
|
||||||
public bool frontFacing;
|
public bool frontFacing;
|
||||||
public bool logErrors = false;
|
public bool logErrors = false;
|
||||||
|
|
||||||
[SpineSlot]
|
// Submesh Separation
|
||||||
public string[] submeshSeparators = new string[0];
|
[SpineSlot] public string[] submeshSeparators = new string[0];
|
||||||
|
[HideInInspector] public List<Slot> submeshSeparatorSlots = new List<Slot>();
|
||||||
|
#endregion
|
||||||
|
|
||||||
[HideInInspector]
|
[System.NonSerialized] public bool valid;
|
||||||
public List<Slot> submeshSeparatorSlots = new List<Slot>();
|
[System.NonSerialized] public Skeleton skeleton;
|
||||||
|
|
||||||
private MeshRenderer meshRenderer;
|
private MeshRenderer meshRenderer;
|
||||||
private MeshFilter meshFilter;
|
private MeshFilter meshFilter;
|
||||||
|
|
||||||
private Mesh mesh1, mesh2;
|
private Mesh mesh1, mesh2;
|
||||||
private bool useMesh1;
|
private bool useMesh1;
|
||||||
|
|
||||||
private float[] tempVertices = new float[8];
|
private float[] tempVertices = new float[8];
|
||||||
private Vector3[] vertices;
|
private Vector3[] vertices;
|
||||||
private Color32[] colors;
|
private Color32[] colors;
|
||||||
private Vector2[] uvs;
|
private Vector2[] uvs;
|
||||||
private Material[] sharedMaterials = new Material[0];
|
private Material[] sharedMaterials = new Material[0];
|
||||||
|
|
||||||
|
private MeshState meshState = new MeshState();
|
||||||
private readonly ExposedList<Material> submeshMaterials = new ExposedList<Material>();
|
private readonly ExposedList<Material> submeshMaterials = new ExposedList<Material>();
|
||||||
private readonly ExposedList<Submesh> submeshes = new ExposedList<Submesh>();
|
private readonly ExposedList<Submesh> submeshes = new ExposedList<Submesh>();
|
||||||
private SkeletonUtilitySubmeshRenderer[] submeshRenderers;
|
private SkeletonUtilitySubmeshRenderer[] submeshRenderers;
|
||||||
private MeshState meshState = new MeshState();
|
|
||||||
|
public virtual void Awake () {
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void Reset () {
|
public virtual void Reset () {
|
||||||
if (meshFilter != null)
|
if (meshFilter != null)
|
||||||
@ -144,10 +151,6 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
submeshRenderers = GetComponentsInChildren<SkeletonUtilitySubmeshRenderer>();
|
submeshRenderers = GetComponentsInChildren<SkeletonUtilitySubmeshRenderer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Awake () {
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void OnDestroy () {
|
public virtual void OnDestroy () {
|
||||||
if (mesh1 != null) {
|
if (mesh1 != null) {
|
||||||
if (Application.isPlaying)
|
if (Application.isPlaying)
|
||||||
@ -167,7 +170,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
mesh2 = null;
|
mesh2 = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mesh newMesh () {
|
private static Mesh newMesh () {
|
||||||
Mesh mesh = new Mesh();
|
Mesh mesh = new Mesh();
|
||||||
mesh.name = "Skeleton Mesh";
|
mesh.name = "Skeleton Mesh";
|
||||||
mesh.hideFlags = HideFlags.HideAndDontSave;
|
mesh.hideFlags = HideFlags.HideAndDontSave;
|
||||||
@ -185,6 +188,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
|
|
||||||
// Count vertices and submesh triangles.
|
// Count vertices and submesh triangles.
|
||||||
int vertexCount = 0;
|
int vertexCount = 0;
|
||||||
|
|
||||||
int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0;
|
int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0;
|
||||||
Material lastMaterial = null;
|
Material lastMaterial = null;
|
||||||
ExposedList<Slot> drawOrder = skeleton.drawOrder;
|
ExposedList<Slot> drawOrder = skeleton.drawOrder;
|
||||||
@ -193,26 +197,41 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
bool renderMeshes = this.renderMeshes;
|
bool renderMeshes = this.renderMeshes;
|
||||||
|
|
||||||
// Clear last state of attachments and submeshes
|
// Clear last state of attachments and submeshes
|
||||||
MeshState.SingleMeshState stateTemp = meshState.stateTemp;
|
MeshState.SingleMeshState workingState = meshState.buffer;
|
||||||
stateTemp.attachments.Clear(true);
|
var workingAttachments = workingState.attachments;
|
||||||
stateTemp.UpdateDrawOrderCount(drawOrderCount);
|
var workingFlips = workingState.attachmentsFlipState;
|
||||||
|
var workingSubmeshArguments = workingState.addSubmeshArguments;
|
||||||
|
workingAttachments.Clear(true);
|
||||||
|
workingState.UpdateAttachmentCount(drawOrderCount);
|
||||||
|
workingSubmeshArguments.Clear(false);
|
||||||
|
|
||||||
|
MeshState.SingleMeshState storedState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2;
|
||||||
|
var storedAttachments = storedState.attachments;
|
||||||
|
var storedFlips = storedState.attachmentsFlipState;
|
||||||
|
|
||||||
|
bool mustUpdateMeshStructure = storedState.requiresUpdate || // Force update if the mesh was cleared. (prevents flickering due to incorrect state)
|
||||||
|
drawOrder.Count != storedAttachments.Count || // Number of slots changed (when does this happen?)
|
||||||
|
immutableTriangles != storedState.immutableTriangles; // Immutable Triangles flag changed.
|
||||||
|
|
||||||
stateTemp.addSubmeshArguments.Clear(false);
|
|
||||||
for (int i = 0; i < drawOrderCount; i++) {
|
for (int i = 0; i < drawOrderCount; i++) {
|
||||||
Slot slot = drawOrder.Items[i];
|
Slot slot = drawOrder.Items[i];
|
||||||
Bone bone = slot.bone;
|
Bone bone = slot.bone;
|
||||||
Attachment attachment = slot.attachment;
|
Attachment attachment = slot.attachment;
|
||||||
|
|
||||||
object rendererObject;
|
object rendererObject; // An AtlasRegion in plain Spine-Unity. Spine-TK2D hooks into TK2D's system. eventual source of Material object.
|
||||||
int attachmentVertexCount, attachmentTriangleCount;
|
int attachmentVertexCount, attachmentTriangleCount;
|
||||||
bool worldScaleXIsPositive = bone.worldScaleX >= 0f;
|
|
||||||
bool worldScaleYIsPositive = bone.worldScaleY >= 0f;
|
|
||||||
bool worldScaleIsSameSigns = (worldScaleXIsPositive && worldScaleYIsPositive) ||
|
|
||||||
(!worldScaleXIsPositive && !worldScaleYIsPositive);
|
|
||||||
bool flip = frontFacing && ((bone.worldFlipX != bone.worldFlipY) == worldScaleIsSameSigns);
|
|
||||||
stateTemp.attachmentsFlipState.Items[i] = flip;
|
|
||||||
|
|
||||||
stateTemp.attachments.Items[i] = attachment;
|
// Handle flipping for normals (for lighting).
|
||||||
|
bool worldScaleIsSameSigns = ((bone.worldScaleY >= 0f) == (bone.worldScaleX >= 0f));
|
||||||
|
bool flip = frontFacing && ((bone.worldFlipX != bone.worldFlipY) == worldScaleIsSameSigns); // TODO: bone flipX and flipY will be removed in Spine 3.0
|
||||||
|
|
||||||
|
workingFlips.Items[i] = flip;
|
||||||
|
workingAttachments.Items[i] = attachment;
|
||||||
|
|
||||||
|
mustUpdateMeshStructure = mustUpdateMeshStructure || // Always prefer short circuited or. || and not |=.
|
||||||
|
(attachment != storedAttachments.Items[i]) || // Attachment order changed. // This relies on the drawOrder.Count != storedAttachments.Count check above as a bounds check.
|
||||||
|
(flip != storedFlips.Items[i]); // Flip states changed.
|
||||||
|
|
||||||
RegionAttachment regionAttachment = attachment as RegionAttachment;
|
RegionAttachment regionAttachment = attachment as RegionAttachment;
|
||||||
if (regionAttachment != null) {
|
if (regionAttachment != null) {
|
||||||
rendererObject = regionAttachment.RendererObject;
|
rendererObject = regionAttachment.RendererObject;
|
||||||
@ -237,17 +256,27 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate submesh when material changes.
|
#if !SPINE_TK2D
|
||||||
#if !SPINE_TK2D
|
|
||||||
Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject;
|
Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject;
|
||||||
#else
|
#else
|
||||||
Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject;
|
Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Populate submesh when material changes. (or when forced to separate by a submeshSeparator)
|
||||||
if ((lastMaterial != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) ||
|
if ((lastMaterial != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) ||
|
||||||
(submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) {
|
(submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) {
|
||||||
stateTemp.addSubmeshArguments.Add(
|
|
||||||
new MeshState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false)
|
workingSubmeshArguments.Add(
|
||||||
);
|
new MeshState.AddSubmeshArguments {
|
||||||
|
material = lastMaterial,
|
||||||
|
startSlot = submeshStartSlotIndex,
|
||||||
|
endSlot = i,
|
||||||
|
triangleCount = submeshTriangleCount,
|
||||||
|
firstVertex = submeshFirstVertex,
|
||||||
|
isLastSubmesh = false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
submeshTriangleCount = 0;
|
submeshTriangleCount = 0;
|
||||||
submeshFirstVertex = vertexCount;
|
submeshFirstVertex = vertexCount;
|
||||||
submeshStartSlotIndex = i;
|
submeshStartSlotIndex = i;
|
||||||
@ -257,24 +286,41 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
submeshTriangleCount += attachmentTriangleCount;
|
submeshTriangleCount += attachmentTriangleCount;
|
||||||
vertexCount += attachmentVertexCount;
|
vertexCount += attachmentVertexCount;
|
||||||
}
|
}
|
||||||
stateTemp.addSubmeshArguments.Add(
|
|
||||||
new MeshState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true)
|
|
||||||
);
|
|
||||||
|
|
||||||
bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(stateTemp.attachments, stateTemp.attachmentsFlipState, stateTemp.addSubmeshArguments);
|
|
||||||
|
workingSubmeshArguments.Add(
|
||||||
|
new MeshState.AddSubmeshArguments {
|
||||||
|
material = lastMaterial,
|
||||||
|
startSlot = submeshStartSlotIndex,
|
||||||
|
endSlot = drawOrderCount,
|
||||||
|
triangleCount = submeshTriangleCount,
|
||||||
|
firstVertex = submeshFirstVertex,
|
||||||
|
isLastSubmesh = true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
mustUpdateMeshStructure = mustUpdateMeshStructure ||
|
||||||
|
this.sharedMaterials.Length != workingSubmeshArguments.Count || // Material array changed in size
|
||||||
|
CheckIfMustUpdateMeshStructure(workingSubmeshArguments); // Submesh Argument Array changed.
|
||||||
|
|
||||||
|
// CheckIfMustUpdateMaterialArray (workingMaterials, sharedMaterials)
|
||||||
|
if (!mustUpdateMeshStructure) {
|
||||||
|
// Narrow phase material array check.
|
||||||
|
var workingMaterials = workingSubmeshArguments.Items;
|
||||||
|
for (int i = 0, n = sharedMaterials.Length; i < n; i++) {
|
||||||
|
if (this.sharedMaterials[i] != workingMaterials[i].material) { // Bounds check is implied above.
|
||||||
|
mustUpdateMeshStructure = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOT ELSE
|
||||||
|
|
||||||
if (mustUpdateMeshStructure) {
|
if (mustUpdateMeshStructure) {
|
||||||
submeshMaterials.Clear();
|
this.submeshMaterials.Clear();
|
||||||
for (int i = 0, n = stateTemp.addSubmeshArguments.Count; i < n; i++) {
|
for (int i = 0, n = workingSubmeshArguments.Count; i < n; i++) {
|
||||||
MeshState.AddSubmeshArguments arguments = stateTemp.addSubmeshArguments.Items[i];
|
AddSubmesh(workingSubmeshArguments.Items[i], workingFlips);
|
||||||
AddSubmesh(
|
|
||||||
arguments.material,
|
|
||||||
arguments.startSlot,
|
|
||||||
arguments.endSlot,
|
|
||||||
arguments.triangleCount,
|
|
||||||
arguments.firstVertex,
|
|
||||||
arguments.lastSubmesh,
|
|
||||||
stateTemp.attachmentsFlipState
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set materials.
|
// Set materials.
|
||||||
@ -286,6 +332,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
meshRenderer.sharedMaterials = sharedMaterials;
|
meshRenderer.sharedMaterials = sharedMaterials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Ensure mesh data is the right size.
|
// Ensure mesh data is the right size.
|
||||||
Vector3[] vertices = this.vertices;
|
Vector3[] vertices = this.vertices;
|
||||||
bool newTriangles = vertexCount > vertices.Length;
|
bool newTriangles = vertexCount > vertices.Length;
|
||||||
@ -297,8 +344,8 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
|
|
||||||
mesh1.Clear();
|
mesh1.Clear();
|
||||||
mesh2.Clear();
|
mesh2.Clear();
|
||||||
meshState.stateMesh1.forceUpdate = true;
|
meshState.stateMesh1.requiresUpdate = true;
|
||||||
meshState.stateMesh2.forceUpdate = true;
|
meshState.stateMesh2.requiresUpdate = true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Too many vertices, zero the extra.
|
// Too many vertices, zero the extra.
|
||||||
@ -507,12 +554,8 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
for (int i = 0; i < submeshCount; ++i)
|
for (int i = 0; i < submeshCount; ++i)
|
||||||
mesh.SetTriangles(submeshes.Items[i].triangles, i);
|
mesh.SetTriangles(submeshes.Items[i].triangles, i);
|
||||||
|
|
||||||
// Done updating mesh. Clear the force update state.
|
// Done updating mesh.
|
||||||
if (useMesh1) {
|
storedState.requiresUpdate = false;
|
||||||
meshState.stateMesh1.forceUpdate = false;
|
|
||||||
} else {
|
|
||||||
meshState.stateMesh2.forceUpdate = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin;
|
Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin;
|
||||||
@ -537,24 +580,25 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
mesh2.tangents = tangents;
|
mesh2.tangents = tangents;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update previous state
|
// Update previous state
|
||||||
MeshState.SingleMeshState currentMeshState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2;
|
storedState.immutableTriangles = immutableTriangles;
|
||||||
currentMeshState.immutableTriangles = immutableTriangles;
|
|
||||||
|
|
||||||
currentMeshState.attachments.Clear(true);
|
storedAttachments.Clear(true);
|
||||||
currentMeshState.attachments.GrowIfNeeded(stateTemp.attachments.Capacity);
|
storedAttachments.GrowIfNeeded(workingAttachments.Capacity);
|
||||||
currentMeshState.attachments.Count = stateTemp.attachments.Count;
|
storedAttachments.Count = workingAttachments.Count;
|
||||||
stateTemp.attachments.CopyTo(currentMeshState.attachments.Items);
|
workingAttachments.CopyTo(storedAttachments.Items);
|
||||||
|
|
||||||
currentMeshState.attachmentsFlipState.GrowIfNeeded(stateTemp.attachmentsFlipState.Capacity);
|
storedFlips.GrowIfNeeded(workingFlips.Capacity);
|
||||||
currentMeshState.attachmentsFlipState.Count = stateTemp.attachmentsFlipState.Count;
|
storedFlips.Count = workingFlips.Count;
|
||||||
stateTemp.attachmentsFlipState.CopyTo(currentMeshState.attachmentsFlipState.Items);
|
workingFlips.CopyTo(storedFlips.Items);
|
||||||
|
|
||||||
currentMeshState.addSubmeshArguments.GrowIfNeeded(stateTemp.addSubmeshArguments.Capacity);
|
storedState.addSubmeshArguments.GrowIfNeeded(workingSubmeshArguments.Capacity);
|
||||||
currentMeshState.addSubmeshArguments.Count = stateTemp.addSubmeshArguments.Count;
|
storedState.addSubmeshArguments.Count = workingSubmeshArguments.Count;
|
||||||
stateTemp.addSubmeshArguments.CopyTo(currentMeshState.addSubmeshArguments.Items);
|
workingSubmeshArguments.CopyTo(storedState.addSubmeshArguments.Items);
|
||||||
|
|
||||||
|
|
||||||
|
// Submesh Renderers
|
||||||
if (submeshRenderers.Length > 0) {
|
if (submeshRenderers.Length > 0) {
|
||||||
for (int i = 0; i < submeshRenderers.Length; i++) {
|
for (int i = 0; i < submeshRenderers.Length; i++) {
|
||||||
SkeletonUtilitySubmeshRenderer submeshRenderer = submeshRenderers[i];
|
SkeletonUtilitySubmeshRenderer submeshRenderer = submeshRenderers[i];
|
||||||
@ -569,60 +613,32 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
useMesh1 = !useMesh1;
|
useMesh1 = !useMesh1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckIfMustUpdateMeshStructure (ExposedList<Attachment> attachmentsTemp, ExposedList<bool> attachmentsFlipStateTemp, ExposedList<MeshState.AddSubmeshArguments> addSubmeshArgumentsTemp) {
|
private bool CheckIfMustUpdateMeshStructure (ExposedList<MeshState.AddSubmeshArguments> workingAddSubmeshArguments) {
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (!Application.isPlaying)
|
if (!Application.isPlaying)
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Check if any mesh settings were changed
|
// Check if any mesh settings were changed
|
||||||
MeshState.SingleMeshState currentMeshState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2;
|
MeshState.SingleMeshState currentMeshState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2;
|
||||||
|
|
||||||
bool mustUpdateMeshStructure =
|
// Check if submesh structures has changed
|
||||||
(immutableTriangles != currentMeshState.immutableTriangles) || currentMeshState.forceUpdate;
|
|
||||||
|
|
||||||
if (mustUpdateMeshStructure)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Check if any attachments were enabled/disabled
|
|
||||||
// or submesh structures has changed
|
|
||||||
ExposedList<Attachment> attachmentsCurrentMesh = currentMeshState.attachments;
|
|
||||||
ExposedList<MeshState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh = currentMeshState.addSubmeshArguments;
|
ExposedList<MeshState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh = currentMeshState.addSubmeshArguments;
|
||||||
ExposedList<bool> attachmentsFlipStateCurrentMesh = currentMeshState.attachmentsFlipState;
|
int submeshCount = workingAddSubmeshArguments.Count;
|
||||||
|
|
||||||
// Check attachments
|
|
||||||
int attachmentCount = attachmentsTemp.Count;
|
|
||||||
if (attachmentsCurrentMesh.Count != attachmentCount)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
for (int i = 0; i < attachmentCount; i++) {
|
|
||||||
if (attachmentsCurrentMesh.Items[i] != attachmentsTemp.Items[i])
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check flip state
|
|
||||||
for (int i = 0; i < attachmentCount; i++) {
|
|
||||||
if (attachmentsFlipStateCurrentMesh.Items[i] != attachmentsFlipStateTemp.Items[i])
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check submeshes
|
|
||||||
int submeshCount = addSubmeshArgumentsTemp.Count;
|
|
||||||
if (addSubmeshArgumentsCurrentMesh.Count != submeshCount)
|
if (addSubmeshArgumentsCurrentMesh.Count != submeshCount)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for (int i = 0; i < submeshCount; i++) {
|
for (int i = 0; i < submeshCount; i++) {
|
||||||
if (!addSubmeshArgumentsCurrentMesh.Items[i].Equals(ref addSubmeshArgumentsTemp.Items[i]))
|
if (!addSubmeshArgumentsCurrentMesh.Items[i].Equals(ref workingAddSubmeshArguments.Items[i]))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Stores vertices and triangles for a single material. */
|
private void AddSubmesh (MeshState.AddSubmeshArguments submeshArguments, ExposedList<bool> flipStates) {
|
||||||
private void AddSubmesh (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh, ExposedList<bool> flipStates) {
|
|
||||||
int submeshIndex = submeshMaterials.Count;
|
int submeshIndex = submeshMaterials.Count;
|
||||||
submeshMaterials.Add(material);
|
submeshMaterials.Add(submeshArguments.material);
|
||||||
|
|
||||||
if (submeshes.Count <= submeshIndex)
|
if (submeshes.Count <= submeshIndex)
|
||||||
submeshes.Add(new Submesh());
|
submeshes.Add(new Submesh());
|
||||||
@ -630,10 +646,13 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Submesh submesh = submeshes.Items[submeshIndex];
|
Submesh submesh = submeshes.Items[submeshIndex];
|
||||||
|
|
||||||
int[] triangles = submesh.triangles;
|
int[] triangles = submesh.triangles;
|
||||||
|
|
||||||
|
int triangleCount = submeshArguments.triangleCount;
|
||||||
|
int firstVertex = submeshArguments.firstVertex;
|
||||||
|
|
||||||
int trianglesCapacity = triangles.Length;
|
int trianglesCapacity = triangles.Length;
|
||||||
if (lastSubmesh && trianglesCapacity > triangleCount) {
|
if (submeshArguments.isLastSubmesh && trianglesCapacity > triangleCount) {
|
||||||
// Last submesh may have more triangles than required, so zero triangles to the end.
|
// Last submesh may have more triangles than required, so zero triangles to the end.
|
||||||
for (int i = triangleCount; i < trianglesCapacity; i++)
|
for (int i = triangleCount; i < trianglesCapacity; i++)
|
||||||
triangles[i] = 0;
|
triangles[i] = 0;
|
||||||
@ -649,8 +668,8 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
if (submesh.firstVertex != firstVertex || submesh.triangleCount < triangleCount) {
|
if (submesh.firstVertex != firstVertex || submesh.triangleCount < triangleCount) {
|
||||||
submesh.triangleCount = triangleCount;
|
submesh.triangleCount = triangleCount;
|
||||||
submesh.firstVertex = firstVertex;
|
submesh.firstVertex = firstVertex;
|
||||||
int drawOrderIndex = 0;
|
//int drawOrderIndex = 0;
|
||||||
for (int i = 0; i < triangleCount; i += 6, firstVertex += 4, drawOrderIndex++) {
|
for (int i = 0; i < triangleCount; i += 6, firstVertex += 4/*, drawOrderIndex++*/) {
|
||||||
triangles[i] = firstVertex;
|
triangles[i] = firstVertex;
|
||||||
triangles[i + 1] = firstVertex + 2;
|
triangles[i + 1] = firstVertex + 2;
|
||||||
triangles[i + 2] = firstVertex + 1;
|
triangles[i + 2] = firstVertex + 1;
|
||||||
@ -662,14 +681,16 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store triangles.
|
// Iterate through all slots and store their triangles.
|
||||||
ExposedList<Slot> drawOrder = skeleton.DrawOrder;
|
ExposedList<Slot> drawOrder = skeleton.DrawOrder;
|
||||||
for (int i = startSlot, triangleIndex = 0; i < endSlot; i++) {
|
int triangleIndex = 0; // Modified by loop
|
||||||
|
for (int i = submeshArguments.startSlot, n = submeshArguments.endSlot; i < n; i++) {
|
||||||
Slot slot = drawOrder.Items[i];
|
Slot slot = drawOrder.Items[i];
|
||||||
Attachment attachment = slot.attachment;
|
Attachment attachment = slot.attachment;
|
||||||
|
|
||||||
bool flip = flipStates.Items[i];
|
bool flip = flipStates.Items[i];
|
||||||
|
|
||||||
|
// Add RegionAttachment triangles
|
||||||
if (attachment is RegionAttachment) {
|
if (attachment is RegionAttachment) {
|
||||||
if (!flip) {
|
if (!flip) {
|
||||||
triangles[triangleIndex] = firstVertex;
|
triangles[triangleIndex] = firstVertex;
|
||||||
@ -691,16 +712,18 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
firstVertex += 4;
|
firstVertex += 4;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add (Skinned)MeshAttachment triangles
|
||||||
int[] attachmentTriangles;
|
int[] attachmentTriangles;
|
||||||
int attachmentVertexCount;
|
int attachmentVertexCount;
|
||||||
MeshAttachment meshAttachment = attachment as MeshAttachment;
|
MeshAttachment meshAttachment = attachment as MeshAttachment;
|
||||||
if (meshAttachment != null) {
|
if (meshAttachment != null) {
|
||||||
attachmentVertexCount = meshAttachment.vertices.Length >> 1;
|
attachmentVertexCount = meshAttachment.vertices.Length >> 1; // length/2
|
||||||
attachmentTriangles = meshAttachment.triangles;
|
attachmentTriangles = meshAttachment.triangles;
|
||||||
} else {
|
} else {
|
||||||
SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
|
SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
|
||||||
if (skinnedMeshAttachment != null) {
|
if (skinnedMeshAttachment != null) {
|
||||||
attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1;
|
attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; // length/2
|
||||||
attachmentTriangles = skinnedMeshAttachment.triangles;
|
attachmentTriangles = skinnedMeshAttachment.triangles;
|
||||||
} else
|
} else
|
||||||
continue;
|
continue;
|
||||||
@ -722,7 +745,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
void OnDrawGizmos () {
|
void OnDrawGizmos () {
|
||||||
// Make selection easier by drawing a clear gizmo over the skeleton.
|
// Make selection easier by drawing a clear gizmo over the skeleton.
|
||||||
meshFilter = GetComponent<MeshFilter>();
|
meshFilter = GetComponent<MeshFilter>();
|
||||||
@ -736,27 +759,27 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
Gizmos.matrix = transform.localToWorldMatrix;
|
Gizmos.matrix = transform.localToWorldMatrix;
|
||||||
Gizmos.DrawCube(meshBounds.center, meshBounds.size);
|
Gizmos.DrawCube(meshBounds.center, meshBounds.size);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private class MeshState {
|
private class MeshState {
|
||||||
public int vertexCount;
|
public int vertexCount;
|
||||||
public readonly SingleMeshState stateTemp = new SingleMeshState();
|
public readonly SingleMeshState buffer = new SingleMeshState();
|
||||||
public readonly SingleMeshState stateMesh1 = new SingleMeshState();
|
public readonly SingleMeshState stateMesh1 = new SingleMeshState();
|
||||||
public readonly SingleMeshState stateMesh2 = new SingleMeshState();
|
public readonly SingleMeshState stateMesh2 = new SingleMeshState();
|
||||||
|
|
||||||
public class SingleMeshState {
|
public class SingleMeshState {
|
||||||
public bool immutableTriangles;
|
public bool immutableTriangles;
|
||||||
public bool forceUpdate;
|
public bool requiresUpdate;
|
||||||
public readonly ExposedList<Attachment> attachments = new ExposedList<Attachment>();
|
public readonly ExposedList<Attachment> attachments = new ExposedList<Attachment>();
|
||||||
public readonly ExposedList<bool> attachmentsFlipState = new ExposedList<bool>();
|
public readonly ExposedList<bool> attachmentsFlipState = new ExposedList<bool>();
|
||||||
public readonly ExposedList<AddSubmeshArguments> addSubmeshArguments = new ExposedList<AddSubmeshArguments>();
|
public readonly ExposedList<AddSubmeshArguments> addSubmeshArguments = new ExposedList<AddSubmeshArguments>();
|
||||||
|
|
||||||
public void UpdateDrawOrderCount(int drawOrderCount) {
|
public void UpdateAttachmentCount (int attachmentCount) {
|
||||||
attachmentsFlipState.GrowIfNeeded(drawOrderCount);
|
attachmentsFlipState.GrowIfNeeded(attachmentCount);
|
||||||
attachmentsFlipState.Count = drawOrderCount;
|
attachmentsFlipState.Count = attachmentCount;
|
||||||
|
|
||||||
attachments.GrowIfNeeded(drawOrderCount);
|
attachments.GrowIfNeeded(attachmentCount);
|
||||||
attachments.Count = drawOrderCount;
|
attachments.Count = attachmentCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,22 +789,13 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
public int endSlot;
|
public int endSlot;
|
||||||
public int triangleCount;
|
public int triangleCount;
|
||||||
public int firstVertex;
|
public int firstVertex;
|
||||||
public bool lastSubmesh;
|
public bool isLastSubmesh;
|
||||||
|
|
||||||
public AddSubmeshArguments (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh) {
|
|
||||||
this.material = material;
|
|
||||||
this.startSlot = startSlot;
|
|
||||||
this.endSlot = endSlot;
|
|
||||||
this.triangleCount = triangleCount;
|
|
||||||
this.firstVertex = firstVertex;
|
|
||||||
this.lastSubmesh = lastSubmesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals (ref AddSubmeshArguments other) {
|
public bool Equals (ref AddSubmeshArguments other) {
|
||||||
return
|
return
|
||||||
!ReferenceEquals(material, null) &&
|
//!ReferenceEquals(material, null) &&
|
||||||
!ReferenceEquals(other.material, null) &&
|
//!ReferenceEquals(other.material, null) &&
|
||||||
material.GetInstanceID() == other.material.GetInstanceID() &&
|
//material.GetInstanceID() == other.material.GetInstanceID() &&
|
||||||
startSlot == other.startSlot &&
|
startSlot == other.startSlot &&
|
||||||
endSlot == other.endSlot &&
|
endSlot == other.endSlot &&
|
||||||
triangleCount == other.triangleCount &&
|
triangleCount == other.triangleCount &&
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user