< 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:67
Uncovered lines:2
Coverable lines:69
Total lines:195
Line coverage:97.1% (67 of 69)
Covered branches:0
Total branches:0
Covered methods:18
Total methods:18
Method coverage:100% (18 of 18)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
AvatarMeshCombinerHelper(...)0%110100%
Combine(...)0%110100%
Combine(...)0%440100%
CombineInternal(...)0%6.016094.12%
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 System.Collections.Generic;
 5using UnityEngine;
 6using UnityEngine.Assertions;
 7using UnityEngine.Profiling;
 8using Object = UnityEngine.Object;
 9using logger = DCL.MeshCombinerLogger;
 10
 11namespace DCL
 12{
 13    public interface IAvatarMeshCombinerHelper : IDisposable
 14    {
 15        public bool useCullOpaqueHeuristic { get; set; }
 16        public bool prepareMeshForGpuSkinning { get; set; }
 17        public bool uploadMeshToGpu { get; set; }
 18        public bool enableCombinedMesh { get; set; }
 19
 20        public GameObject container { get; }
 21        public SkinnedMeshRenderer renderer { get; }
 22
 23        public bool Combine(SkinnedMeshRenderer bonesContainer, IReadOnlyList<SkinnedMeshRenderer> renderersToCombine, b
 24        public bool Combine(SkinnedMeshRenderer bonesContainer, IReadOnlyList<SkinnedMeshRenderer> renderersToCombine, M
 25    }
 26
 27    /// <summary>
 28    /// AvatarMeshCombinerHelper uses the AvatarMeshCombiner utility class to combine many skinned renderers
 29    /// into a single one.
 30    ///
 31    /// This class will recycle the same gameObject and renderer each time it is called,
 32    /// and binds the AvatarMeshCombiner output to a proper well configured SkinnedMeshRenderer.
 33    /// </summary>
 34    public class AvatarMeshCombinerHelper : IAvatarMeshCombinerHelper
 35    {
 109736        public GameObject container { get; private set; }
 11737        public SkinnedMeshRenderer renderer { get; private set; }
 38
 1039        public bool useCullOpaqueHeuristic { get; set; } = false;
 52940        public bool prepareMeshForGpuSkinning { get; set; } = false;
 105741        public bool uploadMeshToGpu { get; set; } = true;
 53742        public bool enableCombinedMesh { get; set; } = true;
 43
 44        private AvatarMeshCombiner.Output? lastOutput;
 45
 52746        public AvatarMeshCombinerHelper (GameObject container = null)
 47        {
 52748            this.container = container;
 52749        }
 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>
 62        /// <param name="keepPose"></param>
 1163        public bool Combine(SkinnedMeshRenderer bonesContainer, IReadOnlyList<SkinnedMeshRenderer> renderersToCombine, b
 64
 65        /// <summary>
 66        /// Combine will use AvatarMeshCombiner to generate a combined avatar mesh.
 67        /// After the avatar is combined, it will generate a new GameObject with a SkinnedMeshRenderer that contains
 68        /// the generated mesh. This GameObject and Renderer will be preserved over any number of Combine() calls.
 69        ///
 70        /// For more details on the combining check out AvatarMeshCombiner.CombineSkinnedMeshes.
 71        /// </summary>
 72        /// <param name="bonesContainer">A SkinnedMeshRenderer that must contain the bones and bindposes that will be us
 73        /// <param name="renderersToCombine">A list of avatar parts to be combined</param>
 74        /// <param name="materialAsset">A material asset that will serve as the base of the combine result. A new materi
 75        /// <param name="keepPose"></param>
 76        /// <returns>true if succeeded, false if not</returns>
 77        public bool Combine(SkinnedMeshRenderer bonesContainer, IReadOnlyList<SkinnedMeshRenderer> renderersToCombine, M
 78        {
 1179            Profiler.BeginSample($"{nameof(AvatarMeshCombinerHelper)}.{nameof(Combine)}");
 80
 1181            Assert.IsTrue(bonesContainer != null, "bonesContainer should never be null!");
 1182            Assert.IsTrue(renderersToCombine != null, "renderersToCombine should never be null!");
 1183            Assert.IsTrue(materialAsset != null, "materialAsset should never be null!");
 84
 1185            var renderers = renderersToCombine;
 86
 87            // Sanitize renderers list
 7888            renderers = renderers.Where( (x) => x != null && x.sharedMesh != null ).ToList();
 89
 1190            if ( renderers.Count == 0 )
 91            {
 192                Profiler.EndSample();
 193                return false;
 94            }
 95
 1096            bool success = CombineInternal(
 97                bonesContainer,
 98                renderers,
 99                materialAsset,
 100                keepPose);
 101
 102            // Disable original renderers
 134103            for ( int i = 0; i < renderers.Count; i++ )
 104            {
 57105                renderers[i].enabled = false;
 106            }
 107
 10108            Profiler.EndSample();
 109
 10110            return success;
 111        }
 112
 113        private bool CombineInternal(SkinnedMeshRenderer bonesContainer, IReadOnlyList<SkinnedMeshRenderer> renderers, M
 114        {
 10115            var bones = bonesContainer.bones;
 10116            var bindPoses = bonesContainer.sharedMesh.bindposes;
 117
 10118            Assert.IsTrue(bonesContainer != null, "bonesContainer should never be null!");
 10119            Assert.IsTrue(bonesContainer.sharedMesh != null, "the shared mesh of this bones container is null, check if 
 10120            Assert.IsTrue(bindPoses != null, "bonesContainer bindPoses should never be null!");
 10121            Assert.IsTrue(bones != null, "bonesContainer bones should never be null!");
 10122            Assert.IsTrue(renderers != null, "renderers should never be null!");
 10123            Assert.IsTrue(materialAsset != null, "materialAsset should never be null!");
 124
 10125            CombineLayerUtils.ENABLE_CULL_OPAQUE_HEURISTIC = useCullOpaqueHeuristic;
 10126            AvatarMeshCombiner.Output output = AvatarMeshCombiner.CombineSkinnedMeshes(
 127                bindPoses,
 128                bones,
 129                renderers,
 130                materialAsset,
 131                keepPose);
 132
 10133            if ( !output.isValid )
 134            {
 0135                logger.LogError("AvatarMeshCombiner: Combine failed!");
 0136                return false;
 137            }
 10138            Transform rootBone = bonesContainer.rootBone;
 139
 10140            if ( container == null )
 8141                this.container = new GameObject("CombinedAvatar");
 142
 10143            if ( renderer == null )
 8144                renderer = container.AddComponent<SkinnedMeshRenderer>();
 145
 10146            UnloadAssets();
 10147            lastOutput = output;
 148
 10149            container.layer = bonesContainer.gameObject.layer;
 10150            renderer.sharedMesh = output.mesh;
 10151            renderer.bones = bones;
 10152            renderer.rootBone = rootBone;
 10153            renderer.sharedMaterials = output.materials;
 10154            renderer.quality = SkinQuality.Bone4;
 10155            renderer.updateWhenOffscreen = false;
 10156            renderer.skinnedMotionVectors = false;
 10157            renderer.enabled = enableCombinedMesh;
 158
 10159            if (prepareMeshForGpuSkinning)
 1160                GPUSkinningUtils.EncodeBindPosesIntoMesh(renderer);
 161
 10162            if (uploadMeshToGpu)
 8163                output.mesh.UploadMeshData(true);
 164
 165            logger.Log("AvatarMeshCombiner: Finish combining avatar. Click here to focus on GameObject.", container);
 10166            return true;
 167        }
 168
 169        private void UnloadAssets()
 170        {
 538171            if (!lastOutput.HasValue)
 530172                return;
 173
 8174            if (lastOutput.Value.mesh != null)
 8175                Object.Destroy(lastOutput.Value.mesh);
 176
 8177            if (lastOutput.Value.materials != null)
 178            {
 48179                foreach ( var material in lastOutput.Value.materials )
 180                {
 16181                    Object.Destroy(material);
 182                }
 183            }
 8184        }
 185
 186        /// <summary>
 187        /// Disposes the created mesh, materials, GameObject and Renderer.
 188        /// </summary>
 189        public void Dispose()
 190        {
 528191            UnloadAssets();
 528192            Object.Destroy(container);
 528193        }
 194    }
 195}