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.
 
 
 
 
 

269 lines
9.6 KiB

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.VFX;
namespace UnityEditor.VFX.Operator
{
sealed class RandomSelectorProvider : VariantProvider
{
public override IEnumerable<Variant> GetVariants()
{
yield return new Variant(
"Random Selector",
"Random",
typeof(RandomSelector),
new[]
{
new KeyValuePair<string, object>("m_Weighted", false),
new KeyValuePair<string, object>("m_ClampWeight", true)
});
yield return new Variant(
"Random Selector Weighted",
"Random",
typeof(RandomSelector),
new[]
{
new KeyValuePair<string, object>("m_Weighted", true),
new KeyValuePair<string, object>("m_ClampWeight", true)
});
}
}
[VFXHelpURL("Operator-ProbabilitySampling")]
[VFXInfo(category = "Random", synonyms = new [] { "Probability Sampling" }, variantProvider = typeof(RandomSelectorProvider))]
class RandomSelector : VFXOperatorDynamicBranch
{
enum Mode
{
Random,
Custom
}
[VFXSetting(VFXSettingAttribute.VisibleFlags.None), SerializeField, FormerlySerializedAs("m_IntegratedRandom")]
private bool m_IntegratedRandomDeprecated = true;
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), SerializeField]
private Mode m_Mode = Mode.Random;
[VFXSetting, Tooltip("Generate a random number for each particle, or one that is shared by the whole system."), SerializeField]
private VFXSeedMode m_Seed = VFXSeedMode.PerParticle;
[VFXSetting, Tooltip("The random number may either remain constant, or change every time it is evaluated."), SerializeField]
private bool m_Constant = true;
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), Tooltip(" When enabled, it reveals the weights of values, influencing their likelihood of being randomly selected."), SerializeField]
private bool m_Weighted = true;
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), Tooltip("When enabled, clamps weights to a defined 0-1 range."), SerializeField]
private bool m_ClampWeight = false;
[VFXSetting, SerializeField, Tooltip("Set the number of possible entries to be sampled. The maximum count is 32 entries.")]
private uint m_EntryCount = 3u;
public class ConstantInputProperties
{
[Tooltip("The seed this operator uses to create a constant random value.")]
public uint seed = 0u;
}
public class ManualRandomProperties
{
[Tooltip("Value used to sample the weighted curve on a 0 to 1 range.")]
public float s = 0.0f;
}
public override IEnumerable<Type> validTypes
{
get
{
foreach (var validType in base.validTypes)
{
bool isPerParticleRandom = false;
if (m_Mode == Mode.Random)
{
isPerParticleRandom = m_Seed != VFXSeedMode.PerVFXComponent;
}
//Avoid listing of mesh or texture base switch in case of random per particle
if (isPerParticleRandom &&
(validType.IsSubclassOf(typeof(Texture))
|| validType == typeof(Mesh)
|| validType == typeof(SkinnedMeshRenderer)
|| validType == typeof(GraphicsBuffer)))
continue;
yield return validType;
}
}
}
public override string name
{
get
{
var current = string.Empty;
if (m_Mode == Mode.Random)
current += "Random ";
current += "Selector";
if (m_Weighted)
current += " Weighted";
return current;
}
}
public override IEnumerable<int> staticSlotIndex
{
get
{
var stride = ComputeStride();
for (int i = 0; i < m_EntryCount; ++i)
yield return i * stride + 1;
if (m_Constant || m_Mode == Mode.Custom)
yield return stride * (int)m_EntryCount;
}
}
protected override Type defaultValueType => typeof(float);
protected override IEnumerable<string> filteredOutSettings
{
get
{
if (m_Mode == Mode.Custom)
{
yield return nameof(m_Seed);
yield return nameof(m_Constant);
}
if (!m_Weighted)
{
yield return nameof(m_ClampWeight);
}
}
}
public sealed override void Sanitize(int version)
{
if (version < 18)
m_Mode = m_IntegratedRandomDeprecated ? Mode.Random : Mode.Custom;
base.Sanitize(version);
}
protected override void OnInvalidate(VFXModel model, InvalidationCause cause)
{
if (m_EntryCount < 2) m_EntryCount = 2;
if (m_EntryCount > 32) m_EntryCount = 32;
base.OnInvalidate(model, cause);
}
protected override IEnumerable<VFXPropertyWithValue> inputProperties
{
get
{
var type = (Type)GetOperandType();
var defaultValue = GetDefaultValueForType(type);
for (uint i = 0; i < m_EntryCount; ++i)
{
var prefix = i.ToString();
var currentValue = defaultValue;
if (type == typeof(float))
{
//Handle default values from variant provider, we are displaying different entries for each slot.
currentValue = (float)i;
}
yield return new VFXPropertyWithValue(new VFXProperty((Type)GetOperandType(), $"Value {prefix}"), currentValue);
if (m_Weighted)
{
if (m_ClampWeight)
yield return new VFXPropertyWithValue(new VFXProperty(typeof(float), $"Weight {prefix}", new RangeAttribute(0.0f, 1.0f)), 1.0f);
else
yield return new VFXPropertyWithValue(new VFXProperty(typeof(float), $"Weight {prefix}"), 1.0f);
}
}
if (m_Mode == Mode.Random)
{
if (m_Constant)
{
var constantProperties = PropertiesFromType(nameof(ConstantInputProperties));
foreach (var property in constantProperties)
yield return property;
}
}
else
{
var manualRandomProperties = PropertiesFromType(nameof(ManualRandomProperties));
foreach (var property in manualRandomProperties)
yield return property;
}
}
}
int ComputeStride()
{
if (m_Weighted)
return expressionCountPerUniqueSlot + 1;
return expressionCountPerUniqueSlot;
}
protected override VFXExpression[] BuildExpression(VFXExpression[] inputExpression)
{
VFXExpression rand = null;
if (m_Mode == Mode.Random)
{
if (m_Constant)
rand = VFXOperatorUtility.FixedRandom(inputExpression[^1], m_Seed);
else
rand = new VFXExpressionRandom(m_Seed == VFXSeedMode.PerParticle, new RandId(this));
}
else
{
rand = inputExpression[^1];
}
int stride = ComputeStride();
var prefixedProbabilities = new VFXExpression[m_EntryCount];
if (m_Weighted)
{
var expressionCountPerUniqueSlot = this.expressionCountPerUniqueSlot;
int offsetProbabilities = expressionCountPerUniqueSlot;
prefixedProbabilities[0] = inputExpression[offsetProbabilities];
for (uint i = 1; i < m_EntryCount; i++)
{
offsetProbabilities += stride;
prefixedProbabilities[i] = prefixedProbabilities[i - 1] + inputExpression[offsetProbabilities];
}
}
else
{
for (uint i = 0; i < m_EntryCount; i++)
{
prefixedProbabilities[i] = VFXValue.Constant(i + 1.0f);
}
}
rand = rand * prefixedProbabilities[^1];
var compare = new VFXExpression[m_EntryCount - 1];
for (int i = 0; i < m_EntryCount - 1; i++)
{
compare[i] = new VFXExpressionCondition(VFXValueType.Float, VFXCondition.GreaterOrEqual, prefixedProbabilities[i], rand);
}
var startValueIndex = new int[m_EntryCount];
for (int i = 0; i < m_EntryCount; ++i)
{
startValueIndex[i] = i * stride;
}
return ChainedBranchResult(compare, inputExpression, startValueIndex);
}
}
}