SW 중심대학 OSS GIT 서버
박건태, 이승준, 고기완, 이준호
새로운 배포
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.
|
|
using System;using UnityEngine.Playables;
namespace UnityEngine.Timeline{ /// <summary>
/// Playable that synchronizes a particle system simulation.
/// </summary>
public class ParticleControlPlayable : PlayableBehaviour { const float kUnsetTime = -1; float m_LastTime = kUnsetTime; uint m_RandomSeed = 1;
// particleSystem.time can not be relied on for an accurate time. It does not advance until a delta threshold is reached(fixedUpdate) and until the start delay has elapsed.
float m_SystemTime;
/// <summary>
/// Creates a Playable with a ParticleControlPlayable behaviour attached
/// </summary>
/// <param name="graph">The PlayableGraph to inject the Playable into.</param>
/// <param name="component">The particle systtem to control</param>
/// <param name="randomSeed">A random seed to use for particle simulation</param>
/// <returns>Returns the created Playable.</returns>
public static ScriptPlayable<ParticleControlPlayable> Create(PlayableGraph graph, ParticleSystem component, uint randomSeed) { if (component == null) return ScriptPlayable<ParticleControlPlayable>.Null;
var handle = ScriptPlayable<ParticleControlPlayable>.Create(graph); handle.GetBehaviour().Initialize(component, randomSeed); return handle; }
/// <summary>
/// The particle system to control
/// </summary>
public ParticleSystem particleSystem { get; private set; }
/// <summary>
/// Initializes the behaviour with a particle system and random seed.
/// </summary>
/// <param name="ps"></param>
/// <param name="randomSeed"></param>
public void Initialize(ParticleSystem ps, uint randomSeed) { m_RandomSeed = Math.Max(1, randomSeed); particleSystem = ps; m_SystemTime = 0; SetRandomSeed();
#if UNITY_EDITOR
if (!Application.isPlaying && UnityEditor.PrefabUtility.IsPartOfPrefabInstance(ps)) UnityEditor.PrefabUtility.prefabInstanceUpdated += OnPrefabUpdated; #endif
}
#if UNITY_EDITOR
/// <summary>
/// This function is called when the Playable that owns the PlayableBehaviour is destroyed.
/// </summary>
/// <param name="playable">The playable this behaviour is attached to.</param>
public override void OnPlayableDestroy(Playable playable) { if (!Application.isPlaying) UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabUpdated; }
void OnPrefabUpdated(GameObject go) { // When the instance is updated from, this will cause the next evaluate to resimulate.
if (UnityEditor.PrefabUtility.GetRootGameObject(particleSystem) == go) m_LastTime = kUnsetTime; }
#endif
void SetRandomSeed() { particleSystem.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); var systems = particleSystem.gameObject.GetComponentsInChildren<ParticleSystem>(); uint seed = m_RandomSeed; foreach (var ps in systems) { // don't overwrite user set random seeds
if (ps.useAutoRandomSeed) { ps.useAutoRandomSeed = false; ps.randomSeed = seed; seed++; } } }
/// <summary>
/// This function is called during the PrepareFrame phase of the PlayableGraph.
/// </summary>
/// <param name="playable">The Playable that owns the current PlayableBehaviour.</param>
/// <param name="data">A FrameData structure that contains information about the current frame context.</param>
public override void PrepareFrame(Playable playable, FrameData data) { if (particleSystem == null || !particleSystem.gameObject.activeInHierarchy) return;
float localTime = (float)playable.GetTime(); bool shouldUpdate = Mathf.Approximately(m_LastTime, kUnsetTime) || !Mathf.Approximately(m_LastTime, localTime); if (shouldUpdate) { float epsilon = Time.fixedDeltaTime * 0.5f; float simTime = localTime; float expectedDelta = simTime - m_LastTime;
// The first iteration includes the start delay. Evaluate(particleSystem.randomSeed) is how the particle system generates the random value internally.
float startDelay = particleSystem.main.startDelay.Evaluate(particleSystem.randomSeed); float particleSystemDurationLoop0 = particleSystem.main.duration + startDelay;
// The particle system time does not include the start delay so we need to remove this for our own system time.
float expectedSystemTime = simTime > particleSystemDurationLoop0 ? m_SystemTime : m_SystemTime - startDelay;
// conditions for restart
bool restart = (simTime < m_LastTime) || // time went backwards
(simTime < epsilon) || // time is set to 0
Mathf.Approximately(m_LastTime, kUnsetTime) || // object disabled
(expectedDelta > particleSystem.main.duration) || // large jump (bug workaround)
!(Mathf.Abs(expectedSystemTime - particleSystem.time) < Time.maximumParticleDeltaTime); // particle system isn't where we left it
if (restart) { // work around for a bug where simulate(simTime, true, true) doesn't work on loops
particleSystem.Simulate(0, true, true); particleSystem.Simulate(simTime, true, false); m_SystemTime = simTime; } else { // ps.time will wrap, so we need to account for that in computing delta time
float particleSystemDuration = simTime > particleSystemDurationLoop0 ? particleSystem.main.duration : particleSystemDurationLoop0; float fracTime = simTime % particleSystemDuration; float deltaTime = fracTime - m_SystemTime;
if (deltaTime < -epsilon) // detect wrapping of ps.time
deltaTime = fracTime + particleSystemDurationLoop0 - m_SystemTime;
particleSystem.Simulate(deltaTime, true, false); m_SystemTime += deltaTime; }
m_LastTime = localTime; } }
/// <summary>
/// This function is called when the Playable play state is changed to Playables.PlayState.Playing.
/// </summary>
/// <param name="playable">The Playable that owns the current PlayableBehaviour.</param>
/// <param name="info">A FrameData structure that contains information about the current frame context.</param>
public override void OnBehaviourPlay(Playable playable, FrameData info) { m_LastTime = kUnsetTime; }
/// <summary>
/// This function is called when the Playable play state is changed to PlayState.Paused.
/// </summary>
/// <param name="playable">The playable this behaviour is attached to.</param>
/// <param name="info">A FrameData structure that contains information about the current frame context.</param>
public override void OnBehaviourPause(Playable playable, FrameData info) { m_LastTime = kUnsetTime; } }}
|