reduce method calls overhead in SkeletonRenderer

reduce GC pressure in SkeletonAnimator
This commit is contained in:
ZimM 2015-02-26 06:34:31 +02:00
parent 0635c19fef
commit 169ec15285
3 changed files with 91 additions and 50 deletions

View File

@ -139,12 +139,14 @@ namespace Spine {
/// <summary>Updates the world transform for each bone and applies IK constraints.</summary> /// <summary>Updates the world transform for each bone and applies IK constraints.</summary>
public void UpdateWorldTransform () { public void UpdateWorldTransform () {
ExposedList<Bone> bones = this.bones; ExposedList<Bone> bones = this.bones;
for (int ii = 0, nn = bones.Count; ii < nn; ii++) { ExposedList<IkConstraint> ikConstraints = this.ikConstraints;
Bone bone = bones.Items[ii]; if (ikConstraints.Count > 0) {
bone.rotationIK = bone.rotation; for (int ii = 0, nn = bones.Count; ii < nn; ii++) {
} Bone bone = bones.Items[ii];
ExposedList<ExposedList<Bone>> boneCache = this.boneCache; bone.rotationIK = bone.rotation;
ExposedList<IkConstraint> ikConstraints = this.ikConstraints; }
}
ExposedList<ExposedList<Bone>> boneCache = this.boneCache;
int i = 0, last = boneCache.Count - 1; int i = 0, last = boneCache.Count - 1;
while (true) { while (true) {
ExposedList<Bone> updateBones = boneCache.Items[i]; ExposedList<Bone> updateBones = boneCache.Items[i];

View File

@ -63,6 +63,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
protected event UpdateBonesDelegate _UpdateComplete; protected event UpdateBonesDelegate _UpdateComplete;
Dictionary<string, Spine.Animation> animationTable = new Dictionary<string, Spine.Animation>(); Dictionary<string, Spine.Animation> animationTable = new Dictionary<string, Spine.Animation>();
Dictionary<AnimationClip, string> clipNameTable = new Dictionary<AnimationClip, string>();
Animator animator; Animator animator;
public override void Reset () { public override void Reset () {
@ -71,6 +72,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
return; return;
animationTable.Clear(); animationTable.Clear();
clipNameTable.Clear();
var data = skeletonDataAsset.GetSkeletonData(true); var data = skeletonDataAsset.GetSkeletonData(true);
@ -122,7 +124,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = stateInfo.normalizedTime * info.clip.length; float time = stateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null, weight); animationTable[GetAnimationClipName(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null, weight);
} }
foreach (var info in nextClipInfo) { foreach (var info in nextClipInfo) {
@ -131,7 +133,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = nextStateInfo.normalizedTime * info.clip.length; float time = nextStateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight); animationTable[GetAnimationClipName(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight);
} }
} else if (mode >= MixMode.MixNext) { } else if (mode >= MixMode.MixNext) {
//apply first non-zero weighted clip //apply first non-zero weighted clip
@ -144,7 +146,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = stateInfo.normalizedTime * info.clip.length; float time = stateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null); animationTable[GetAnimationClipName(info.clip)].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null);
break; break;
} }
@ -156,7 +158,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = stateInfo.normalizedTime * info.clip.length; float time = stateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null, weight); animationTable[GetAnimationClipName(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null, weight);
} }
c = 0; c = 0;
@ -170,7 +172,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = nextStateInfo.normalizedTime * info.clip.length; float time = nextStateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null); animationTable[GetAnimationClipName(info.clip)].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null);
break; break;
} }
} }
@ -183,7 +185,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = nextStateInfo.normalizedTime * info.clip.length; float time = nextStateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight); animationTable[GetAnimationClipName(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight);
} }
} }
} }
@ -202,4 +204,14 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
_UpdateComplete(this); _UpdateComplete(this);
} }
} }
private string GetAnimationClipName(AnimationClip clip) {
string clipName;
if (!clipNameTable.TryGetValue(clip, out clipName)) {
clipName = clip.name;
clipNameTable.Add(clip, clipName);
}
return clipName;
}
} }

View File

@ -173,8 +173,9 @@ public class SkeletonRenderer : MonoBehaviour {
int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0;
Material lastMaterial = null; Material lastMaterial = null;
submeshMaterials.Clear(); submeshMaterials.Clear();
ExposedList<Slot> drawOrder = skeleton.DrawOrder; ExposedList<Slot> drawOrder = skeleton.drawOrder;
int drawOrderCount = drawOrder.Count; int drawOrderCount = drawOrder.Count;
int submeshSeparatorSlotsCount = submeshSeparatorSlots.Count;
bool renderMeshes = this.renderMeshes; bool renderMeshes = this.renderMeshes;
for (int i = 0; i < drawOrderCount; i++) { for (int i = 0; i < drawOrderCount; i++) {
Slot slot = drawOrder.Items[i]; Slot slot = drawOrder.Items[i];
@ -183,33 +184,34 @@ public class SkeletonRenderer : MonoBehaviour {
object rendererObject; object rendererObject;
int attachmentVertexCount, attachmentTriangleCount; int attachmentVertexCount, attachmentTriangleCount;
if (attachment is RegionAttachment) { RegionAttachment regionAttachment = attachment as RegionAttachment;
rendererObject = ((RegionAttachment)attachment).RendererObject; if (regionAttachment != null) {
rendererObject = regionAttachment.RendererObject;
attachmentVertexCount = 4; attachmentVertexCount = 4;
attachmentTriangleCount = 6; attachmentTriangleCount = 6;
} else { } else {
if (!renderMeshes) if (!renderMeshes)
continue; continue;
MeshAttachment meshAttachment = attachment as MeshAttachment; MeshAttachment meshAttachment = attachment as MeshAttachment;
if (meshAttachment != null) { if (meshAttachment != null) {
rendererObject = meshAttachment.RendererObject; rendererObject = meshAttachment.RendererObject;
attachmentVertexCount = meshAttachment.vertices.Length >> 1; attachmentVertexCount = meshAttachment.vertices.Length >> 1;
attachmentTriangleCount = meshAttachment.triangles.Length; attachmentTriangleCount = meshAttachment.triangles.Length;
} else { } else {
SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment; SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
if (skinnedMeshAttachment != null) { if (skinnedMeshAttachment != null) {
rendererObject = skinnedMeshAttachment.RendererObject; rendererObject = skinnedMeshAttachment.RendererObject;
attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1;
attachmentTriangleCount = skinnedMeshAttachment.triangles.Length; attachmentTriangleCount = skinnedMeshAttachment.triangles.Length;
} else } else
continue; continue;
} }
} }
// Populate submesh when material changes. // Populate submesh when material changes.
Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject; Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject;
if ((lastMaterial != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) ||
if ((lastMaterial != material && lastMaterial != null) || submeshSeparatorSlots.Contains(slot)) { (submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) {
AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false); AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false);
submeshTriangleCount = 0; submeshTriangleCount = 0;
submeshFirstVertex = vertexCount; submeshFirstVertex = vertexCount;
@ -258,15 +260,23 @@ public class SkeletonRenderer : MonoBehaviour {
for (int i = 0; i < drawOrderCount; i++) { for (int i = 0; i < drawOrderCount; i++) {
Slot slot = drawOrder.Items[i]; Slot slot = drawOrder.Items[i];
Attachment attachment = slot.attachment; Attachment attachment = slot.attachment;
if (attachment is RegionAttachment) { RegionAttachment regionAttachment = attachment as RegionAttachment;
RegionAttachment regionAttachment = (RegionAttachment)attachment; if (regionAttachment != null) {
regionAttachment.ComputeWorldVertices(slot.bone, tempVertices); regionAttachment.ComputeWorldVertices(slot.bone, tempVertices);
float z = i * zSpacing; float z = i * zSpacing;
vertices[vertexIndex] = new Vector3(tempVertices[RegionAttachment.X1], tempVertices[RegionAttachment.Y1], z); vertices[vertexIndex].x = tempVertices[RegionAttachment.X1];
vertices[vertexIndex + 1] = new Vector3(tempVertices[RegionAttachment.X4], tempVertices[RegionAttachment.Y4], z); vertices[vertexIndex].y = tempVertices[RegionAttachment.Y1];
vertices[vertexIndex + 2] = new Vector3(tempVertices[RegionAttachment.X2], tempVertices[RegionAttachment.Y2], z); vertices[vertexIndex].z = z;
vertices[vertexIndex + 3] = new Vector3(tempVertices[RegionAttachment.X3], tempVertices[RegionAttachment.Y3], z); vertices[vertexIndex + 1].x = tempVertices[RegionAttachment.X4];
vertices[vertexIndex + 1].y = tempVertices[RegionAttachment.Y4];
vertices[vertexIndex + 1].z = z;
vertices[vertexIndex + 2].x = tempVertices[RegionAttachment.X2];
vertices[vertexIndex + 2].y = tempVertices[RegionAttachment.Y2];
vertices[vertexIndex + 2].z = z;
vertices[vertexIndex + 3].x = tempVertices[RegionAttachment.X3];
vertices[vertexIndex + 3].y = tempVertices[RegionAttachment.Y3];
vertices[vertexIndex + 3].z = z;
color.a = (byte)(a * slot.a * regionAttachment.a); color.a = (byte)(a * slot.a * regionAttachment.a);
color.r = (byte)(r * slot.r * regionAttachment.r * color.a); color.r = (byte)(r * slot.r * regionAttachment.r * color.a);
@ -280,10 +290,14 @@ public class SkeletonRenderer : MonoBehaviour {
colors[vertexIndex + 3] = color; colors[vertexIndex + 3] = color;
float[] regionUVs = regionAttachment.uvs; float[] regionUVs = regionAttachment.uvs;
uvs[vertexIndex] = new Vector2(regionUVs[RegionAttachment.X1], regionUVs[RegionAttachment.Y1]); uvs[vertexIndex].x = regionUVs[RegionAttachment.X1];
uvs[vertexIndex + 1] = new Vector2(regionUVs[RegionAttachment.X4], regionUVs[RegionAttachment.Y4]); uvs[vertexIndex].y = regionUVs[RegionAttachment.Y1];
uvs[vertexIndex + 2] = new Vector2(regionUVs[RegionAttachment.X2], regionUVs[RegionAttachment.Y2]); uvs[vertexIndex + 1].x = regionUVs[RegionAttachment.X4];
uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], regionUVs[RegionAttachment.Y3]); 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];
vertexIndex += 4; vertexIndex += 4;
} else { } else {
@ -306,9 +320,12 @@ public class SkeletonRenderer : MonoBehaviour {
float[] meshUVs = meshAttachment.uvs; float[] meshUVs = meshAttachment.uvs;
float z = i * zSpacing; float z = i * zSpacing;
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z); vertices[vertexIndex].x = tempVertices[ii];
vertices[vertexIndex].y = tempVertices[ii + 1];
vertices[vertexIndex].z = z;
colors[vertexIndex] = color; colors[vertexIndex] = color;
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]); uvs[vertexIndex].x = meshUVs[ii];
uvs[vertexIndex].y = meshUVs[ii + 1];
} }
} else if (attachment is SkinnedMeshAttachment) { } else if (attachment is SkinnedMeshAttachment) {
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment; SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
@ -327,9 +344,12 @@ public class SkeletonRenderer : MonoBehaviour {
float[] meshUVs = meshAttachment.uvs; float[] meshUVs = meshAttachment.uvs;
float z = i * zSpacing; float z = i * zSpacing;
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z); vertices[vertexIndex].x = tempVertices[ii];
vertices[vertexIndex].y = tempVertices[ii + 1];
vertices[vertexIndex].z = z;
colors[vertexIndex] = color; colors[vertexIndex] = color;
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]); uvs[vertexIndex].x = meshUVs[ii];
uvs[vertexIndex].y = meshUVs[ii + 1];
} }
} }
} }
@ -420,7 +440,12 @@ public class SkeletonRenderer : MonoBehaviour {
Slot slot = drawOrder.Items[i]; Slot slot = drawOrder.Items[i];
Attachment attachment = slot.attachment; Attachment attachment = slot.attachment;
Bone bone = slot.bone; Bone bone = slot.bone;
bool flip = frontFacing && ((bone.WorldFlipX != bone.WorldFlipY) != (Mathf.Sign(bone.WorldScaleX) != Mathf.Sign(bone.WorldScaleY)));
bool worldScaleXIsPositive = bone.worldScaleX >= 0f;
bool worldScaleYIsPositive = bone.worldScaleY >= 0f;
bool worldScaleIsSameSigns = (worldScaleXIsPositive && worldScaleYIsPositive) ||
(!worldScaleXIsPositive && !worldScaleYIsPositive);
bool flip = frontFacing && ((bone.worldFlipX != bone.worldFlipY) != worldScaleIsSameSigns);
if (attachment is RegionAttachment) { if (attachment is RegionAttachment) {
if (!flip) { if (!flip) {
@ -445,16 +470,18 @@ public class SkeletonRenderer : MonoBehaviour {
} }
int[] attachmentTriangles; int[] attachmentTriangles;
int attachmentVertexCount; int attachmentVertexCount;
if (attachment is MeshAttachment) { MeshAttachment meshAttachment = attachment as MeshAttachment;
MeshAttachment meshAttachment = (MeshAttachment)attachment; if (meshAttachment != null) {
attachmentVertexCount = meshAttachment.vertices.Length >> 1; attachmentVertexCount = meshAttachment.vertices.Length >> 1;
attachmentTriangles = meshAttachment.triangles; attachmentTriangles = meshAttachment.triangles;
} else if (attachment is SkinnedMeshAttachment) { } else {
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment; SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
attachmentVertexCount = meshAttachment.uvs.Length >> 1; if (skinnedMeshAttachment != null) {
attachmentTriangles = meshAttachment.triangles; attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1;
} else attachmentTriangles = skinnedMeshAttachment.triangles;
continue; } else
continue;
}
if (flip) { if (flip) {
for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) { for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) {