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.
302 lines
14 KiB
302 lines
14 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.VFX;
|
|
using UnityEditor.VFX.Block;
|
|
using System.Reflection;
|
|
|
|
namespace UnityEditor.VFX
|
|
{
|
|
[CustomEditor(typeof(VFXBasicUpdate))]
|
|
[CanEditMultipleObjects]
|
|
class VFXBasicUpdateEditor : VFXContextEditor
|
|
{
|
|
class UpdateStyles
|
|
{
|
|
public static GUIContent header = new GUIContent("Particle Update Options", "Particle Update Options");
|
|
public static GUIContent updatePosition = new GUIContent("Update Position", "When enabled, particle positions are automatically updated using their velocity.");
|
|
public static GUIContent updateRotation = new GUIContent("Update Rotation", "When enabled, particle rotations are automatically updated using their angular velocity.");
|
|
public static GUIContent ageParticles = new GUIContent("Age Particles", "When enabled, the particle age attribute will increase every frame based on deltaTime.");
|
|
public static GUIContent reapParticles = new GUIContent("Reap Particles", "When enabled, particles whose age exceeds their lifetime will be destroyed.");
|
|
public static GUIContent skipZeroDeltaTime = new GUIContent("Skip Zero Delta Time", "When enabled, filters out block execution if deltaTime is equal to 0.");
|
|
}
|
|
|
|
SerializedProperty m_IntegrationProperty;
|
|
SerializedProperty m_AngularIntegrationProperty;
|
|
SerializedProperty m_AgeParticlesProperty;
|
|
SerializedProperty m_ReapParticlesProperty;
|
|
SerializedProperty m_SkipZeroDeltaTimeProperty;
|
|
|
|
protected new void OnEnable()
|
|
{
|
|
base.OnEnable();
|
|
m_IntegrationProperty = serializedObject.FindProperty("integration");
|
|
m_AngularIntegrationProperty = serializedObject.FindProperty("angularIntegration");
|
|
m_AgeParticlesProperty = serializedObject.FindProperty("ageParticles");
|
|
m_ReapParticlesProperty = serializedObject.FindProperty("reapParticles");
|
|
m_SkipZeroDeltaTimeProperty = serializedObject.FindProperty("skipZeroDeltaUpdate");
|
|
}
|
|
|
|
private static Func<VFXBasicUpdate, IEnumerable<string>> s_fnGetFilteredOutSettings = delegate (VFXBasicUpdate context)
|
|
{
|
|
var property = typeof(VFXBasicUpdate).GetProperty("filteredOutSettings", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
return property.GetValue(context) as IEnumerable<string>;
|
|
};
|
|
|
|
void DisplayToggle(GUIContent content, SerializedProperty property, bool? input, bool isIntegrationMode)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
bool actualInput = input.HasValue ? input.Value : false;
|
|
if (!input.HasValue)
|
|
{
|
|
EditorGUI.showMixedValue = true;
|
|
}
|
|
actualInput = EditorGUILayout.Toggle(content, actualInput);
|
|
EditorGUI.showMixedValue = false;
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
if (isIntegrationMode)
|
|
property.enumValueIndex = actualInput ? (int)VFXBasicUpdate.VFXIntegrationMode.Euler : (int)VFXBasicUpdate.VFXIntegrationMode.None;
|
|
else
|
|
property.boolValue = actualInput;
|
|
}
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
PrepareContextEditorGUI();
|
|
|
|
var referenceContext = serializedObject.targetObject as VFXContext;
|
|
var resource = referenceContext.GetResource();
|
|
GUI.enabled = resource == null || resource.IsAssetEditable();
|
|
|
|
DisplayName();
|
|
DisplaySpace();
|
|
|
|
EditorGUILayout.LabelField(UpdateStyles.header, EditorStyles.boldLabel);
|
|
|
|
bool? updatePosition = null;
|
|
bool? updateRotation = null;
|
|
bool? ageParticles = null;
|
|
bool? reapParticles = null;
|
|
bool? skipZeroDeltaTimeUpdate = null;
|
|
|
|
if (!m_IntegrationProperty.hasMultipleDifferentValues)
|
|
updatePosition = m_IntegrationProperty.enumValueIndex == (int)VFXBasicUpdate.VFXIntegrationMode.Euler;
|
|
if (!m_AngularIntegrationProperty.hasMultipleDifferentValues)
|
|
updateRotation = m_AngularIntegrationProperty.enumValueIndex == (int)VFXBasicUpdate.VFXIntegrationMode.Euler;
|
|
if (!m_AgeParticlesProperty.hasMultipleDifferentValues)
|
|
ageParticles = m_AgeParticlesProperty.boolValue;
|
|
if (!m_ReapParticlesProperty.hasMultipleDifferentValues)
|
|
reapParticles = m_ReapParticlesProperty.boolValue;
|
|
if (!m_SkipZeroDeltaTimeProperty.hasMultipleDifferentValues)
|
|
skipZeroDeltaTimeUpdate = m_SkipZeroDeltaTimeProperty.boolValue;
|
|
|
|
bool filterOutUpdatePosition = targets.OfType<VFXBasicUpdate>().All(o => s_fnGetFilteredOutSettings(o).Contains("updatePosition"));
|
|
bool filterOutUpdateRotation = targets.OfType<VFXBasicUpdate>().All(o => s_fnGetFilteredOutSettings(o).Contains("updateRotation"));
|
|
bool filterOutAgeParticles = targets.OfType<VFXBasicUpdate>().All(o => s_fnGetFilteredOutSettings(o).Contains("ageParticles"));
|
|
bool filterOutReapParticles = targets.OfType<VFXBasicUpdate>().All(o => s_fnGetFilteredOutSettings(o).Contains("reapParticles"));
|
|
|
|
if (!filterOutUpdatePosition)
|
|
DisplayToggle(UpdateStyles.updatePosition, m_IntegrationProperty, updatePosition, true);
|
|
if (!filterOutUpdateRotation)
|
|
DisplayToggle(UpdateStyles.updateRotation, m_AngularIntegrationProperty, updateRotation, true);
|
|
if (!filterOutAgeParticles)
|
|
DisplayToggle(UpdateStyles.ageParticles, m_AgeParticlesProperty, ageParticles, false);
|
|
if (!filterOutReapParticles)
|
|
DisplayToggle(UpdateStyles.reapParticles, m_ReapParticlesProperty, reapParticles, false);
|
|
DisplayToggle(UpdateStyles.skipZeroDeltaTime, m_SkipZeroDeltaTimeProperty, skipZeroDeltaTimeUpdate, false);
|
|
|
|
ApplyAndInvalidate();
|
|
|
|
DisplayWarnings();
|
|
DisplaySummary();
|
|
}
|
|
}
|
|
|
|
[VFXHelpURL("Context-Update")]
|
|
[VFXInfo(name = "Update Particle", category = "#0Common")]
|
|
class VFXBasicUpdate : VFXContext
|
|
{
|
|
public enum VFXIntegrationMode
|
|
{
|
|
Euler,
|
|
None
|
|
}
|
|
|
|
[Header("Particle Update Options")]
|
|
[SerializeField, VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), Tooltip("When enabled, particle positions are automatically updated using their velocity.")]
|
|
private VFXIntegrationMode integration = VFXIntegrationMode.Euler;
|
|
|
|
[SerializeField, VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), Tooltip("When enabled, particle rotations are automatically updated using their angular velocity.")]
|
|
private VFXIntegrationMode angularIntegration = VFXIntegrationMode.Euler;
|
|
|
|
[SerializeField, VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), Tooltip("When enabled, the particle age attribute will increase every frame based on deltaTime.")]
|
|
private bool ageParticles = true;
|
|
|
|
[SerializeField, VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), Tooltip("When enabled, particles whose age exceeds their lifetime will be destroyed.")]
|
|
private bool reapParticles = true;
|
|
|
|
[SerializeField, VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), Tooltip("When enabled, filters out block execution if deltaTime is equal to 0.")]
|
|
private bool skipZeroDeltaUpdate = false;
|
|
|
|
public VFXBasicUpdate() : base(VFXContextType.Update, VFXDataType.None, VFXDataType.None) { }
|
|
public override string name { get { return "Update " + ObjectNames.NicifyVariableName(ownedType.ToString()); } }
|
|
public override string codeGeneratorTemplate { get { return VisualEffectGraphPackageInfo.assetPackagePath + "/Shaders/VFXUpdate"; } }
|
|
public override bool codeGeneratorCompute { get { return true; } }
|
|
public override VFXTaskType taskType { get { return VFXTaskType.Update; } }
|
|
public override VFXDataType inputType { get { return GetData() == null ? VFXDataType.Particle : GetData().type; } }
|
|
public override VFXDataType outputType { get { return GetData() == null ? VFXDataType.Particle : GetData().type; } }
|
|
|
|
public override IEnumerable<VFXAttributeInfo> attributes
|
|
{
|
|
get
|
|
{
|
|
VFXDataParticle particleData = GetData() as VFXDataParticle;
|
|
|
|
if (particleData.IsCurrentAttributeRead(VFXAttribute.OldPosition))
|
|
{
|
|
yield return new VFXAttributeInfo(VFXAttribute.Position, VFXAttributeMode.Read);
|
|
yield return new VFXAttributeInfo(VFXAttribute.OldPosition, VFXAttributeMode.Write);
|
|
}
|
|
|
|
if (particleData.IsCurrentAttributeWritten(VFXAttribute.Alive) && particleData.attachedStripData != null)
|
|
yield return new VFXAttributeInfo(VFXAttribute.StripAlive, VFXAttributeMode.ReadWrite);
|
|
|
|
if (particleData && (particleData.NeedsComputeBounds(this) || particleData.NeedsSharedAabbBuffer()))
|
|
{
|
|
yield return new VFXAttributeInfo(VFXAttribute.Alive, VFXAttributeMode.Read);
|
|
foreach (var attribute in VFXAttributesManager.AffectingAABBAttributes)
|
|
yield return new VFXAttributeInfo(attribute, VFXAttributeMode.Read);
|
|
}
|
|
|
|
if (GetData().IsAttributeUsed(VFXAttribute.Alive))
|
|
{
|
|
yield return new VFXAttributeInfo(VFXAttribute.Alive, VFXAttributeMode.Read);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override IEnumerable<string> filteredOutSettings
|
|
{
|
|
get
|
|
{
|
|
foreach (var setting in base.filteredOutSettings)
|
|
yield return setting;
|
|
|
|
|
|
var data = GetData();
|
|
var lifeTime = data.IsCurrentAttributeWritten(VFXAttribute.Lifetime);
|
|
var age = data.IsCurrentAttributeUsed(VFXAttribute.Age);
|
|
var positionVelocity = data.IsCurrentAttributeWritten(VFXAttribute.Velocity);
|
|
var angularVelocity = data.IsCurrentAttributeWritten(VFXAttribute.AngularVelocityX) ||
|
|
data.IsCurrentAttributeWritten(VFXAttribute.AngularVelocityY) ||
|
|
data.IsCurrentAttributeWritten(VFXAttribute.AngularVelocityZ);
|
|
|
|
if (!age && !lifeTime)
|
|
yield return "ageParticles";
|
|
|
|
if (!lifeTime)
|
|
yield return "reapParticles";
|
|
|
|
if (!positionVelocity)
|
|
yield return "updatePosition";
|
|
|
|
if (!angularVelocity)
|
|
yield return "updateRotation";
|
|
}
|
|
}
|
|
|
|
protected override IEnumerable<VFXBlock> implicitPreBlock
|
|
{
|
|
get
|
|
{
|
|
var data = GetData();
|
|
if (data.IsCurrentAttributeUsed(VFXAttribute.OldPosition))
|
|
{
|
|
yield return GetOrCreateImplicitBlock<BackupOldPosition>(data);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override IEnumerable<VFXBlock> implicitPostBlock
|
|
{
|
|
get
|
|
{
|
|
var data = GetData();
|
|
|
|
if (integration == VFXIntegrationMode.Euler && data.IsCurrentAttributeWritten(VFXAttribute.Velocity))
|
|
yield return GetOrCreateImplicitBlock<EulerIntegration>(data);
|
|
|
|
if (angularIntegration == VFXIntegrationMode.Euler &&
|
|
(
|
|
data.IsCurrentAttributeWritten(VFXAttribute.AngularVelocityX) ||
|
|
data.IsCurrentAttributeWritten(VFXAttribute.AngularVelocityY) ||
|
|
data.IsCurrentAttributeWritten(VFXAttribute.AngularVelocityZ))
|
|
)
|
|
yield return GetOrCreateImplicitBlock<AngularEulerIntegration>(data);
|
|
|
|
var lifeTime = GetData().IsCurrentAttributeWritten(VFXAttribute.Lifetime);
|
|
var age = GetData().IsCurrentAttributeUsed(VFXAttribute.Age);
|
|
|
|
if (age || lifeTime)
|
|
{
|
|
if (ageParticles)
|
|
yield return GetOrCreateImplicitBlock<Age>(data);
|
|
|
|
if (lifeTime && reapParticles)
|
|
yield return GetOrCreateImplicitBlock<Reap>(data);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override VFXExpressionMapper GetExpressionMapper(VFXDeviceTarget target)
|
|
{
|
|
var mapper = base.GetExpressionMapper(target);
|
|
if (target == VFXDeviceTarget.GPU && skipZeroDeltaUpdate)
|
|
mapper.AddExpression(VFXBuiltInExpression.DeltaTime, "deltaTime", -1);
|
|
var dataParticle = GetData() as VFXDataParticle;
|
|
|
|
if (target == VFXDeviceTarget.GPU && dataParticle && (dataParticle.NeedsComputeBounds(this) || dataParticle.NeedsSharedAabbBuffer()) && space == VFXSpace.World)
|
|
{
|
|
mapper.AddExpression(VFXBuiltInExpression.WorldToLocal, "worldToLocal", -1);
|
|
}
|
|
return mapper;
|
|
}
|
|
public override IEnumerable<VFXMapping> additionalMappings
|
|
{
|
|
get
|
|
{
|
|
if ((GetData() as VFXDataParticle).NeedsSharedAabbBuffer())
|
|
yield return new VFXMapping("contextComputesAabb", 1);
|
|
}
|
|
}
|
|
|
|
public IEnumerable<string> rayTracingDefines = null;
|
|
public override IEnumerable<string> additionalDefines
|
|
{
|
|
get
|
|
{
|
|
if ((GetData() as VFXDataParticle).NeedsGlobalIndirectBuffer())
|
|
yield return "VFX_HAS_INDIRECT_DRAW";
|
|
|
|
if (ownedType == VFXDataType.ParticleStrip)
|
|
yield return "HAS_STRIPS";
|
|
|
|
if (skipZeroDeltaUpdate)
|
|
yield return "VFX_UPDATE_SKIP_ZERO_DELTA_TIME";
|
|
if ((GetData() as VFXDataParticle).NeedsComputeBounds(this))
|
|
yield return "VFX_COMPUTE_BOUNDS";
|
|
if ((GetData() as VFXDataParticle).NeedsSharedAabbBuffer() && rayTracingDefines != null)
|
|
{
|
|
foreach (var define in rayTracingDefines)
|
|
{
|
|
yield return define;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|