< Summary

Class:DCL.Components.PBRMaterial
Assembly:MainScripts
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Materials/PBRMaterial.cs
Covered lines:142
Uncovered lines:27
Coverable lines:169
Total lines:345
Line coverage:84% (142 of 169)
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%2100%
GetClassId()0%2100%
AttachTo(...)0%2.032080%
ApplyChanges()0%990100%
SetupTransparencyMode()0%13.738055.26%
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%880100%

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 UnityEngine;
 7using UnityEngine.Rendering;
 8
 9namespace DCL.Components
 10{
 11    public class PBRMaterial : BaseDisposable
 12    {
 13        [System.Serializable]
 14        public class Model : BaseModel
 15        {
 16            [Range(0f, 1f)]
 8117            public float alphaTest = 0.5f;
 18
 8119            public Color albedoColor = Color.white;
 20            public string albedoTexture;
 8121            public float metallic = 0.5f;
 8122            public float roughness = 0.5f;
 8123            public float microSurface = 1f; // Glossiness
 8124            public float specularIntensity = 1f;
 25
 26            public string alphaTexture;
 27            public string emissiveTexture;
 8128            public Color emissiveColor = Color.black;
 8129            public float emissiveIntensity = 2f;
 8130            public Color reflectivityColor = Color.white;
 8131            public float directIntensity = 1f;
 32            public string bumpTexture;
 8133            public bool castShadows = true;
 34
 35            [Range(0, 4)]
 8136            public int transparencyMode = 4; // 0: OPAQUE; 1: ALPHATEST; 2: ALPHBLEND; 3: ALPHATESTANDBLEND; 4: AUTO (En
 37
 2838            public override BaseModel GetDataFromJSON(string json) { return Utils.SafeFromJson<Model>(json); }
 39        }
 40
 41        enum TransparencyMode
 42        {
 43            OPAQUE,
 44            ALPHA_TEST,
 45            ALPHA_BLEND,
 46            ALPHA_TEST_AND_BLEND,
 47            AUTO
 48        }
 49
 050        public Material material { get; set; }
 51        private string currentMaterialResourcesFilename;
 52
 53        const string MATERIAL_RESOURCES_PATH = "Materials/";
 54        const string PBR_MATERIAL_NAME = "ShapeMaterial";
 55
 56        DCLTexture albedoDCLTexture = null;
 57        DCLTexture alphaDCLTexture = null;
 58        DCLTexture emissiveDCLTexture = null;
 59        DCLTexture bumpDCLTexture = null;
 60
 2561        private List<Coroutine> textureFetchCoroutines = new List<Coroutine>();
 62
 2563        public PBRMaterial()
 64        {
 2565            model = new Model();
 66
 2567            LoadMaterial(PBR_MATERIAL_NAME);
 68
 2569            OnAttach += OnMaterialAttached;
 2570            OnDetach += OnMaterialDetached;
 2571        }
 72
 073        new public Model GetModel() { return (Model) model; }
 74
 075        public override int GetClassId() { return (int) CLASS_ID.PBR_MATERIAL; }
 76
 77        public override void AttachTo(IDCLEntity entity, System.Type overridenAttachedType = null)
 78        {
 2579            if (attachedEntities.Contains(entity))
 80            {
 081                return;
 82            }
 83
 2584            entity.RemoveSharedComponent(typeof(BasicMaterial));
 2585            base.AttachTo(entity);
 2586        }
 87
 88        public override IEnumerator ApplyChanges(BaseModel newModel)
 89        {
 2890            Model model = (Model) newModel;
 91
 2892            LoadMaterial(PBR_MATERIAL_NAME);
 93
 2894            material.SetColor(ShaderUtils.BaseColor, model.albedoColor);
 95
 2896            if (model.emissiveColor != Color.clear && model.emissiveColor != Color.black)
 97            {
 498                material.EnableKeyword("_EMISSION");
 99            }
 100
 101            // METALLIC/SPECULAR CONFIGURATIONS
 28102            material.SetColor(ShaderUtils.EmissionColor, model.emissiveColor * model.emissiveIntensity);
 28103            material.SetColor(ShaderUtils.SpecColor, model.reflectivityColor);
 104
 28105            material.SetFloat(ShaderUtils.Metallic, model.metallic);
 28106            material.SetFloat(ShaderUtils.Smoothness, 1 - model.roughness);
 28107            material.SetFloat(ShaderUtils.EnvironmentReflections, model.microSurface);
 28108            material.SetFloat(ShaderUtils.SpecularHighlights, model.specularIntensity * model.directIntensity);
 109
 110
 111            // FETCH AND LOAD EMISSIVE TEXTURE
 28112            var fetchEmission = FetchTexture(ShaderUtils.EmissionMap, model.emissiveTexture, emissiveDCLTexture);
 113
 28114            SetupTransparencyMode();
 115
 116            // FETCH AND LOAD TEXTURES
 28117            var fetchBaseMap = FetchTexture(ShaderUtils.BaseMap, model.albedoTexture, albedoDCLTexture);
 28118            var fetchAlpha = FetchTexture(ShaderUtils.AlphaTexture, model.alphaTexture, alphaDCLTexture);
 28119            var fetchBump = FetchTexture(ShaderUtils.BumpMap, model.bumpTexture, bumpDCLTexture);
 120
 28121            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchEmission));
 28122            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchBaseMap));
 28123            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchAlpha));
 28124            textureFetchCoroutines.Add(CoroutineStarter.Start(fetchBump));
 125
 28126            yield return fetchBaseMap;
 28127            yield return fetchAlpha;
 28128            yield return fetchBump;
 26129            yield return fetchEmission;
 130
 96131            foreach (IDCLEntity entity in attachedEntities)
 22132                InitMaterial(entity);
 26133        }
 134
 135        private void SetupTransparencyMode()
 136        {
 28137            Model model = (Model) this.model;
 138
 139            // Reset shader keywords
 28140            material.DisableKeyword("_ALPHATEST_ON"); // Cut Out Transparency
 28141            material.DisableKeyword("_ALPHABLEND_ON"); // Fade Transparency
 28142            material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); // Transparent
 143
 28144            TransparencyMode transparencyMode = (TransparencyMode) model.transparencyMode;
 145
 28146            if (transparencyMode == TransparencyMode.AUTO)
 147            {
 20148                if (!string.IsNullOrEmpty(model.alphaTexture) || model.albedoColor.a < 1f) //AlphaBlend
 149                {
 2150                    transparencyMode = TransparencyMode.ALPHA_BLEND;
 2151                }
 152                else // Opaque
 153                {
 18154                    transparencyMode = TransparencyMode.OPAQUE;
 155                }
 156            }
 157
 158            switch (transparencyMode)
 159            {
 160                case TransparencyMode.OPAQUE:
 18161                    material.renderQueue = (int) UnityEngine.Rendering.RenderQueue.Geometry;
 18162                    material.SetFloat(ShaderUtils.AlphaClip, 0);
 18163                    break;
 164                case TransparencyMode.ALPHA_TEST: // ALPHATEST
 0165                    material.EnableKeyword("_ALPHATEST_ON");
 166
 0167                    material.SetInt(ShaderUtils.SrcBlend, (int) UnityEngine.Rendering.BlendMode.One);
 0168                    material.SetInt(ShaderUtils.DstBlend, (int) UnityEngine.Rendering.BlendMode.Zero);
 0169                    material.SetInt(ShaderUtils.ZWrite, 1);
 0170                    material.SetFloat(ShaderUtils.AlphaClip, 1);
 0171                    material.SetFloat(ShaderUtils.Cutoff, model.alphaTest);
 0172                    material.SetInt("_Surface", 0);
 0173                    material.renderQueue = (int) UnityEngine.Rendering.RenderQueue.AlphaTest;
 0174                    break;
 175                case TransparencyMode.ALPHA_BLEND: // ALPHABLEND
 10176                    material.EnableKeyword("_ALPHABLEND_ON");
 177
 10178                    material.SetInt(ShaderUtils.SrcBlend, (int) UnityEngine.Rendering.BlendMode.SrcAlpha);
 10179                    material.SetInt(ShaderUtils.DstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
 10180                    material.SetInt(ShaderUtils.ZWrite, 0);
 10181                    material.SetFloat(ShaderUtils.AlphaClip, 0);
 10182                    material.renderQueue = (int) UnityEngine.Rendering.RenderQueue.Transparent;
 10183                    material.SetInt("_Surface", 1);
 10184                    break;
 185                case TransparencyMode.ALPHA_TEST_AND_BLEND:
 0186                    material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
 187
 0188                    material.SetInt(ShaderUtils.SrcBlend, (int) UnityEngine.Rendering.BlendMode.One);
 0189                    material.SetInt(ShaderUtils.DstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
 0190                    material.SetInt(ShaderUtils.ZWrite, 0);
 0191                    material.SetFloat(ShaderUtils.AlphaClip, 1);
 0192                    material.renderQueue = (int) UnityEngine.Rendering.RenderQueue.Transparent;
 0193                    material.SetInt("_Surface", 1);
 194                    break;
 195            }
 0196        }
 197
 198        private void LoadMaterial(string resourcesFilename)
 199        {
 53200            if (material == null || currentMaterialResourcesFilename != resourcesFilename)
 201            {
 25202                if (material != null)
 0203                    Object.Destroy(material);
 204
 25205                material = new Material(Utils.EnsureResourcesMaterial(MATERIAL_RESOURCES_PATH + resourcesFilename));
 206#if UNITY_EDITOR
 25207                material.name = "PBRMaterial_" + id;
 208#endif
 25209                currentMaterialResourcesFilename = resourcesFilename;
 210            }
 53211        }
 212
 213        void OnMaterialAttached(IDCLEntity entity)
 214        {
 25215            entity.OnShapeUpdated -= OnShapeUpdated;
 25216            entity.OnShapeUpdated += OnShapeUpdated;
 217
 25218            if (entity.meshRootGameObject != null)
 219            {
 22220                var meshRenderer = entity.meshRootGameObject.GetComponent<MeshRenderer>();
 221
 22222                if (meshRenderer != null)
 22223                    InitMaterial(entity);
 224            }
 25225        }
 226
 227        void InitMaterial(IDCLEntity entity)
 228        {
 47229            var meshGameObject = entity.meshRootGameObject;
 230
 47231            if (meshGameObject == null)
 2232                return;
 233
 45234            var meshRenderer = meshGameObject.GetComponent<MeshRenderer>();
 235
 45236            if (meshRenderer == null)
 0237                return;
 238
 45239            Model model = (Model) this.model;
 240
 45241            meshRenderer.shadowCastingMode = model.castShadows ? ShadowCastingMode.On : ShadowCastingMode.Off;
 242
 45243            if (meshRenderer.sharedMaterial == material)
 22244                return;
 245
 23246            MaterialTransitionController
 247                matTransition = meshGameObject.GetComponent<MaterialTransitionController>();
 248
 23249            if (matTransition != null && matTransition.canSwitchMaterial)
 250            {
 0251                matTransition.finalMaterials = new Material[] { material };
 0252                matTransition.PopulateTargetRendererWithMaterial(matTransition.finalMaterials);
 253            }
 254
 23255            Material oldMaterial = meshRenderer.sharedMaterial;
 23256            meshRenderer.sharedMaterial = material;
 23257            SRPBatchingHelper.OptimizeMaterial(material);
 258
 23259            DataStore.i.sceneWorldObjects.RemoveMaterial(scene.sceneData.id, entity.entityId, oldMaterial);
 23260            DataStore.i.sceneWorldObjects.AddMaterial(scene.sceneData.id, entity.entityId, material);
 23261        }
 262
 263        private void OnShapeUpdated(IDCLEntity entity)
 264        {
 3265            if (entity != null)
 3266                InitMaterial(entity);
 3267        }
 268
 269        private void OnMaterialDetached(IDCLEntity entity)
 270        {
 7271            if (entity.meshRootGameObject == null)
 3272                return;
 273
 4274            entity.OnShapeUpdated -= OnShapeUpdated;
 275
 4276            var meshRenderer = entity.meshRootGameObject.GetComponent<MeshRenderer>();
 277
 4278            if (meshRenderer && meshRenderer.sharedMaterial == material)
 4279                meshRenderer.sharedMaterial = null;
 280
 4281            DataStore.i.sceneWorldObjects.RemoveMaterial(scene.sceneData.id, entity.entityId, material);
 4282        }
 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                        {
 25293                            if (material == null)
 0294                                return;
 295
 25296                            material.SetTexture(materialPropertyId, fetchedDCLTexture.texture);
 25297                            SwitchTextureComponent(cachedDCLTexture, fetchedDCLTexture);
 25298                        });
 299                }
 27300            }
 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        {
 25317            cachedTexture?.DetachFrom(this);
 25318            cachedTexture = newTexture;
 25319            cachedTexture.AttachTo(this);
 25320        }
 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            {
 7331                Utils.SafeDestroy(material);
 332            }
 333
 100334            for (int i = 0; i < textureFetchCoroutines.Count; i++)
 335            {
 40336                var coroutine = textureFetchCoroutines[i];
 337
 40338                if ( coroutine != null )
 17339                    CoroutineStarter.Stop(coroutine);
 340            }
 341
 10342            base.Dispose();
 10343        }
 344    }
 345}