private void AddSubmesh(MeshState.AddSubmeshArguments submeshArguments, ExposedList <bool> flipStates) { int submeshIndex = submeshMaterials.Count; submeshMaterials.Add(submeshArguments.material); if (submeshes.Count <= submeshIndex) { submeshes.Add(new Submesh()); } else if (immutableTriangles) { return; } Submesh submesh = submeshes.Items[submeshIndex]; int[] triangles = submesh.triangles; int triangleCount = submeshArguments.triangleCount; int firstVertex = submeshArguments.firstVertex; int trianglesCapacity = triangles.Length; if (submeshArguments.isLastSubmesh && trianglesCapacity > triangleCount) { // Last submesh may have more triangles than required, so zero triangles to the end. for (int i = triangleCount; i < trianglesCapacity; i++) { triangles[i] = 0; } submesh.triangleCount = triangleCount; } else if (trianglesCapacity != triangleCount) { // Reallocate triangles when not the exact size needed. submesh.triangles = triangles = new int[triangleCount]; submesh.triangleCount = 0; } if (!renderMeshes && !frontFacing) { // Use stored triangles if possible. if (submesh.firstVertex != firstVertex || submesh.triangleCount < triangleCount) { submesh.triangleCount = triangleCount; submesh.firstVertex = firstVertex; //int drawOrderIndex = 0; for (int i = 0; i < triangleCount; i += 6, firstVertex += 4 /*, drawOrderIndex++*/) { triangles[i] = firstVertex; triangles[i + 1] = firstVertex + 2; triangles[i + 2] = firstVertex + 1; triangles[i + 3] = firstVertex + 2; triangles[i + 4] = firstVertex + 3; triangles[i + 5] = firstVertex + 1; } } return; } // Iterate through all slots and store their triangles. ExposedList <Slot> drawOrder = skeleton.DrawOrder; int triangleIndex = 0; // Modified by loop for (int i = submeshArguments.startSlot, n = submeshArguments.endSlot; i < n; i++) { Slot slot = drawOrder.Items[i]; Attachment attachment = slot.attachment; bool flip = flipStates.Items[i]; // Add RegionAttachment triangles if (attachment is RegionAttachment) { if (!flip) { triangles[triangleIndex] = firstVertex; triangles[triangleIndex + 1] = firstVertex + 2; triangles[triangleIndex + 2] = firstVertex + 1; triangles[triangleIndex + 3] = firstVertex + 2; triangles[triangleIndex + 4] = firstVertex + 3; triangles[triangleIndex + 5] = firstVertex + 1; } else { triangles[triangleIndex] = firstVertex + 1; triangles[triangleIndex + 1] = firstVertex + 2; triangles[triangleIndex + 2] = firstVertex; triangles[triangleIndex + 3] = firstVertex + 1; triangles[triangleIndex + 4] = firstVertex + 3; triangles[triangleIndex + 5] = firstVertex + 2; } triangleIndex += 6; firstVertex += 4; continue; } // Add (Skinned)MeshAttachment triangles int[] attachmentTriangles; int attachmentVertexCount; MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { attachmentVertexCount = meshAttachment.vertices.Length >> 1; // length/2 attachmentTriangles = meshAttachment.triangles; } else { SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment; if (skinnedMeshAttachment != null) { attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; // length/2 attachmentTriangles = skinnedMeshAttachment.triangles; } else { continue; } } if (flip) { for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) { triangles[triangleIndex + 2] = firstVertex + attachmentTriangles[ii]; triangles[triangleIndex + 1] = firstVertex + attachmentTriangles[ii + 1]; triangles[triangleIndex] = firstVertex + attachmentTriangles[ii + 2]; } } else { for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) { triangles[triangleIndex] = firstVertex + attachmentTriangles[ii]; } } firstVertex += attachmentVertexCount; } }
private void AddSubmesh(MeshState.AddSubmeshArguments submeshArguments, ExposedList <bool> flipStates) { int submeshIndex = submeshMaterials.Count; submeshMaterials.Add(submeshArguments.material); if (submeshes.Count <= submeshIndex) { submeshes.Add(new Submesh()); } else if (immutableTriangles) { return; } Submesh currentSubmesh = submeshes.Items[submeshIndex]; int[] triangles = currentSubmesh.triangles; int triangleCount = submeshArguments.triangleCount; int firstVertex = submeshArguments.firstVertex; int trianglesCapacity = triangles.Length; if (submeshArguments.isLastSubmesh && trianglesCapacity > triangleCount) { // Last submesh may have more triangles than required, so zero triangles to the end. for (int i = triangleCount; i < trianglesCapacity; i++) { triangles[i] = 0; } currentSubmesh.triangleCount = triangleCount; } else if (trianglesCapacity != triangleCount) { // Reallocate triangles when not the exact size needed. currentSubmesh.triangles = triangles = new int[triangleCount]; currentSubmesh.triangleCount = 0; } if (!this.renderMeshes && !this.frontFacing) { // Use stored triangles if possible. if (currentSubmesh.firstVertex != firstVertex || currentSubmesh.triangleCount < triangleCount) //|| currentSubmesh.triangleCount == 0 { currentSubmesh.triangleCount = triangleCount; currentSubmesh.firstVertex = firstVertex; for (int i = 0; i < triangleCount; i += 6, firstVertex += 4) { triangles[i] = firstVertex; triangles[i + 1] = firstVertex + 2; triangles[i + 2] = firstVertex + 1; triangles[i + 3] = firstVertex + 2; triangles[i + 4] = firstVertex + 3; triangles[i + 5] = firstVertex + 1; } } return; } // This method caches several .Items arrays. Whenever it does, there should be no mutations done on the overlying ExposedList object. // Iterate through all slots and store their triangles. var drawOrderItems = skeleton.DrawOrder.Items; var flipStatesItems = flipStates.Items; int triangleIndex = 0; // Modified by loop for (int i = submeshArguments.startSlot, n = submeshArguments.endSlot; i < n; i++) { Attachment attachment = drawOrderItems[i].attachment; bool flip = flipStatesItems[i]; // Add RegionAttachment triangles if (attachment is RegionAttachment) { if (!flip) { triangles[triangleIndex] = firstVertex; triangles[triangleIndex + 1] = firstVertex + 2; triangles[triangleIndex + 2] = firstVertex + 1; triangles[triangleIndex + 3] = firstVertex + 2; triangles[triangleIndex + 4] = firstVertex + 3; triangles[triangleIndex + 5] = firstVertex + 1; } else { triangles[triangleIndex] = firstVertex + 1; triangles[triangleIndex + 1] = firstVertex + 2; triangles[triangleIndex + 2] = firstVertex; triangles[triangleIndex + 3] = firstVertex + 1; triangles[triangleIndex + 4] = firstVertex + 3; triangles[triangleIndex + 5] = firstVertex + 2; } triangleIndex += 6; firstVertex += 4; continue; } // Add (Weighted)MeshAttachment triangles 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; } } if (flip) { for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) { triangles[triangleIndex + 2] = firstVertex + attachmentTriangles[ii]; triangles[triangleIndex + 1] = firstVertex + attachmentTriangles[ii + 1]; triangles[triangleIndex] = firstVertex + attachmentTriangles[ii + 2]; } } else { for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) { triangles[triangleIndex] = firstVertex + attachmentTriangles[ii]; } } firstVertex += attachmentVertexCount; } }
public virtual void LateUpdate() { if (!valid) { return; } // Exit early if there is nothing to render if (!meshRenderer.enabled && submeshRenderers.Length == 0) { return; } // Count vertices and submesh triangles. int vertexCount = 0; int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; Material lastMaterial = null; ExposedList <Slot> drawOrder = skeleton.drawOrder; int drawOrderCount = drawOrder.Count; int submeshSeparatorSlotsCount = submeshSeparatorSlots.Count; bool renderMeshes = this.renderMeshes; // Clear last state of attachments and submeshes MeshState.SingleMeshState stateTemp = meshState.stateTemp; stateTemp.attachments.Clear(true); stateTemp.UpdateDrawOrderCount(drawOrderCount); stateTemp.addSubmeshArguments.Clear(false); for (int i = 0; i < drawOrderCount; i++) { Slot slot = drawOrder.Items[i]; Bone bone = slot.bone; Attachment attachment = slot.attachment; object rendererObject; 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; RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { rendererObject = regionAttachment.RendererObject; attachmentVertexCount = 4; attachmentTriangleCount = 6; } else { if (!renderMeshes) { continue; } MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { rendererObject = meshAttachment.RendererObject; attachmentVertexCount = meshAttachment.vertices.Length >> 1; attachmentTriangleCount = meshAttachment.triangles.Length; } else { SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment; if (skinnedMeshAttachment != null) { rendererObject = skinnedMeshAttachment.RendererObject; attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; attachmentTriangleCount = skinnedMeshAttachment.triangles.Length; } else { continue; } } } // Populate submesh when material changes. #if !SPINE_TK2D Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject; #else Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject; #endif if ((lastMaterial != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) || (submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) { stateTemp.addSubmeshArguments.Add( new MeshState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false) ); submeshTriangleCount = 0; submeshFirstVertex = vertexCount; submeshStartSlotIndex = i; } lastMaterial = material; submeshTriangleCount += attachmentTriangleCount; vertexCount += attachmentVertexCount; } stateTemp.addSubmeshArguments.Add( new MeshState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true) ); bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(stateTemp.attachments, stateTemp.attachmentsFlipState, stateTemp.addSubmeshArguments); if (mustUpdateMeshStructure) { submeshMaterials.Clear(); for (int i = 0, n = stateTemp.addSubmeshArguments.Count; i < n; i++) { MeshState.AddSubmeshArguments arguments = stateTemp.addSubmeshArguments.Items[i]; AddSubmesh( arguments.material, arguments.startSlot, arguments.endSlot, arguments.triangleCount, arguments.firstVertex, arguments.lastSubmesh, stateTemp.attachmentsFlipState ); } // Set materials. if (submeshMaterials.Count == sharedMaterials.Length) { submeshMaterials.CopyTo(sharedMaterials); } else { sharedMaterials = submeshMaterials.ToArray(); } meshRenderer.sharedMaterials = sharedMaterials; } // Ensure mesh data is the right size. Vector3[] vertices = this.vertices; bool newTriangles = vertexCount > vertices.Length; if (newTriangles) { // Not enough vertices, increase size. this.vertices = vertices = new Vector3[vertexCount]; this.colors = new Color32[vertexCount]; this.uvs = new Vector2[vertexCount]; mesh1.Clear(); mesh2.Clear(); } else { // Too many vertices, zero the extra. Vector3 zero = Vector3.zero; for (int i = vertexCount, n = meshState.vertexCount; i < n; i++) { vertices[i] = zero; } } meshState.vertexCount = vertexCount; // Setup mesh. float zSpacing = this.zSpacing; float[] tempVertices = this.tempVertices; Vector2[] uvs = this.uvs; Color32[] colors = this.colors; int vertexIndex = 0; Color32 color; float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; Vector3 meshBoundsMin; Vector3 meshBoundsMax; if (vertexCount == 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 * (drawOrderCount - 1); } else { meshBoundsMin.z = zSpacing * (drawOrderCount - 1); meshBoundsMax.z = 0f; } int i = 0; do { Slot slot = drawOrder.Items[i]; Attachment attachment = slot.attachment; RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { regionAttachment.ComputeWorldVertices(slot.bone, tempVertices); float z = i * zSpacing; float x1 = tempVertices[RegionAttachment.X1], y1 = tempVertices[RegionAttachment.Y1]; float x2 = tempVertices[RegionAttachment.X2], y2 = tempVertices[RegionAttachment.Y2]; float x3 = tempVertices[RegionAttachment.X3], y3 = tempVertices[RegionAttachment.Y3]; float x4 = tempVertices[RegionAttachment.X4], y4 = tempVertices[RegionAttachment.Y4]; vertices[vertexIndex].x = x1; vertices[vertexIndex].y = y1; vertices[vertexIndex].z = z; vertices[vertexIndex + 1].x = x4; vertices[vertexIndex + 1].y = y4; vertices[vertexIndex + 1].z = z; vertices[vertexIndex + 2].x = x2; vertices[vertexIndex + 2].y = y2; vertices[vertexIndex + 2].z = z; vertices[vertexIndex + 3].x = x3; vertices[vertexIndex + 3].y = y3; vertices[vertexIndex + 3].z = z; color.a = (byte)(a * slot.a * regionAttachment.a); color.r = (byte)(r * slot.r * regionAttachment.r * color.a); color.g = (byte)(g * slot.g * regionAttachment.g * color.a); color.b = (byte)(b * slot.b * regionAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } colors[vertexIndex] = color; colors[vertexIndex + 1] = color; colors[vertexIndex + 2] = color; colors[vertexIndex + 3] = color; float[] regionUVs = regionAttachment.uvs; uvs[vertexIndex].x = regionUVs[RegionAttachment.X1]; uvs[vertexIndex].y = regionUVs[RegionAttachment.Y1]; uvs[vertexIndex + 1].x = regionUVs[RegionAttachment.X4]; uvs[vertexIndex + 1].y = regionUVs[RegionAttachment.Y4]; uvs[vertexIndex + 2].x = regionUVs[RegionAttachment.X2]; uvs[vertexIndex + 2].y = regionUVs[RegionAttachment.Y2]; uvs[vertexIndex + 3].x = regionUVs[RegionAttachment.X3]; uvs[vertexIndex + 3].y = regionUVs[RegionAttachment.Y3]; // Calculate min/max X if (x1 < meshBoundsMin.x) { meshBoundsMin.x = x1; } else if (x1 > meshBoundsMax.x) { meshBoundsMax.x = x1; } if (x2 < meshBoundsMin.x) { meshBoundsMin.x = x2; } else if (x2 > meshBoundsMax.x) { meshBoundsMax.x = x2; } if (x3 < meshBoundsMin.x) { meshBoundsMin.x = x3; } else if (x3 > meshBoundsMax.x) { meshBoundsMax.x = x3; } if (x4 < meshBoundsMin.x) { meshBoundsMin.x = x4; } else if (x4 > meshBoundsMax.x) { meshBoundsMax.x = x4; } // Calculate min/max Y if (y1 < meshBoundsMin.y) { meshBoundsMin.y = y1; } else if (y1 > meshBoundsMax.y) { meshBoundsMax.y = y1; } if (y2 < meshBoundsMin.y) { meshBoundsMin.y = y2; } else if (y2 > meshBoundsMax.y) { meshBoundsMax.y = y2; } if (y3 < meshBoundsMin.y) { meshBoundsMin.y = y3; } else if (y3 > meshBoundsMax.y) { meshBoundsMax.y = y3; } if (y4 < meshBoundsMin.y) { meshBoundsMin.y = y4; } else if (y4 > meshBoundsMax.y) { meshBoundsMax.y = y4; } vertexIndex += 4; } else { if (!renderMeshes) { continue; } MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { int meshVertexCount = meshAttachment.vertices.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } meshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } float[] meshUVs = meshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { float x = tempVertices[ii], y = tempVertices[ii + 1]; vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z; colors[vertexIndex] = color; uvs[vertexIndex].x = meshUVs[ii]; uvs[vertexIndex].y = meshUVs[ii + 1]; if (x < meshBoundsMin.x) { meshBoundsMin.x = x; } else if (x > meshBoundsMax.x) { meshBoundsMax.x = x; } if (y < meshBoundsMin.y) { meshBoundsMin.y = y; } else if (y > meshBoundsMax.y) { meshBoundsMax.y = y; } } } else { SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment; if (skinnedMeshAttachment != null) { int meshVertexCount = skinnedMeshAttachment.uvs.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } skinnedMeshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * skinnedMeshAttachment.a); color.r = (byte)(r * slot.r * skinnedMeshAttachment.r * color.a); color.g = (byte)(g * slot.g * skinnedMeshAttachment.g * color.a); color.b = (byte)(b * slot.b * skinnedMeshAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } float[] meshUVs = skinnedMeshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { float x = tempVertices[ii], y = tempVertices[ii + 1]; vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z; colors[vertexIndex] = color; uvs[vertexIndex].x = meshUVs[ii]; uvs[vertexIndex].y = meshUVs[ii + 1]; if (x < meshBoundsMin.x) { meshBoundsMin.x = x; } else if (x > meshBoundsMax.x) { meshBoundsMax.x = x; } if (y < meshBoundsMin.y) { meshBoundsMin.y = y; } else if (y > meshBoundsMax.y) { meshBoundsMax.y = y; } } } } } } while (++i < drawOrderCount); } // Double buffer mesh. Mesh mesh = useMesh1 ? mesh1 : mesh2; meshFilter.sharedMesh = mesh; mesh.vertices = vertices; mesh.colors32 = colors; mesh.uv = uvs; if (mustUpdateMeshStructure) { int submeshCount = submeshMaterials.Count; mesh.subMeshCount = submeshCount; for (int i = 0; i < submeshCount; ++i) { mesh.SetTriangles(submeshes.Items[i].triangles, i); } } Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin; Vector3 meshBoundsCenter = meshBoundsMin + meshBoundsExtents * 0.5f; mesh.bounds = new Bounds(meshBoundsCenter, meshBoundsExtents); if (newTriangles && calculateNormals) { Vector3[] normals = new Vector3[vertexCount]; Vector3 normal = new Vector3(0, 0, -1); for (int i = 0; i < vertexCount; i++) { normals[i] = normal; } (useMesh1 ? mesh2 : mesh1).vertices = vertices; // Set other mesh vertices. mesh1.normals = normals; mesh2.normals = normals; if (calculateTangents) { Vector4[] tangents = new Vector4[vertexCount]; Vector3 tangent = new Vector3(0, 0, 1); for (int i = 0; i < vertexCount; i++) { tangents[i] = tangent; } mesh1.tangents = tangents; mesh2.tangents = tangents; } } // Update previous state MeshState.SingleMeshState currentMeshState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2; currentMeshState.immutableTriangles = immutableTriangles; currentMeshState.attachments.Clear(true); currentMeshState.attachments.GrowIfNeeded(stateTemp.attachments.Capacity); currentMeshState.attachments.Count = stateTemp.attachments.Count; stateTemp.attachments.CopyTo(currentMeshState.attachments.Items); currentMeshState.attachmentsFlipState.GrowIfNeeded(stateTemp.attachmentsFlipState.Capacity); currentMeshState.attachmentsFlipState.Count = stateTemp.attachmentsFlipState.Count; stateTemp.attachmentsFlipState.CopyTo(currentMeshState.attachmentsFlipState.Items); currentMeshState.addSubmeshArguments.GrowIfNeeded(stateTemp.addSubmeshArguments.Capacity); currentMeshState.addSubmeshArguments.Count = stateTemp.addSubmeshArguments.Count; stateTemp.addSubmeshArguments.CopyTo(currentMeshState.addSubmeshArguments.Items); if (submeshRenderers.Length > 0) { for (int i = 0; i < submeshRenderers.Length; i++) { SkeletonUtilitySubmeshRenderer submeshRenderer = submeshRenderers[i]; if (submeshRenderer.submeshIndex < sharedMaterials.Length) { submeshRenderer.SetMesh(meshRenderer, useMesh1 ? mesh1 : mesh2, sharedMaterials[submeshRenderer.submeshIndex]); } else { submeshRenderer.GetComponent <Renderer>().enabled = false; } } } useMesh1 = !useMesh1; }