Skip to content

Commit

Permalink
Merge pull request #1275 from anatawa12/vertex-index-usage
Browse files Browse the repository at this point in the history
feat: support shaders uses vertex index
  • Loading branch information
anatawa12 authored Oct 18, 2024
2 parents d0e9ba1 + 520b28c commit 969201f
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 14 deletions.
20 changes: 20 additions & 0 deletions API-Editor/ShaderInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@ public enum ShaderInformationKind
/// Providing this information will allow Avatar Optimizer to optimize the texture usage like UV Packing.
/// </summary>
TextureAndUVUsage = 1,
/// <summary>
/// The vertex index usage information.
///
/// If you don't provide this information, Avatar Optimizer will assume that vertex indices are <b>not</b> used
/// in the shader, so Avatar Optimizer may shuffle the vertex indices.
/// </summary>
VertexIndexUsage = 2,
}

/// <summary>
Expand Down Expand Up @@ -258,6 +265,19 @@ public abstract void RegisterTextureUVUsage(
SamplerStateInformation samplerState,
UsingUVChannels uvChannels,
Matrix2x3? uvMatrix);

/// <summary>
/// Registers the vertex index usage.
///
/// Calling this will prevent Avatar Optimizer from automatically caning the vertex indices.
/// If user ask, Avatar Optimizer may change the vertex indices.
///
/// If vertex indices are used only for noise or other purposes that don't affect the mesh much,
/// tou don't need to call this function.
/// </summary>
/// <remarks>This API is to provide <see cref="ShaderInformationKind.VertexIndexUsage"/>.</remarks>
[PublicAPI]
public abstract void RegisterVertexIndexUsage();
}

/// <summary>
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG-PRERELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ The format is based on [Keep a Changelog].
- 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
- Support for Shaders that depends on vertex index `#1275`
- Avatar Optimizer will not automatically merge meshes that are using vertex index
- since merging them may change vertex order, which changes vertex index

### Changed
- Transform gizmo are now hidden while you're editing box of Remove Mesh in Box `#1259`
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ The format is based on [Keep a Changelog].
- Many NDMF tools uses `zh-hans` so previously you may see both 中文 (中国) and 中文 (简体).
- I think zh-hans is more accurate expression so I changed so.
- Improve RemoveMeshByMask compability with Tex Trans Tool `#1269`
- Support for Shaders that depends on vertex index `#1275`
- Avatar Optimizer will not automatically merge meshes that are using vertex index
- since merging them may change vertex order, which changes vertex index

### Deprecated

Expand Down
19 changes: 18 additions & 1 deletion Editor/APIInternal/ShaderInformation.Liltoon.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Reflection;
using Anatawa12.AvatarOptimizer.API;
using UnityEditor;
Expand All @@ -12,7 +13,7 @@ internal class LiltoonShaderInformation : ShaderInformation
internal override bool IsInternalInformation => true;

public override ShaderInformationKind SupportedInformationKind =>
ShaderInformationKind.TextureAndUVUsage;
ShaderInformationKind.TextureAndUVUsage | ShaderInformationKind.VertexIndexUsage;

static LiltoonShaderInformation()
{
Expand Down Expand Up @@ -558,6 +559,22 @@ public override void GetMaterialInformation(MaterialInformationCallback matInfo)

// _BaseMap and _BaseColorMap are unused

// Vertex ID
var idMaskProperties = new[]
{
"_IDMask1", "_IDMask2", "_IDMask3", "_IDMask4", "_IDMask5", "_IDMask6", "_IDMask7", "_IDMask8",
"_IDMaskPrior1", "_IDMaskPrior2", "_IDMaskPrior3", "_IDMaskPrior4", "_IDMaskPrior5", "_IDMaskPrior6", "_IDMaskPrior7", "_IDMaskPrior8",
"_IDMaskIsBitmap", "_IDMaskCompile"
};
if (idMaskProperties.Any(prop => matInfo.GetInteger(prop) != 0))
{
// with _IDMaskFrom = 0..7, uv is used for ID Mask, but it will only use integer part
// (cast to int with normal rounding in hlsl) so it's not necessary to register UV usage.
matInfo.RegisterVertexIndexUsage();
}

// fur shader will use vertex ID, but it's for noise so it's not necessary to register UV usage.

return;

void LIL_SAMPLE_1D(string textureName, SamplerStateInformation samplerName, UsingUVChannels uvChannel)
Expand Down
16 changes: 16 additions & 0 deletions Editor/ContextExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Anatawa12.AvatarOptimizer.AnimatorParsersV2;
using nadena.dev.ndmf;
using UnityEngine;
Expand Down Expand Up @@ -61,5 +63,19 @@ public static AnimationComponentInfo<PropertyInfo> GetAnimationComponent(this Bu

return null;
}

public static IEnumerable<Material> GetAllPossibleMaterialFor(this BuildContext context, Renderer renderer)
{
if (context == null) throw new ArgumentNullException(nameof(context));
if (renderer == null) throw new ArgumentNullException(nameof(renderer));
var materialsRaw =
renderer is SkinnedMeshRenderer skinned
? context.GetMeshInfoFor(skinned).SubMeshes.SelectMany(x => x.SharedMaterials)
: renderer.sharedMaterials;
var materials = materialsRaw.OfType<Material>();
var animated = context.GetAnimationComponent(renderer).GetAllObjectProperties()
.SelectMany(x => x.node.Value.PossibleValues).OfType<Material>();
return materials.Concat(animated).Distinct();
}
}
}
26 changes: 13 additions & 13 deletions Editor/Processors/ShaderMaterialInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,8 @@ protected override void Execute(BuildContext context)
var renderersByMaterial = new Dictionary<Material, List<Renderer>>();

foreach (var renderer in context.GetComponents<Renderer>())
{
IEnumerable<Material?> materials;

if (renderer is SkinnedMeshRenderer skinnedMeshRenderer)
materials = context.GetMeshInfoFor(skinnedMeshRenderer).SubMeshes.SelectMany(x => x.SharedMaterials);
else
materials = renderer.sharedMaterials;

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

foreach (var material in materials)
{
foreach (var material in context.GetAllPossibleMaterialFor(renderer))
{
if (material == null) continue;

Expand Down Expand Up @@ -67,6 +57,7 @@ internal class MaterialInformation

public readonly bool HasShaderInformation;
public readonly List<TextureUsageInformation>? TextureUsageInformationList;
public readonly bool UseVertexIndex;

public MaterialInformation(Material material, List<Renderer> renderers, BuildContext context)
{
Expand All @@ -76,6 +67,7 @@ public MaterialInformation(Material material, List<Renderer> renderers, BuildCon
// collect texture usage information

HasShaderInformation = false;
UseVertexIndex = false;
TextureUsageInformationList = null;
if (ShaderInformationRegistry.GetShaderInformation(material.shader) is { } information)
{
Expand All @@ -88,17 +80,18 @@ public MaterialInformation(Material material, List<Renderer> renderers, BuildCon
renderers.Select(renderer => context.GetAnimationComponent(renderer)).ToList());
information.GetMaterialInformation(provider);
TextureUsageInformationList = provider.TextureUsageInformations;
UseVertexIndex = provider.UseVertexIndex;
}
}


class MaterialInformationCallbackImpl : MaterialInformationCallback
{
private readonly Material _material;
private readonly List<AnimationComponentInfo<PropertyInfo>> _infos;
private List<TextureUsageInformation>? _textureUsageInformations;
private readonly ShaderInformationKind _supportedKind;

public bool UseVertexIndex { get; private set; }
public List<TextureUsageInformation>? TextureUsageInformations => _textureUsageInformations;

public MaterialInformationCallbackImpl(Material material, ShaderInformationKind supportedKind,
Expand Down Expand Up @@ -227,6 +220,13 @@ public override void RegisterTextureUVUsage(
_textureUsageInformations?.Add(new TextureUsageInformation(textureMaterialPropertyName, uvChannel,
wrapModeU, wrapModeV));
}

public override void RegisterVertexIndexUsage()
{
if ((_supportedKind & ShaderInformationKind.VertexIndexUsage) == 0)
throw new InvalidOperationException("RegisterVertexIndexUsage is not registered as supported information");
UseVertexIndex = true;
}
}

}
Expand Down
8 changes: 8 additions & 0 deletions Editor/Processors/TraceAndOptimize/AutoMergeSkinnedMesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ public static List<MeshInfo2> FilterMergeMeshes(BuildContext context, TraceAndOp
// light probe proxy volume override must be defined if light probe usage is UseProxyVolume
&& (meshRenderer.lightProbeUsage != LightProbeUsage.UseProxyVolume
|| meshRenderer.lightProbeProxyVolumeOverride != null)
// shader must not use vertex index.
// Even if the original mesh is already shuffled, we won't merge automatically because
// user may configure material to match with affected vertex index.
// Note for users reading this comment: Vertex Index after remove mesh or merge mesh is
// not guaranteed so upgrading Avatar Optimizer may break your avatar if you rely on vertex index
// after Remove Mesh By **** or Merge Skinned Mesh.
&& !context.GetAllPossibleMaterialFor(meshRenderer)
.Any(x => context.GetMaterialInformation(x)?.UseVertexIndex ?? false)

// other notes:
// - activeness animation can be ignored here because we'll combine based on activeness animation
Expand Down

0 comments on commit 969201f

Please sign in to comment.