< 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:60
Uncovered lines:5
Coverable lines:65
Total lines:179
Line coverage:92.3% (60 of 65)
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%2100%
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);
 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
 131936        public GameObject container { get; private set; }
 037        public SkinnedMeshRenderer renderer { get; private set; }
 38
 039        public bool useCullOpaqueHeuristic { get; set; } = false;
 130440        public bool prepareMeshForGpuSkinning { get; set; } = false;
 262341        public bool uploadMeshToGpu { get; set; } = true;
 131942        public bool enableCombinedMesh { get; set; } = true;
 43
 44        private AvatarMeshCombiner.Output? lastOutput;
 45
 395746        public AvatarMeshCombinerHelper (GameObject container = null) { this.container = container; }
 47
 48        /// <summary>
 49        /// Combine will use AvatarMeshCombiner to generate a combined avatar mesh.
 50        /// After the avatar is combined, it will generate a new GameObject with a SkinnedMeshRenderer that contains
 51        /// the generated mesh. This GameObject and Renderer will be preserved over any number of Combine() calls.
 52        ///
 53        /// Uses a predefined Material ready for the Avatar
 54        ///
 55        /// For more details on the combining check out AvatarMeshCombiner.CombineSkinnedMeshes.
 56        /// </summary>
 57        /// <param name="bonesContainer">A SkinnedMeshRenderer that must contain the bones and bindposes that will be us
 58        /// <param name="renderersToCombine">A list of avatar parts to be combined</param>
 059        public bool Combine(SkinnedMeshRenderer bonesContainer, SkinnedMeshRenderer[] renderersToCombine) { return Combi
 60
 61        /// <summary>
 62        /// Combine will use AvatarMeshCombiner to generate a combined avatar mesh.
 63        /// After the avatar is combined, it will generate a new GameObject with a SkinnedMeshRenderer that contains
 64        /// the generated mesh. This GameObject and Renderer will be preserved over any number of Combine() calls.
 65        ///
 66        /// For more details on the combining check out AvatarMeshCombiner.CombineSkinnedMeshes.
 67        /// </summary>
 68        /// <param name="bonesContainer">A SkinnedMeshRenderer that must contain the bones and bindposes that will be us
 69        /// <param name="renderersToCombine">A list of avatar parts to be combined</param>
 70        /// <param name="materialAsset">A material asset that will serve as the base of the combine result. A new materi
 71        /// <returns>true if succeeded, false if not</returns>
 72        public bool Combine(SkinnedMeshRenderer bonesContainer, SkinnedMeshRenderer[] renderersToCombine, Material mater
 73        {
 1774            Assert.IsTrue(bonesContainer != null, "bonesContainer should never be null!");
 1775            Assert.IsTrue(renderersToCombine != null, "renderersToCombine should never be null!");
 1776            Assert.IsTrue(materialAsset != null, "materialAsset should never be null!");
 77
 1778            SkinnedMeshRenderer[] renderers = renderersToCombine;
 79
 80            // Sanitize renderers list
 9681            renderers = renderers.Where( (x) => x != null && x.sharedMesh != null ).ToArray();
 82
 1783            if ( renderers.Length == 0 )
 184                return false;
 85
 1686            bool success = CombineInternal(
 87                bonesContainer,
 88                renderers,
 89                materialAsset);
 90
 91            // Disable original renderers
 17092            for ( int i = 0; i < renderers.Length; i++ )
 93            {
 6994                renderers[i].enabled = false;
 95            }
 96
 1697            return success;
 98        }
 99
 100        private bool CombineInternal(SkinnedMeshRenderer bonesContainer, SkinnedMeshRenderer[] renderers, Material mater
 101        {
 16102            Assert.IsTrue(bonesContainer != null, "bonesContainer should never be null!");
 16103            Assert.IsTrue(bonesContainer.sharedMesh != null, "bonesContainer should never be null!");
 16104            Assert.IsTrue(bonesContainer.sharedMesh.bindposes != null, "bonesContainer bindPoses should never be null!")
 16105            Assert.IsTrue(bonesContainer.bones != null, "bonesContainer bones should never be null!");
 16106            Assert.IsTrue(renderers != null, "renderers should never be null!");
 16107            Assert.IsTrue(materialAsset != null, "materialAsset should never be null!");
 108
 16109            CombineLayerUtils.ENABLE_CULL_OPAQUE_HEURISTIC = useCullOpaqueHeuristic;
 110
 16111            AvatarMeshCombiner.Output output = AvatarMeshCombiner.CombineSkinnedMeshes(
 112                bonesContainer.sharedMesh.bindposes,
 113                bonesContainer.bones,
 114                renderers,
 115                materialAsset);
 116
 16117            if ( !output.isValid )
 118            {
 0119                logger.LogError("AvatarMeshCombiner", "Combine failed!");
 0120                return false;
 121            }
 16122            Transform rootBone = bonesContainer.rootBone;
 123
 16124            if ( container == null )
 14125                this.container = new GameObject("CombinedAvatar");
 126
 16127            if ( renderer == null )
 14128                renderer = container.AddComponent<SkinnedMeshRenderer>();
 129
 16130            UnloadAssets();
 16131            lastOutput = output;
 132
 16133            container.layer = bonesContainer.gameObject.layer;
 16134            renderer.sharedMesh = output.mesh;
 16135            renderer.bones = bonesContainer.bones;
 16136            renderer.rootBone = rootBone;
 16137            renderer.sharedMaterials = output.materials;
 16138            renderer.quality = SkinQuality.Bone4;
 16139            renderer.updateWhenOffscreen = false;
 16140            renderer.skinnedMotionVectors = false;
 16141            renderer.enabled = enableCombinedMesh;
 142
 16143            if (prepareMeshForGpuSkinning)
 1144                GPUSkinningUtils.EncodeBindPosesIntoMesh(renderer);
 145
 16146            if (uploadMeshToGpu)
 8147                output.mesh.UploadMeshData(true);
 148
 16149            logger.Log("AvatarMeshCombiner", "Finish combining avatar. Click here to focus on GameObject.", container);
 16150            return true;
 151        }
 152
 153        private void UnloadAssets()
 154        {
 1510155            if (!lastOutput.HasValue)
 1496156                return;
 157
 14158            if (lastOutput.Value.mesh != null)
 14159                Object.Destroy(lastOutput.Value.mesh);
 160
 14161            if (lastOutput.Value.materials != null)
 162            {
 74163                foreach ( var material in lastOutput.Value.materials )
 164                {
 23165                    Object.Destroy(material);
 166                }
 167            }
 14168        }
 169
 170        /// <summary>
 171        /// Disposes the created mesh, materials, GameObject and Renderer.
 172        /// </summary>
 173        public void Dispose()
 174        {
 1494175            UnloadAssets();
 1494176            Object.Destroy(container);
 1494177        }
 178    }
 179}