Skip to content

Commit

Permalink
Merge pull request #1041 from ReinaS-64892/feat-material-unused-prope…
Browse files Browse the repository at this point in the history
…rty-remove

Feat material unused property remove
  • Loading branch information
anatawa12 authored Oct 18, 2024
2 parents ed5c538 + bae5ed4 commit d0e9ba1
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG-PRERELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ The format is based on [Keep a Changelog].
- This component removes polygons like UV Tile Discard with Vertex Discard Mode.
- Texture Optimizer support for tiling UV `#1268`
- API for AtlasTexture Compability `#1269`
- Automatically remove unnecessary material properties based on shader `#1041`
- This feature is added to `Remove Unused Objects` in `Trace and Optimize`.
- When you changed shader for an material, properties for previously used shaders might be remain
- This may increase your avatar size by unexpectedly including unused textures

### Changed
- Transform gizmo are now hidden while you're editing box of Remove Mesh in Box `#1259`
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ The format is based on [Keep a Changelog].
- Remove Mesh By UV Tile, a new way to remove polygons `#1263`
- You now easily remove some polygons of models configured for UV Tile Discard.
- This component removes polygons like UV Tile Discard with Vertex Discard Mode.
- Automatically remove unnecessary material properties based on shader `#1041`
- This feature is added to `Remove Unused Objects` in `Trace and Optimize`.
- When you changed shader for an material, properties for previously used shaders might be remain
- This may increase your avatar size by unexpectedly including unused textures

### Changed
- Skip Enablement Mismatched Renderers is now disabled by default `#1169`
Expand Down
3 changes: 2 additions & 1 deletion Editor/OptimizerPlugin.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using Anatawa12.AvatarOptimizer.ndmf;
using nadena.dev.ndmf;
using nadena.dev.ndmf.builtin;
Expand Down Expand Up @@ -77,6 +77,7 @@ protected override void Configure()
.Then.Run(Processors.TraceAndOptimizes.AutoMergeSkinnedMesh.Instance)
.Then.Run(Processors.TraceAndOptimizes.FindUnusedObjects.Instance)
.Then.Run(Processors.TraceAndOptimizes.ConfigureRemoveZeroSizedPolygon.Instance)
.Then.Run(Processors.TraceAndOptimizes.RemoveUnusedMaterialProperties.Instance)
.Then.Run(Processors.MergeBoneProcessor.Instance)
.Then.Run(Processors.RemoveZeroSizedPolygonProcessor.Instance)
.Then.Run(Processors.TraceAndOptimizes.OptimizeTexture.Instance)
Expand Down
125 changes: 125 additions & 0 deletions Editor/Processors/TraceAndOptimize/RemoveUnusedMaterialProperties.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using System.Collections.Generic;
using System.Linq;
using nadena.dev.ndmf;
using UnityEditor;
using UnityEngine;

namespace Anatawa12.AvatarOptimizer.Processors.TraceAndOptimizes
{
internal class RemoveUnusedMaterialProperties : TraceAndOptimizePass<RemoveUnusedMaterialProperties>
{
public override string DisplayName => "T&O: RemoveUnusedMaterialProperties";
protected override void Execute(BuildContext context, TraceAndOptimizeState state)
{
if (!state.RemoveUnusedObjects) { return; }
if (state.SkipRemoveMaterialUnusedProperties) { return; }

var renderers = context.GetComponents<Renderer>();
var cleaned = new HashSet<Material>();

void CleanMaterial(IEnumerable<Material?> materials)
{
foreach (var m in materials)
{
if (m != null && !cleaned.Contains(m))
{
if (context.IsTemporaryAsset(m))
RemoveUnusedProperties(m);
cleaned.Add(m);
}
}
}

foreach (var renderer in renderers)
{
if (renderer is SkinnedMeshRenderer smr)
{
var meshInfo = context.GetMeshInfoFor(smr);
foreach (var subMesh in meshInfo.SubMeshes)
CleanMaterial(subMesh.SharedMaterials);
}
else
{
CleanMaterial(renderer.sharedMaterials);
}

CleanMaterial(context.GetAnimationComponent(renderer).GetAllObjectProperties()
.SelectMany(x => x.node.Value.PossibleValues)
.OfType<Material>());
}
}

//MIT License
//Copyright (c) 2020-2021 lilxyzw
//https://github.com/lilxyzw/lilToon/blob/b96470d3dd9092b840052578048b2307fe6d8786/Assets/lilToon/Editor/lilMaterialUtils.cs#L658-L686
//
//https://light11.hatenadiary.com/entry/2018/12/04/224253
public static void RemoveUnusedProperties(Material material)
{
// TODO: support material variant
var so = new SerializedObject(material);
so.Update();
var savedProps = so.FindProperty("m_SavedProperties");

var texs = savedProps.FindPropertyRelative("m_TexEnvs");
DeleteUnused(ref texs, material);

var floats = savedProps.FindPropertyRelative("m_Floats");
DeleteUnused(ref floats, material);

var colors = savedProps.FindPropertyRelative("m_Colors");
DeleteUnused(ref colors, material);

so.ApplyModifiedProperties();
}

public static void DeleteUnused(ref SerializedProperty props, Material material)
{
for (var i = props.arraySize - 1; i >= 0; i--)
{
var porpertyName = props.GetArrayElementAtIndex(i).FindPropertyRelative("first").stringValue;
if (!material.HasProperty(porpertyName) && !fallbackShaderProperties.Contains(porpertyName))
{
props.DeleteArrayElementAtIndex(i);
}
}
}

// TODO: change set of properties by fallback shader names
// https://creators.vrchat.com/avatars/shader-fallback-system
private static HashSet<string> fallbackShaderProperties = new HashSet<string>
{
"_MainTex",
"_MetallicGlossMap",
"_SpecGlossMap",
"_BumpMap",
"_ParallaxMap",
"_OcclusionMap",
"_EmissionMap",
"_DetailMask",
"_DetailAlbedoMap",
"_DetailNormalMap",
"_Color",
"_EmissionColor",
"_SpecColor",
"_Cutoff",
"_Glossiness",
"_GlossMapScale",
"_SpecularHighlights",
"_GlossyReflections",
"_SmoothnessTextureChannel",
"_Metallic",
"_SpecularHighlights",
"_GlossyReflections",
"_BumpScale",
"_Parallax",
"_OcclusionStrength",
"_DetailNormalMapScale",
"_UVSec",
"_Mode",
"_SrcBlend",
"_DstBlend",
"_ZWrite",
};
}
}

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

2 changes: 2 additions & 0 deletions Internal/TraceAndOptimizeBase/TraceAndOptimizeProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class TraceAndOptimizeState
public bool SkipMergeMaterials;
public bool SkipRemoveEmptySubMesh;
public bool SkipAnyStateToEntryExit;
public bool SkipRemoveMaterialUnusedProperties;

public Dictionary<SkinnedMeshRenderer, HashSet<string>> PreserveBlendShapes =
new Dictionary<SkinnedMeshRenderer, HashSet<string>>();
Expand Down Expand Up @@ -72,6 +73,7 @@ internal void Initialize(TraceAndOptimize config)
SkipMergeMaterials = config.debugOptions.skipMergeMaterials;
SkipRemoveEmptySubMesh = config.debugOptions.skipRemoveEmptySubMesh;
SkipAnyStateToEntryExit = config.debugOptions.skipAnyStateToEntryExit;
SkipRemoveMaterialUnusedProperties = config.debugOptions.skipRemoveMaterialUnusedProperties;

Enabled = true;
}
Expand Down
2 changes: 2 additions & 0 deletions Runtime/TraceAndOptimize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ internal struct DebugOptions
public bool skipRemoveEmptySubMesh;
[ToggleLeft]
public bool skipAnyStateToEntryExit;
[ToggleLeft]
public bool skipRemoveMaterialUnusedProperties;
}
}
}

0 comments on commit d0e9ba1

Please sign in to comment.