diff --git a/Editor/AvatarAidNdmfPlugin.cs b/Editor/AvatarAidNdmfPlugin.cs index 5c83cdb..286eb6f 100644 --- a/Editor/AvatarAidNdmfPlugin.cs +++ b/Editor/AvatarAidNdmfPlugin.cs @@ -15,6 +15,7 @@ public class AvatarAidNdmfPlugin : Plugin protected override void Configure() { InPhase(BuildPhase.Generating).Run("Apply FaceEmote", ctx => new FaceEmoteProcessor().Process(ctx)); + InPhase(BuildPhase.Transforming).Run("Apply DistanceFade", ctx => new LiltoonDistanceFadeProcessor().Process(ctx)); } } } diff --git a/Editor/LiltoonDistanceFadeProcessor.cs b/Editor/LiltoonDistanceFadeProcessor.cs new file mode 100644 index 0000000..68d0786 --- /dev/null +++ b/Editor/LiltoonDistanceFadeProcessor.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using nadena.dev.ndmf; + +namespace Paltee.AvatarAid +{ + public class LiltoonDistanceFadeProcessor + { + protected readonly string DistanceFadeParamName = "_DistanceFade"; + public void Process(BuildContext context) + { + var installerComponent = context.AvatarRootObject.GetComponent(); + if (installerComponent == null) return; + + Apply(context, installerComponent); + + UnityEngine.Object.DestroyImmediate(installerComponent); + } + + protected void Apply(BuildContext context, Runtime.ApplyLiltoonDistanceFade installer) + { + ProcessRecursively(context.AvatarRootObject.transform, installer); + } + + protected void ProcessRecursively(Transform parent, Runtime.ApplyLiltoonDistanceFade installer) + { + var children = parent.GetComponentsInChildren(true); + foreach (var child in children.Skip(1)) + { + ProcessRecursively(child, installer); + } + + ApplyDistanceFade(parent.gameObject, installer); + } + + protected void ApplyDistanceFade(GameObject gameObject, Runtime.ApplyLiltoonDistanceFade installer) + { + var meshRenderer = gameObject.GetComponent(); + if (meshRenderer == null) return; + + var newMats = new Material[meshRenderer.sharedMaterials.Length]; + for (int i = 0; i < meshRenderer.sharedMaterials.Length; i++) + { + if (meshRenderer.sharedMaterials[i] == null) + { + continue; + } + var newMat = new Material(meshRenderer.sharedMaterials[i]); + ApplyDistanceFadeToMaterial(newMat, installer); + newMats[i] = newMat; + } + + meshRenderer.sharedMaterials = newMats; + } + + protected void ApplyDistanceFadeToMaterial(Material mat, Runtime.ApplyLiltoonDistanceFade installer) + { + var names = mat.GetPropertyNames(MaterialPropertyType.Vector); + if (!names.Contains(DistanceFadeParamName)) + { + Debug.LogWarning($"_DistanceFade parameter not found: {mat.name}"); + } + var color = mat.GetColor(DistanceFadeParamName); + // R: 開始距離 [0-1] + // G: 終了距離 [0-1] + // B: 強度 [0-1] + color.b = 1; + mat.SetColor(DistanceFadeParamName, color); + } + } +} diff --git a/Editor/LiltoonDistanceFadeProcessor.cs.meta b/Editor/LiltoonDistanceFadeProcessor.cs.meta new file mode 100644 index 0000000..2cc591e --- /dev/null +++ b/Editor/LiltoonDistanceFadeProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da0e53173407a55449e573dd7ba44d62 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ApplyLiltoonDistanceFade.cs b/Runtime/ApplyLiltoonDistanceFade.cs new file mode 100644 index 0000000..e8180f7 --- /dev/null +++ b/Runtime/ApplyLiltoonDistanceFade.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using VRC.SDKBase; + +namespace Paltee.AvatarAid.Runtime +{ + [DisallowMultipleComponent] + [AddComponentMenu("ApplyDistanceFade")] + public class ApplyLiltoonDistanceFade : MonoBehaviour, IEditorOnly + { + } +} diff --git a/Runtime/ApplyLiltoonDistanceFade.cs.meta b/Runtime/ApplyLiltoonDistanceFade.cs.meta new file mode 100644 index 0000000..f60bca1 --- /dev/null +++ b/Runtime/ApplyLiltoonDistanceFade.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 53e175169ac9499409b447fde7de27ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/LiltoonDistanceFadeProcessorTest.cs b/Tests/LiltoonDistanceFadeProcessorTest.cs new file mode 100644 index 0000000..43fec4d --- /dev/null +++ b/Tests/LiltoonDistanceFadeProcessorTest.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +using UnityEngine; +using nadena.dev.ndmf; + +namespace Paltee.AvatarAid.Tests +{ + public class LiltoonDistanceFadeProcessorTest + { + [Test] + public void TestProcess_SetsMaterialParameters() + { + var gameObject = new GameObject("Test Target"); + var shader = Shader.Find("Custom/MockLiltoon"); + var mat = new Material(shader); + var renderer = gameObject.AddComponent(); + renderer.sharedMaterial = mat; + Assert.AreEqual(0, mat.GetColor("_DistanceFade").b); + + var installerComponent = gameObject.AddComponent(); + + var context = new BuildContext(gameObject, "Assets/_TestingResources"); + + // act + var errors = ErrorReport.CaptureErrors(() => new LiltoonDistanceFadeProcessor().Process(context)); + + // assert + Assert.Zero(errors.Count); + Assert.IsNull(gameObject.GetComponentInChildren()); + + // ensure the original material was not modified + var originalFadeParamColor = mat.GetColor("_DistanceFade"); + Assert.AreEqual(0, originalFadeParamColor.b); + // check modified parameter value + var modifiedRenderer = gameObject.GetComponent(); + var fadeParamColor = modifiedRenderer.sharedMaterial.GetColor("_DistanceFade"); + Assert.AreEqual(1, fadeParamColor.b); + } + } +} diff --git a/Tests/LiltoonDistanceFadeProcessorTest.cs.meta b/Tests/LiltoonDistanceFadeProcessorTest.cs.meta new file mode 100644 index 0000000..016cc66 --- /dev/null +++ b/Tests/LiltoonDistanceFadeProcessorTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 23f3c59efc6cef346add4b1eb1dc6270 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/MockLiltoon.shader b/Tests/MockLiltoon.shader new file mode 100644 index 0000000..006fb85 --- /dev/null +++ b/Tests/MockLiltoon.shader @@ -0,0 +1,54 @@ +Shader "Custom/MockLiltoon" +{ + Properties + { + _Color ("Color", Color) = (1,1,1,1) + _MainTex ("Albedo (RGB)", 2D) = "white" {} + _Glossiness("Smoothness", Range(0,1)) = 0.5 + _Metallic("Metallic", Range(0,1)) = 0.0 + _DistanceFade("DistanceFade", Color) = (0,0,0,0) + } + SubShader + { + Tags { "RenderType"="Opaque" } + LOD 200 + + CGPROGRAM + // Physically based Standard lighting model, and enable shadows on all light types + #pragma surface surf Standard fullforwardshadows + + // Use shader model 3.0 target, to get nicer looking lighting + #pragma target 3.0 + + sampler2D _MainTex; + + struct Input + { + float2 uv_MainTex; + }; + + half _Glossiness; + half _Metallic; + fixed4 _Color; + + // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader. + // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing. + // #pragma instancing_options assumeuniformscaling + UNITY_INSTANCING_BUFFER_START(Props) + // put more per-instance properties here + UNITY_INSTANCING_BUFFER_END(Props) + + void surf (Input IN, inout SurfaceOutputStandard o) + { + // Albedo comes from a texture tinted by color + fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; + o.Albedo = c.rgb; + // Metallic and smoothness come from slider variables + o.Metallic = _Metallic; + o.Smoothness = _Glossiness; + o.Alpha = c.a; + } + ENDCG + } + FallBack "Diffuse" +} diff --git a/Tests/MockLiltoon.shader.meta b/Tests/MockLiltoon.shader.meta new file mode 100644 index 0000000..12a590f --- /dev/null +++ b/Tests/MockLiltoon.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3988efc3f1bdade47857cf0e85c53583 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: