-
-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f35283d
commit 2c3e243
Showing
20 changed files
with
375 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
using UnityEditor; | ||
using static nadena.dev.modular_avatar.core.editor.Localization; | ||
|
||
namespace nadena.dev.modular_avatar.core.editor | ||
{ | ||
[CustomPropertyDrawer(typeof(ModularAvatarRemoveVertexColor.RemoveMode))] | ||
[SuppressMessage("ReSharper", "InconsistentNaming")] | ||
internal class RVCModeDrawer : EnumDrawer<ModularAvatarRemoveVertexColor.RemoveMode> | ||
{ | ||
protected override string localizationPrefix => "remove-vertex-color.mode"; | ||
} | ||
|
||
[CustomEditor(typeof(ModularAvatarRemoveVertexColor))] | ||
internal class RemoveVertexColorEditor : MAEditorBase | ||
{ | ||
private SerializedProperty _p_mode; | ||
|
||
protected void OnEnable() | ||
{ | ||
_p_mode = serializedObject.FindProperty(nameof(ModularAvatarRemoveVertexColor.Mode)); | ||
} | ||
|
||
protected override void OnInnerInspectorGUI() | ||
{ | ||
serializedObject.Update(); | ||
|
||
EditorGUI.BeginChangeCheck(); | ||
EditorGUILayout.PropertyField(_p_mode, G("remove-vertex-color.mode")); | ||
|
||
if (EditorGUI.EndChangeCheck()) | ||
{ | ||
serializedObject.ApplyModifiedProperties(); | ||
} | ||
|
||
ShowLanguageUI(); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
#nullable enable | ||
|
||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using nadena.dev.ndmf.preview; | ||
using UnityEngine; | ||
|
||
namespace nadena.dev.modular_avatar.core.editor | ||
{ | ||
internal class RemoveVertexColorPreview : IRenderFilter | ||
{ | ||
private static string ToPathString(ComputeContext ctx, Transform t) | ||
{ | ||
return string.Join("/", ctx.ObservePath(t).Select(t2 => t2.gameObject.name).Reverse()); | ||
} | ||
|
||
public ImmutableList<RenderGroup> GetTargetGroups(ComputeContext context) | ||
{ | ||
var roots = context.GetAvatarRoots(); | ||
var removers = roots | ||
.SelectMany(r => context.GetComponentsInChildren<ModularAvatarRemoveVertexColor>(r, true)) | ||
.Select(rvc => (ToPathString(context, rvc.transform), | ||
context.Observe(rvc, r => r.Mode) == ModularAvatarRemoveVertexColor.RemoveMode.Remove)) | ||
.OrderBy(pair => pair.Item1) | ||
.ToList(); | ||
var targets = roots.SelectMany( | ||
r => context.GetComponentsInChildren<SkinnedMeshRenderer>(r, true) | ||
.Concat( | ||
context.GetComponentsInChildren<MeshFilter>(r, true) | ||
.SelectMany(mf => context.GetComponents<Renderer>(mf.gameObject)) | ||
) | ||
); | ||
|
||
targets = targets.Where(target => | ||
{ | ||
var stringPath = ToPathString(context, target.transform); | ||
var index = removers.BinarySearch((stringPath, true)); | ||
|
||
if (index >= 0) | ||
{ | ||
// There is a component on this mesh | ||
return true; | ||
} | ||
|
||
var priorIndex = ~index - 1; | ||
if (priorIndex < 0) return false; // no match | ||
|
||
var (maybeParent, mode) = removers[priorIndex]; | ||
if (!stringPath.StartsWith(maybeParent)) return false; // no parent matched | ||
return mode; | ||
}); | ||
|
||
return targets.Select(RenderGroup.For).ToImmutableList(); | ||
} | ||
|
||
public Task<IRenderFilterNode> Instantiate(RenderGroup group, IEnumerable<(Renderer, Renderer)> proxyPairs, | ||
ComputeContext context) | ||
{ | ||
Dictionary<Mesh, Mesh> conversionMap = new(); | ||
|
||
foreach (var (_, proxy) in proxyPairs) | ||
{ | ||
Component c = proxy; | ||
if (!(c is SkinnedMeshRenderer)) | ||
{ | ||
c = context.GetComponent<MeshFilter>(proxy.gameObject); | ||
} | ||
|
||
if (c == null) continue; | ||
|
||
RemoveVertexColorPass.ForceRemove(_ => false, c, conversionMap); | ||
} | ||
|
||
return Task.FromResult<IRenderFilterNode>(new Node(conversionMap.Values.FirstOrDefault())); | ||
} | ||
|
||
private class Node : IRenderFilterNode | ||
{ | ||
private readonly Mesh? _theMesh; | ||
|
||
public Node(Mesh? theMesh) | ||
{ | ||
_theMesh = theMesh; | ||
} | ||
|
||
public Task<IRenderFilterNode> Refresh(IEnumerable<(Renderer, Renderer)> proxyPairs, ComputeContext context, | ||
RenderAspects updatedAspects) | ||
{ | ||
if (updatedAspects.HasFlag(RenderAspects.Mesh)) return Task.FromResult<IRenderFilterNode>(null); | ||
if (_theMesh == null) return Task.FromResult<IRenderFilterNode>(null); | ||
|
||
return Task.FromResult<IRenderFilterNode>(this); | ||
} | ||
|
||
public RenderAspects WhatChanged => RenderAspects.Mesh; | ||
|
||
public void Dispose() | ||
{ | ||
if (_theMesh != null) Object.DestroyImmediate(_theMesh); | ||
} | ||
|
||
public void OnFrame(Renderer original, Renderer proxy) | ||
{ | ||
if (_theMesh == null) return; | ||
|
||
switch (proxy) | ||
{ | ||
case SkinnedMeshRenderer smr: smr.sharedMesh = _theMesh; break; | ||
default: | ||
{ | ||
var mf = proxy.GetComponent<MeshFilter>(); | ||
if (mf != null) mf.sharedMesh = _theMesh; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#nullable enable | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using nadena.dev.ndmf; | ||
using UnityEditor; | ||
using UnityEngine; | ||
using UnityEngine.Rendering; | ||
using Object = UnityEngine.Object; | ||
|
||
namespace nadena.dev.modular_avatar.core.editor | ||
{ | ||
internal class RemoveVertexColorPass : Pass<RemoveVertexColorPass> | ||
{ | ||
protected override void Execute(ndmf.BuildContext context) | ||
{ | ||
var removers = context.AvatarRootTransform.GetComponentsInChildren<ModularAvatarRemoveVertexColor>(true)!; | ||
|
||
Dictionary<Mesh, Mesh> conversionMap = new(); | ||
|
||
foreach (var remover in removers) | ||
{ | ||
foreach (var smr in remover!.GetComponentsInChildren<SkinnedMeshRenderer>(true)) | ||
{ | ||
TryRemove(context.IsTemporaryAsset, smr, conversionMap); | ||
} | ||
|
||
foreach (var mf in remover.GetComponentsInChildren<MeshFilter>(true)) | ||
{ | ||
TryRemove(context.IsTemporaryAsset, mf, conversionMap); | ||
} | ||
} | ||
} | ||
|
||
private const string PropPath = "m_Mesh"; | ||
|
||
private static void TryRemove( | ||
Func<Mesh, bool> isTempAsset, | ||
Component c, | ||
Dictionary<Mesh, Mesh> conversionMap | ||
) | ||
{ | ||
var nearestRemover = c.GetComponentInParent<ModularAvatarRemoveVertexColor>()!; | ||
if (nearestRemover.Mode != ModularAvatarRemoveVertexColor.RemoveMode.Remove) return; | ||
|
||
ForceRemove(isTempAsset, c, conversionMap); | ||
} | ||
|
||
internal static void ForceRemove(Func<Mesh, bool> isTempAsset, Component c, | ||
Dictionary<Mesh, Mesh> conversionMap) | ||
{ | ||
var obj = new SerializedObject(c); | ||
var prop = obj.FindProperty("m_Mesh"); | ||
if (prop == null) | ||
{ | ||
throw new Exception("Property not found: " + PropPath); | ||
} | ||
|
||
var mesh = prop.objectReferenceValue as Mesh; | ||
if (mesh == null) | ||
{ | ||
return; | ||
} | ||
|
||
var originalMesh = mesh; | ||
|
||
if (conversionMap.TryGetValue(mesh, out var converted)) | ||
{ | ||
prop.objectReferenceValue = converted; | ||
obj.ApplyModifiedPropertiesWithoutUndo(); | ||
return; | ||
} | ||
|
||
if (mesh.GetVertexAttributes().All(va => va.attribute != VertexAttribute.Color)) | ||
{ | ||
// no-op | ||
return; | ||
} | ||
|
||
if (!isTempAsset(mesh)) | ||
{ | ||
mesh = Object.Instantiate(mesh); | ||
prop.objectReferenceValue = mesh; | ||
obj.ApplyModifiedPropertiesWithoutUndo(); | ||
} | ||
|
||
mesh.colors = null; | ||
|
||
conversionMap[originalMesh] = mesh; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System; | ||
using JetBrains.Annotations; | ||
using UnityEngine; | ||
|
||
namespace nadena.dev.modular_avatar.core | ||
{ | ||
[AddComponentMenu("Modular Avatar/MA Remove Vertex Color")] | ||
[DisallowMultipleComponent] | ||
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/remove-vertex-color?lang=auto")] | ||
[PublicAPI] | ||
public class ModularAvatarRemoveVertexColor : AvatarTagComponent | ||
{ | ||
[Serializable] | ||
[PublicAPI] | ||
public enum RemoveMode | ||
{ | ||
Remove, | ||
DontRemove | ||
} | ||
|
||
public RemoveMode Mode = RemoveMode.Remove; | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Remove Vertex Color | ||
|
||
![Remove Vertex Color](remove-vertex-color.png) | ||
|
||
The Remove Vertex Color component removes vertex colors from the object it is attached to and its children. | ||
|
||
## When should I use it? | ||
|
||
Sometimes, models come with vertex colors that aren't intended for display. When changing to a shader that | ||
makes use of vertex colors, such as the VRChat mobile shaders, this can result in undesired discoloration. You can use | ||
this component to remove these vertex colors nondestructively. | ||
|
||
<div style={{display: "flex", "flex-direction": "row"}}> | ||
<div style={{margin: "1em"}}> | ||
<div> | ||
![With unwanted vertex colors](remove-vertex-color-before.png) | ||
</div> | ||
*Without Remove Vertex Color, some unwanted vertex colors discolor this avatar's hair.* | ||
</div> | ||
<div style={{margin: "1em"}}> | ||
<div> | ||
![After removing vertex colors](remove-vertex-color-after.png) | ||
</div> | ||
*After adding Remove Vertex Color, the avatar's hair is the correct color.* | ||
</div> | ||
</div> | ||
|
||
## Detailed usage | ||
|
||
Simply attach the Remove Vertex Color component to an object in your avatar - often, you can just add it to the root | ||
object. All objects below that object in the hierarchy will have their vertex colors removed. | ||
|
||
If you want to exclude some objects, add a Remove Vertex Color component to the object you want to exclude and set | ||
the mode to "Keep Vertex Colors". Any objects below this object will not have their vertex colors removed. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+378 KB
.../docusaurus-plugin-content-docs/current/reference/remove-vertex-color-after.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+380 KB
...docusaurus-plugin-content-docs/current/reference/remove-vertex-color-before.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.