< Summary

Class:DCL.Components.PBRMaterial
Assembly:DCL.Components.Materials
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Materials/PBRMaterial.cs
Covered lines:142
Uncovered lines:26
Coverable lines:168
Total lines:351
Line coverage:84.5% (142 of 168)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Model()0%110100%
GetDataFromJSON(...)0%110100%
PBRMaterial()0%110100%
GetModel()0%110100%
GetClassId()0%2100%
AttachTo(...)0%2.032080%
ApplyChanges()0%990100%
SetupTransparencyMode()0%15.378051.35%
LoadMaterial(...)0%4.054085.71%
OnMaterialAttached(...)0%330100%
InitMaterial(...)0%8.228085%
OnShapeUpdated(...)0%220100%
OnMaterialDetached(...)0%440100%
FetchTexture()0%660100%
AreSameTextureComponent(...)0%2.152066.67%
SwitchTextureComponent(...)0%220100%
Dispose()0%990100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Materials/PBRMaterial.cs

#LineLine coverage
 1using DCL.Controllers;
 2using DCL.Helpers;
 3using DCL.Models;
 4using System.Collections;
 5using System.Collections.Generic;
 6using System.Linq;
 7using UnityEngine;
 8using UnityEngine.Rendering;
 9
 10namespace DCL.Components
 11{
 12    public class PBRMaterial : BaseDisposable
 13    {
 14        [System.Serializable]
 15        public class Model : BaseModel
 16        {
 17            [Range(0f, 1f)]
 7518            public float alphaTest = 0.5f;
 19
 7520            public Color albedoColor = Color.white;
 21            public string albedoTexture;
 7522            public float metallic = 0.5f;
 7523            public float roughness = 0.5f;
 7524            public float microSurface = 1f; // Glossiness
 7525            public float specularIntensity = 1f;
 26
 27            public string alphaTexture;
 28            public string emissiveTexture;
 7529            public Color emissiveColor = Color.black;
 7530            public float emissiveIntensity = 2f;
 7531            public Color reflectivityColor = Color.white;
 7532            public float directIntensity = 1f;
 33            public string bumpTexture;
 7534            public bool castShadows = true;
 35
 36            [Range(0, 4)]
 7537            public int transparencyMode = 4; // 0: OPAQUE; 1: ALPHATEST; 2: ALPHBLEND; 3: ALPHATESTANDBLEND; 4: AUTO (En
 38
 2639            public override BaseModel GetDataFromJSON(string json) { return Utils.SafeFromJson<Model>(json); }
 40        }
 41
 42        enum TransparencyMode
 43        {
 44            OPAQUE,
 45            ALPHA_TEST,
 46            ALPHA_BLEND,
 47            ALPHA_TEST_AND_BLEND,
 48            AUTO
 49        }
 50
 77551        public Material material { get; set; }
 52        private string currentMaterialResourcesFilename;
 53
 54        const string MATERIAL_RESOURCES_PATH = "Materials/";
 55        const string PBR_MATERIAL_NAME = "ShapeMaterial";
 56
 57        DCLTexture albedoDCLTexture = null;
 58        DCLTexture alphaDCLTexture = null;
 59        DCLTexture emissiveDCLTexture = null;
 60        DCLTexture bumpDCLTexture = null;
 61
 2362        private List<Coroutine> textureFetchCoroutines = new List<Coroutine>();
 63
 2364        public PBRMaterial()
 65        {
 2366            model = new Model();
 67
 2368            LoadMaterial(PBR_MATERIAL_NAME);
 69
 2370            OnAttach += OnMaterialAttached;
 2371            OnDetach += OnMaterialDetached;
 2372        }
 73
 874        new public Model GetModel() { return (Model) model; }
 75
 076        public override int GetClassId() { return (int) CLASS_ID.PBR_MATERIAL; }
 77
 78        public override void AttachTo(IDCLEntity entity, System.Type overridenAttachedType = null)
 79        {
 2380            if (attachedEntities.Contains(entity))
 81            {
 082                return;
 83            }
 84
 2385            scene.componentsManagerLegacy.RemoveSharedComponent(entity, (typeof(BasicMaterial)));
 2386            base.AttachTo(entity);
 2387        }
 88
 89        public override IEnumerator ApplyChanges(BaseModel newModel)
 90        {
 2691            Model model = (Model) newModel;
 92
 2693            LoadMaterial(PBR_MATERIAL_NAME);
 94
 2695            material.SetColor(ShaderUtils.BaseColor, model.albedoColor);
 96
 2697            if (model.emissiveColor != Color.clear && model.emissiveColor != Color.black)
 98            {
 499                material.EnableKeyword("_EMISSION");
 100            }
 101
 102            // METALLIC/SPECULAR CONFIGURATIONS
 26103            material.SetColor(ShaderUtils.EmissionColor, model.emissiveColor * model.emissiveIntensity);
 26104            material.SetColor(ShaderUtils.SpecColor, model.reflectivityColor);
 105
 26106            material.SetFloat(ShaderUtils.Metallic, model.metallic);
 26107            material.SetFloat(ShaderUtils.Smoothness, 1 - model.roughness);
 26108            material.SetFloat(ShaderUtils.EnvironmentReflections, model.microSurface);
 26109            material.SetFloat(ShaderUtils.SpecularHighlights, model.specularIntensity * model.directIntensity);
 110
 111
 112            // FETCH AND LOAD EMISSIVE TEXTURE
 26113            var fetchEmission = FetchTexture(ShaderUtils.EmissionMap, model.emissiveTexture, emissiveDCLTexture);
 114
 26115            SetupTransparencyMode();
 116
 117            // FETCH AND LOAD TEXTURES
 26118            var fetchBaseMap = FetchTexture(ShaderUtils.BaseMap, model.albedoTexture, albedoDCLTexture);
 26119            var fetchAlpha = FetchTexture(ShaderUtils.AlphaTexture, model.alphaTexture, alphaDCLTexture);
 26120            var fetchBump = FetchTexture(ShaderUtils.BumpMap, model.bumpTexture, bumpDCLTexture);
 121
 26122            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchEmission));
 26123            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchBaseMap));
 26124            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchAlpha));
 26125            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchBump));
 126
 26127            yield return fetchBaseMap;
 26128            yield return fetchAlpha;
 26129            yield return fetchBump;
 26130            yield return fetchEmission;
 131
 88132            foreach (IDCLEntity entity in attachedEntities)
 20133                InitMaterial(entity);
 24134        }
 135
 136        private void SetupTransparencyMode()
 137        {
 26138            Model model = (Model) this.model;
 139
 140            // Reset shader keywords
 26141            material.DisableKeyword("_ALPHATEST_ON"); // Cut Out Transparency
 26142            material.DisableKeyword("_ALPHABLEND_ON"); // Fade Transparency
 26143            material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); // Transparent
 144
 26145            TransparencyMode transparencyMode = (TransparencyMode) model.transparencyMode;
 146
 26147            if (transparencyMode == TransparencyMode.AUTO)
 148            {
 18149                if (!string.IsNullOrEmpty(model.alphaTexture) || model.albedoColor.a < 1f) //AlphaBlend
 150                {
 0151                    transparencyMode = TransparencyMode.ALPHA_BLEND;
 152                }
 153                else // Opaque
 154                {
 18155                    transparencyMode = TransparencyMode.OPAQUE;
 156                }
 157            }
 158
 159            switch (transparencyMode)
 160            {
 161                case TransparencyMode.OPAQUE:
 18162                    material.renderQueue = (int) UnityEngine.Rendering.RenderQueue.Geometry;
 18163                    material.SetFloat(ShaderUtils.AlphaClip, 0);
 18164                    break;
 165                case TransparencyMode.ALPHA_TEST: // ALPHATEST
 0166                    material.EnableKeyword("_ALPHATEST_ON");
 167
 0168                    material.SetInt(ShaderUtils.SrcBlend, (int) UnityEngine.Rendering.BlendMode.One);
 0169                    material.SetInt(ShaderUtils.DstBlend, (int) UnityEngine.Rendering.BlendMode.Zero);
 0170                    material.SetInt(ShaderUtils.ZWrite, 1);
 0171                    material.SetFloat(ShaderUtils.AlphaClip, 1);
 0172                    material.SetFloat(ShaderUtils.Cutoff, model.alphaTest);
 0173                    material.SetInt("_Surface", 0);
 0174                    material.renderQueue = (int) UnityEngine.Rendering.RenderQueue.AlphaTest;
 0175                    break;
 176                case TransparencyMode.ALPHA_BLEND: // ALPHABLEND
 8177                    material.EnableKeyword("_ALPHABLEND_ON");
 178
 8179                    material.SetInt(ShaderUtils.SrcBlend, (int) UnityEngine.Rendering.BlendMode.SrcAlpha);
 8180                    material.SetInt(ShaderUtils.DstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
 8181                    material.SetInt(ShaderUtils.ZWrite, 0);
 8182                    material.SetFloat(ShaderUtils.AlphaClip, 0);
 8183                    material.renderQueue = (int) UnityEngine.Rendering.RenderQueue.Transparent;
 8184                    material.SetInt("_Surface", 1);
 8185                    break;
 186                case TransparencyMode.ALPHA_TEST_AND_BLEND:
 0187                    material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
 188
 0189                    material.SetInt(ShaderUtils.SrcBlend, (int) UnityEngine.Rendering.BlendMode.One);
 0190                    material.SetInt(ShaderUtils.DstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
 0191                    material.SetInt(ShaderUtils.ZWrite, 0);
 0192                    material.SetFloat(ShaderUtils.AlphaClip, 1);
 0193                    material.renderQueue = (int) UnityEngine.Rendering.RenderQueue.Transparent;
 0194                    material.SetInt("_Surface", 1);
 195                    break;
 196            }
 0197        }
 198
 199        private void LoadMaterial(string resourcesFilename)
 200        {
 49201            if (material == null || currentMaterialResourcesFilename != resourcesFilename)
 202            {
 23203                if (material != null)
 0204                    Object.Destroy(material);
 205
 23206                material = new Material(Utils.EnsureResourcesMaterial(MATERIAL_RESOURCES_PATH + resourcesFilename));
 207#if UNITY_EDITOR
 23208                material.name = "PBRMaterial_" + id;
 209#endif
 23210                currentMaterialResourcesFilename = resourcesFilename;
 211            }
 49212        }
 213
 214        void OnMaterialAttached(IDCLEntity entity)
 215        {
 23216            entity.OnShapeUpdated -= OnShapeUpdated;
 23217            entity.OnShapeUpdated += OnShapeUpdated;
 218
 23219            if (entity.meshRootGameObject != null)
 220            {
 20221                var meshRenderer = entity.meshRootGameObject.GetComponent<MeshRenderer>();
 222
 20223                if (meshRenderer != null)
 20224                    InitMaterial(entity);
 225            }
 23226        }
 227
 228        void InitMaterial(IDCLEntity entity)
 229        {
 72230            var meshGameObject = entity.meshRootGameObject;
 231
 72232            if (meshGameObject == null)
 11233                return;
 234
 61235            var meshRenderer = meshGameObject.GetComponent<MeshRenderer>();
 236
 61237            if (meshRenderer == null)
 0238                return;
 239
 61240            Model model = (Model) this.model;
 241
 61242            meshRenderer.shadowCastingMode = model.castShadows ? ShadowCastingMode.On : ShadowCastingMode.Off;
 243
 61244            if (meshRenderer.sharedMaterial == material)
 40245                return;
 246
 21247            MaterialTransitionController
 248                matTransition = meshGameObject.GetComponent<MaterialTransitionController>();
 249
 21250            if (matTransition != null && matTransition.canSwitchMaterial)
 251            {
 0252                matTransition.finalMaterials = new Material[] { material };
 0253                matTransition.PopulateTargetRendererWithMaterial(matTransition.finalMaterials);
 254            }
 255
 21256            Material oldMaterial = meshRenderer.sharedMaterial;
 21257            meshRenderer.sharedMaterial = material;
 21258            SRPBatchingHelper.OptimizeMaterial(material);
 259
 21260            DataStore.i.sceneWorldObjects.RemoveMaterial(scene.sceneData.id, entity.entityId, oldMaterial);
 21261            DataStore.i.sceneWorldObjects.AddMaterial(scene.sceneData.id, entity.entityId, material);
 21262        }
 263
 264        private void OnShapeUpdated(IDCLEntity entity)
 265        {
 32266            if (entity != null)
 32267                InitMaterial(entity);
 32268        }
 269
 270        private void OnMaterialDetached(IDCLEntity entity)
 271        {
 16272            if (entity.meshRootGameObject != null)
 273            {
 3274                entity.OnShapeUpdated -= OnShapeUpdated;
 275
 3276                var meshRenderer = entity.meshRootGameObject.GetComponent<MeshRenderer>();
 277
 3278                if (meshRenderer && meshRenderer.sharedMaterial == material)
 3279                    meshRenderer.sharedMaterial = null;
 280            }
 16281            DataStore.i.sceneWorldObjects.RemoveMaterial(scene.sceneData.id, entity.entityId, material);
 16282        }
 283
 284        IEnumerator FetchTexture(int materialPropertyId, string textureComponentId, DCLTexture cachedDCLTexture)
 285        {
 104286            if (!string.IsNullOrEmpty(textureComponentId))
 287            {
 19288                if (!AreSameTextureComponent(cachedDCLTexture, textureComponentId))
 289                {
 19290                    yield return DCLTexture.FetchTextureComponent(scene, textureComponentId,
 291                        (fetchedDCLTexture) =>
 292                        {
 19293                            if (material == null)
 0294                                return;
 295
 19296                            material.SetTexture(materialPropertyId, fetchedDCLTexture.texture);
 19297                            SwitchTextureComponent(cachedDCLTexture, fetchedDCLTexture);
 19298                        });
 299                }
 300            }
 301            else
 302            {
 85303                material.SetTexture(materialPropertyId, null);
 85304                cachedDCLTexture?.DetachFrom(this);
 305            }
 104306        }
 307
 308        bool AreSameTextureComponent(DCLTexture dclTexture, string textureId)
 309        {
 19310            if (dclTexture == null)
 19311                return false;
 0312            return dclTexture.id == textureId;
 313        }
 314
 315        void SwitchTextureComponent(DCLTexture cachedTexture, DCLTexture newTexture)
 316        {
 19317            cachedTexture?.DetachFrom(this);
 19318            cachedTexture = newTexture;
 19319            cachedTexture.AttachTo(this);
 19320        }
 321
 322        public override void Dispose()
 323        {
 6324            albedoDCLTexture?.DetachFrom(this);
 6325            alphaDCLTexture?.DetachFrom(this);
 6326            emissiveDCLTexture?.DetachFrom(this);
 6327            bumpDCLTexture?.DetachFrom(this);
 328
 6329            if (material != null)
 330            {
 331                // we make sure we detach this material from every entity
 332                // before disposing it
 7333                while ( attachedEntities.Count > 0 )
 334                {
 2335                    DetachFrom(attachedEntities.First());
 336                }
 5337                Utils.SafeDestroy(material);
 338            }
 339
 60340            for (int i = 0; i < textureFetchCoroutines.Count; i++)
 341            {
 24342                var coroutine = textureFetchCoroutines[i];
 343
 24344                if ( coroutine != null )
 1345                    CoroutineStarter.Stop(coroutine);
 346            }
 347
 6348            base.Dispose();
 6349        }
 350    }
 351}