< Summary

Class:DCL.SliceByRenderState
Assembly:AvatarMeshCombiner
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarMeshCombiner/SliceByRenderState.cs
Covered lines:34
Uncovered lines:5
Coverable lines:39
Total lines:144
Line coverage:87.1% (34 of 39)
Covered branches:0
Total branches:0
Covered methods:10
Total methods:11
Method coverage:90.9% (10 of 11)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
SliceByRenderState()0%110100%
LayerKey(...)0%110100%
Equals(...)0%220100%
Equals(...)0%6200%
GetHashCode()0%110100%
Execute(...)0%550100%
GetCullMode(...)0%110100%
GetCullMode(...)0%4.123050%
GetCullModeWithoutCullOff(...)0%220100%
IsOpaque(...)0%110100%
IsOpaque(...)0%7.077088.89%

File(s)

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

#LineLine coverage
 1using DCL.Shaders;
 2using System;
 3using System.Collections.Generic;
 4using UnityEngine;
 5using UnityEngine.Pool;
 6using UnityEngine.Rendering;
 7
 8namespace DCL
 9{
 10    public static class SliceByRenderState
 11    {
 112        private static readonly Dictionary<Shader, bool> SHADERS_OPACITY = new ();
 13
 14        private readonly struct LayerKey : IEquatable<LayerKey>
 15        {
 16            public readonly bool IsOpaque;
 17            public readonly CullMode CullMode;
 18
 19            public LayerKey(bool isOpaque, CullMode cullMode)
 20            {
 11821                IsOpaque = isOpaque;
 11822                CullMode = cullMode;
 11823            }
 24
 25            public bool Equals(LayerKey other) =>
 8226                IsOpaque == other.IsOpaque && CullMode == other.CullMode;
 27
 28            public override bool Equals(object obj) =>
 029                obj is LayerKey other && Equals(other);
 30
 31            public override int GetHashCode() =>
 15332                HashCode.Combine(IsOpaque, (int)CullMode);
 33        }
 34
 35        /// <summary>
 36        /// <p>
 37        /// This method takes a skinned mesh renderer list and turns it into a series of CombineLayer elements.
 38        /// Each CombineLayer element represents a combining group, and the renderers are grouped using a set of criteri
 39        /// </p>
 40        /// <p>
 41        /// For SliceByRenderState, the returned CombineLayer list will be grouped according to shared cull mode and
 42        /// blend state.
 43        /// </p>
 44        /// </summary>
 45        /// <param name="renderers">List of renderers to slice.</param>
 46        /// <returns>List of CombineLayer objects that can be used to produce a highly optimized combined mesh.</returns
 47        internal static void Execute(IReadOnlyList<SkinnedMeshRenderer> renderers, List<CombineLayer> result, bool cullO
 48        {
 1749            var grouping = DictionaryPool<LayerKey, CombineLayer>.Get();
 50
 51            // Group renderers on opaque and transparent materials
 52            // Then, make subgroups to divide them between culling modes
 27053            foreach (var meshRenderer in renderers)
 54            {
 11855                var opaque = IsOpaque(meshRenderer);
 11856                var cullMode = cullOpaque && opaque ? GetCullModeWithoutCullOff(meshRenderer) : GetCullMode(meshRenderer
 11857                var key = new LayerKey(opaque, cullMode);
 58
 11859                if (!grouping.TryGetValue(key, out var combineLayer))
 60                {
 3661                    grouping[key] = combineLayer = CombineLayer.Rent(cullMode, opaque);
 3662                    result.Add(combineLayer);
 63                }
 64
 11865                combineLayer.AddRenderer(meshRenderer);
 66            }
 67
 1768            DictionaryPool<LayerKey, CombineLayer>.Release(grouping);
 69
 70            /*
 71            * The grouping outcome ends up like this:
 72            *
 73            *                 Opaque           Transparent
 74            *             /     |     \        /    |    \
 75            *          Back - Front - Off - Back - Front - Off -> rendererGroups
 76            */
 1777        }
 78
 79        internal static CullMode GetCullMode(Renderer renderer) =>
 11880            GetCullMode(renderer.sharedMaterial);
 81
 82        internal static CullMode GetCullMode(Material material)
 83        {
 12484            if (material.HasProperty(ShaderUtils.Cull))
 85            {
 12486                CullMode result = (CullMode)material.GetInt(ShaderUtils.Cull);
 12487                return result;
 88            }
 89
 90            // GLTFast materials dont have culling, instead they have the "Double Sided" check toggled on "double" suffi
 091            if (material.shader.name.Contains("double"))
 092                return CullMode.Off;
 93
 094            return CullMode.Back;
 95        }
 96
 97        /// <summary>
 98        ///
 99        /// </summary>
 100        /// <param name="renderer"></param>
 101        /// <returns></returns>
 102        internal static CullMode GetCullModeWithoutCullOff(Renderer renderer)
 103        {
 3104            CullMode result = GetCullMode(renderer.sharedMaterial);
 105
 3106            if (result == CullMode.Off)
 1107                result = CullMode.Back;
 108
 3109            return result;
 110        }
 111
 112        /// <summary>
 113        /// Determines if the given renderer is going to be enqueued at the opaque section of the rendering pipeline.
 114        /// </summary>
 115        /// <param name="renderer">Renderer to be checked.</param>
 116        /// <returns>True if its opaque</returns>
 118117        internal static bool IsOpaque(Renderer renderer) => IsOpaque(renderer.sharedMaterial);
 118
 119        /// <summary>
 120        /// Determines if the given renderer is going to be enqueued at the opaque section of the rendering pipeline.
 121        /// </summary>
 122        /// <param name="material">Material to be checked</param>
 123        /// <returns>True if its opaque</returns>
 124        internal static bool IsOpaque(Material material)
 125        {
 124126            if (material == null)
 0127                return true;
 128
 124129            var shader = material.shader;
 130
 124131            if (!SHADERS_OPACITY.TryGetValue(shader, out var isOpaqueShader))
 132            {
 133                // NOTE(Kinerius): Since GLTFast materials doesn't have ZWrite property, we check if the shader name is 
 1134                bool hasOpaqueName = shader.name.Contains("opaque", StringComparison.OrdinalIgnoreCase);
 1135                SHADERS_OPACITY[shader] = isOpaqueShader = hasOpaqueName;
 136            }
 137
 124138            bool hasZWrite = material.HasProperty(ShaderUtils.ZWrite);
 124139            isOpaqueShader = (!hasZWrite && !isOpaqueShader) || (hasZWrite && (int)material.GetFloat(ShaderUtils.ZWrite)
 140
 124141            return !isOpaqueShader;
 142        }
 143    }
 144}