public void RenderParts(ExposedList <SubmeshInstruction> instructions, int startSubmesh, int endSubmesh)
        {
            LazyIntialize();

            // STEP 1: Create instruction
            var smartMesh = buffers.GetNextMesh();

            currentInstructions.SetWithSubset(instructions, startSubmesh, endSubmesh);
            bool updateTriangles = SkeletonRendererInstruction.GeometryNotEqual(currentInstructions, smartMesh.instructionUsed);

            // STEP 2: Generate mesh buffers.
            var currentInstructionsSubmeshesItems = currentInstructions.submeshInstructions.Items;

            meshGenerator.Begin();
            if (currentInstructions.hasActiveClipping)
            {
                for (int i = 0; i < currentInstructions.submeshInstructions.Count; i++)
                {
                    meshGenerator.AddSubmesh(currentInstructionsSubmeshesItems[i], updateTriangles);
                }
            }
            else
            {
                meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles);
            }

            buffers.UpdateSharedMaterials(currentInstructions.submeshInstructions);

            // STEP 3: modify mesh.
            var mesh = smartMesh.mesh;

            if (meshGenerator.VertexCount <= 0)               // Clear an empty mesh
            {
                updateTriangles = false;
                mesh.Clear();
            }
            else
            {
                meshGenerator.FillVertexData(mesh);
                if (updateTriangles)
                {
                    meshGenerator.FillTriangles(mesh);
                    meshRenderer.sharedMaterials = buffers.GetUpdatedSharedMaterialsArray();
                }
                else if (buffers.MaterialsChangedInLastUpdate())
                {
                    meshRenderer.sharedMaterials = buffers.GetUpdatedSharedMaterialsArray();
                }
                meshGenerator.FillLateVertexData(mesh);
            }

            meshFilter.sharedMesh = mesh;
            smartMesh.instructionUsed.Set(currentInstructions);

            if (OnMeshAndMaterialsUpdated != null)
            {
                OnMeshAndMaterialsUpdated(this);
            }
        }
        /// <summary>
        /// Generates a new UnityEngine.Mesh from the internal Skeleton.</summary>
        public virtual void LateUpdate()
        {
            if (!valid)
            {
                return;
            }

                        #if UNITY_EDITOR && NEW_PREFAB_SYSTEM
            // Don't store mesh or material at the prefab, otherwise it will permanently reload
            var prefabType = UnityEditor.PrefabUtility.GetPrefabAssetType(this);
            if (UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this) &&
                (prefabType == UnityEditor.PrefabAssetType.Regular || prefabType == UnityEditor.PrefabAssetType.Variant))
            {
                return;
            }
                        #endif

            if (updateMode != UpdateMode.FullUpdate)
            {
                return;
            }

                        #if SPINE_OPTIONAL_RENDEROVERRIDE
            bool doMeshOverride = generateMeshOverride != null;
            if ((!meshRenderer.enabled) && !doMeshOverride)
            {
                return;
            }
                        #else
            const bool doMeshOverride = false;
            if (!meshRenderer.enabled)
            {
                return;
            }
                        #endif
            var currentInstructions        = this.currentInstructions;
            var workingSubmeshInstructions = currentInstructions.submeshInstructions;
            var currentSmartMesh           = rendererBuffers.GetNextMesh();   // Double-buffer for performance.

            bool updateTriangles;

            if (this.singleSubmesh)
            {
                // STEP 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes. =============================================
                MeshGenerator.GenerateSingleSubmeshInstruction(currentInstructions, skeleton, skeletonDataAsset.atlasAssets[0].PrimaryMaterial);

                // STEP 1.9. Post-process workingInstructions. ==================================================================================
                                #if SPINE_OPTIONAL_MATERIALOVERRIDE
                if (customMaterialOverride.Count > 0)                 // isCustomMaterialOverridePopulated
                {
                    MeshGenerator.TryReplaceMaterials(workingSubmeshInstructions, customMaterialOverride);
                }
                                #endif

                // STEP 2. Update vertex buffer based on verts from the attachments. ===========================================================
                meshGenerator.settings = new MeshGenerator.Settings {
                    pmaVertexColors   = this.pmaVertexColors,
                    zSpacing          = this.zSpacing,
                    useClipping       = this.useClipping,
                    tintBlack         = this.tintBlack,
                    calculateTangents = this.calculateTangents,
                    addNormals        = this.addNormals
                };
                meshGenerator.Begin();
                updateTriangles = SkeletonRendererInstruction.GeometryNotEqual(currentInstructions, currentSmartMesh.instructionUsed);
                if (currentInstructions.hasActiveClipping)
                {
                    meshGenerator.AddSubmesh(workingSubmeshInstructions.Items[0], updateTriangles);
                }
                else
                {
                    meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles);
                }
            }
            else
            {
                // STEP 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes. =============================================
                MeshGenerator.GenerateSkeletonRendererInstruction(currentInstructions, skeleton, customSlotMaterials, separatorSlots, doMeshOverride, this.immutableTriangles);

                // STEP 1.9. Post-process workingInstructions. ==================================================================================
#if SPINE_OPTIONAL_MATERIALOVERRIDE
                if (customMaterialOverride.Count > 0)                 // isCustomMaterialOverridePopulated
                {
                    MeshGenerator.TryReplaceMaterials(workingSubmeshInstructions, customMaterialOverride);
                }
#endif

#if SPINE_OPTIONAL_RENDEROVERRIDE
                if (doMeshOverride)
                {
                    this.generateMeshOverride(currentInstructions);
                    if (disableRenderingOnOverride)
                    {
                        return;
                    }
                }
#endif

                updateTriangles = SkeletonRendererInstruction.GeometryNotEqual(currentInstructions, currentSmartMesh.instructionUsed);

                // STEP 2. Update vertex buffer based on verts from the attachments. ===========================================================
                meshGenerator.settings = new MeshGenerator.Settings {
                    pmaVertexColors   = this.pmaVertexColors,
                    zSpacing          = this.zSpacing,
                    useClipping       = this.useClipping,
                    tintBlack         = this.tintBlack,
                    calculateTangents = this.calculateTangents,
                    addNormals        = this.addNormals
                };
                meshGenerator.Begin();
                if (currentInstructions.hasActiveClipping)
                {
                    meshGenerator.BuildMesh(currentInstructions, updateTriangles);
                }
                else
                {
                    meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles);
                }
            }

            if (OnPostProcessVertices != null)
            {
                OnPostProcessVertices.Invoke(this.meshGenerator.Buffers);
            }

            // STEP 3. Move the mesh data into a UnityEngine.Mesh ===========================================================================
            var currentMesh = currentSmartMesh.mesh;
            meshGenerator.FillVertexData(currentMesh);

            rendererBuffers.UpdateSharedMaterials(workingSubmeshInstructions);

            bool materialsChanged = rendererBuffers.MaterialsChangedInLastUpdate();
            if (updateTriangles)               // Check if the triangles should also be updated.
            {
                meshGenerator.FillTriangles(currentMesh);
                meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedSharedMaterialsArray();
            }
            else if (materialsChanged)
            {
                meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedSharedMaterialsArray();
            }
            if (materialsChanged && (this.maskMaterials.AnyMaterialCreated))
            {
                this.maskMaterials = new SpriteMaskInteractionMaterials();
            }

            meshGenerator.FillLateVertexData(currentMesh);

            // STEP 4. The UnityEngine.Mesh is ready. Set it as the MeshFilter's mesh. Store the instructions used for that mesh. ===========
            meshFilter.sharedMesh = currentMesh;
            currentSmartMesh.instructionUsed.Set(currentInstructions);

                        #if BUILT_IN_SPRITE_MASK_COMPONENT
            if (meshRenderer != null)
            {
                AssignSpriteMaskMaterials();
            }
                        #endif

                        #if PER_MATERIAL_PROPERTY_BLOCKS
            if (fixDrawOrder && meshRenderer.sharedMaterials.Length > 2)
            {
                SetMaterialSettingsToFixDrawOrder();
            }
                        #endif

            if (OnMeshAndMaterialsUpdated != null)
            {
                OnMeshAndMaterialsUpdated(this);
            }
        }
        /// <summary>
        /// Generates a new UnityEngine.Mesh from the internal Skeleton.</summary>
        public virtual void LateUpdate()
        {
            if (!valid)
            {
                return;
            }

                        #if SPINE_OPTIONAL_RENDEROVERRIDE
            bool doMeshOverride = generateMeshOverride != null;
            if ((!meshRenderer.enabled) && !doMeshOverride)
            {
                return;
            }
                        #else
            const bool doMeshOverride = false;
            if (!meshRenderer.enabled)
            {
                return;
            }
                        #endif
            var currentInstructions        = this.currentInstructions;
            var workingSubmeshInstructions = currentInstructions.submeshInstructions;
            var currentSmartMesh           = rendererBuffers.GetNextMesh();   // Double-buffer for performance.

            bool updateTriangles;

            if (this.singleSubmesh)
            {
                // STEP 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes. =============================================
                MeshGenerator.GenerateSingleSubmeshInstruction(currentInstructions, skeleton, skeletonDataAsset.atlasAssets[0].PrimaryMaterial);

                // STEP 1.9. Post-process workingInstructions. ==================================================================================
                                #if SPINE_OPTIONAL_MATERIALOVERRIDE
                if (customMaterialOverride.Count > 0)                 // isCustomMaterialOverridePopulated
                {
                    MeshGenerator.TryReplaceMaterials(workingSubmeshInstructions, customMaterialOverride);
                }
                                #endif

                // STEP 2. Update vertex buffer based on verts from the attachments.  ===========================================================
                meshGenerator.settings = new MeshGenerator.Settings {
                    pmaVertexColors   = this.pmaVertexColors,
                    zSpacing          = this.zSpacing,
                    useClipping       = this.useClipping,
                    tintBlack         = this.tintBlack,
                    calculateTangents = this.calculateTangents,
                    addNormals        = this.addNormals
                };
                meshGenerator.Begin();
                updateTriangles = SkeletonRendererInstruction.GeometryNotEqual(currentInstructions, currentSmartMesh.instructionUsed);
                if (currentInstructions.hasActiveClipping)
                {
                    meshGenerator.AddSubmesh(workingSubmeshInstructions.Items[0], updateTriangles);
                }
                else
                {
                    meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles);
                }
            }
            else
            {
                // STEP 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes. =============================================
                MeshGenerator.GenerateSkeletonRendererInstruction(currentInstructions, skeleton, customSlotMaterials, separatorSlots, doMeshOverride, this.immutableTriangles);

                // STEP 1.9. Post-process workingInstructions. ==================================================================================
                                #if SPINE_OPTIONAL_MATERIALOVERRIDE
                if (customMaterialOverride.Count > 0)                 // isCustomMaterialOverridePopulated
                {
                    MeshGenerator.TryReplaceMaterials(workingSubmeshInstructions, customMaterialOverride);
                }
                                #endif

                                #if SPINE_OPTIONAL_RENDEROVERRIDE
                if (doMeshOverride)
                {
                    this.generateMeshOverride(currentInstructions);
                    if (disableRenderingOnOverride)
                    {
                        return;
                    }
                }
                                #endif

                updateTriangles = SkeletonRendererInstruction.GeometryNotEqual(currentInstructions, currentSmartMesh.instructionUsed);

                // STEP 2. Update vertex buffer based on verts from the attachments.  ===========================================================
                meshGenerator.settings = new MeshGenerator.Settings {
                    pmaVertexColors   = this.pmaVertexColors,
                    zSpacing          = this.zSpacing,
                    useClipping       = this.useClipping,
                    tintBlack         = this.tintBlack,
                    calculateTangents = this.calculateTangents,
                    addNormals        = this.addNormals
                };
                meshGenerator.Begin();
                if (currentInstructions.hasActiveClipping)
                {
                    meshGenerator.BuildMesh(currentInstructions, updateTriangles);
                }
                else
                {
                    meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles);
                }
            }

            if (OnPostProcessVertices != null)
            {
                OnPostProcessVertices.Invoke(this.meshGenerator.Buffers);
            }

            // STEP 3. Move the mesh data into a UnityEngine.Mesh ===========================================================================
            var currentMesh = currentSmartMesh.mesh;
            meshGenerator.FillVertexData(currentMesh);

            rendererBuffers.UpdateSharedMaterials(workingSubmeshInstructions);

            if (updateTriangles)               // Check if the triangles should also be updated.
            {
                meshGenerator.FillTriangles(currentMesh);
                meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedSharedMaterialsArray();
            }
            else if (rendererBuffers.MaterialsChangedInLastUpdate())
            {
                meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedSharedMaterialsArray();
            }

            meshGenerator.FillLateVertexData(currentMesh);

            // STEP 4. The UnityEngine.Mesh is ready. Set it as the MeshFilter's mesh. Store the instructions used for that mesh. ===========
            meshFilter.sharedMesh = currentMesh;
            currentSmartMesh.instructionUsed.Set(currentInstructions);

                        #if BUILT_IN_SPRITE_MASK_COMPONENT
            if (meshRenderer != null)
            {
                AssignSpriteMaskMaterials();
            }
                        #endif
        }