2021-09-09 20:42:29 -04:00

140 lines
4.5 KiB
C#

using System.Collections.Generic;
using UnityEngine.VFX;
namespace UnityEngine.VFX.Utility
{
[AddComponentMenu("VFX/Property Binders/Hierarchy to Attribute Map Binder")]
[VFXBinder("Point Cache/Hierarchy to Attribute Map")]
class VFXHierarchyAttributeMapBinder : VFXBinderBase
{
[VFXPropertyBinding("System.UInt32"), SerializeField]
protected ExposedProperty m_BoneCount = "BoneCount";
[VFXPropertyBinding("UnityEngine.Texture2D"), SerializeField]
protected ExposedProperty m_PositionMap = "PositionMap";
[VFXPropertyBinding("UnityEngine.Texture2D"), SerializeField]
protected ExposedProperty m_TargetPositionMap = "TargetPositionMap";
[VFXPropertyBinding("UnityEngine.Texture2D"), SerializeField]
protected ExposedProperty m_RadiusPositionMap = "RadiusPositionMap";
public enum RadiusMode
{
Fixed,
Interpolate
}
public Transform HierarchyRoot;
public float DefaultRadius = 0.1f;
public uint MaximumDepth = 3;
public RadiusMode Radius = RadiusMode.Fixed;
private Texture2D position;
private Texture2D targetPosition;
private Texture2D radius;
private List<Bone> bones;
private struct Bone
{
public Transform source;
public float sourceRadius;
public Transform target;
public float targetRadius;
}
protected override void OnEnable()
{
base.OnEnable();
UpdateHierarchy();
}
void OnValidate()
{
UpdateHierarchy();
}
void UpdateHierarchy()
{
bones = ChildrenOf(HierarchyRoot, MaximumDepth);
int count = bones.Count;
position = new Texture2D(count, 1, TextureFormat.RGBAHalf, false, true);
targetPosition = new Texture2D(count, 1, TextureFormat.RGBAHalf, false, true);
radius = new Texture2D(count, 1, TextureFormat.RHalf, false, true);
UpdateData();
}
List<Bone> ChildrenOf(Transform source, uint depth)
{
List<Bone> output = new List<Bone>();
if (source == null)
return output;
foreach (Transform child in source)
{
output.Add(new Bone()
{
source = source.transform,
target = child.transform,
sourceRadius = DefaultRadius,
targetRadius = DefaultRadius,
});
if (depth > 0)
output.AddRange(ChildrenOf(child, depth - 1));
}
return output;
}
void UpdateData()
{
int count = bones.Count;
if (position.width != count) return;
List<Color> positionList = new List<Color>();
List<Color> targetList = new List<Color>();
List<Color> radiusList = new List<Color>();
for (int i = 0; i < count; i++)
{
Bone b = bones[i];
positionList.Add(new Color(b.source.position.x, b.source.position.y, b.source.position.z, 1));
targetList.Add(new Color(b.target.position.x, b.target.position.y, b.target.position.z, 1));
radiusList.Add(new Color(b.sourceRadius, 0, 0, 1));
}
position.SetPixels(positionList.ToArray());
targetPosition.SetPixels(targetList.ToArray());
radius.SetPixels(radiusList.ToArray());
position.Apply();
targetPosition.Apply();
radius.Apply();
}
public override bool IsValid(VisualEffect component)
{
return HierarchyRoot != null
&& component.HasTexture(m_PositionMap)
&& component.HasTexture(m_TargetPositionMap)
&& component.HasTexture(m_RadiusPositionMap)
&& component.HasUInt(m_BoneCount);
}
public override void UpdateBinding(VisualEffect component)
{
UpdateData();
component.SetTexture(m_PositionMap, position);
component.SetTexture(m_TargetPositionMap, targetPosition);
component.SetTexture(m_RadiusPositionMap, radius);
component.SetUInt(m_BoneCount, (uint)bones.Count);
}
public override string ToString()
{
return string.Format("Hierarchy: {0} -> {1}", HierarchyRoot == null ? "(null)" : HierarchyRoot.name, m_PositionMap);
}
}
}