You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

240 lines
9.3 KiB

using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.VFX.Block
{
class PositionShapeBase
{
public enum Type
{
Sphere,
OrientedBox,
Cone,
Torus,
Circle,
Line,
SignedDistanceField,
}
public static string GetName(Type type)
{
switch (type)
{
case Type.Sphere: return "Sphere";
case Type.OrientedBox: return "Box";
case Type.Cone: return "Cone / Cylinder";
case Type.Torus: return "Torus";
case Type.Circle: return "Circle";
case Type.Line: return "Line";
case Type.SignedDistanceField: return "Signed Distance Field";
}
throw new InvalidOperationException("Unexpected type: " + type);
}
public static System.Type GetType(Type type)
{
switch (type)
{
case Type.Sphere: return typeof(PositionSphere);
case Type.OrientedBox: return typeof(PositionBox);
case Type.Cone: return typeof(PositionCone);
case Type.Torus: return typeof(PositionTorus);
case Type.Circle: return typeof(PositionCircle);
case Type.Line: return typeof(PositionLine);
case Type.SignedDistanceField: return typeof(PositionSDF);
}
throw new InvalidOperationException("Unexpected type: " + type);
}
public virtual IEnumerable<VFXNamedExpression> GetParameters(PositionShape positionBase, List<VFXNamedExpression> allSlots)
{
throw new NotImplementedException();
}
public static VFXExpression CalculateVolumeFactor(PositionBase.PositionMode positionMode, VFXExpression radius, VFXExpression thickness, float thicknessDimensions)
{
VFXExpression factor = VFXValue.Constant(0.0f);
switch (positionMode)
{
case PositionBase.PositionMode.Surface:
factor = VFXValue.Constant(0.0f);
break;
case PositionBase.PositionMode.Volume:
factor = VFXValue.Constant(1.0f);
break;
case PositionBase.PositionMode.ThicknessAbsolute:
case PositionBase.PositionMode.ThicknessRelative:
{
if (positionMode == PositionBase.PositionMode.ThicknessAbsolute)
{
thickness = thickness / radius;
}
factor = VFXOperatorUtility.Saturate(thickness);
break;
}
}
return new VFXExpressionPow(VFXValue.Constant(1.0f) - factor, VFXValue.Constant(thicknessDimensions));
}
public virtual string GetSource(PositionShape positionBase)
{
return string.Empty;
}
public virtual bool hasBase => false;
public virtual bool supportCustomSpawn => true;
public virtual bool supportVolume => true;
}
class PositionShapeSubVariants : VariantProvider
{
public override IEnumerable<Variant> GetVariants()
{
foreach (PositionShapeBase.Type shape in Enum.GetValues(typeof(PositionShapeBase.Type)))
{
yield return new Variant(
"Position On " + PositionShapeBase.GetName(shape),
string.Empty,
typeof(PositionShape),
new[] { new KeyValuePair<string, object>("shape", shape) }
);
}
}
}
class PositionShapeVariants : VariantProvider
{
public override IEnumerable<Variant> GetVariants()
{
yield return new Variant(
"Position On Shape",
"Position",
typeof(PositionShape),
new[] { new KeyValuePair<string, object>("shape", PositionShapeBase.Type.Sphere) },
() => new PositionShapeSubVariants()
);
yield return new Variant(
"Position On Signed Distance Field",
"Position",
typeof(PositionShape),
new[] { new KeyValuePair<string, object>("shape", PositionShapeBase.Type.SignedDistanceField) }
);
}
}
[VFXInfo(category = "Attribute/position/Composition/{0}", variantProvider = typeof(PositionShapeVariants))]
sealed class PositionShape : PositionBase
{
public override string name => string.Format(base.name, PositionShapeBase.GetName(shape));
[SerializeField, VFXSetting] PositionShapeBase.Type shape = PositionShapeBase.Type.Sphere;
[VFXSetting,
Tooltip("Controls whether particles are spawned on the base of the cone, or throughout the entire volume.")]
public HeightMode heightMode = HeightMode.Volume;
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), SerializeField,
Tooltip(
"Orient particles conform to the geometry of the mesh they are sampled from.\nThe AxisX/AxisY/AxisZ attributes and/or the attribute direction can be written.")]
public Orientation applyOrientation = Orientation.Direction;
//This field could be save as SerializableReference if we need to store additional data
PositionShapeBase m_Shape;
private PositionShapeBase GetOrRefreshShape()
{
var newType = PositionShapeBase.GetType(shape);
if (m_Shape == null || newType != m_Shape.GetType())
{
m_Shape = Activator.CreateInstance(newType) as PositionShapeBase;
}
return m_Shape;
}
protected override bool needDirectionWrite => applyOrientation.HasFlag(Orientation.Direction);
protected override bool needAxesWrite => applyOrientation.HasFlag(Orientation.Axes);
public override IEnumerable<VFXNamedExpression> parameters
{
get
{
var allSlots = new List<VFXNamedExpression>(GetExpressionsFromSlots(this));
foreach (var parameter in allSlots)
{
if (parameter.name == nameof(CustomPropertiesBlendPosition.blendPosition)
|| parameter.name == nameof(CustomPropertiesBlendDirection.blendDirection)
|| parameter.name == nameof(CustomPropertiesBlendAxes.blendAxes))
yield return parameter;
}
foreach (var shapeParameter in GetOrRefreshShape().GetParameters(this, allSlots))
yield return shapeParameter;
}
}
public override string source => GetOrRefreshShape().GetSource(this);
protected override bool supportsVolumeSpawning => GetOrRefreshShape().supportVolume;
protected override IEnumerable<string> filteredOutSettings
{
get
{
foreach (var settings in base.filteredOutSettings)
yield return settings;
var currentShape = GetOrRefreshShape();
if (!currentShape.hasBase)
yield return nameof(heightMode);
if (!currentShape.supportCustomSpawn)
yield return nameof(spawnMode);
if (shape != PositionShapeBase.Type.SignedDistanceField)
{
yield return nameof(killOutliers);
yield return nameof(projectionSteps);
}
}
}
protected override IEnumerable<VFXPropertyWithValue> inputProperties
{
get
{
var currentShape = GetOrRefreshShape();
foreach (var shapeProperty in PropertiesFromType(currentShape.GetType().GetRecursiveNestedType("InputProperties")))
yield return shapeProperty;
if (spawnMode == SpawnMode.Custom && currentShape.supportCustomSpawn)
foreach (var customProperty in PropertiesFromType(currentShape.GetType().GetRecursiveNestedType("CustomProperties")))
yield return customProperty;
foreach (var property in base.inputProperties)
yield return property;
}
}
// SDF specific
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), Tooltip("Specifies whether we want to kill particles whose position is off the desired surface or volume")]
public bool killOutliers = false;
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), Tooltip("Specifies the number of steps used by the block to project the particle on the surface of the SDF. This can impact performance, but can yield less outliers. "), Min(1u)]
public uint projectionSteps = 2u;
public override IEnumerable<VFXAttributeInfo> attributes
{
get
{
foreach (var a in base.attributes)
yield return a;
if (shape == PositionShapeBase.Type.SignedDistanceField && killOutliers)
yield return new VFXAttributeInfo(VFXAttribute.Alive, VFXAttributeMode.Write);
}
}
}
}