< Summary

Class:DCL.AvatarMeshCombinerHelper
Assembly:AvatarMeshCombiner
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarMeshCombiner/AvatarMeshCombinerHelper.cs
Covered lines:65
Uncovered lines:2
Coverable lines:67
Total lines:183
Line coverage:97% (65 of 67)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
AvatarMeshCombinerHelper()0%330100%
AvatarMeshCombinerHelper(...)0%110100%
Combine(...)0%110100%
Combine(...)0%440100%
CombineInternal(...)0%6.016093.94%
UnloadAssets()0%550100%
Dispose()0%110100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarMeshCombiner/AvatarMeshCombinerHelper.cs

#LineLine coverage
 1using System;
 2using System.Linq;
 3using GPUSkinning;
 4using UnityEngine;
 5using UnityEngine.Assertions;
 6using Object = UnityEngine.Object;
 7
 8namespace DCL
 9{
 10    public interface IAvatarMeshCombinerHelper : IDisposable
 11    {
 12        public bool useCullOpaqueHeuristic { get; set; }
 13        public bool prepareMeshForGpuSkinning { get; set; }
 14        public bool uploadMeshToGpu { get; set; }
 15        public bool enableCombinedMesh { get; set; }
 16
 17        public GameObject container { get; }
 18        public SkinnedMeshRenderer renderer { get; }
 19
 20        public bool Combine(SkinnedMeshRenderer bonesContainer, SkinnedMeshRenderer[] renderersToCombine, bool keepPose 
 21        public bool Combine(SkinnedMeshRenderer bonesContainer, SkinnedMeshRenderer[] renderersToCombine, Material mater
 22    }
 23
 24    /// <summary>
 25    /// AvatarMeshCombinerHelper uses the AvatarMeshCombiner utility class to combine many skinned renderers
 26    /// into a single one.
 27    ///
 28    /// This class will recycle the same gameObject and renderer each time it is called,
 29    /// and binds the AvatarMeshCombiner output to a proper well configured SkinnedMeshRenderer.
 30    /// </summary>
 31    public class AvatarMeshCombinerHelper : IAvatarMeshCombinerHelper
 32    {
 133        private static bool VERBOSE = false;
 134        private static ILogger logger = new Logger(Debug.unityLogger.logHandler) { filterLogType = VERBOSE ? LogType.Log
 35
 145236        public GameObject container { get; private set; }
 17737        public SkinnedMeshRenderer renderer { get; private set; }
 38
 1639        public bool useCullOpaqueHeuristic { get; set; } = false;
 68540        public bool prepareMeshForGpuSkinning { get; set; } = false;
 136341        public bool uploadMeshToGpu { get; set; } = true;
 69342        public bool enableCombinedMesh { get; set; } = true;
 43
 44        private AvatarMeshCombiner.Output? lastOutput;
 45
 67746        public AvatarMeshCombinerHelper (GameObject container = null)
 47        {
 67748            this.container = container;
 67749        }
 50
 51        /// <summary>
 52        /// Combine will use AvatarMeshCombiner to generate a combined avatar mesh.
 53        /// After the avatar is combined, it will generate a new GameObject with a SkinnedMeshRenderer that contains
 54        /// the generated mesh. This GameObject and Renderer will be preserved over any number of Combine() calls.
 55        ///
 56        /// Uses a predefined Material ready for the Avatar
 57        ///
 58        /// For more details on the combining check out AvatarMeshCombiner.CombineSkinnedMeshes.
 59        /// </summary>
 60        /// <param name="bonesContainer">A SkinnedMeshRenderer that must contain the bones and bindposes that will be us
 61        /// <param name="renderersToCombine">A list of avatar parts to be combined</param>
 1162        public bool Combine(SkinnedMeshRenderer bonesContainer, SkinnedMeshRenderer[] renderersToCombine, bool keepPose 
 63
 64        /// <summary>
 65        /// Combine will use AvatarMeshCombiner to generate a combined avatar mesh.
 66        /// After the avatar is combined, it will generate a new GameObject with a SkinnedMeshRenderer that contains
 67        /// the generated mesh. This GameObject and Renderer will be preserved over any number of Combine() calls.
 68        ///
 69        /// For more details on the combining check out AvatarMeshCombiner.CombineSkinnedMeshes.
 70        /// </summary>
 71        /// <param name="bonesContainer">A SkinnedMeshRenderer that must contain the bones and bindposes that will be us
 72        /// <param name="renderersToCombine">A list of avatar parts to be combined</param>
 73        /// <param name="materialAsset">A material asset that will serve as the base of the combine result. A new materi
 74        /// <returns>true if succeeded, false if not</returns>
 75        public bool Combine(SkinnedMeshRenderer bonesContainer, SkinnedMeshRenderer[] renderersToCombine, Material mater
 76        {
 1777            Assert.IsTrue(bonesContainer != null, "bonesContainer should never be null!");
 1778            Assert.IsTrue(renderersToCombine != null, "renderersToCombine should never be null!");
 1779            Assert.IsTrue(materialAsset != null, "materialAsset should never be null!");
 80
 1781            SkinnedMeshRenderer[] renderers = renderersToCombine;
 82
 83            // Sanitize renderers list
 9684            renderers = renderers.Where( (x) => x != null && x.sharedMesh != null ).ToArray();
 85
 1786            if ( renderers.Length == 0 )
 187                return false;
 88
 1689            bool success = CombineInternal(
 90                bonesContainer,
 91                renderers,
 92                materialAsset,
 93                keepPose);
 94
 95            // Disable original renderers
 17096            for ( int i = 0; i < renderers.Length; i++ )
 97            {
 6998                renderers[i].enabled = false;
 99            }
 100
 16101            return success;
 102        }
 103
 104        private bool CombineInternal(SkinnedMeshRenderer bonesContainer, SkinnedMeshRenderer[] renderers, Material mater
 105        {
 16106            Assert.IsTrue(bonesContainer != null, "bonesContainer should never be null!");
 16107            Assert.IsTrue(bonesContainer.sharedMesh != null, "the shared mesh of this bones container is null, check if 
 16108            Assert.IsTrue(bonesContainer.sharedMesh.bindposes != null, "bonesContainer bindPoses should never be null!")
 16109            Assert.IsTrue(bonesContainer.bones != null, "bonesContainer bones should never be null!");
 16110            Assert.IsTrue(renderers != null, "renderers should never be null!");
 16111            Assert.IsTrue(materialAsset != null, "materialAsset should never be null!");
 112
 16113            CombineLayerUtils.ENABLE_CULL_OPAQUE_HEURISTIC = useCullOpaqueHeuristic;
 16114            AvatarMeshCombiner.Output output = AvatarMeshCombiner.CombineSkinnedMeshes(
 115                bonesContainer.sharedMesh.bindposes,
 116                bonesContainer.bones,
 117                renderers,
 118                materialAsset,
 119                keepPose);
 120
 16121            if ( !output.isValid )
 122            {
 0123                logger.LogError("AvatarMeshCombiner", "Combine failed!");
 0124                return false;
 125            }
 16126            Transform rootBone = bonesContainer.rootBone;
 127
 16128            if ( container == null )
 14129                this.container = new GameObject("CombinedAvatar");
 130
 16131            if ( renderer == null )
 14132                renderer = container.AddComponent<SkinnedMeshRenderer>();
 133
 16134            UnloadAssets();
 16135            lastOutput = output;
 136
 16137            container.layer = bonesContainer.gameObject.layer;
 16138            renderer.sharedMesh = output.mesh;
 16139            renderer.bones = bonesContainer.bones;
 16140            renderer.rootBone = rootBone;
 16141            renderer.sharedMaterials = output.materials;
 16142            renderer.quality = SkinQuality.Bone4;
 16143            renderer.updateWhenOffscreen = false;
 16144            renderer.skinnedMotionVectors = false;
 16145            renderer.enabled = enableCombinedMesh;
 146
 16147            if (prepareMeshForGpuSkinning)
 1148                GPUSkinningUtils.EncodeBindPosesIntoMesh(renderer);
 149
 16150            if (uploadMeshToGpu)
 8151                output.mesh.UploadMeshData(true);
 152
 16153            logger.Log("AvatarMeshCombiner", "Finish combining avatar. Click here to focus on GameObject.", container);
 16154            return true;
 155        }
 156
 157        private void UnloadAssets()
 158        {
 697159            if (!lastOutput.HasValue)
 683160                return;
 161
 14162            if (lastOutput.Value.mesh != null)
 14163                Object.Destroy(lastOutput.Value.mesh);
 164
 14165            if (lastOutput.Value.materials != null)
 166            {
 74167                foreach ( var material in lastOutput.Value.materials )
 168                {
 23169                    Object.Destroy(material);
 170                }
 171            }
 14172        }
 173
 174        /// <summary>
 175        /// Disposes the created mesh, materials, GameObject and Renderer.
 176        /// </summary>
 177        public void Dispose()
 178        {
 681179            UnloadAssets();
 681180            Object.Destroy(container);
 681181        }
 182    }
 183}