using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace AllIn13DShader { [System.Serializable] public class MaterialOverrideData : ScriptableObject { public class MaterialOverride { public Material sourceMaterial; public Material previewMaterial; public MaterialOverride(Material sourceMaterial) { this.sourceMaterial = sourceMaterial; if(sourceMaterial == null) { this.previewMaterial = null; } else { this.previewMaterial = new Material(sourceMaterial); this.previewMaterial.name = this.previewMaterial.name + "_PREVIEW"; } } public void ApplyPreviewToSource() { sourceMaterial.CopyMatchingPropertiesFromMaterial(previewMaterial); } public bool ApplySourceToPreview() { bool res = true; if (previewMaterial == null || sourceMaterial == null) { res = false; } else { previewMaterial.CopyMatchingPropertiesFromMaterial(sourceMaterial); } return res; } } public class RendererOverride { public Renderer renderer; public MaterialOverride[] materialsOverrides; public Material[] sourceMaterials; public Material[] previewMaterials; public RendererOverride(Renderer renderer) { this.renderer = renderer; this.materialsOverrides = new MaterialOverride[renderer.sharedMaterials.Length]; sourceMaterials = new Material[materialsOverrides.Length]; previewMaterials = new Material[materialsOverrides.Length]; for (int i = 0; i < materialsOverrides.Length; i++) { materialsOverrides[i] = new MaterialOverride(renderer.sharedMaterials[i]); sourceMaterials[i] = materialsOverrides[i].sourceMaterial; previewMaterials[i] = materialsOverrides[i].previewMaterial; } } public void UsePreviewMaterials() { if (renderer != null) { renderer.sharedMaterials = previewMaterials; } } public void UseMaterialSource() { if (renderer != null) { renderer.sharedMaterials = sourceMaterials; } } public void ApplyPreviewMaterial() { for (int i = 0; i < materialsOverrides.Length; i++) { materialsOverrides[i].ApplyPreviewToSource(); renderer.sharedMaterials[i] = materialsOverrides[i].sourceMaterial; } } public void DiscardChanges() { renderer.hideFlags = HideFlags.None; UseMaterialSource(); } public Material[] GetPreviewMaterials() { return previewMaterials; } public void CleanPreviewMaterials() { for(int i = 0; i < materialsOverrides.Length; i++) { MaterialOverride matOverride = materialsOverrides[i]; matOverride.ApplySourceToPreview(); string[] keywords = new string[matOverride.sourceMaterial.shaderKeywords.Length]; matOverride.sourceMaterial.shaderKeywords.CopyTo(keywords, 0); matOverride.previewMaterial.shaderKeywords = keywords; } } } public enum ApplyTarget { CURRENT_SCENE, SELECTED_FOLDERS, ALL_PROJECT, } public List effectOverrides; public List generalPropertiesOverrides; public RendererOverride[] rendererOverrides; public ApplyTarget applyTarget; [SerializeField] private Object[] folders; public void Initialize() { ResetData(); } public void ResetData() { effectOverrides = new List(); generalPropertiesOverrides = new List(); rendererOverrides = new RendererOverride[0]; applyTarget = ApplyTarget.CURRENT_SCENE; } public void CreateRendererOverride() { Renderer[] renderers = FindObjectsByType(FindObjectsSortMode.None); for (int i = 0; i < renderers.Length; i++) { if (renderers[i] is ParticleSystemRenderer) { continue; } if (renderers[i].sharedMaterial == null) { continue; } renderers[i].hideFlags = HideFlags.NotEditable; RendererOverride rendererOverride = new RendererOverride(renderers[i]); ArrayUtility.Add(ref rendererOverrides, rendererOverride); } } public List CollectAffectedMaterials() { List res = new List(); switch (applyTarget) { case ApplyTarget.SELECTED_FOLDERS: CollectAffectedMaterialsOnSelectedFolders(res); break; case ApplyTarget.CURRENT_SCENE: CollectAffectedMaterialsOnCurrentScene(res); break; case ApplyTarget.ALL_PROJECT: CollectAffectedMaterialsAllProject(res); break; } return res; } public void UsePreviewMaterials() { for (int i = 0; i < rendererOverrides.Length; i++) { rendererOverrides[i].UsePreviewMaterials(); } } public void UseMaterialSource() { for (int i = 0; i < rendererOverrides.Length; i++) { rendererOverrides[i].UseMaterialSource(); } } public void EndOverrideProcess() { for (int i = 0; i < rendererOverrides.Length; i++) { if (rendererOverrides[i].renderer == null) { continue; } rendererOverrides[i].DiscardChanges(); } //for(int i = 0; i < rendererOverrides.Length; i++) //{ // rendererOverrides[i].renderer.hideFlags = HideFlags.None; //} //UseMaterialSource(); effectOverrides = new List(); rendererOverrides = new RendererOverride[0]; } public void ApplyChangesToMaterials(Material[] materials) { for (int i = 0; i < materials.Length; i++) { ApplyChangesToMaterial(materials[i]); } } public void ApplyChangesToMaterials(List materials) { for(int i = 0; i < materials.Count; i++) { ApplyChangesToMaterial(materials[i]); } } public void ApplyChangesToMaterial(Material mat) { for (int i = 0; i < effectOverrides.Count; i++) { effectOverrides[i].ApplyChangesToMaterial(mat); } for (int i = 0; i < generalPropertiesOverrides.Count; i++) { generalPropertiesOverrides[i].ApplyChangesToMaterial(mat); } } private void CollectAffectedMaterialsOnCurrentScene(List affectedMaterials) { for (int i = 0; i < rendererOverrides.Length; i++) { affectedMaterials.AddRange(rendererOverrides[i].sourceMaterials); } } private void CollectAffectedMaterialsOnSelectedFolders(List affectedMaterials) { HashSet materialsInFolderGUIDs = new HashSet(); for (int i = 0; i < folders.Length; i++) { string folderPath = AssetDatabase.GetAssetPath(folders[i]); if (AssetDatabase.IsValidFolder(folderPath)) { string[] assetsPathsInFolder = AssetDatabase.FindAssets("t: Material", new string[] { folderPath }); for (int j = 0; j < assetsPathsInFolder.Length; j++) { materialsInFolderGUIDs.Add(assetsPathsInFolder[j]); } } } foreach (string guid in materialsInFolderGUIDs) { string path = AssetDatabase.GUIDToAssetPath(guid); Material mat = AssetDatabase.LoadAssetAtPath(path); if (EditorUtils.IsAllIn13DShader(mat.shader)) { affectedMaterials.Add(mat); } } } private void CollectAffectedMaterialsAllProject(List affectedMaterials) { string[] materialsGUIDs = AssetDatabase.FindAssets("t: Material"); foreach (string guid in materialsGUIDs) { string path = AssetDatabase.GUIDToAssetPath(guid); Material mat = AssetDatabase.LoadAssetAtPath(path); if (EditorUtils.IsAllIn13DShader(mat.shader)) { affectedMaterials.Add(mat); } } } public bool IsApplyEnabled() { bool res = false; switch (applyTarget) { case ApplyTarget.SELECTED_FOLDERS: res = (folders != null) && (folders.Length > 0); break; case ApplyTarget.CURRENT_SCENE: res = true; break; case ApplyTarget.ALL_PROJECT: res = true; break; } return res; } public AbstractEffectOverride AddEffectOverride(AllIn13DEffectConfig effectConfig) { AbstractEffectOverride res = FindEffectOverride(effectConfig.keywordPropertyName); if (res == null) { switch (effectConfig.effectConfigType) { case EffectConfigType.EFFECT_ENUM: res = new EffectEnumOverride(effectConfig); break; case EffectConfigType.EFFECT_TOGGLE: res = new EffectToggleOverride(effectConfig); break; } effectOverrides.Add(res); } return res; } public void AddCopmleteEffectOverride(AllIn13DEffectConfig effectConfig, Shader shader) { AbstractEffectOverride effectOverride = FindEffectOverride(effectConfig.keywordPropertyName); if(effectOverride == null) { effectOverride = AddEffectOverride(effectConfig); } for (int i = 0; i < effectConfig.effectProperties.Count; i++) { effectOverride.AddPropertyOverride(effectConfig.effectProperties[i], shader); } } public void AddPropertyOverride(AllIn13DEffectConfig effectConfig, EffectProperty effectProperty, Shader shader) { AbstractEffectOverride effectOverride = FindEffectOverride(effectConfig.keywordPropertyName); effectOverride = AddEffectOverride(effectConfig); effectOverride.AddPropertyOverride(effectProperty.propertyIndex, shader); } public void AddGeneralPropertyOverride(int propertyIndex, Shader shader) { PropertyOverride propertyOverride = new PropertyOverride(null, propertyIndex, shader); if (!generalPropertiesOverrides.Contains(propertyOverride)) { generalPropertiesOverrides.Add(propertyOverride); } } public void RemoveEffectOverride(AbstractEffectOverride effectOverrideToRemove) { effectOverrides.Remove(effectOverrideToRemove); RebuildPreviewMaterial(); } public void RemovePropertyOverride(PropertyOverride propertyOverride) { bool removeSuccessfully = propertyOverride.Remove(); if (!removeSuccessfully) { generalPropertiesOverrides.Remove(propertyOverride); } } public void RebuildPreviewMaterial() { for (int i = 0; i < rendererOverrides.Length; i++) { rendererOverrides[i].CleanPreviewMaterials(); } ShowPreviewChanges(); } public void ShowPreviewChanges() { for (int i = 0; i < rendererOverrides.Length; i++) { RendererOverride rendererOverride = rendererOverrides[i]; rendererOverride.UsePreviewMaterials(); ApplyChangesToMaterials(rendererOverride.previewMaterials); } } public AbstractEffectOverride FindEffectOverride(string effectPropertyName) { AbstractEffectOverride res = null; for(int i = 0; i < effectOverrides.Count; i++) { if (effectOverrides[i].propertyName == effectPropertyName) { res = effectOverrides[i]; break; } } return res; } public bool IsEmpty() { bool res = effectOverrides.Count <= 0 && generalPropertiesOverrides.Count <= 0; return res; } public bool DiscardChanges(Renderer[] renderers) { bool changes = false; for(int i = this.rendererOverrides.Length - 1; i >= 0; i--) { for(int j = 0; j < renderers.Length; j++) { if (this.rendererOverrides[i].renderer == renderers[j]) { rendererOverrides[i].DiscardChanges(); ArrayUtility.RemoveAt(ref this.rendererOverrides, i); changes = true; break; } } } return changes; } } }