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.
239 lines
10 KiB
239 lines
10 KiB
using System;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
|
|
using UnityEditor.VFX.UI;
|
|
using UnityEngine;
|
|
using UnityEngine.VFX;
|
|
|
|
namespace UnityEditor.VFX
|
|
{
|
|
class InitializeVariantProvider : VariantProvider
|
|
{
|
|
public override IEnumerable<Variant> GetVariants()
|
|
{
|
|
foreach (var dataType in Enum.GetValues(typeof(VFXDataParticle.DataType)))
|
|
{
|
|
yield return new Variant(
|
|
"Initialize " + ObjectNames.NicifyVariableName(dataType.ToString()),
|
|
null,
|
|
typeof(VFXBasicInitialize),
|
|
new[] {new KeyValuePair<string, object>("dataType", dataType)}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
[VFXHelpURL("Context-Initialize")]
|
|
[VFXInfo(variantProvider = typeof(InitializeVariantProvider))]
|
|
class VFXBasicInitialize : VFXContext
|
|
{
|
|
public VFXBasicInitialize() : base(VFXContextType.Init, VFXDataType.SpawnEvent, VFXDataType.None) { }
|
|
public override string name { get { return "Initialize " + ObjectNames.NicifyVariableName(ownedType.ToString()); } }
|
|
public override string codeGeneratorTemplate { get { return VisualEffectGraphPackageInfo.assetPackagePath + "/Shaders/VFXInit"; } }
|
|
public override bool codeGeneratorCompute { get { return true; } }
|
|
public override VFXTaskType taskType { get { return VFXTaskType.Initialize; } }
|
|
public override VFXDataType outputType { get { return GetData() == null ? VFXDataType.Particle : GetData().type; } }
|
|
|
|
|
|
private bool hasGPUSpawner => inputContexts.Any(o => o.contextType == VFXContextType.SpawnerGPU);
|
|
|
|
private bool hasDynamicSourceCount => GetData() != null ? ((VFXDataParticle)GetData()).hasDynamicSourceCount : false;
|
|
|
|
public override IEnumerable<string> additionalDefines
|
|
{
|
|
get
|
|
{
|
|
if (hasGPUSpawner)
|
|
yield return "VFX_USE_SPAWNER_FROM_GPU";
|
|
|
|
if (hasDynamicSourceCount)
|
|
yield return "VFX_USE_DYNAMIC_SOURCE_COUNT";
|
|
|
|
if (ownedType == VFXDataType.ParticleStrip)
|
|
yield return "HAS_STRIPS";
|
|
|
|
yield return "VFX_STATIC_SOURCE_COUNT (" + GetData().staticSourceCount + ")";
|
|
}
|
|
}
|
|
|
|
public class InputPropertiesBounds
|
|
{
|
|
[Tooltip(
|
|
"The culling bounds of this system. The Visual Effect is only visible if the bounding box specified here is visible to the camera.")]
|
|
public AABox bounds = new AABox() { size = Vector3.one };
|
|
}
|
|
|
|
public class InputPropertiesPadding
|
|
{
|
|
[Range(Single.MinValue * 0.5f, Single.MaxValue * 0.5f), /*Avoids overflow when converting from size to extents*/
|
|
Tooltip(
|
|
"Some additional padding to add the culling bounds set above. It can be helpful when using recorded bounds.")]
|
|
public Vector3 boundsPadding = Vector3.zero;
|
|
}
|
|
|
|
public class StripInputProperties
|
|
{
|
|
public uint stripIndex = 0;
|
|
}
|
|
|
|
protected override void OnInvalidate(VFXModel model, InvalidationCause cause)
|
|
{
|
|
if (cause == InvalidationCause.kConnectionChanged)
|
|
{
|
|
if (model == this)
|
|
ResyncSlots(false); // To add/remove stripIndex
|
|
RefreshErrors();
|
|
}
|
|
|
|
base.OnInvalidate(model, cause);
|
|
}
|
|
|
|
internal override void GenerateErrors(VFXErrorReporter report)
|
|
{
|
|
VFXSetting capacitySetting = GetSetting("capacity");
|
|
|
|
if ((uint)capacitySetting.value > UnityEngine.VFX.VFXManager.maxCapacity)
|
|
report.RegisterError("CapacityOverMaximum", VFXErrorType.Error, "Systems capacity is greater than maximum capacity. This system will be skipped during rendering.\nYou can modify this limit in ProjectSettings/VFX.", this);
|
|
else if ((uint)capacitySetting.value > 1000000)
|
|
report.RegisterError("CapacityOver1M", VFXErrorType.PerfWarning, "Systems with large capacities can be slow to simulate", this);
|
|
var data = GetData() as VFXDataParticle;
|
|
if (data != null && CanBeCompiled())
|
|
{
|
|
if (data.boundsMode == BoundsSettingMode.Recorded)
|
|
{
|
|
if (VFXViewWindow.GetWindow(GetGraph(), false, false)?.graphView?.attachedComponent == null ||
|
|
!BoardPreferenceHelper.IsVisible(BoardPreferenceHelper.Board.componentBoard, false))
|
|
{
|
|
report.RegisterError("NeedsRecording", VFXErrorType.Warning,
|
|
"In order to record the bounds, the current graph needs to be attached to a scene instance via the Target Game Object panel", this);
|
|
}
|
|
var boundsSlot = inputSlots.FirstOrDefault(s => s.name == nameof(InputPropertiesBounds.bounds));
|
|
if (boundsSlot != null && boundsSlot.HasLink(true))
|
|
{
|
|
report.RegisterError("OverriddenRecording", VFXErrorType.Warning,
|
|
"This system bounds will not be recorded because they are set from operators.", this);
|
|
}
|
|
}
|
|
|
|
if (data.boundsMode == BoundsSettingMode.Automatic)
|
|
{
|
|
report.RegisterError("CullingFlagAlwaysSimulate", VFXErrorType.Warning,
|
|
"Setting the system Bounds Mode to Automatic will switch the culling flags of the Visual Effect asset" +
|
|
" to 'Always recompute bounds and simulate'.", this);
|
|
}
|
|
|
|
if (data.hasTooManyContext)
|
|
{
|
|
report.RegisterError("TooManyContexts", VFXErrorType.Error, $"Too many contexts within the same system, maximum is {VFXData.kMaxContexts}", this);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override IEnumerable<VFXPropertyWithValue> inputProperties
|
|
{
|
|
get
|
|
{
|
|
var particleData = GetData() as VFXDataParticle;
|
|
|
|
var prop = Enumerable.Empty<VFXPropertyWithValue>();
|
|
if (particleData)
|
|
{
|
|
if (particleData.boundsMode == BoundsSettingMode.Manual)
|
|
{
|
|
prop = prop.Concat(PropertiesFromType("InputPropertiesBounds"));
|
|
}
|
|
if (particleData.boundsMode == BoundsSettingMode.Recorded)
|
|
{
|
|
prop = prop.Concat(PropertiesFromType("InputPropertiesBounds"));
|
|
prop = prop.Concat(PropertiesFromType("InputPropertiesPadding"));
|
|
}
|
|
if (particleData.boundsMode == BoundsSettingMode.Automatic)
|
|
{
|
|
prop = prop.Concat(PropertiesFromType("InputPropertiesPadding"));
|
|
}
|
|
}
|
|
|
|
if (ownedType == VFXDataType.ParticleStrip && !hasGPUSpawner)
|
|
prop = prop.Concat(PropertiesFromType("StripInputProperties"));
|
|
return prop;
|
|
}
|
|
}
|
|
|
|
public override IEnumerable<VFXAttributeInfo> attributes
|
|
{
|
|
get
|
|
{
|
|
foreach (var attribute in base.attributes)
|
|
yield return attribute;
|
|
}
|
|
}
|
|
|
|
public sealed override VFXSpace GetOutputSpaceFromSlot(VFXSlot slot)
|
|
{
|
|
if (slot.name == nameof(InputPropertiesBounds.bounds))
|
|
return VFXSpace.Local;
|
|
return base.GetOutputSpaceFromSlot(slot);
|
|
}
|
|
|
|
public override VFXExpressionMapper GetExpressionMapper(VFXDeviceTarget target)
|
|
{
|
|
var particleData = GetData() as VFXDataParticle;
|
|
bool isRecordedBounds = particleData && particleData.boundsMode == BoundsSettingMode.Recorded;
|
|
// GPU
|
|
if (target == VFXDeviceTarget.GPU)
|
|
{
|
|
var gpuMapper = VFXExpressionMapper.FromBlocks(activeFlattenedChildrenWithImplicit);
|
|
if (ownedType == VFXDataType.ParticleStrip && !hasGPUSpawner)
|
|
gpuMapper.AddExpressionsFromSlot(inputSlots[(isRecordedBounds ? 2 : 1)], -1); // strip index
|
|
return gpuMapper;
|
|
}
|
|
|
|
// CPU
|
|
var cpuMapper = new VFXExpressionMapper();
|
|
if (particleData)
|
|
{
|
|
switch (particleData.boundsMode)
|
|
{
|
|
case BoundsSettingMode.Manual:
|
|
cpuMapper.AddExpressionsFromSlot(inputSlots[0], -1); // bounds
|
|
break;
|
|
case BoundsSettingMode.Recorded:
|
|
cpuMapper.AddExpressionsFromSlot(inputSlots[0], -1); // bounds
|
|
cpuMapper.AddExpressionsFromSlot(inputSlots[1], -1); //bounds padding
|
|
break;
|
|
case BoundsSettingMode.Automatic:
|
|
cpuMapper.AddExpressionsFromSlot(inputSlots[0], -1); //bounds padding
|
|
break;
|
|
}
|
|
}
|
|
|
|
return cpuMapper;
|
|
}
|
|
|
|
public override VFXSetting GetSetting(string name)
|
|
{
|
|
return GetData().GetSetting(name); // Just a bridge on data
|
|
}
|
|
|
|
public override IEnumerable<VFXSetting> GetSettings(bool listHidden, VFXSettingAttribute.VisibleFlags flags)
|
|
{
|
|
return GetData().GetSettings(listHidden, flags); // Just a bridge on data
|
|
}
|
|
|
|
protected override IEnumerable<VFXBlock> implicitPreBlock
|
|
{
|
|
get
|
|
{
|
|
var data = GetData();
|
|
if (hasGPUSpawner)
|
|
{
|
|
// Force "alive" attribute when a system can spawn particles from GPU, because we are updating the entire capacity
|
|
var block = VFXBlock.CreateImplicitBlock<Block.SetAttribute>(data);
|
|
block.SetSettingValue(nameof(Block.SetAttribute.attribute), VFXAttribute.Alive.name);
|
|
yield return block;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|