Skip to content

Commit

Permalink
Cleaned up code a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
bigibas123 committed Jun 8, 2024
1 parent 7b47b0a commit ce78cd5
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 122 deletions.
59 changes: 59 additions & 0 deletions Editor/MatSlotExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using cc.dingemans.bigibas123.MaterialDedup.Editor.Model;
using cc.dingemans.bigibas123.MaterialDedup.Runtime;
using UnityEngine;

namespace cc.dingemans.bigibas123.MaterialDedup.Editor
{
public static class MatSlotExtensions
{
public static IEnumerable<MaterialReference> AsMaterialRefs(this MaterialDeduplicatorBehavior dup)
{
//TODO add materials referenced in animations as well
return dup.Renderers.AsMaterialRefs();
}

public static IEnumerable<MaterialReference> AsMaterialRefs(this IEnumerable<Renderer> renders) =>
renders.SelectMany(renderer => renderer.AsMaterialRefs());

public static IEnumerable<MaterialReference> AsMaterialRefs(this Renderer rend) =>
rend.sharedMaterials.Select((_, b) => new MaterialReference(rend, b));

public static List<DeduplicatedMaterial> AsDedupList(this IEnumerable<MaterialReference> avatarMaterials)
{
var resolvedMaterials = new List<DeduplicatedMaterial>();
foreach (var avatarMat in avatarMaterials)
{
if (avatarMat.Material == null) continue;

var found = false;
foreach (var resolved in resolvedMaterials)
{
if (
avatarMat.HasPropertiesSameAs(resolved)
&& IsAnimatedTheSame(resolved,avatarMat)
)
{
found = true;
resolved.AddRefForReplacement(avatarMat);
break;
}
}

if (found) continue;
var newMaterial = new DeduplicatedMaterial(avatarMat.Material);
newMaterial.AddRefForReplacement(avatarMat);
resolvedMaterials.Add(newMaterial);
}

return resolvedMaterials;
}

private static bool IsAnimatedTheSame(DeduplicatedMaterial dedupped, MaterialReference mat)
{
return true; //TODO
}
}
}
3 changes: 3 additions & 0 deletions Editor/MatSlotExtensions.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

109 changes: 2 additions & 107 deletions Editor/MaterialDedup.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using cc.dingemans.bigibas123.MaterialDedup.Editor;
using cc.dingemans.bigibas123.MaterialDedup.Runtime;
using nadena.dev.ndmf;
using UnityEngine;

[assembly: ExportsPlugin(typeof(MaterialDedup))]

Expand All @@ -15,7 +11,7 @@ public class MaterialDedup : Plugin<MaterialDedup>
public override string QualifiedName => "cc.dingemans.bigibas123.MaterialDedup.MaterialDedup";
public override string DisplayName => "Material Deduplicator";

private static readonly string TAG = "[MaterialDedup]";
public static readonly string TAG = "[MaterialDedup]";

protected override void Configure()
{
Expand All @@ -26,111 +22,10 @@ protected override void Configure()
var roots = ctx.AvatarRootTransform.GetComponentsInChildren<MaterialDeduplicatorBehavior>();
foreach (var root in roots)
{
var materials = CollectMaterials(root.gameObject);
var mappings = ResolveDeDups(materials);
RunDeduplication(mappings);
root.AsMaterialRefs().AsDedupList().ForEach(d => d.ApplyToDests());
UnityEngine.Object.DestroyImmediate(root);
}
});
}

private List<MaterialReference> CollectMaterials(GameObject root)
{
var materials = new List<MaterialReference>();
foreach (var smr in root.GetComponentsInChildren<SkinnedMeshRenderer>())
{
var mats = smr.sharedMaterials;
materials.AddRange(mats.Select((material, slot) => new MaterialReference(smr, slot)));
}

foreach (var mr in root.GetComponentsInChildren<MeshRenderer>())
{
var mats = mr.sharedMaterials;
materials.AddRange(mats.Select((_, slot) => new MaterialReference(mr, slot)));
}

return materials;
}

private List<DeduplicatedMaterial> ResolveDeDups(List<MaterialReference> avatarMaterials)
{
var resolvedMaterials = new List<DeduplicatedMaterial>();
foreach (var avatarMat in avatarMaterials)
{
if (avatarMat.Material == null) continue;

var found = false;
foreach (var resolved in resolvedMaterials)
{
if (TwoMaterialsAreSame(avatarMat.Material, resolved.Material) &&
MaterialsAreAnimatedTheSame(resolved, avatarMat))
{
found = true;
resolved.AddRefForReplacement(avatarMat);
break;
}
}

if (found) continue;
var newMaterial = new DeduplicatedMaterial(avatarMat.Material);
newMaterial.AddRefForReplacement(avatarMat);
resolvedMaterials.Add(newMaterial);
}

return resolvedMaterials;
}

private bool MaterialsAreAnimatedTheSame(DeduplicatedMaterial resolved, MaterialReference avatarMat)
{
//TODO
return true;
}

private bool TwoMaterialsAreSame(Material mat1, Material mat2)
{
if (mat1.shader != mat2.shader) return false;

foreach (MaterialPropertyType propType in (MaterialPropertyType[])Enum.GetValues(
typeof(MaterialPropertyType)))
{
var mat1Props = mat1.GetPropertyNames(propType);
var mat2Props = mat2.GetPropertyNames(propType);
if (mat1Props.Length != mat2Props.Length) return false;
if (mat1Props.Any(mat1Prop => !mat2Props.Contains(mat1Prop))) return false;

foreach (var propName in mat1Props)
{
switch (propType)
{
case MaterialPropertyType.Float when Math.Abs(mat1.GetFloat(propName) - mat2.GetFloat(propName)) > Double.Epsilon:
return false;
case MaterialPropertyType.Int when mat1.GetInteger(propName) != mat2.GetInteger(propName):
return false;
case MaterialPropertyType.Vector when mat1.GetVector(propName) != mat2.GetVector(propName):
return false;
case MaterialPropertyType.Matrix when mat1.GetMatrix(propName) != mat2.GetMatrix(propName):
return false;
case MaterialPropertyType.Texture when mat1.GetTexture(propName) != mat2.GetTexture(propName):
return false;
case MaterialPropertyType.ConstantBuffer when mat1.GetConstantBuffer(propName) != mat2.GetConstantBuffer(propName):
return false;
case MaterialPropertyType.ComputeBuffer:
Debug.LogError($"{TAG} Checking compute buffer equality is not supported right now!");
return false;
}
}

}

return true;
}

private void RunDeduplication(List<DeduplicatedMaterial> mappings)
{
foreach (var dupMap in mappings)
{
dupMap.ApplyToDests();
}
}
}
}
40 changes: 38 additions & 2 deletions Editor/MaterialDeduplicatorBehaviorEditor.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,47 @@
using cc.dingemans.bigibas123.MaterialDedup.Runtime;
using System.Linq;
using cc.dingemans.bigibas123.MaterialDedup.Runtime;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

namespace cc.dingemans.bigibas123.MaterialDedup.Editor
{
[CustomEditor(typeof(MaterialDeduplicatorBehavior))]
public class MaterialDeduplicatorBehaviorEditor : UnityEditor.Editor
{

public override VisualElement CreateInspectorGUI()
{
VisualElement inspector = new VisualElement();
foreach (var renderer in ((MaterialDeduplicatorBehavior)target).Renderers)
{
var rendererFold = new Foldout
{
text = renderer.name,
};
var container = rendererFold.contentContainer;

var list = renderer.AsMaterialRefs().ToList();
var listView = new ListView(list,
makeItem: () => new GroupBox { focusable = false},
bindItem: (elem, i) =>
{
var matRef = list[i];
var gb = elem as GroupBox;
var of = new ObjectField(){focusable = false, objectType = typeof(Material)};
of.label = matRef.Slot.ToString();
of.value = matRef.Material;
of.SetEnabled(false);
gb.contentContainer.Add(of);
}
);
container.Add(listView);


inspector.Add(rendererFold);
}

return inspector;
}
}
}
13 changes: 11 additions & 2 deletions Editor/MaterialDeduplicatorBehaviorEditor.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Editor/Model.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
using UnityEngine;

namespace cc.dingemans.bigibas123.MaterialDedup.Editor
namespace cc.dingemans.bigibas123.MaterialDedup.Editor.Model
{
public class DeduplicatedMaterial
public class DeduplicatedMaterial : MaterialContainer
{
private string _prefix = "Dedup_";
private List<MaterialReference> _destinations;
private Material _original;
private Material _material;
[CanBeNull] private string _destName;

public Material Material
public override Material Material
{
get
{
Expand All @@ -22,11 +23,11 @@ public Material Material
}
}

public string Name
public override string Name
{
get
{
return _destName ??= $"{_prefix}{_original.name}:{string.Join("_", _destinations.Select((matRef) => matRef.DestinationName))}";
return _destName ??= $"{_prefix}{_original.name}:{string.Join("_", _destinations.Select((matRef) => matRef.Name))}";
}
}

Expand Down
File renamed without changes.
60 changes: 60 additions & 0 deletions Editor/Model/MaterialContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Linq;
using UnityEngine;

namespace cc.dingemans.bigibas123.MaterialDedup.Editor.Model
{
public abstract class MaterialContainer
{
public abstract Material Material { get; }
public abstract string Name { get; }

public bool HasPropertiesSameAs(MaterialContainer other)
{
return HasPropertiesSameAs(this, other);
}

public static bool HasPropertiesSameAs(MaterialContainer matc1, MaterialContainer matc2)
{
var mat1 = matc1.Material;
var mat2 = matc2.Material;
if (mat1.shader != mat2.shader) return false;

foreach (MaterialPropertyType propType in (MaterialPropertyType[])Enum.GetValues(
typeof(MaterialPropertyType)))
{
var mat1Props = mat1.GetPropertyNames(propType);
var mat2Props = mat2.GetPropertyNames(propType);
if (mat1Props.Length != mat2Props.Length) return false;
if (mat1Props.Any(mat1Prop => !mat2Props.Contains(mat1Prop))) return false;

foreach (var propName in mat1Props)
{
switch (propType)
{
case MaterialPropertyType.Float
when Math.Abs(mat1.GetFloat(propName) - mat2.GetFloat(propName)) > Double.Epsilon:
return false;
case MaterialPropertyType.Int when mat1.GetInteger(propName) != mat2.GetInteger(propName):
return false;
case MaterialPropertyType.Vector when mat1.GetVector(propName) != mat2.GetVector(propName):
return false;
case MaterialPropertyType.Matrix when mat1.GetMatrix(propName) != mat2.GetMatrix(propName):
return false;
case MaterialPropertyType.Texture when mat1.GetTexture(propName) != mat2.GetTexture(propName):
return false;
case MaterialPropertyType.ConstantBuffer
when mat1.GetConstantBuffer(propName) != mat2.GetConstantBuffer(propName):
return false;
case MaterialPropertyType.ComputeBuffer:
Debug.LogError(
$"{MaterialDedup.TAG} Checking compute buffer equality is not supported right now!");
return false;
}
}
}
return true;
}

}
}
3 changes: 3 additions & 0 deletions Editor/Model/MaterialContainer.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
using JetBrains.Annotations;
using nadena.dev.ndmf.util;
using UnityEngine;

namespace cc.dingemans.bigibas123.MaterialDedup
namespace cc.dingemans.bigibas123.MaterialDedup.Editor.Model
{
public class MaterialReference
public class MaterialReference : MaterialContainer
{
public int Slot { get; }

public Material Material => Renderer.sharedMaterials[Slot];
public string DestinationName => $"{Renderer.gameObject.name}[{Slot}]";
public override Material Material => Renderer.sharedMaterials[Slot];
public override string Name => $"{Renderer.gameObject.name}[{Slot}]";
[CanBeNull] public SkinnedMeshRenderer SkinnedMeshRenderer { get; private set; }
[CanBeNull] public MeshRenderer MeshRenderer { get; private set; }

Expand Down
File renamed without changes.
Loading

0 comments on commit ce78cd5

Please sign in to comment.