< 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:147
Uncovered lines:25
Coverable lines:172
Total lines:356
Line coverage:85.4% (147 of 172)
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%14.218054.05%
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.Helpers;
 2using DCL.Models;
 3using System.Collections;
 4using System.Collections.Generic;
 5using System.Linq;
 6using UnityEngine;
 7using UnityEngine.Rendering;
 8using DCL.Shaders;
 9
 10namespace DCL.Components
 11{
 12    public class PBRMaterial : BaseDisposable
 13    {
 14        [System.Serializable]
 15        public class Model : BaseModel
 16        {
 17            [Range(0f, 1f)]
 8118            public float alphaTest = 0.5f;
 19
 8120            public Color albedoColor = Color.white;
 21            public string albedoTexture;
 8122            public float metallic = 0.5f;
 8123            public float roughness = 0.5f;
 8124            public float microSurface = 1f; // Glossiness
 8125            public float specularIntensity = 1f;
 26
 27            public string alphaTexture;
 28            public string emissiveTexture;
 8129            public Color emissiveColor = Color.black;
 8130            public float emissiveIntensity = 2f;
 8131            public Color reflectivityColor = Color.white;
 8132            public float directIntensity = 1f;
 33            public string bumpTexture;
 8134            public bool castShadows = true;
 35
 36            [Range(0, 4)]
 8137            public int transparencyMode = 4; // 0: OPAQUE; 1: ALPHATEST; 2: ALPHBLEND; 3: ALPHATESTANDBLEND; 4: AUTO (En
 38
 2839            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
 85751        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
 2562        private List<Coroutine> textureFetchCoroutines = new List<Coroutine>();
 63
 2564        public PBRMaterial()
 65        {
 2566            model = new Model();
 67
 2568            LoadMaterial(PBR_MATERIAL_NAME);
 69
 2570            OnAttach += OnMaterialAttached;
 2571            OnDetach += OnMaterialDetached;
 2572        }
 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        {
 2580            if (attachedEntities.Contains(entity))
 81            {
 082                return;
 83            }
 84
 2585            scene.componentsManagerLegacy.RemoveSharedComponent(entity, (typeof(BasicMaterial)));
 2586            base.AttachTo(entity);
 2587        }
 88
 89        public override IEnumerator ApplyChanges(BaseModel newModel)
 90        {
 2891            Model model = (Model) newModel;
 92
 2893            LoadMaterial(PBR_MATERIAL_NAME);
 94
 2895            material.SetColor(ShaderUtils.BaseColor, model.albedoColor);
 96
 2897            if (model.emissiveColor != Color.clear && model.emissiveColor != Color.black)
 98            {
 499                material.EnableKeyword("_EMISSION");
 100            }
 101
 102            // METALLIC/SPECULAR CONFIGURATIONS
 28103            material.SetColor(ShaderUtils.EmissionColor, model.emissiveColor * model.emissiveIntensity);
 28104            material.SetColor(ShaderUtils.SpecColor, model.reflectivityColor);
 105
 28106            material.SetFloat(ShaderUtils.Metallic, model.metallic);
 28107            material.SetFloat(ShaderUtils.Smoothness, 1 - model.roughness);
 28108            material.SetFloat(ShaderUtils.EnvironmentReflections, model.microSurface);
 28109            material.SetFloat(ShaderUtils.SpecularHighlights, model.specularIntensity * model.directIntensity);
 110
 111
 112            // FETCH AND LOAD EMISSIVE TEXTURE
 28113            var fetchEmission = FetchTexture(ShaderUtils.EmissionMap, model.emissiveTexture, emissiveDCLTexture);
 114
 28115            SetupTransparencyMode();
 116
 117            // FETCH AND LOAD TEXTURES
 28118            var fetchBaseMap = FetchTexture(ShaderUtils.BaseMap, model.albedoTexture, albedoDCLTexture);
 28119            var fetchAlpha = FetchTexture(ShaderUtils.AlphaTexture, model.alphaTexture, alphaDCLTexture);
 28120            var fetchBump = FetchTexture(ShaderUtils.BumpMap, model.bumpTexture, bumpDCLTexture);
 121
 28122            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchEmission));
 28123            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchBaseMap));
 28124            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchAlpha));
 28125            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchBump));
 126
 28127            yield return fetchBaseMap;
 28128            yield return fetchAlpha;
 28129            yield return fetchBump;
 28130            yield return fetchEmission;
 131
 100132            foreach (IDCLEntity entity in attachedEntities)
 22133                InitMaterial(entity);
 28134        }
 135
 136        private void SetupTransparencyMode()
 137        {
 28138            Model model = (Model) this.model;
 139
 140            // Reset shader keywords
 28141            material.DisableKeyword("_ALPHATEST_ON"); // Cut Out Transparency
 28142            material.DisableKeyword("_ALPHABLEND_ON"); // Fade Transparency
 28143            material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); // Transparent
 144
 28145            TransparencyMode transparencyMode = (TransparencyMode) model.transparencyMode;
 146
 28147            if (transparencyMode == TransparencyMode.AUTO)
 148            {
 20149                if (!string.IsNullOrEmpty(model.alphaTexture) || model.albedoColor.a < 1f) //AlphaBlend
 150                {
 2151                    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
 10177                    material.EnableKeyword("_ALPHABLEND_ON");
 178
 10179                    material.SetInt(ShaderUtils.SrcBlend, (int) UnityEngine.Rendering.BlendMode.SrcAlpha);
 10180                    material.SetInt(ShaderUtils.DstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
 10181                    material.SetInt(ShaderUtils.ZWrite, 0);
 10182                    material.SetFloat(ShaderUtils.AlphaClip, 0);
 10183                    material.renderQueue = (int) UnityEngine.Rendering.RenderQueue.Transparent;
 10184                    material.SetInt("_Surface", 1);
 10185                    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        {
 53201            if (material == null || currentMaterialResourcesFilename != resourcesFilename)
 202            {
 25203                if (material != null)
 0204                    Object.Destroy(material);
 205
 25206                material = new Material(Utils.EnsureResourcesMaterial(MATERIAL_RESOURCES_PATH + resourcesFilename));
 207#if UNITY_EDITOR
 25208                material.name = "PBRMaterial_" + id;
 209#endif
 25210                currentMaterialResourcesFilename = resourcesFilename;
 211            }
 53212        }
 213
 214        void OnMaterialAttached(IDCLEntity entity)
 215        {
 25216            entity.OnShapeUpdated -= OnShapeUpdated;
 25217            entity.OnShapeUpdated += OnShapeUpdated;
 218
 25219            if (entity.meshRootGameObject != null)
 220            {
 22221                var meshRenderer = entity.meshRootGameObject.GetComponent<MeshRenderer>();
 222
 22223                if (meshRenderer != null)
 22224                    InitMaterial(entity);
 225            }
 25226        }
 227
 228        void InitMaterial(IDCLEntity entity)
 229        {
 78230            var meshGameObject = entity.meshRootGameObject;
 231
 78232            if (meshGameObject == null)
 11233                return;
 234
 67235            var meshRenderer = meshGameObject.GetComponent<MeshRenderer>();
 236
 67237            if (meshRenderer == null)
 0238                return;
 239
 67240            Model model = (Model) this.model;
 241
 67242            meshRenderer.shadowCastingMode = model.castShadows ? ShadowCastingMode.On : ShadowCastingMode.Off;
 243
 67244            if (meshRenderer.sharedMaterial == material)
 44245                return;
 246
 23247            MaterialTransitionController
 248                matTransition = meshGameObject.GetComponent<MaterialTransitionController>();
 249
 23250            if (matTransition != null && matTransition.canSwitchMaterial)
 251            {
 0252                matTransition.finalMaterials = new Material[] { material };
 0253                matTransition.PopulateTargetRendererWithMaterial(matTransition.finalMaterials);
 254            }
 255
 23256            Material oldMaterial = meshRenderer.sharedMaterial;
 23257            meshRenderer.sharedMaterial = material;
 23258            SRPBatchingHelper.OptimizeMaterial(material);
 259
 23260            DataStore.i.sceneWorldObjects.RemoveMaterial(scene.sceneData.sceneNumber, entity.entityId, oldMaterial);
 23261            DataStore.i.sceneWorldObjects.AddMaterial(scene.sceneData.sceneNumber, entity.entityId, material);
 23262        }
 263
 264        private void OnShapeUpdated(IDCLEntity entity)
 265        {
 34266            if (entity != null)
 34267                InitMaterial(entity);
 34268        }
 269
 270        private void OnMaterialDetached(IDCLEntity entity)
 271        {
 18272            if (entity.meshRootGameObject != null)
 273            {
 5274                entity.OnShapeUpdated -= OnShapeUpdated;
 275
 5276                var meshRenderer = entity.meshRootGameObject.GetComponent<MeshRenderer>();
 277
 5278                if (meshRenderer && meshRenderer.sharedMaterial == material)
 5279                    meshRenderer.sharedMaterial = null;
 280            }
 18281            DataStore.i.sceneWorldObjects.RemoveMaterial(scene.sceneData.sceneNumber, entity.entityId, material);
 18282        }
 283
 284        IEnumerator FetchTexture(int materialPropertyId, string textureComponentId, DCLTexture cachedDCLTexture)
 285        {
 112286            if (!string.IsNullOrEmpty(textureComponentId))
 287            {
 27288                if (!AreSameTextureComponent(cachedDCLTexture, textureComponentId))
 289                {
 27290                    yield return DCLTexture.FetchTextureComponent(scene, textureComponentId,
 291                        (fetchedDCLTexture) =>
 292                        {
 27293                            if (material == null)
 0294                                return;
 295
 27296                            material.SetTexture(materialPropertyId, fetchedDCLTexture.texture);
 27297                            SwitchTextureComponent(cachedDCLTexture, fetchedDCLTexture);
 27298                        });
 299                }
 300            }
 301            else
 302            {
 85303                material.SetTexture(materialPropertyId, null);
 85304                cachedDCLTexture?.DetachFrom(this);
 305            }
 112306        }
 307
 308        bool AreSameTextureComponent(DCLTexture dclTexture, string textureId)
 309        {
 27310            if (dclTexture == null)
 27311                return false;
 0312            return dclTexture.id == textureId;
 313        }
 314
 315        void SwitchTextureComponent(DCLTexture cachedTexture, DCLTexture newTexture)
 316        {
 27317            cachedTexture?.DetachFrom(this);
 27318            cachedTexture = newTexture;
 27319            cachedTexture.AttachTo(this);
 27320        }
 321
 322        public override void Dispose()
 323        {
 10324            albedoDCLTexture?.DetachFrom(this);
 10325            alphaDCLTexture?.DetachFrom(this);
 10326            emissiveDCLTexture?.DetachFrom(this);
 10327            bumpDCLTexture?.DetachFrom(this);
 328
 10329            if (material != null)
 330            {
 331                // we make sure we detach this material from every entity
 332                // before disposing it
 11333                while ( attachedEntities.Count > 0 )
 334                {
 4335                    DetachFrom(attachedEntities.First());
 336                }
 7337                Utils.SafeDestroy(material);
 338            }
 339
 100340            for (int i = 0; i < textureFetchCoroutines.Count; i++)
 341            {
 40342                var coroutine = textureFetchCoroutines[i];
 343
 40344                if ( coroutine != null )
 17345                    CoroutineStarter.Stop(coroutine);
 346            }
 347
 10348            albedoDCLTexture = null;
 10349            alphaDCLTexture = null;
 10350            emissiveDCLTexture = null;
 10351            bumpDCLTexture = null;
 352
 10353            base.Dispose();
 10354        }
 355    }
 356}