public void UpdateMesh() { if (!this.IsValid) { return; } skeleton.SetColor(this.color); var smartMesh = meshBuffers.GetNext(); var currentInstructions = this.currentInstructions; MeshGenerator.GenerateSingleSubmeshInstruction(currentInstructions, skeleton, null); bool updateTriangles = SkeletonRendererInstruction.GeometryNotEqual(currentInstructions, smartMesh.instructionUsed); meshGenerator.Begin(); if (currentInstructions.hasActiveClipping) { meshGenerator.AddSubmesh(currentInstructions.submeshInstructions.Items[0], updateTriangles); } else { meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles); } if (canvas != null) { meshGenerator.ScaleVertexData(canvas.referencePixelsPerUnit); } if (OnPostProcessVertices != null) { OnPostProcessVertices.Invoke(this.meshGenerator.Buffers); } var mesh = smartMesh.mesh; meshGenerator.FillVertexData(mesh); if (updateTriangles) { meshGenerator.FillTriangles(mesh); } meshGenerator.FillLateVertexData(mesh); canvasRenderer.SetMesh(mesh); smartMesh.instructionUsed.Set(currentInstructions); if (currentInstructions.submeshInstructions.Count > 0) { var material = currentInstructions.submeshInstructions.Items[0].material; if (material != null && baseTexture != material.mainTexture) { baseTexture = material.mainTexture; if (overrideTexture == null) { canvasRenderer.SetTexture(this.mainTexture); } } } //this.UpdateMaterial(); // TODO: This allocates memory. }
protected void UpdateMeshSingleCanvasRenderer() { if (canvasRenderers.Count > 0) { DisableUnusedCanvasRenderers(usedCount: 0); } var smartMesh = meshBuffers.GetNext(); MeshGenerator.GenerateSingleSubmeshInstruction(currentInstructions, skeleton, null); bool updateTriangles = SkeletonRendererInstruction.GeometryNotEqual(currentInstructions, smartMesh.instructionUsed); meshGenerator.Begin(); if (currentInstructions.hasActiveClipping && currentInstructions.submeshInstructions.Count > 0) { meshGenerator.AddSubmesh(currentInstructions.submeshInstructions.Items[0], updateTriangles); } else { meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles); } if (canvas != null) { meshGenerator.ScaleVertexData(canvas.referencePixelsPerUnit); } if (OnPostProcessVertices != null) { OnPostProcessVertices.Invoke(this.meshGenerator.Buffers); } var mesh = smartMesh.mesh; meshGenerator.FillVertexData(mesh); if (updateTriangles) { meshGenerator.FillTriangles(mesh); } meshGenerator.FillLateVertexData(mesh); canvasRenderer.SetMesh(mesh); smartMesh.instructionUsed.Set(currentInstructions); if (currentInstructions.submeshInstructions.Count > 0) { var material = currentInstructions.submeshInstructions.Items[0].material; if (material != null && baseTexture != material.mainTexture) { baseTexture = material.mainTexture; if (overrideTexture == null) { canvasRenderer.SetTexture(this.mainTexture); } } } //this.UpdateMaterial(); // note: This would allocate memory. usedRenderersCount = 0; }
protected void UpdateMeshMultipleCanvasRenderers(SkeletonRendererInstruction currentInstructions) { MeshGenerator.GenerateSkeletonRendererInstruction(currentInstructions, skeleton, null, enableSeparatorSlots ? separatorSlots : null, enableSeparatorSlots ? separatorSlots.Count > 0 : false, false); int submeshCount = currentInstructions.submeshInstructions.Count; EnsureCanvasRendererCount(submeshCount); EnsureMeshesCount(submeshCount); EnsureSeparatorPartCount(); var c = canvas; float scale = (c == null) ? 100 : c.referencePixelsPerUnit; // Generate meshes. var meshesItems = meshes.Items; bool useOriginalTextureAndMaterial = (customMaterialOverride.Count == 0 && customTextureOverride.Count == 0); int separatorSlotGroupIndex = 0; Transform parent = this.separatorSlots.Count == 0 ? this.transform : this.separatorParts[0]; if (updateSeparatorPartLocation) { for (int p = 0; p < this.separatorParts.Count; ++p) { separatorParts[p].position = this.transform.position; separatorParts[p].rotation = this.transform.rotation; } } int targetSiblingIndex = 0; for (int i = 0; i < submeshCount; i++) { var submeshInstructionItem = currentInstructions.submeshInstructions.Items[i]; meshGenerator.Begin(); meshGenerator.AddSubmesh(submeshInstructionItem); var targetMesh = meshesItems[i]; meshGenerator.ScaleVertexData(scale); if (OnPostProcessVertices != null) { OnPostProcessVertices.Invoke(this.meshGenerator.Buffers); } meshGenerator.FillVertexData(targetMesh); meshGenerator.FillTriangles(targetMesh); meshGenerator.FillLateVertexData(targetMesh); var submeshMaterial = submeshInstructionItem.material; var canvasRenderer = canvasRenderers[i]; canvasRenderer.gameObject.SetActive(true); canvasRenderer.SetMesh(targetMesh); canvasRenderer.materialCount = 1; if (canvasRenderer.transform.parent != parent.transform) { canvasRenderer.transform.SetParent(parent.transform, false); canvasRenderer.transform.localPosition = Vector3.zero; } canvasRenderer.transform.SetSiblingIndex(targetSiblingIndex++); if (submeshInstructionItem.forceSeparate) { targetSiblingIndex = 0; parent = separatorParts[++separatorSlotGroupIndex]; } if (useOriginalTextureAndMaterial) { canvasRenderer.SetMaterial(this.materialForRendering, submeshMaterial.mainTexture); } else { var originalTexture = submeshMaterial.mainTexture; Material usedMaterial; Texture usedTexture; if (!customMaterialOverride.TryGetValue(originalTexture, out usedMaterial)) { usedMaterial = material; } if (!customTextureOverride.TryGetValue(originalTexture, out usedTexture)) { usedTexture = originalTexture; } canvasRenderer.SetMaterial(usedMaterial, usedTexture); } } DisableUnusedCanvasRenderers(usedCount: submeshCount); }
/// <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].materials[0]); // 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(); } // 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); }
protected void UpdateMeshMultipleCanvasRenderers(SkeletonRendererInstruction currentInstructions, bool keepRendererCount) { MeshGenerator.GenerateSkeletonRendererInstruction(currentInstructions, skeleton, null, enableSeparatorSlots ? separatorSlots : null, enableSeparatorSlots ? separatorSlots.Count > 0 : false, false); int submeshCount = currentInstructions.submeshInstructions.Count; if (keepRendererCount && submeshCount != usedRenderersCount) { return; } EnsureCanvasRendererCount(submeshCount); EnsureMeshesCount(submeshCount); EnsureSeparatorPartCount(); var c = canvas; float scale = (c == null) ? 100 : c.referencePixelsPerUnit; // Generate meshes. var meshesItems = meshes.Items; bool useOriginalTextureAndMaterial = (customMaterialOverride.Count == 0 && customTextureOverride.Count == 0); int separatorSlotGroupIndex = 0; Transform parent = this.separatorSlots.Count == 0 ? this.transform : this.separatorParts[0]; if (updateSeparatorPartLocation) { for (int p = 0; p < this.separatorParts.Count; ++p) { separatorParts[p].position = this.transform.position; separatorParts[p].rotation = this.transform.rotation; } } BlendModeMaterials blendModeMaterials = skeletonDataAsset.blendModeMaterials; bool hasBlendModeMaterials = blendModeMaterials.RequiresBlendModeMaterials; #if HAS_CULL_TRANSPARENT_MESH bool mainCullTransparentMesh = this.canvasRenderer.cullTransparentMesh; #endif bool pmaVertexColors = meshGenerator.settings.pmaVertexColors; int targetSiblingIndex = 0; for (int i = 0; i < submeshCount; i++) { var submeshInstructionItem = currentInstructions.submeshInstructions.Items[i]; meshGenerator.Begin(); meshGenerator.AddSubmesh(submeshInstructionItem); Mesh targetMesh = meshesItems[i]; meshGenerator.ScaleVertexData(scale); if (OnPostProcessVertices != null) { OnPostProcessVertices.Invoke(this.meshGenerator.Buffers); } meshGenerator.FillVertexData(targetMesh); meshGenerator.FillTriangles(targetMesh); meshGenerator.FillLateVertexData(targetMesh); var submeshMaterial = submeshInstructionItem.material; var canvasRenderer = canvasRenderers[i]; if (i >= usedRenderersCount) { canvasRenderer.gameObject.SetActive(true); } canvasRenderer.SetMesh(targetMesh); canvasRenderer.materialCount = 1; if (canvasRenderer.transform.parent != parent.transform) { canvasRenderer.transform.SetParent(parent.transform, false); canvasRenderer.transform.localPosition = Vector3.zero; } canvasRenderer.transform.SetSiblingIndex(targetSiblingIndex++); if (submeshInstructionItem.forceSeparate) { targetSiblingIndex = 0; parent = separatorParts[++separatorSlotGroupIndex]; } SkeletonSubmeshGraphic submeshGraphic = submeshGraphics[i]; if (useOriginalTextureAndMaterial) { Texture usedTexture = submeshMaterial.mainTexture; if (!hasBlendModeMaterials) { canvasRenderer.SetMaterial(this.materialForRendering, usedTexture); } else { bool allowCullTransparentMesh = true; BlendMode blendMode = blendModeMaterials.BlendModeForMaterial(submeshMaterial); Material usedMaterial = this.materialForRendering; if (blendMode == BlendMode.Normal) { if (submeshInstructionItem.hasPMAAdditiveSlot) { allowCullTransparentMesh = false; } } else if (blendMode == BlendMode.Additive) { if (pmaVertexColors) { allowCullTransparentMesh = false; } else if (additiveMaterial) { usedMaterial = additiveMaterial; } } else if (blendMode == BlendMode.Multiply && multiplyMaterial) { usedMaterial = multiplyMaterial; } else if (blendMode == BlendMode.Screen && screenMaterial) { usedMaterial = screenMaterial; } usedMaterial = submeshGraphic.GetModifiedMaterial(usedMaterial); canvasRenderer.SetMaterial(usedMaterial, usedTexture); #if HAS_CULL_TRANSPARENT_MESH canvasRenderer.cullTransparentMesh = allowCullTransparentMesh ? mainCullTransparentMesh : false; #endif } } else { var originalTexture = submeshMaterial.mainTexture; Material usedMaterial; Texture usedTexture; if (!customMaterialOverride.TryGetValue(originalTexture, out usedMaterial)) { usedMaterial = material; } if (!customTextureOverride.TryGetValue(originalTexture, out usedTexture)) { usedTexture = originalTexture; } usedMaterial = submeshGraphic.GetModifiedMaterial(usedMaterial); canvasRenderer.SetMaterial(usedMaterial, usedTexture); } } DisableUnusedCanvasRenderers(usedCount: submeshCount); usedRenderersCount = submeshCount; }