Added Particle Playground library, fixed cinema director deprecated code.
|
@ -17,15 +17,15 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
void Awake()
|
||||
{
|
||||
if (guiTexture == null)
|
||||
if (GetComponent<GUITexture>() == null)
|
||||
{
|
||||
gameObject.transform.position = Vector3.zero;
|
||||
gameObject.transform.localScale = new Vector3(100, 100, 100);
|
||||
gameObject.AddComponent<GUITexture>();
|
||||
guiTexture.enabled = false;
|
||||
guiTexture.texture = new Texture2D(1, 1);
|
||||
guiTexture.pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
guiTexture.color = Color.clear;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
GetComponent<GUITexture>().texture = new Texture2D(1, 1);
|
||||
GetComponent<GUITexture>().pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
GetComponent<GUITexture>().color = Color.clear;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,9 +34,9 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void Trigger()
|
||||
{
|
||||
guiTexture.enabled = true;
|
||||
guiTexture.pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
guiTexture.color = From;
|
||||
GetComponent<GUITexture>().enabled = true;
|
||||
GetComponent<GUITexture>().pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
GetComponent<GUITexture>().color = From;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -67,12 +67,12 @@ namespace CinemaDirector
|
|||
{
|
||||
if (time >= 0 && time <= Duration)
|
||||
{
|
||||
guiTexture.enabled = true;
|
||||
GetComponent<GUITexture>().enabled = true;
|
||||
UpdateTime(time, deltaTime);
|
||||
}
|
||||
else if (guiTexture.enabled)
|
||||
else if (GetComponent<GUITexture>().enabled)
|
||||
{
|
||||
guiTexture.enabled = false;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void End()
|
||||
{
|
||||
guiTexture.enabled = false;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -89,9 +89,9 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void ReverseEnd()
|
||||
{
|
||||
guiTexture.enabled = true;
|
||||
guiTexture.pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
guiTexture.color = To;
|
||||
GetComponent<GUITexture>().enabled = true;
|
||||
GetComponent<GUITexture>().pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
GetComponent<GUITexture>().color = To;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -99,9 +99,9 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void Stop()
|
||||
{
|
||||
if (guiTexture != null)
|
||||
if (GetComponent<GUITexture>() != null)
|
||||
{
|
||||
guiTexture.enabled = false;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ namespace CinemaDirector
|
|||
/// <param name="transition">the Lerp transition value</param>
|
||||
private void FadeToColor(Color from, Color to, float transition)
|
||||
{
|
||||
guiTexture.color = Color.Lerp(from, to, transition);
|
||||
GetComponent<GUITexture>().color = Color.Lerp(from, to, transition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,15 +17,15 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
void Awake()
|
||||
{
|
||||
if (guiTexture == null)
|
||||
if (GetComponent<GUITexture>() == null)
|
||||
{
|
||||
gameObject.transform.position = Vector3.zero;
|
||||
gameObject.transform.localScale = new Vector3(100, 100, 100);
|
||||
gameObject.AddComponent<GUITexture>();
|
||||
guiTexture.enabled = false;
|
||||
guiTexture.texture = new Texture2D(1, 1);
|
||||
guiTexture.pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
guiTexture.color = Color.clear;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
GetComponent<GUITexture>().texture = new Texture2D(1, 1);
|
||||
GetComponent<GUITexture>().pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
GetComponent<GUITexture>().color = Color.clear;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,9 +34,9 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void Trigger()
|
||||
{
|
||||
guiTexture.enabled = true;
|
||||
guiTexture.pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
guiTexture.color = From;
|
||||
GetComponent<GUITexture>().enabled = true;
|
||||
GetComponent<GUITexture>().pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
GetComponent<GUITexture>().color = From;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -67,12 +67,12 @@ namespace CinemaDirector
|
|||
{
|
||||
if (time >= 0 && time <= Duration)
|
||||
{
|
||||
guiTexture.enabled = true;
|
||||
GetComponent<GUITexture>().enabled = true;
|
||||
UpdateTime(time, deltaTime);
|
||||
}
|
||||
else if (guiTexture.enabled)
|
||||
else if (GetComponent<GUITexture>().enabled)
|
||||
{
|
||||
guiTexture.enabled = false;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void End()
|
||||
{
|
||||
guiTexture.enabled = false;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -89,9 +89,9 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void ReverseEnd()
|
||||
{
|
||||
guiTexture.enabled = true;
|
||||
guiTexture.pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
guiTexture.color = To;
|
||||
GetComponent<GUITexture>().enabled = true;
|
||||
GetComponent<GUITexture>().pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
GetComponent<GUITexture>().color = To;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -99,9 +99,9 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void Stop()
|
||||
{
|
||||
if (guiTexture != null)
|
||||
if (GetComponent<GUITexture>() != null)
|
||||
{
|
||||
guiTexture.enabled = false;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ namespace CinemaDirector
|
|||
/// <param name="transition">the Lerp transition value</param>
|
||||
private void FadeToColor(Color from, Color to, float transition)
|
||||
{
|
||||
guiTexture.color = Color.Lerp(from, to, transition);
|
||||
GetComponent<GUITexture>().color = Color.Lerp(from, to, transition);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,15 +17,15 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
void Awake()
|
||||
{
|
||||
if (guiTexture == null)
|
||||
if (GetComponent<GUITexture>() == null)
|
||||
{
|
||||
gameObject.transform.position = Vector3.zero;
|
||||
gameObject.transform.localScale = new Vector3(100, 100, 100);
|
||||
gameObject.AddComponent<GUITexture>();
|
||||
guiTexture.enabled = false;
|
||||
guiTexture.texture = new Texture2D(1, 1);
|
||||
guiTexture.pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
guiTexture.color = Color.clear;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
GetComponent<GUITexture>().texture = new Texture2D(1, 1);
|
||||
GetComponent<GUITexture>().pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
GetComponent<GUITexture>().color = Color.clear;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,9 +34,9 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void Trigger()
|
||||
{
|
||||
guiTexture.enabled = true;
|
||||
guiTexture.pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
guiTexture.color = From;
|
||||
GetComponent<GUITexture>().enabled = true;
|
||||
GetComponent<GUITexture>().pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
GetComponent<GUITexture>().color = From;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -67,12 +67,12 @@ namespace CinemaDirector
|
|||
{
|
||||
if (time >= 0 && time <= Duration)
|
||||
{
|
||||
guiTexture.enabled = true;
|
||||
GetComponent<GUITexture>().enabled = true;
|
||||
UpdateTime(time, deltaTime);
|
||||
}
|
||||
else if (guiTexture.enabled)
|
||||
else if (GetComponent<GUITexture>().enabled)
|
||||
{
|
||||
guiTexture.enabled = false;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void End()
|
||||
{
|
||||
guiTexture.enabled = false;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -89,9 +89,9 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void ReverseEnd()
|
||||
{
|
||||
guiTexture.enabled = true;
|
||||
guiTexture.pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
guiTexture.color = To;
|
||||
GetComponent<GUITexture>().enabled = true;
|
||||
GetComponent<GUITexture>().pixelInset = new Rect(0f, 0f, Screen.width, Screen.height);
|
||||
GetComponent<GUITexture>().color = To;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -99,9 +99,9 @@ namespace CinemaDirector
|
|||
/// </summary>
|
||||
public override void Stop()
|
||||
{
|
||||
if (guiTexture != null)
|
||||
if (GetComponent<GUITexture>() != null)
|
||||
{
|
||||
guiTexture.enabled = false;
|
||||
GetComponent<GUITexture>().enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ namespace CinemaDirector
|
|||
/// <param name="transition">the Lerp transition value</param>
|
||||
private void FadeToColor(Color from, Color to, float transition)
|
||||
{
|
||||
guiTexture.color = Color.Lerp(from, to, transition);
|
||||
GetComponent<GUITexture>().color = Color.Lerp(from, to, transition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
9
Assets/Particle Playground/Extensions.meta
Normal file
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6e4f0fc9ae1da904a83344cd4ecd4adb
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984948
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1c30893a4ccf6094fba8c75c3fce2cae
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984948
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,307 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ParticlePlayground {
|
||||
public class PlaygroundFollow : MonoBehaviour {
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the particle system.
|
||||
/// </summary>
|
||||
public PlaygroundParticlesC particles;
|
||||
/// <summary>
|
||||
/// Reference to an existing GameObject. This will be cloned to be used on every particle.
|
||||
/// </summary>
|
||||
public GameObject referenceObject;
|
||||
/// <summary>
|
||||
/// The lifetime of the followers. Set 0 to follow during each particle's individual lifetime.
|
||||
/// </summary>
|
||||
public float followerLifetime = 0;
|
||||
/// <summary>
|
||||
/// The size of the cache. Set 0 to automatically set the needed amount.
|
||||
/// </summary>
|
||||
public int cacheSize = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the Playground Followers should broadcast to any event listeners.
|
||||
/// </summary>
|
||||
public bool sendEvents = false;
|
||||
|
||||
/// <summary>
|
||||
/// This event occurs when followers are born and sendEvents are set to true.
|
||||
/// </summary>
|
||||
public event OnPlaygroundFollower followerEventBirth;
|
||||
/// <summary>
|
||||
/// This event occurs when follower dies and sendEvents are set to true.
|
||||
/// </summary>
|
||||
public event OnPlaygroundFollower followerEventDeath;
|
||||
|
||||
/// <summary>
|
||||
/// The reference to the trail renderer (if existing)
|
||||
/// </summary>
|
||||
TrailRenderer referenceTrailRenderer;
|
||||
/// <summary>
|
||||
/// If the follower has a Trail Renderer component, this sets trail time once the follower is active again.
|
||||
/// </summary>
|
||||
float trailTime = 0;
|
||||
/// <summary>
|
||||
/// The list of active followers.
|
||||
/// </summary>
|
||||
List<PlaygroundFollower> followers = new List<PlaygroundFollower>();
|
||||
/// <summary>
|
||||
/// As Playground is running in a multithreaded environment we need a queue for instantiation (which cannot be called from a different thread).
|
||||
/// </summary>
|
||||
List<PlaygroundFollower> waitingFollowers = new List<PlaygroundFollower>();
|
||||
PlaygroundFollower[] referenceObjectsCache;
|
||||
PlaygroundFollower[] queue = new PlaygroundFollower[0];
|
||||
int cacheIndex = 0;
|
||||
|
||||
PlaygroundEventC birthEvent;
|
||||
PlaygroundEventC deathEvent;
|
||||
Transform followerParent;
|
||||
|
||||
void Start ()
|
||||
{
|
||||
if (referenceObject == null || particles == null)
|
||||
return;
|
||||
|
||||
// Create and setup the birth event
|
||||
birthEvent = PlaygroundC.CreateEvent(particles);
|
||||
birthEvent.broadcastType = EVENTBROADCASTC.EventListeners;
|
||||
birthEvent.eventType = EVENTTYPEC.Birth;
|
||||
|
||||
// Create and setup the death event
|
||||
deathEvent = PlaygroundC.CreateEvent(particles);
|
||||
deathEvent.broadcastType = EVENTBROADCASTC.EventListeners;
|
||||
deathEvent.eventType = EVENTTYPEC.Death;
|
||||
|
||||
// Hook up the event listeners to the delegates
|
||||
birthEvent.particleEvent += OnParticleDidBirth;
|
||||
deathEvent.particleEvent += OnParticleDidDie;
|
||||
|
||||
// Create a parent for all followers (for Hierarchy convenience)
|
||||
followerParent = new GameObject("Followers").transform;
|
||||
followerParent.parent = transform;
|
||||
|
||||
// Get the trail renderer (if available) and its time
|
||||
referenceTrailRenderer = referenceObject.GetComponent<TrailRenderer>();
|
||||
if (referenceTrailRenderer!=null)
|
||||
trailTime = referenceTrailRenderer.time;
|
||||
|
||||
// Set an extra amount of followers if required (a trail's time will exceed a particle's)
|
||||
int extra = followerLifetime<=0?
|
||||
Mathf.CeilToInt(Mathf.Abs (particles.lifetime-trailTime)+(trailTime-particles.lifetime))+2 :
|
||||
Mathf.CeilToInt(Mathf.Abs (particles.lifetime-followerLifetime)+(followerLifetime-particles.lifetime))+2 ;
|
||||
if (particles.lifetime<=1f) extra++;
|
||||
|
||||
// Create the follower cache (this will be iterated through and reused whenever a particle rebirths)
|
||||
referenceObjectsCache = new PlaygroundFollower[cacheSize>0? cacheSize : particles.particleCount+Mathf.CeilToInt(particles.particleCount*extra)];
|
||||
for (int i = 0; i<referenceObjectsCache.Length; i++) {
|
||||
GameObject clone = (GameObject)Instantiate(referenceObject);
|
||||
referenceObjectsCache[i] = new PlaygroundFollower(clone.transform, clone, clone.GetComponent<TrailRenderer>(), 0, 0);
|
||||
referenceObjectsCache[i].transform.parent = followerParent;
|
||||
if (referenceObjectsCache[i].trailRenderer!=null)
|
||||
referenceObjectsCache[i].trailRenderer.time = 0;
|
||||
referenceObjectsCache[i].gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event listener for particle birth.
|
||||
/// </summary>
|
||||
/// <param name="particle">Particle.</param>
|
||||
void OnParticleDidBirth (PlaygroundEventParticle particle)
|
||||
{
|
||||
waitingFollowers.Add (new PlaygroundFollower(null, null, null, followerLifetime<=0? particle.totalLifetime+trailTime : followerLifetime, particle.particleId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event listener for particle death.
|
||||
/// </summary>
|
||||
/// <param name="particle">Particle.</param>
|
||||
void OnParticleDidDie (PlaygroundEventParticle particle)
|
||||
{
|
||||
int followerId = GetFollowerWithId(particle.particleId);
|
||||
if (followerId<0) return;
|
||||
followers[followerId].enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the follower which has the passed in particle identifier.
|
||||
/// </summary>
|
||||
/// <returns>The follower with particle identifier.</returns>
|
||||
/// <param name="particleId">Particle identifier.</param>
|
||||
int GetFollowerWithId (int particleId)
|
||||
{
|
||||
float lowestLife = 999f;
|
||||
int returnIndex = -1;
|
||||
for (int i = 0; i<followers.Count; i++)
|
||||
if (followers[i].particleId==particleId && followers[i].lifetime<lowestLife)
|
||||
returnIndex = i;
|
||||
return returnIndex;
|
||||
}
|
||||
|
||||
void Update ()
|
||||
{
|
||||
if (waitingFollowers.Count>0)
|
||||
{
|
||||
queue = waitingFollowers.ToArray();
|
||||
}
|
||||
}
|
||||
void LateUpdate ()
|
||||
{
|
||||
UpdateFollowers();
|
||||
}
|
||||
|
||||
void UpdateFollowers ()
|
||||
{
|
||||
|
||||
// Follow, lifetime, remove
|
||||
for (int i = 0; i<followers.Count; i++)
|
||||
{
|
||||
// Follow particle
|
||||
if (followers[i].enabled)
|
||||
followers[i].transform.position = particles.particleCache[followers[i].particleId].position;
|
||||
|
||||
// Subtract lifetime
|
||||
followers[i].lifetime -= Time.deltaTime;
|
||||
|
||||
// Remove if no lifetime left
|
||||
if (followers[i].lifetime<=0) {
|
||||
RemoveFollower(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Add any waiting followers to the live follower list. The waiting list may change during iteration!
|
||||
if (queue.Length>0)
|
||||
{
|
||||
if (queue.Length!=waitingFollowers.Count) return;
|
||||
int inQueueThisFrame = waitingFollowers.Count;
|
||||
|
||||
foreach (PlaygroundFollower wFollower in queue)
|
||||
{
|
||||
AddFollower (wFollower, followers.Count-1);
|
||||
}
|
||||
if (inQueueThisFrame==waitingFollowers.Count)
|
||||
waitingFollowers = new List<PlaygroundFollower>();
|
||||
else waitingFollowers.RemoveRange (0, inQueueThisFrame-1);
|
||||
queue = new PlaygroundFollower[0];
|
||||
}
|
||||
}
|
||||
|
||||
void AddFollower (PlaygroundFollower follower, int i)
|
||||
{
|
||||
if (follower==null) return;
|
||||
followers.Add (follower.Clone());
|
||||
followers[followers.Count-1].enabled = true;
|
||||
followers[followers.Count-1].gameObject = referenceObjectsCache[cacheIndex].gameObject;
|
||||
followers[followers.Count-1].gameObject.SetActive(true);
|
||||
followers[followers.Count-1].transform = referenceObjectsCache[cacheIndex].transform;
|
||||
followers[followers.Count-1].trailRenderer = referenceObjectsCache[cacheIndex].trailRenderer;
|
||||
followers[followers.Count-1].particleId = follower.particleId;
|
||||
followers[followers.Count-1].transform.position = particles.playgroundCache.position[followers[followers.Count-1].particleId];
|
||||
if (followers[followers.Count-1].trailRenderer!=null)
|
||||
followers[followers.Count-1].trailRenderer.time = trailTime;
|
||||
if (sendEvents && followerEventBirth!=null)
|
||||
followerEventBirth(followers[followers.Count-1]);
|
||||
NextCacheIndex();
|
||||
}
|
||||
|
||||
void RemoveFollower (int i)
|
||||
{
|
||||
if (sendEvents && followerEventDeath!=null)
|
||||
followerEventDeath(followers[i]);
|
||||
followers[i].enabled = false;
|
||||
if (followers[i].trailRenderer!=null)
|
||||
followers[i].trailRenderer.time = 0;
|
||||
followers[i].gameObject.SetActive(false);
|
||||
followers.RemoveAt(i);
|
||||
}
|
||||
|
||||
void NextCacheIndex ()
|
||||
{
|
||||
cacheIndex = (cacheIndex+1)%referenceObjectsCache.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an active follower at index. This will only return active followers.
|
||||
/// </summary>
|
||||
/// <returns>The active follower.</returns>
|
||||
/// <param name="index">Index.</param>
|
||||
public PlaygroundFollower GetActiveFollower (int index)
|
||||
{
|
||||
index = Mathf.Clamp (index, 0, followers.Count);
|
||||
return followers[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a cached follower at index. This can return inactive followers waiting for their turn to be enabled.
|
||||
/// </summary>
|
||||
/// <returns>The cached follower.</returns>
|
||||
/// <param name="index">Index.</param>
|
||||
public PlaygroundFollower GetCachedFollower (int index)
|
||||
{
|
||||
index = Mathf.Clamp (index, 0, referenceObjectsCache.Length);
|
||||
return referenceObjectsCache[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of active followers.
|
||||
/// </summary>
|
||||
/// <returns>The active followers count.</returns>
|
||||
public int GetActiveFollowersCount ()
|
||||
{
|
||||
return followers.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of cached followers.
|
||||
/// </summary>
|
||||
/// <returns>The cached followers count.</returns>
|
||||
public int GetCachedFollowersCount ()
|
||||
{
|
||||
return referenceObjectsCache.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Playground follower class.
|
||||
/// </summary>
|
||||
public class PlaygroundFollower {
|
||||
public bool enabled = true;
|
||||
public float lifetime;
|
||||
public Transform transform;
|
||||
public GameObject gameObject;
|
||||
public TrailRenderer trailRenderer;
|
||||
public int particleId;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlaygroundFollower"/> class.
|
||||
/// </summary>
|
||||
/// <param name="setTransform">Transform to reposition.</param>
|
||||
/// <param name="setLifetime">Start lifetifetime.</param>
|
||||
/// <param name="setParticleId">Particle identifier to follow.</param>
|
||||
public PlaygroundFollower (Transform setTransform, GameObject setGameObject, TrailRenderer setTrailRenderer, float setLifetime, int setParticleId)
|
||||
{
|
||||
transform = setTransform;
|
||||
gameObject = setGameObject;
|
||||
trailRenderer = setTrailRenderer;
|
||||
lifetime = setLifetime;
|
||||
particleId = setParticleId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clones this instance.
|
||||
/// </summary>
|
||||
public PlaygroundFollower Clone ()
|
||||
{
|
||||
return new PlaygroundFollower (transform, gameObject, trailRenderer, lifetime, particleId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event delegate for sending a PlaygroundFollower to any event listeners.
|
||||
/// </summary>
|
||||
public delegate void OnPlaygroundFollower(PlaygroundFollower follower);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 69a4e0a274d7945b59605c627b7dbf90
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fca2eae157067c046ae30a5902fcdcc8
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984949
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9d7ebe11a5a45774f9e587f3626d6e5a
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984949
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,83 @@
|
|||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using ParticlePlayground;
|
||||
using ParticlePlaygroundLanguage;
|
||||
|
||||
[CustomEditor (typeof(PlaygroundFollow))]
|
||||
public class PlaygroundFollowInspector : Editor {
|
||||
|
||||
PlaygroundFollow follow;
|
||||
|
||||
SerializedObject s_follow;
|
||||
SerializedProperty s_particles;
|
||||
SerializedProperty s_referenceObject;
|
||||
SerializedProperty s_followerLifetime;
|
||||
SerializedProperty s_cacheSize;
|
||||
SerializedProperty s_sendEvents;
|
||||
|
||||
// GUI
|
||||
public static GUIStyle boxStyle;
|
||||
public static PlaygroundSettingsC playgroundSettings;
|
||||
public static PlaygroundLanguageC playgroundLanguage;
|
||||
|
||||
public void OnEnable ()
|
||||
{
|
||||
follow = target as PlaygroundFollow;
|
||||
s_follow = new SerializedObject(follow);
|
||||
|
||||
s_particles = s_follow.FindProperty("particles");
|
||||
s_referenceObject = s_follow.FindProperty("referenceObject");
|
||||
s_followerLifetime = s_follow.FindProperty("followerLifetime");
|
||||
s_cacheSize = s_follow.FindProperty("cacheSize");
|
||||
s_sendEvents = s_follow.FindProperty("sendEvents");
|
||||
|
||||
playgroundSettings = PlaygroundSettingsC.GetReference();
|
||||
playgroundLanguage = PlaygroundSettingsC.GetLanguage();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI ()
|
||||
{
|
||||
if (boxStyle==null)
|
||||
boxStyle = GUI.skin.FindStyle("box");
|
||||
|
||||
s_follow.UpdateIfDirtyOrScript();
|
||||
|
||||
bool hasParticleSystem = follow.particles != null;
|
||||
if (!hasParticleSystem)
|
||||
EditorGUILayout.HelpBox(playgroundLanguage.missingParticleSystemWarning, MessageType.Warning);
|
||||
|
||||
EditorGUILayout.BeginVertical (boxStyle);
|
||||
playgroundSettings.playgroundFollowFoldout = GUILayout.Toggle(playgroundSettings.playgroundFollowFoldout, playgroundLanguage.playgroundFollow, EditorStyles.foldout);
|
||||
if (playgroundSettings.playgroundFollowFoldout)
|
||||
{
|
||||
EditorGUILayout.BeginVertical (boxStyle);
|
||||
|
||||
// Followers foldout
|
||||
int activeFollowers = follow.GetActiveFollowersCount();
|
||||
if (GUILayout.Button(playgroundLanguage.followers+" ("+(follow.referenceObject==null?playgroundLanguage.unassigned : activeFollowers.ToString())+")", EditorStyles.toolbarDropDown)) playgroundSettings.followFollowersFoldout=!playgroundSettings.followFollowersFoldout;
|
||||
if (playgroundSettings.followFollowersFoldout)
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.PropertyField(s_referenceObject, new GUIContent(playgroundLanguage.referenceObject));
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
if (GUILayout.Button(playgroundLanguage.advanced, EditorStyles.toolbarDropDown)) playgroundSettings.followAdvancedFoldout=!playgroundSettings.followAdvancedFoldout;
|
||||
if (playgroundSettings.followAdvancedFoldout)
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.PropertyField(s_particles, new GUIContent(playgroundLanguage.particleSystem, "The particle system to follow within the scene."));
|
||||
EditorGUILayout.PropertyField(s_followerLifetime, new GUIContent(playgroundLanguage.lifetime, "The lifetime of the followers, when set to 0 the followers will get automatically controlled lifetime based on the particles."));
|
||||
EditorGUILayout.PropertyField(s_cacheSize, new GUIContent(playgroundLanguage.cacheSize, "The object pool of the followers, when set to 0 the pool will be sized to match their lifetime."));
|
||||
EditorGUILayout.PropertyField(s_sendEvents, new GUIContent(playgroundLanguage.sendEvents, "Determines if the followers should broadcast events upon birth and death."));
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
s_follow.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c8afa032381aa42a1a9c9162ea41d166
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 27a1b15eb416264479979c2f2f014038
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984948
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,82 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace ParticlePlayground {
|
||||
|
||||
/// <summary>
|
||||
/// The Particle Playground Multi Recorder enables playback and scrubbing of multiple recorded synchronized particle systems.
|
||||
/// </summary>
|
||||
public class PlaygroundMultiRecorder : MonoBehaviour {
|
||||
|
||||
/// <summary>
|
||||
/// The Particle Playground Recorders you wish to record/playback from.
|
||||
/// </summary>
|
||||
public PlaygroundRecorder[] playgroundRecorders;
|
||||
|
||||
public void StartRecording (float frameIntervalInSeconds)
|
||||
{
|
||||
for (int i = 0; i<playgroundRecorders.Length; i++)
|
||||
playgroundRecorders[i].StartRecording(frameIntervalInSeconds);
|
||||
}
|
||||
|
||||
public void StartRecording (float recordingLength, float frameIntervalInSeconds)
|
||||
{
|
||||
for (int i = 0; i<playgroundRecorders.Length; i++)
|
||||
playgroundRecorders[i].StartRecording(recordingLength, frameIntervalInSeconds);
|
||||
}
|
||||
|
||||
public void RecordOneFrame ()
|
||||
{
|
||||
for (int i = 0; i<playgroundRecorders.Length; i++)
|
||||
playgroundRecorders[i].RecordOneFrame();
|
||||
}
|
||||
|
||||
public void InsertOneFrame (int frame)
|
||||
{
|
||||
for (int i = 0; i<playgroundRecorders.Length; i++)
|
||||
playgroundRecorders[i].InsertOneFrame(frame);
|
||||
}
|
||||
|
||||
public void StopRecording ()
|
||||
{
|
||||
for (int i = 0; i<playgroundRecorders.Length; i++)
|
||||
playgroundRecorders[i].StopRecording();
|
||||
}
|
||||
|
||||
public void ClearRecording ()
|
||||
{
|
||||
for (int i = 0; i<playgroundRecorders.Length; i++)
|
||||
playgroundRecorders[i].ClearRecording();
|
||||
}
|
||||
|
||||
public void Play (float speed)
|
||||
{
|
||||
for (int i = 0; i<playgroundRecorders.Length; i++)
|
||||
playgroundRecorders[i].Play(speed);
|
||||
}
|
||||
|
||||
public void Play (float fromNormalizedTime, float speed, bool repeat)
|
||||
{
|
||||
for (int i = 0; i<playgroundRecorders.Length; i++)
|
||||
playgroundRecorders[i].Play(fromNormalizedTime, speed, repeat);
|
||||
}
|
||||
|
||||
public void Stop ()
|
||||
{
|
||||
for (int i = 0; i<playgroundRecorders.Length; i++)
|
||||
playgroundRecorders[i].Stop();
|
||||
}
|
||||
|
||||
public void Pause ()
|
||||
{
|
||||
for (int i = 0; i<playgroundRecorders.Length; i++)
|
||||
playgroundRecorders[i].Pause();
|
||||
}
|
||||
|
||||
public void Scrub (float normalizedTime)
|
||||
{
|
||||
for (int i = 0; i<playgroundRecorders.Length; i++)
|
||||
playgroundRecorders[i].Scrub(normalizedTime);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f58689db6f7e049468c12a0774b78a88
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 862e30d6db16744f0b75c4c2b1a6418c
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fb029d4f11194b9488546682b95a95f5
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984949
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 307516dc12f418a49a2fc0045bfc9dde
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984949
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,294 @@
|
|||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ParticlePlayground;
|
||||
using ParticlePlaygroundLanguage;
|
||||
|
||||
[CustomEditor (typeof(PlaygroundRecorder))]
|
||||
public class PlaygroundRecorderInspector : Editor {
|
||||
|
||||
// References
|
||||
PlaygroundRecorder recorder;
|
||||
|
||||
// GUI
|
||||
public static GUIStyle boxStyle;
|
||||
public static PlaygroundSettingsC playgroundSettings;
|
||||
public static PlaygroundLanguageC playgroundLanguage;
|
||||
|
||||
// Trimming
|
||||
private bool _inTrimming;
|
||||
private float _leftTrimPos = 0;
|
||||
private float _rightTrimPos = 1f;
|
||||
private bool _leftWasLastMoved = true;
|
||||
|
||||
void OnEnable ()
|
||||
{
|
||||
// Set references
|
||||
recorder = target as PlaygroundRecorder;
|
||||
|
||||
// Load settings
|
||||
playgroundSettings = PlaygroundSettingsC.GetReference();
|
||||
|
||||
// Load language
|
||||
playgroundLanguage = PlaygroundSettingsC.GetLanguage();
|
||||
|
||||
// Load data
|
||||
if (recorder.recorderData != null)
|
||||
recorder.LoadAsync();
|
||||
else
|
||||
recorder.recordedFrames = new List<RecordedFrame>();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI ()
|
||||
{
|
||||
if (boxStyle==null)
|
||||
boxStyle = GUI.skin.FindStyle("box");
|
||||
|
||||
bool hasParticleSystem = recorder.playgroundSystem != null;
|
||||
if (!hasParticleSystem)
|
||||
EditorGUILayout.HelpBox(playgroundLanguage.missingParticleSystemWarning, MessageType.Warning);
|
||||
bool hasRecorderData = recorder.recorderData != null;
|
||||
|
||||
EditorGUILayout.BeginVertical (boxStyle);
|
||||
playgroundSettings.playgroundRecorderFoldout = GUILayout.Toggle(playgroundSettings.playgroundRecorderFoldout, playgroundLanguage.playgroundRecorder, EditorStyles.foldout);
|
||||
if (playgroundSettings.playgroundRecorderFoldout)
|
||||
{
|
||||
EditorGUILayout.BeginVertical (boxStyle);
|
||||
|
||||
// Playback & Recorder foldout
|
||||
if (GUILayout.Button(playgroundLanguage.player, EditorStyles.toolbarDropDown)) playgroundSettings.recorderPlaybackFoldout=!playgroundSettings.recorderPlaybackFoldout;
|
||||
if (playgroundSettings.recorderPlaybackFoldout)
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
if (!hasRecorderData)
|
||||
{
|
||||
EditorGUILayout.BeginVertical(boxStyle);
|
||||
EditorGUILayout.HelpBox(playgroundLanguage.missingRecorderDataWarning, MessageType.Warning);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button(playgroundLanguage.createNew, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
PlaygroundRecorderData newData = CreateNewRecorderDataDialogue();
|
||||
if (newData!=null)
|
||||
recorder.recorderData = newData;
|
||||
}
|
||||
recorder.recorderData = (PlaygroundRecorderData)EditorGUILayout.ObjectField(recorder.recorderData, typeof(PlaygroundRecorderData), false);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.EndVertical();
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
GUI.enabled = !recorder.IsRecording() && hasParticleSystem && recorder.HasRecordedFrames();
|
||||
if (GUILayout.Button (recorder.IsReplaying()? playgroundLanguage.pauseSymbol : playgroundLanguage.playSymbol, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
if (recorder.IsReplaying())
|
||||
recorder.Pause();
|
||||
else
|
||||
recorder.Play(recorder.playHead, recorder.playbackSpeed, recorder.loopPlayback);
|
||||
}
|
||||
GUI.enabled = hasParticleSystem && recorder.HasRecordedFrames();
|
||||
|
||||
if (GUILayout.Button (playgroundLanguage.stopSymbol, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
if (recorder.IsInPlayback())
|
||||
recorder.SetParticleSystemAsCurrentPlayback();
|
||||
else
|
||||
{
|
||||
recorder.StopAndSerialize();
|
||||
recorder.playHead = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GUI.enabled = hasParticleSystem;
|
||||
|
||||
if (recorder.IsRecording())
|
||||
GUI.color = Color.red;
|
||||
|
||||
GUILayout.Space(4f);
|
||||
|
||||
if (GUILayout.Button (playgroundLanguage.recordSymbol, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
if (!recorder.IsRecording())
|
||||
recorder.StartRecording();
|
||||
else
|
||||
{
|
||||
recorder.StopAndSerialize();
|
||||
recorder.playHead = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GUI.color = Color.white;
|
||||
|
||||
GUI.enabled = recorder.HasRecordedFrames() && hasParticleSystem;
|
||||
if (GUILayout.Button (playgroundLanguage.clear, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog(playgroundLanguage.clearRecording, playgroundLanguage.clearRecordingMsg, playgroundLanguage.yes, playgroundLanguage.no))
|
||||
recorder.ClearRecording();
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
_inTrimming = GUILayout.Toggle (_inTrimming, playgroundLanguage.trim, EditorStyles.toolbarButton);
|
||||
|
||||
GUI.enabled = true;
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
GUI.enabled = recorder.HasRecordedFrames();
|
||||
|
||||
float currentPlayHead = recorder.playHead;
|
||||
|
||||
if (!_inTrimming)
|
||||
recorder.playHead = EditorGUILayout.Slider(playgroundLanguage.playHeadPosition, recorder.playHead, 0, 1f);
|
||||
else
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
EditorGUILayout.Separator();
|
||||
if (GUILayout.Button (playgroundLanguage.trimOuter, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
string framesRemoved = "[0-"+recorder.GetFrameAtTime(_leftTrimPos)+"] - ["+recorder.GetFrameAtTime(_rightTrimPos)+"-"+recorder.FrameCount()+"]";
|
||||
if (EditorUtility.DisplayDialog(playgroundLanguage.trim, playgroundLanguage.trimMsg+framesRemoved+"?", playgroundLanguage.yes, playgroundLanguage.no))
|
||||
if (recorder.Trim(_leftTrimPos, _rightTrimPos))
|
||||
{
|
||||
_leftTrimPos = 0;
|
||||
_rightTrimPos = 1f;
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button (playgroundLanguage.trimInner, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
string framesRemoved = "["+recorder.GetFrameAtTime(_leftTrimPos)+"-"+recorder.GetFrameAtTime(_rightTrimPos)+"]";
|
||||
if (EditorUtility.DisplayDialog(playgroundLanguage.trim, playgroundLanguage.trimMsg+framesRemoved+"?", playgroundLanguage.yes, playgroundLanguage.no))
|
||||
{
|
||||
recorder.TrimInner(_leftTrimPos, _rightTrimPos);
|
||||
_leftTrimPos = 0;
|
||||
_rightTrimPos = 1f;
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
float l = _leftTrimPos;
|
||||
float r = _rightTrimPos;
|
||||
EditorGUILayout.MinMaxSlider(ref _leftTrimPos, ref _rightTrimPos, 0, 1f);
|
||||
|
||||
|
||||
if (!Mathf.Approximately(_leftTrimPos, l))
|
||||
_leftWasLastMoved = true;
|
||||
if (!Mathf.Approximately(_rightTrimPos, r))
|
||||
_leftWasLastMoved = false;
|
||||
|
||||
if (!recorder.IsReplaying())
|
||||
recorder.playHead = _leftWasLastMoved? _leftTrimPos : _rightTrimPos;
|
||||
else
|
||||
_leftWasLastMoved = true;
|
||||
|
||||
if (recorder.playHead >= _rightTrimPos && recorder.IsReplaying())
|
||||
recorder.playHead = _leftTrimPos;
|
||||
if (recorder.playHead < _leftTrimPos && recorder.IsReplaying() && recorder.playbackSpeed>0)
|
||||
recorder.playHead = _leftTrimPos;
|
||||
if (recorder.playHead <= _leftTrimPos && (!_leftWasLastMoved || recorder.IsReplaying() && recorder.playbackSpeed<0))
|
||||
recorder.playHead = _rightTrimPos;
|
||||
}
|
||||
|
||||
if (currentPlayHead != recorder.playHead)
|
||||
recorder.Scrub (recorder.playHead);
|
||||
|
||||
string playbackStatus = "No Recording";
|
||||
string playbackData = "";
|
||||
float recordedSeconds = ((recorder.FrameCount()*1f) * recorder.keyframeInterval) / recorder.playbackSpeed;
|
||||
|
||||
if (_inTrimming)
|
||||
{
|
||||
playbackStatus = "TRIMMING";
|
||||
GUI.color = Color.yellow;
|
||||
}
|
||||
else if (recorder.IsRecording())
|
||||
{
|
||||
playbackStatus = "RECORDING";
|
||||
GUI.color = Color.red;
|
||||
}
|
||||
else if (recorder.IsInPlayback())
|
||||
{
|
||||
playbackStatus = "In Playback";
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else if (!recorder.IsInPlayback() && recorder.HasRecordedFrames())
|
||||
{
|
||||
playbackStatus = "Live Particles";
|
||||
GUI.color = Color.cyan;
|
||||
}
|
||||
if (recorder.HasRecordedFrames() && recorder.IsInPlayback())
|
||||
{
|
||||
if (_inTrimming)
|
||||
playbackData = " (Left: " + recorder.GetFrameAtTime(_leftTrimPos) + " | Right: " + recorder.GetFrameAtTime(_rightTrimPos) + ")";
|
||||
else if (!recorder.IsRecording())
|
||||
playbackData = " (" + (recordedSeconds*recorder.playHead).ToString("F1") + "/" + recordedSeconds.ToString("F1") + " s)";
|
||||
else if (!_inTrimming)
|
||||
playbackData = " (" + (recordedSeconds).ToString("F1") + " s)";
|
||||
}
|
||||
PlaybackBar(recorder.HasRecordedFrames()? (recorder.IsRecording()? 1f : recorder.playHead) : 0, playbackStatus + playbackData, Screen.width - 56f);
|
||||
|
||||
GUI.color = Color.white;
|
||||
GUI.backgroundColor = Color.white;
|
||||
GUILayout.Space (-10f);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Time: " + (recorder.HasRecordedFrames()?(recordedSeconds*recorder.playHead).ToString("F1") + " / " + recordedSeconds.ToString("F1") + " s" + " (" + recorder.playbackSpeed.ToString("F1") + "x)" : "-"), EditorStyles.objectFieldThumb, GUILayout.Width ((Screen.width/2f)-30f));
|
||||
EditorGUILayout.LabelField("Frame: " + (recorder.HasRecordedFrames()?recorder.GetFrameAtTime(recorder.playHead).ToString() + " / " + recorder.FrameCount() : "-"), EditorStyles.objectFieldThumb, GUILayout.Width ((Screen.width/2f)-30f));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUI.enabled = true;
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
// Advanced foldout
|
||||
if (GUILayout.Button(playgroundLanguage.advanced, EditorStyles.toolbarDropDown)) playgroundSettings.recorderAdvancedFoldout=!playgroundSettings.recorderAdvancedFoldout;
|
||||
if (playgroundSettings.recorderAdvancedFoldout)
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
recorder.playgroundSystem = (PlaygroundParticlesC)EditorGUILayout.ObjectField(playgroundLanguage.particleSystem, recorder.playgroundSystem, typeof(PlaygroundParticlesC), true);
|
||||
recorder.recorderData = (PlaygroundRecorderData)EditorGUILayout.ObjectField(playgroundLanguage.recorderData, recorder.recorderData, typeof(PlaygroundRecorderData), false);
|
||||
recorder.keyframeInterval = EditorGUILayout.FloatField(playgroundLanguage.keyframeInterval, recorder.keyframeInterval);
|
||||
recorder.playbackSpeed = EditorGUILayout.FloatField(playgroundLanguage.playbackSpeed, recorder.playbackSpeed);
|
||||
recorder.loopPlayback = GUILayout.Toggle (recorder.loopPlayback, playgroundLanguage.loop);
|
||||
recorder.fadeIn = GUILayout.Toggle (recorder.fadeIn, playgroundLanguage.fadeIn);
|
||||
recorder.sizeIn = GUILayout.Toggle (recorder.sizeIn, playgroundLanguage.sizeIn);
|
||||
recorder.skipInterpolationOnEndFrames = GUILayout.Toggle (recorder.skipInterpolationOnEndFrames, playgroundLanguage.skipInterpolationOnEndFrames);
|
||||
recorder.localSpaceOnPlayback = GUILayout.Toggle (recorder.localSpaceOnPlayback, playgroundLanguage.setLocalSpaceOnPlayback);
|
||||
recorder.multithreading = GUILayout.Toggle (recorder.multithreading, playgroundLanguage.multithreading);
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
public void PlaybackBar (float val, string label, float width) {
|
||||
Rect rect = GUILayoutUtility.GetRect (18, 18, "TextField");
|
||||
rect.width = width;
|
||||
rect.height = 16;
|
||||
if (val<0) val = 0;
|
||||
EditorGUI.ProgressBar (rect, val, label);
|
||||
EditorGUILayout.Space ();
|
||||
}
|
||||
|
||||
public static PlaygroundRecorderData CreateNewRecorderDataDialogue ()
|
||||
{
|
||||
string dataPath = EditorUtility.SaveFilePanelInProject(playgroundLanguage.newPlaygroundRecording, "PlaygroundRecording", "asset", playgroundLanguage.newPlaygroundRecordingMsg);
|
||||
if (dataPath.Length>0)
|
||||
{
|
||||
PlaygroundRecorderData newData = PlaygroundRecorderData.New();
|
||||
AssetDatabase.CreateAsset(newData, dataPath);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
return newData;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 18629149a4cb64676be45a3a0031828a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,40 @@
|
|||
#if UNITY_WSA && !UNITY_EDITOR
|
||||
#else
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Collections;
|
||||
|
||||
namespace ParticlePlayground {
|
||||
public class PlaygroundCompression
|
||||
{
|
||||
public static byte[] SerializeAndCompress(object obj)
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
using (GZipStream zs = new GZipStream(ms, CompressionMode.Compress, true))
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
bf.Serialize(zs, obj);
|
||||
}
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static T DecompressAndDeserialize<T>(byte[] data)
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream(data))
|
||||
{
|
||||
using (GZipStream zs = new GZipStream(ms, CompressionMode.Decompress, true))
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
return (T) bf.Deserialize(zs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9ea72fd6ac8fa4185a40b701662e4bbb
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,60 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ParticlePlayground;
|
||||
|
||||
[Serializable]
|
||||
public class PlaygroundRecorderData : ScriptableObject
|
||||
{
|
||||
[HideInInspector] public float version;
|
||||
public SerializedFrame[] serializedFrames;
|
||||
|
||||
public void Serialize (List<RecordedFrame> recordedFrames)
|
||||
{
|
||||
version = PlaygroundC.version;
|
||||
serializedFrames = null;
|
||||
serializedFrames = new SerializedFrame[recordedFrames.Count];
|
||||
for (int i = 0; i<serializedFrames.Length; i++)
|
||||
serializedFrames[i] = recordedFrames[i].CloneAsSerializedFrame();
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SerializeAsync (List<RecordedFrame> recordedFrames)
|
||||
{
|
||||
version = PlaygroundC.version;
|
||||
PlaygroundC.RunAsync(() => {
|
||||
serializedFrames = null;
|
||||
serializedFrames = new SerializedFrame[recordedFrames.Count];
|
||||
for (int i = 0; i<serializedFrames.Length; i++)
|
||||
serializedFrames[i] = recordedFrames[i].CloneAsSerializedFrame();
|
||||
});
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
public List<RecordedFrame> CloneAsRecordedFrames ()
|
||||
{
|
||||
if (serializedFrames == null)
|
||||
return null;
|
||||
List<RecordedFrame> recordedFrames = new List<RecordedFrame>();
|
||||
for (int i = 0; i<serializedFrames.Length; i++)
|
||||
{
|
||||
recordedFrames.Add(serializedFrames[i].CloneAsRecordedFrame());
|
||||
}
|
||||
return recordedFrames;
|
||||
}
|
||||
|
||||
public void Clear ()
|
||||
{
|
||||
serializedFrames = null;
|
||||
}
|
||||
|
||||
public static PlaygroundRecorderData New () {
|
||||
PlaygroundRecorderData newData = ScriptableObject.CreateInstance<PlaygroundRecorderData>();
|
||||
return newData;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c8586836ef5a445d4b801f769230e702
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,93 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ParticlePlayground {
|
||||
/// <summary>
|
||||
/// The RecordedFrame class contain information of a single frame of recorded particles for the Playground Recorder's recorded data.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class RecordedFrame {
|
||||
/// <summary>
|
||||
/// The array of particle data. PlaybackParticle is a struct and therefore not serialized due to performance.
|
||||
/// </summary>
|
||||
[HideInInspector] public PlaybackParticle[] particles;
|
||||
/// <summary>
|
||||
/// The time during simulation this frame was made.
|
||||
/// </summary>
|
||||
[HideInInspector] public float timeStamp;
|
||||
/// <summary>
|
||||
/// The keyframe interval setting when this frame was made.
|
||||
/// </summary>
|
||||
[HideInInspector] public float keyframeInterval;
|
||||
/// <summary>
|
||||
/// The type of this frame (FrameType.Start, FrameType.Middle or FrameType.End).
|
||||
/// </summary>
|
||||
[HideInInspector] public FrameType frameType = FrameType.Middle;
|
||||
|
||||
public RecordedFrame () {}
|
||||
|
||||
public RecordedFrame (PlaygroundParticlesC playgroundParticles, float keyframeInterval) {
|
||||
particles = new PlaybackParticle[playgroundParticles.particleCache.Length];
|
||||
for (int i = 0; i<particles.Length; i++)
|
||||
{
|
||||
particles[i] = new PlaybackParticle(
|
||||
playgroundParticles.playgroundCache.position[i],
|
||||
playgroundParticles.playgroundCache.velocity[i],
|
||||
playgroundParticles.playgroundCache.rotation[i],
|
||||
playgroundParticles.playgroundCache.size[i],
|
||||
playgroundParticles.particleCache[i].lifetime,
|
||||
playgroundParticles.particleCache[i].startLifetime,
|
||||
playgroundParticles.playgroundCache.life[i],
|
||||
playgroundParticles.playgroundCache.birth[i],
|
||||
playgroundParticles.playgroundCache.death[i],
|
||||
playgroundParticles.playgroundCache.lifetimeSubtraction[i],
|
||||
playgroundParticles.playgroundCache.color[i],
|
||||
|
||||
playgroundParticles.playgroundCache.targetPosition[i],
|
||||
playgroundParticles.playgroundCache.initialSize[i]
|
||||
);
|
||||
}
|
||||
timeStamp = Time.realtimeSinceStartup;
|
||||
this.keyframeInterval = keyframeInterval;
|
||||
}
|
||||
|
||||
public RecordedFrame Clone ()
|
||||
{
|
||||
RecordedFrame recordedFrame = new RecordedFrame();
|
||||
recordedFrame.particles = (PlaybackParticle[])particles.Clone();
|
||||
recordedFrame.timeStamp = timeStamp;
|
||||
recordedFrame.frameType = frameType;
|
||||
return recordedFrame;
|
||||
}
|
||||
|
||||
public ParticleSystem.Particle[] CloneAsParticles ()
|
||||
{
|
||||
ParticleSystem.Particle[] p = new ParticleSystem.Particle[particles.Length];
|
||||
for (int i = 0; i<p.Length; i++)
|
||||
{
|
||||
p[i] = particles[i].CloneAsParticle();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
public SerializedFrame CloneAsSerializedFrame ()
|
||||
{
|
||||
SerializedFrame serializedFrame = new SerializedFrame();
|
||||
serializedFrame.serializedParticles = CloneAsSerializedParticles();
|
||||
serializedFrame.keyframeInterval = keyframeInterval;
|
||||
serializedFrame.timeStamp = timeStamp;
|
||||
serializedFrame.frameType = frameType;
|
||||
return serializedFrame;
|
||||
}
|
||||
|
||||
public SerializedParticle[] CloneAsSerializedParticles ()
|
||||
{
|
||||
SerializedParticle[] serializedParticles = new SerializedParticle[particles.Length];
|
||||
for (int i = 0; i<serializedParticles.Length; i++)
|
||||
serializedParticles[i] = particles[i].CloneAsSerializedParticle();
|
||||
return serializedParticles;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b98b0f52a1a5d4b12a4f9ce463c35185
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,49 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ParticlePlayground {
|
||||
|
||||
/// <summary>
|
||||
/// A serialized frame holds information about one recorded frame of particles.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SerializedFrame
|
||||
{
|
||||
/// <summary>
|
||||
/// The array of particle data.
|
||||
/// </summary>
|
||||
public SerializedParticle[] serializedParticles;
|
||||
/// <summary>
|
||||
/// The time during simulation this frame was made.
|
||||
/// </summary>
|
||||
public float timeStamp;
|
||||
/// <summary>
|
||||
/// The keyframe interval setting when this frame was made.
|
||||
/// </summary>
|
||||
public float keyframeInterval;
|
||||
/// <summary>
|
||||
/// The type of this frame (FrameType.Start, FrameType.Middle or FrameType.End).
|
||||
/// </summary>
|
||||
public FrameType frameType = FrameType.Middle;
|
||||
|
||||
public RecordedFrame CloneAsRecordedFrame ()
|
||||
{
|
||||
RecordedFrame recordedFrame = new RecordedFrame();
|
||||
recordedFrame.particles = CloneAsPlaybackParticles();
|
||||
recordedFrame.keyframeInterval = keyframeInterval;
|
||||
recordedFrame.timeStamp = timeStamp;
|
||||
recordedFrame.frameType = frameType;
|
||||
return recordedFrame;
|
||||
}
|
||||
|
||||
public PlaybackParticle[] CloneAsPlaybackParticles ()
|
||||
{
|
||||
PlaybackParticle[] recordedParticles = new PlaybackParticle[serializedParticles.Length];
|
||||
for (int i = 0; i<serializedParticles.Length; i++)
|
||||
recordedParticles[i] = serializedParticles[i].CloneAsPlaybackParticle();
|
||||
return recordedParticles;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d40e09164bba5450ea41104c1cfa3658
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,82 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ParticlePlayground {
|
||||
|
||||
/// <summary>
|
||||
/// A serialized particle holds information for one single serializable particle inside a recorded frame for the Playground Recorder's recorded data.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SerializedParticle
|
||||
{
|
||||
public Vector3 position;
|
||||
public Vector3 velocity;
|
||||
public float rotation;
|
||||
public float size;
|
||||
public float lifetime;
|
||||
public float startLifetime;
|
||||
public float playgroundLife;
|
||||
public float playgroundStartLifetime;
|
||||
public float playgroundEndLifetime;
|
||||
public float playgroundLifetimeSubtraction;
|
||||
public Color32 color;
|
||||
|
||||
public Vector3 sourcePosition;
|
||||
public float startingSize;
|
||||
|
||||
public SerializedParticle (Vector3 position,
|
||||
Vector3 velocity,
|
||||
float rotation,
|
||||
float size,
|
||||
float lifetime,
|
||||
float startLifetime,
|
||||
float playgroundLife,
|
||||
float playgroundStartLifetime,
|
||||
float playgroundEndLifetime,
|
||||
float playgroundLifetimeSubtraction,
|
||||
Color32 color,
|
||||
|
||||
Vector3 sourcePosition,
|
||||
float startingSize
|
||||
)
|
||||
{
|
||||
this.position = position;
|
||||
this.velocity = velocity;
|
||||
this.rotation = rotation;
|
||||
this.size = size;
|
||||
this.lifetime = lifetime;
|
||||
this.startLifetime = startLifetime;
|
||||
this.playgroundLife = playgroundLife;
|
||||
this.playgroundStartLifetime = playgroundStartLifetime;
|
||||
this.playgroundEndLifetime = playgroundEndLifetime;
|
||||
this.playgroundLifetimeSubtraction = playgroundLifetimeSubtraction;
|
||||
this.color = color;
|
||||
|
||||
this.sourcePosition = sourcePosition;
|
||||
this.startingSize = startingSize;
|
||||
}
|
||||
|
||||
public PlaybackParticle CloneAsPlaybackParticle ()
|
||||
{
|
||||
PlaybackParticle particle = new PlaybackParticle(
|
||||
position,
|
||||
velocity,
|
||||
rotation,
|
||||
size,
|
||||
lifetime,
|
||||
startLifetime,
|
||||
playgroundLife,
|
||||
playgroundStartLifetime,
|
||||
playgroundEndLifetime,
|
||||
playgroundLifetimeSubtraction,
|
||||
color,
|
||||
|
||||
sourcePosition,
|
||||
startingSize
|
||||
);
|
||||
return particle;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0ed99384141a34198b4a872162f33568
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b248ca5b01a7c4140b1506e64e18065e
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984948
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ea1c64bb5c0b49d409932c31a1af37c3
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984949
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,520 @@
|
|||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using PlaygroundSplines;
|
||||
using ParticlePlayground;
|
||||
using ParticlePlaygroundLanguage;
|
||||
|
||||
[CustomEditor(typeof(PlaygroundSpline))]
|
||||
public class PlaygroundSplineInspector : Editor {
|
||||
|
||||
private const int stepsPerCurve = 10;
|
||||
private const float directionScale = 0.5f;
|
||||
private const float handleSize = 0.04f;
|
||||
private const float pickSize = 0.06f;
|
||||
|
||||
private PlaygroundSpline spline;
|
||||
private Transform handleTransform;
|
||||
private Quaternion handleRotation;
|
||||
private Quaternion bezierHandleRotation;
|
||||
private int selectedIndex = -1;
|
||||
private int selectedNode = -1;
|
||||
private int selectedBezier = -1;
|
||||
private bool selectedIndexIsNode;
|
||||
private UnityEditor.Tool lastActiveTool = UnityEditor.Tool.None;
|
||||
|
||||
public static PlaygroundSettingsC playgroundSettings;
|
||||
public static PlaygroundLanguageC playgroundLanguage;
|
||||
public static GUIStyle boxStyle;
|
||||
|
||||
void OnEnable () {
|
||||
spline = target as PlaygroundSpline;
|
||||
|
||||
playgroundSettings = PlaygroundSettingsC.GetReference();
|
||||
playgroundLanguage = PlaygroundSettingsC.GetLanguage();
|
||||
|
||||
lastActiveTool = UnityEditor.Tools.current;
|
||||
|
||||
UpdateUserList();
|
||||
}
|
||||
|
||||
void OnDisable () {
|
||||
UnityEditor.Tools.current = lastActiveTool;
|
||||
}
|
||||
|
||||
void UpdateUserList () {
|
||||
|
||||
// Check that any user isn't null
|
||||
for (int i = 0; i<spline.usedBy.Count; i++) {
|
||||
if (spline.usedBy[i]==null || !spline.usedBy[i].GetComponent<PlaygroundParticlesC>().splines.Contains(spline)) {
|
||||
spline.usedBy.RemoveAt (i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI () {
|
||||
if (boxStyle==null)
|
||||
boxStyle = GUI.skin.FindStyle("box");
|
||||
|
||||
EditorGUILayout.BeginVertical(boxStyle);
|
||||
playgroundSettings.playgroundSplineFoldout = GUILayout.Toggle(playgroundSettings.playgroundSplineFoldout, playgroundLanguage.playgroundSpline, EditorStyles.foldout);
|
||||
if (playgroundSettings.playgroundSplineFoldout) {
|
||||
|
||||
selectedNode = (selectedIndex+1)/3;
|
||||
selectedBezier = selectedIndex<3?0:(((selectedIndex)%3))%2;
|
||||
selectedIndexIsNode = selectedIndex==0||selectedIndex%3==0;
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
bool currentLoop = spline.Loop;
|
||||
GUI.enabled = spline.NodeCount>1;
|
||||
bool loop = EditorGUILayout.Toggle(playgroundLanguage.loop, spline.Loop);
|
||||
GUI.enabled = true;
|
||||
spline.reverse = EditorGUILayout.Toggle(playgroundLanguage.reverse, spline.reverse);
|
||||
spline.timeOffset = EditorGUILayout.Slider (playgroundLanguage.timeOffset, spline.timeOffset, 0, 1f);
|
||||
spline.positionOffset = EditorGUILayout.Vector3Field (playgroundLanguage.positionOffset, spline.positionOffset);
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.BeginVertical(boxStyle);
|
||||
if (selectedIndex < spline.ControlPointCount) {
|
||||
DrawSelectedPointInspector();
|
||||
}
|
||||
if (currentLoop!=loop) {
|
||||
Undo.RecordObject(spline, "Toggle Loop");
|
||||
EditorUtility.SetDirty(spline);
|
||||
spline.Loop = loop;
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
// List of nodes
|
||||
if (GUILayout.Button(playgroundLanguage.nodes+" ("+(spline.NodeCount+1)+")", EditorStyles.toolbarDropDown)) playgroundSettings.nodesFoldout=!playgroundSettings.nodesFoldout;
|
||||
if (playgroundSettings.nodesFoldout) {
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
EditorGUILayout.BeginVertical(boxStyle, GUILayout.MinHeight(26));
|
||||
for (int i = 0; i<=spline.NodeCount; i++) {
|
||||
if (i==selectedNode && selectedIndex>-1) GUI.backgroundColor = new Color(1f,1f,.2f);
|
||||
EditorGUILayout.BeginVertical(boxStyle);
|
||||
GUI.backgroundColor = Color.white;
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
// Node
|
||||
if (i==selectedNode && selectedIndexIsNode)
|
||||
EditorGUILayout.LabelField("", EditorStyles.foldout, GUILayout.Width(14));
|
||||
else if (i==selectedNode && selectedIndex!=-1) GUILayout.Space (19f);
|
||||
if (GUILayout.Button(playgroundLanguage.node+" "+i+" ("+spline.GetControlPointMode(i*3).ToString()+")", EditorStyles.label, GUILayout.MaxWidth(130)))
|
||||
selectedIndex = SelectIndex(i*3);
|
||||
GUILayout.Space(3f);
|
||||
if (GUILayout.Button(spline.transformNodes[i*3].enabled?playgroundLanguage.transform:playgroundLanguage.vector3, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))){
|
||||
spline.transformNodes[i*3].enabled = !spline.transformNodes[i*3].enabled;
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUIUtility.labelWidth = 1f;
|
||||
Vector3 point;
|
||||
if (spline.transformNodes[i*3].enabled) {
|
||||
spline.transformNodes[i*3].transform = (Transform)EditorGUILayout.ObjectField(spline.transformNodes[i*3].transform, typeof(Transform), true);
|
||||
if (spline.transformNodes[i*3].IsAvailable())
|
||||
point = spline.transformNodes[i*3].GetPosition();
|
||||
else point = spline.GetControlPoint(i*3);
|
||||
} else point = EditorGUILayout.Vector3Field(" ", spline.GetControlPoint(i*3));
|
||||
|
||||
EditorGUIUtility.labelWidth = 0;
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
Undo.RecordObject(spline, "Move Point");
|
||||
EditorUtility.SetDirty(spline);
|
||||
spline.SetControlPoint(i*3, point);
|
||||
}
|
||||
if(GUILayout.Button(playgroundLanguage.upSymbol, EditorStyles.toolbarButton, new GUILayoutOption[]{GUILayout.Width(18), GUILayout.Height(16)})){
|
||||
|
||||
}
|
||||
if(GUILayout.Button(playgroundLanguage.downSymbol, EditorStyles.toolbarButton, new GUILayoutOption[]{GUILayout.Width(18), GUILayout.Height(16)})){
|
||||
|
||||
}
|
||||
EditorGUI.BeginChangeCheck();
|
||||
if (GUILayout.Button("+", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) {
|
||||
Undo.RecordObject(spline, "Add Node");
|
||||
spline.AddNode(i);
|
||||
EditorUtility.SetDirty(spline);
|
||||
selectedIndex = SelectIndex((i+1)*3);
|
||||
}
|
||||
GUI.enabled = (!spline.Loop&&spline.NodeCount>1||spline.Loop&&spline.NodeCount>2);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
if (GUILayout.Button("-", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) {
|
||||
Undo.RecordObject(spline, "Remove Node");
|
||||
spline.RemoveNode(i);
|
||||
EditorUtility.SetDirty(spline);
|
||||
selectedIndex-=3;
|
||||
if (selectedIndex<0)
|
||||
selectedIndex = SelectIndex(0);
|
||||
return;
|
||||
}
|
||||
GUI.enabled = true;
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (i==selectedNode && selectedIndex>-1) {
|
||||
|
||||
int thisBez;
|
||||
|
||||
// Bezier 0
|
||||
if (selectedNode>0) {
|
||||
thisBez = selectedNode>0?(i*3)-1:(spline.NodeCount*3)-1;
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (selectedBezier==0 && !selectedIndexIsNode)
|
||||
EditorGUILayout.LabelField("", EditorStyles.foldout, GUILayout.Width(14));
|
||||
else GUILayout.Space (19f);
|
||||
if (GUILayout.Button(playgroundLanguage.bezier+" 0", EditorStyles.label, GUILayout.MaxWidth(133)))
|
||||
selectedIndex = SelectIndex(thisBez);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUIUtility.labelWidth = 1f;
|
||||
if (GUILayout.Button(spline.transformNodes[thisBez].enabled?playgroundLanguage.transform:playgroundLanguage.vector3, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))){
|
||||
spline.transformNodes[thisBez].enabled = !spline.transformNodes[thisBez].enabled;
|
||||
}
|
||||
if (spline.transformNodes[thisBez].enabled) {
|
||||
spline.transformNodes[thisBez].transform = (Transform)EditorGUILayout.ObjectField(spline.transformNodes[thisBez].transform, typeof(Transform), true);
|
||||
if (spline.transformNodes[thisBez].IsAvailable())
|
||||
point = spline.transformNodes[thisBez].GetPosition();
|
||||
else point = spline.GetControlPoint(thisBez);
|
||||
} else point = EditorGUILayout.Vector3Field(" ", spline.GetControlPoint(thisBez));
|
||||
|
||||
GUILayout.Space (35f);
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
Undo.RecordObject(spline, "Move Point");
|
||||
EditorUtility.SetDirty(spline);
|
||||
spline.SetControlPoint(selectedNode>0?(i*3)-1:(spline.NodeCount*3)-1, point);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUIUtility.labelWidth = 0;
|
||||
}
|
||||
|
||||
// Bezier 1
|
||||
if (selectedNode<spline.NodeCount) {
|
||||
thisBez = selectedNode<spline.NodeCount?(i*3)+1:1;
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if ((selectedIndex==1||selectedBezier==1) && !selectedIndexIsNode)
|
||||
EditorGUILayout.LabelField("", EditorStyles.foldout, GUILayout.Width(14));
|
||||
else GUILayout.Space (19f);
|
||||
if (GUILayout.Button(selectedNode>0?playgroundLanguage.bezier+" 1":playgroundLanguage.bezier+" 0", EditorStyles.label, GUILayout.MaxWidth(133)))
|
||||
selectedIndex = SelectIndex(thisBez);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUIUtility.labelWidth = 1f;
|
||||
if (GUILayout.Button(spline.transformNodes[thisBez].enabled?playgroundLanguage.transform:playgroundLanguage.vector3, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))){
|
||||
spline.transformNodes[thisBez].enabled = !spline.transformNodes[thisBez].enabled;
|
||||
}
|
||||
if (spline.transformNodes[thisBez].enabled) {
|
||||
spline.transformNodes[thisBez].transform = (Transform)EditorGUILayout.ObjectField(spline.transformNodes[thisBez].transform, typeof(Transform), true);
|
||||
if (spline.transformNodes[thisBez].IsAvailable())
|
||||
point = spline.transformNodes[thisBez].GetPosition();
|
||||
else point = spline.GetControlPoint(thisBez);
|
||||
} else point = EditorGUILayout.Vector3Field(" ", spline.GetControlPoint(thisBez));
|
||||
GUILayout.Space (35f);
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
Undo.RecordObject(spline, "Move Point");
|
||||
EditorUtility.SetDirty(spline);
|
||||
spline.SetControlPoint(thisBez, point);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUIUtility.labelWidth = 0;
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button(playgroundLanguage.create, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) {
|
||||
Undo.RecordObject(spline, "Add Node");
|
||||
selectedNode = spline.NodeCount;
|
||||
spline.AddNode(selectedNode);
|
||||
EditorUtility.SetDirty(spline);
|
||||
selectedIndex = SelectIndex((selectedNode+1)*3);
|
||||
}
|
||||
EditorGUILayout.Separator();
|
||||
if (GUILayout.Button(playgroundLanguage.convertAllToTransforms, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) {
|
||||
Transform pTrans = new GameObject("Nodes").transform;
|
||||
pTrans.parent = spline.splineTransform;
|
||||
pTrans.localPosition = Vector3.zero;
|
||||
Transform[] transforms = spline.ExportToTransforms();
|
||||
spline.positionOffset = Vector3.zero;
|
||||
for (int i = 0; i<transforms.Length; i++) {
|
||||
spline.transformNodes[i].transform = transforms[i];
|
||||
spline.transformNodes[i].enabled = true;
|
||||
if (transforms[i].parent==spline.splineTransform)
|
||||
transforms[i].parent = pTrans;
|
||||
}
|
||||
Selection.activeTransform = pTrans;
|
||||
}
|
||||
if (GUILayout.Button(playgroundLanguage.convertAllToVector3, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) {
|
||||
spline.SetPoints(spline.ExportToVector3());
|
||||
spline.positionOffset = Vector3.zero;
|
||||
for (int i = 0; i<spline.ControlPointCount; i++) {
|
||||
spline.transformNodes[i].enabled = false;
|
||||
}
|
||||
}
|
||||
EditorGUILayout.Separator();
|
||||
if (GUILayout.Button(playgroundLanguage.reverseAllNodes, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) {
|
||||
spline.ReverseAllNodes();
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
// List of users
|
||||
if (GUILayout.Button(playgroundLanguage.usedBy+" ("+spline.usedBy.Count+")", EditorStyles.toolbarDropDown)) playgroundSettings.usedByFoldout=!playgroundSettings.usedByFoldout;
|
||||
if (playgroundSettings.usedByFoldout) {
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
if (spline.usedBy.Count>0) {
|
||||
EditorGUILayout.BeginVertical(boxStyle, GUILayout.MinHeight(26));
|
||||
for (int i = 0; i<spline.usedBy.Count; i++) {
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button(spline.usedBy[i].name, EditorStyles.label))
|
||||
Selection.activeTransform = spline.usedBy[i];
|
||||
EditorGUILayout.Separator();
|
||||
if (GUILayout.Button("-", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) {
|
||||
if (EditorUtility.DisplayDialog(playgroundLanguage.removeUserTitle, playgroundLanguage.removeUserMessage, playgroundLanguage.yes, playgroundLanguage.no)) {
|
||||
PlaygroundParticlesC ps = spline.usedBy[i].GetComponent<PlaygroundParticlesC>();
|
||||
Undo.RecordObjects(new Object[]{spline,ps}, "Remove User");
|
||||
if (ps!=null) {
|
||||
Transform user = spline.usedBy[i];
|
||||
if (ps.splines.Contains(spline)) {
|
||||
spline.RemoveUser (user);
|
||||
ps.splines.Remove(spline);
|
||||
}
|
||||
foreach (ManipulatorObjectC m in ps.manipulators) {
|
||||
ManipulatorPropertyC mp = m.property;
|
||||
if (mp.splineTarget!=null && mp.splineTarget==spline)
|
||||
spline.RemoveUser (user);
|
||||
foreach (ManipulatorPropertyC mps in m.properties)
|
||||
if (mps.splineTarget!=null && mps.splineTarget==spline)
|
||||
spline.RemoveUser (user);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
} else {
|
||||
EditorGUILayout.HelpBox(playgroundLanguage.noSplineUserMessage, MessageType.Info);
|
||||
}
|
||||
}
|
||||
|
||||
// Advanced
|
||||
if (GUILayout.Button(playgroundLanguage.advanced, EditorStyles.toolbarDropDown)) playgroundSettings.splineAdvancedFoldout=!playgroundSettings.splineAdvancedFoldout;
|
||||
if (playgroundSettings.splineAdvancedFoldout) {
|
||||
EditorGUILayout.Separator();
|
||||
spline.fixedVelocityOnNewNode = EditorGUILayout.FloatField (playgroundLanguage.velocityOnNewNode, spline.fixedVelocityOnNewNode);
|
||||
spline.moveTransformsAsBeziers = EditorGUILayout.Toggle (playgroundLanguage.moveTransformsAsBeziers, spline.moveTransformsAsBeziers);
|
||||
spline.exportWithNodeStructure = EditorGUILayout.Toggle (playgroundLanguage.exportWithNodeStructure, spline.exportWithNodeStructure);
|
||||
EditorGUILayout.Separator();
|
||||
spline.drawGizmo = EditorGUILayout.Toggle (playgroundLanguage.drawBezierGizmo, spline.drawGizmo);
|
||||
spline.bezierWidth = EditorGUILayout.FloatField (playgroundLanguage.bezierWidth, spline.bezierWidth);
|
||||
if (spline.bezierWidth<0) spline.bezierWidth = 0;
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
|
||||
private void DrawSelectedPointInspector() {
|
||||
if (selectedIndex>=spline.ControlPointCount) selectedIndex = SelectIndex(spline.ControlPointCount-1);
|
||||
EditorGUILayout.PrefixLabel(playgroundLanguage.selection);
|
||||
EditorGUILayout.BeginHorizontal(boxStyle);
|
||||
if (GUILayout.Button(playgroundLanguage.spline, EditorStyles.label, GUILayout.ExpandWidth(false))) {
|
||||
selectedIndex = SelectIndex(-1);
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
if (selectedIndex>=0) {
|
||||
GUILayout.Label(">", EditorStyles.label, GUILayout.MaxWidth(16));
|
||||
if (GUILayout.Button(playgroundLanguage.node+" "+selectedNode.ToString(), EditorStyles.label, GUILayout.ExpandWidth(false))) {
|
||||
selectedIndex = SelectIndex(selectedNode*3);
|
||||
}
|
||||
}
|
||||
if (selectedIndex>=0 && !selectedIndexIsNode) {
|
||||
GUILayout.Label(">", EditorStyles.label, GUILayout.MaxWidth(16));
|
||||
GUILayout.Label(playgroundLanguage.bezier+" "+selectedBezier.ToString(), EditorStyles.label, GUILayout.ExpandWidth(false));
|
||||
}
|
||||
if (selectedIndex>=0) {
|
||||
if (spline.transformNodes[selectedIndex].IsAvailable()) {
|
||||
if (GUILayout.Button(" ("+playgroundLanguage.transform+") ", EditorStyles.label, GUILayout.ExpandWidth(false)))
|
||||
Selection.activeTransform = spline.transformNodes[selectedIndex].transform;
|
||||
} else {
|
||||
GUILayout.Label(" ("+playgroundLanguage.vector3+")", EditorStyles.label, GUILayout.ExpandWidth(false));
|
||||
}
|
||||
}
|
||||
EditorGUILayout.Separator();
|
||||
if (GUILayout.Button ("<", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) {
|
||||
selectedIndex = SelectIndex(selectedIndex-1);
|
||||
if (selectedIndex<0)
|
||||
selectedIndex = SelectIndex(spline.ControlPointCount-1);
|
||||
}
|
||||
if (GUILayout.Button (">", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) {
|
||||
selectedIndex = SelectIndex(selectedIndex+1);
|
||||
if (selectedIndex>spline.ControlPointCount-1)
|
||||
selectedIndex = SelectIndex(0);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
// A node or bezier is selected
|
||||
if (selectedIndex>=0) {
|
||||
Vector3 point = EditorGUILayout.Vector3Field(playgroundLanguage.position, spline.GetControlPoint(selectedIndex));
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
Undo.RecordObject(spline, "Move Point");
|
||||
EditorUtility.SetDirty(spline);
|
||||
spline.SetControlPoint(selectedIndex, point);
|
||||
}
|
||||
EditorGUI.BeginChangeCheck();
|
||||
PlaygroundSplines.BezierControlPointMode mode = (PlaygroundSplines.BezierControlPointMode)EditorGUILayout.EnumPopup(playgroundLanguage.bezierMode, spline.GetControlPointMode(selectedIndex));
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
Undo.RecordObject(spline, "Change Point Mode");
|
||||
spline.SetControlPointMode(selectedIndex, mode);
|
||||
EditorUtility.SetDirty(spline);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button(playgroundLanguage.addNode, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) {
|
||||
Undo.RecordObject(spline, "Add Node");
|
||||
if (selectedIndex<0) selectedNode = spline.NodeCount;
|
||||
spline.AddNode(selectedNode);
|
||||
EditorUtility.SetDirty(spline);
|
||||
selectedIndex = SelectIndex((selectedNode+1)*3);
|
||||
}
|
||||
EditorGUILayout.Separator();
|
||||
GUI.enabled = (!spline.Loop&&spline.NodeCount>1||spline.Loop&&spline.NodeCount>2);
|
||||
if (GUILayout.Button(playgroundLanguage.removeSelectedNode, EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) {
|
||||
Undo.RecordObject(spline, "Remove Node");
|
||||
spline.RemoveNode(selectedNode);
|
||||
EditorUtility.SetDirty(spline);
|
||||
selectedIndex-=3;
|
||||
if (selectedIndex<0)
|
||||
selectedIndex = SelectIndex(0);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
private int SelectIndex (int newIndex) {
|
||||
if (newIndex>-1)
|
||||
UnityEditor.Tools.current = UnityEditor.Tool.None;
|
||||
else UnityEditor.Tools.current = lastActiveTool;
|
||||
selectedNode = (newIndex+1)/3;
|
||||
selectedBezier = newIndex<3?0:(((newIndex)%3))%2;
|
||||
selectedIndexIsNode = newIndex==0||newIndex%3==0;
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
private int foldoutHeight = 0;
|
||||
private bool toolboxFoldout = true;
|
||||
private bool callForAddNode = false;
|
||||
private bool callForRemoveNode = false;
|
||||
private void OnSceneGUI () {
|
||||
|
||||
callForAddNode = (selectedIndex>-1 && Event.current.control && !Event.current.shift && Event.current.type==EventType.mouseUp);
|
||||
callForRemoveNode = (selectedIndex>-1 && Event.current.control && Event.current.shift && Event.current.type==EventType.mouseUp);
|
||||
|
||||
handleTransform = spline.transform;
|
||||
handleRotation = UnityEditor.Tools.pivotRotation == PivotRotation.Local ? handleTransform.rotation : Quaternion.identity;
|
||||
bezierHandleRotation = Camera.current.transform.rotation;
|
||||
|
||||
Event e = Event.current;
|
||||
if (toolboxFoldout)
|
||||
if (selectedIndex<0)
|
||||
foldoutHeight = 68;
|
||||
else foldoutHeight = 120;
|
||||
else
|
||||
foldoutHeight = 0;
|
||||
Rect toolboxRect = new Rect(10f,Screen.height-(70f+foldoutHeight),300f,103f+foldoutHeight);
|
||||
|
||||
// Don't deselect upon click
|
||||
if (toolboxFoldout && e.type == EventType.Layout) {
|
||||
HandleUtility.AddDefaultControl(0);
|
||||
}
|
||||
|
||||
// Toolbox
|
||||
Handles.BeginGUI();
|
||||
GUILayout.BeginArea(toolboxRect);
|
||||
if (boxStyle==null)
|
||||
boxStyle = GUI.skin.FindStyle("box");
|
||||
GUILayout.BeginVertical(boxStyle);
|
||||
toolboxFoldout = GUILayout.Toggle(toolboxFoldout, playgroundLanguage.playgroundSpline, EditorStyles.foldout);
|
||||
if (toolboxFoldout) {
|
||||
DrawSelectedPointInspector();
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.EndArea();
|
||||
Handles.EndGUI();
|
||||
|
||||
Vector3 p0 = ShowPoint(0);
|
||||
for (int i = 1; i < spline.ControlPointCount; i += 3) {
|
||||
Vector3 p1 = ShowPoint(i);
|
||||
Vector3 p2 = ShowPoint(i + 1);
|
||||
Vector3 p3 = ShowPoint(i + 2);
|
||||
|
||||
Handles.color = new Color(1f,.8f,0f);
|
||||
Handles.DrawLine(p0, p1);
|
||||
Handles.DrawLine(p2, p3);
|
||||
|
||||
p0 = p3;
|
||||
}
|
||||
|
||||
if (callForAddNode) {
|
||||
Undo.RecordObject(spline, "Add Node");
|
||||
spline.AddNode(selectedNode);
|
||||
EditorUtility.SetDirty(spline);
|
||||
selectedIndex = SelectIndex((selectedNode+1)*3);
|
||||
}
|
||||
if (callForRemoveNode) {
|
||||
Undo.RecordObject(spline, "Remove Node");
|
||||
spline.RemoveNode(selectedNode);
|
||||
EditorUtility.SetDirty(spline);
|
||||
if (selectedIndex>=spline.ControlPointCount)
|
||||
selectedIndex = SelectIndex(spline.ControlPointCount-1);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowDirections () {
|
||||
Handles.color = Color.green;
|
||||
Vector3 point = spline.GetPoint(0f);
|
||||
Handles.DrawLine(point, point + spline.GetDirection(0f) * directionScale);
|
||||
int steps = stepsPerCurve * spline.NodeCount;
|
||||
for (int i = 1; i <= steps; i++) {
|
||||
point = spline.GetPoint(i / (float)steps);
|
||||
Handles.DrawLine(point, point + spline.GetDirection(i / (float)steps) * directionScale);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 ShowPoint (int index) {
|
||||
Vector3 pointWithOffset = spline.transformNodes[index].IsAvailable()? spline.GetPoint(index)+spline.positionOffset : handleTransform.TransformPoint(spline.GetInversePoint(index)+spline.positionOffset);
|
||||
float size = HandleUtility.GetHandleSize(pointWithOffset);
|
||||
if (index == 0 && spline.Loop) {
|
||||
size *= 2f;
|
||||
}
|
||||
Handles.color = new Color(1f,.5f,0f);
|
||||
if ((index==0||index%3==0)) {
|
||||
if (Handles.Button(pointWithOffset, handleRotation, size * handleSize, size * pickSize, Handles.DotCap)) {
|
||||
selectedIndex = SelectIndex(index);
|
||||
Repaint();
|
||||
}
|
||||
} else {
|
||||
if (Handles.Button(pointWithOffset, bezierHandleRotation, size * handleSize, size * pickSize, Handles.CircleCap)) {
|
||||
selectedIndex = SelectIndex(index);
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedIndex == index) {
|
||||
EditorGUI.BeginChangeCheck();
|
||||
pointWithOffset = Handles.DoPositionHandle(pointWithOffset, handleRotation);
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
Undo.RecordObject(spline, "Move Point");
|
||||
EditorUtility.SetDirty(spline);
|
||||
spline.SetControlPoint(index, spline.transformNodes[index].IsAvailable()?pointWithOffset:handleTransform.InverseTransformPoint(pointWithOffset), spline.positionOffset);
|
||||
}
|
||||
}
|
||||
return pointWithOffset;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 213dc41afb5744746a7e99b5b709b841
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,762 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Collection of methods for working with splines.
|
||||
/// This is based on the great learning tutorial Curves and Splines by Jasper Flick.
|
||||
///
|
||||
/// References:
|
||||
/// http://catlikecoding.com/unity/tutorials/curves-and-splines/
|
||||
/// http://answers.unity3d.com/questions/374333/positioning-an-object-on-a-spline-relative-to-play.html
|
||||
/// </summary>
|
||||
namespace PlaygroundSplines {
|
||||
|
||||
/// <summary>
|
||||
/// Holds information about a spline and contains functions for working with the nodes and bezier handles.
|
||||
/// </summary>
|
||||
[ExecuteInEditMode()]
|
||||
public class PlaygroundSpline : MonoBehaviour {
|
||||
/// <summary>
|
||||
/// The list of nodes and bezier handles making the spline.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private List<Vector3> points = new List<Vector3>();
|
||||
/// <summary>
|
||||
/// The modes of the bezier handles.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private List<BezierControlPointMode> modes = new List<BezierControlPointMode>();
|
||||
/// <summary>
|
||||
/// Determines if the spline is looping.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private bool loop;
|
||||
|
||||
/// <summary>
|
||||
/// The list of transform nodes to set positions live of an existing node.
|
||||
/// </summary>
|
||||
[HideInInspector] public List<TransformNode> transformNodes = new List<TransformNode>();
|
||||
/// <summary>
|
||||
/// Determines if the spline time should be reversed. If you'd like to physically reverse the arrays making the spline then call ReverseAllNodes().
|
||||
/// </summary>
|
||||
[HideInInspector] public bool reverse;
|
||||
/// <summary>
|
||||
/// The time offset of the spline.
|
||||
/// </summary>
|
||||
[HideInInspector] public float timeOffset;
|
||||
/// <summary>
|
||||
/// The position offset of the spline in relation to its transform.
|
||||
/// </summary>
|
||||
[HideInInspector] public Vector3 positionOffset;
|
||||
|
||||
[HideInInspector] public Transform splineTransform;
|
||||
[HideInInspector] public Matrix4x4 splineTransformMx;
|
||||
[HideInInspector] public List<Transform> usedBy = new List<Transform>();
|
||||
[HideInInspector] public float fixedVelocityOnNewNode = .5f;
|
||||
[HideInInspector] public bool moveTransformsAsBeziers = false;
|
||||
[HideInInspector] public bool exportWithNodeStructure = false;
|
||||
|
||||
// Gizmos
|
||||
public static bool drawSplinePreviews = true;
|
||||
[HideInInspector] public bool drawGizmo = true;
|
||||
[HideInInspector] public float bezierWidth = 2f;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnDrawGizmos () {
|
||||
if (drawSplinePreviews && drawGizmo) {
|
||||
Color innerBezier = new Color(1f,1f,1f,1f);
|
||||
Color outerBezier = new Color(.5f,.5f,0,.2f);
|
||||
Vector3 p0 = ShowPoint(0);
|
||||
for (int i = 1; i < ControlPointCount; i += 3) {
|
||||
Vector3 p1 = ShowPoint(i);
|
||||
Vector3 p2 = ShowPoint(i + 1);
|
||||
Vector3 p3 = ShowPoint(i + 2);
|
||||
UnityEditor.Handles.DrawBezier(p0, p3, p1, p2, innerBezier, null, bezierWidth);
|
||||
UnityEditor.Handles.DrawBezier(p0, p3, p1, p2, outerBezier, null, bezierWidth*10f);
|
||||
p0 = p3;
|
||||
}
|
||||
}
|
||||
}
|
||||
Vector3 ShowPoint (int index) {
|
||||
return transformNodes[index].IsAvailable()? GetPoint(index)+positionOffset : splineTransform.TransformPoint(GetInversePoint(index)+positionOffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
Vector3 previousPosition;
|
||||
Quaternion previousRotation;
|
||||
Vector3 previousScale;
|
||||
bool isReady;
|
||||
|
||||
public bool IsReady () {
|
||||
return isReady;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a user to the spline. This helps keeping track of which objects are using the spline.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if user was added, <c>false</c> otherwise.</returns>
|
||||
/// <param name="">.</param>
|
||||
public bool AddUser (Transform thisTransform) {
|
||||
if (!usedBy.Contains(thisTransform)) {
|
||||
usedBy.Add (thisTransform);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a user from the spline. This helps keeping track of which objects are using the spline.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if user was removed, <c>false</c> otherwise.</returns>
|
||||
/// <param name="">.</param>
|
||||
public bool RemoveUser (Transform thisTransform) {
|
||||
if (usedBy.Contains(thisTransform)) {
|
||||
usedBy.Remove (thisTransform);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this spline has the user of passed in transform.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this spline has the user of the passed in transform; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="thisTransform">This transform.</param>
|
||||
public bool HasUser (Transform thisTransform) {
|
||||
return usedBy.Contains (thisTransform);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="PlaygroundSplines.PlaygroundSpline"/> is set to loop.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if set to loop; otherwise, <c>false</c>.</value>
|
||||
public bool Loop {
|
||||
get {
|
||||
return loop;
|
||||
}
|
||||
set {
|
||||
loop = value;
|
||||
if (value == true && NodeCount>1) {
|
||||
modes[modes.Count - 1] = modes[0];
|
||||
SetControlPoint(0, points[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the control point count.
|
||||
/// </summary>
|
||||
/// <value>The control point count.</value>
|
||||
public int ControlPointCount {
|
||||
get {
|
||||
return points.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the control point.
|
||||
/// </summary>
|
||||
/// <returns>The control point.</returns>
|
||||
/// <param name="index">Index.</param>
|
||||
public Vector3 GetControlPoint (int index) {
|
||||
return GetPoint(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the control point and withdraws the offset.
|
||||
/// </summary>
|
||||
/// <param name="index">Index.</param>
|
||||
/// <param name="point">Point.</param>
|
||||
/// <param name="offset">Offset.</param>
|
||||
public void SetControlPoint (int index, Vector3 point, Vector3 offset) {
|
||||
SetControlPoint(index, point-offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the control point.
|
||||
/// </summary>
|
||||
/// <param name="index">Index.</param>
|
||||
/// <param name="point">Position.</param>
|
||||
public void SetControlPoint (int index, Vector3 point) {
|
||||
if (index<0) index = 0;
|
||||
if (index % 3 == 0) {
|
||||
Vector3 delta = (point - GetPoint(index));
|
||||
Vector3 v;
|
||||
if (loop) {
|
||||
if (index == 0) {
|
||||
//if (!PointHasTransform(1))
|
||||
{v = GetPoint(1); SetPoint(1, v+delta);}
|
||||
//if (!PointHasTransform(points.Count-2))
|
||||
{v = GetPoint(points.Count-2); SetPoint(points.Count-2, v+delta);}
|
||||
if (moveTransformsAsBeziers || !PointHasTransform(points.Count-1))
|
||||
{SetPoint(points.Count-1, point);}
|
||||
} else
|
||||
if (index == points.Count - 1) {
|
||||
//if (!PointHasTransform(0))
|
||||
{SetPoint(0, point);}
|
||||
//if (!PointHasTransform(1))
|
||||
{v = GetPoint(1); SetPoint(1, v+delta);}
|
||||
//if (!PointHasTransform(index-1))
|
||||
{v = GetPoint(index-1); SetPoint(index-1, v+delta);}
|
||||
} else {
|
||||
//if (!PointHasTransform(index-1))
|
||||
{v = GetPoint(index-1); SetPoint(index-1, v+delta);}
|
||||
//if (!PointHasTransform(index+1))
|
||||
{v = GetPoint(index+1); SetPoint(index+1, v+delta);}
|
||||
}
|
||||
} else {
|
||||
if (index > 0) {
|
||||
if (moveTransformsAsBeziers || !PointHasTransform(index-1))
|
||||
{v = GetPoint(index-1); SetPoint(index-1, v+delta);}
|
||||
}
|
||||
if (index + 1 < points.Count) {
|
||||
if (moveTransformsAsBeziers || !PointHasTransform(index+1))
|
||||
{v = GetPoint(index+1); SetPoint(index+1, v+delta);}
|
||||
}
|
||||
}
|
||||
}
|
||||
SetPoint(index, point);
|
||||
EnforceMode(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets all points from an array. Please ensure the same length of your passed in vectors as PlaygroundSpline.ControlPointCount.
|
||||
/// </summary>
|
||||
/// <param name="vectors">Vectors.</param>
|
||||
public void SetPoints (Vector3[] vectors) {
|
||||
if (vectors.Length!=points.Count) {
|
||||
Debug.Log ("Please ensure the same length of your passed in vectors ("+vectors.Length+") as the current points ("+points.Count+"). Use PlaygroundSpline.ControlPointCount to get the current count.");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i<points.Count; i++) {
|
||||
points[i] = vectors[i];
|
||||
}
|
||||
}
|
||||
|
||||
public bool PointHasTransform (int index) {
|
||||
return transformNodes[index].IsAvailable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the entire spline separate from its transform component. Use this if you'd like to offset the spline from its transform separately from the positionOffset.
|
||||
/// </summary>
|
||||
/// <param name="translation">The amount to move the spline in Units.</param>
|
||||
public void TranslateSpline (Vector3 translation) {
|
||||
for (int i = 0; i<points.Count; i++) {
|
||||
points[i] += translation;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetTransformPosition () {
|
||||
return previousPosition;
|
||||
}
|
||||
public Quaternion GetTransformRotation () {
|
||||
return previousRotation;
|
||||
}
|
||||
public Vector3 GetTransformScale () {
|
||||
return previousScale;
|
||||
}
|
||||
|
||||
public BezierControlPointMode GetControlPointMode (int index) {
|
||||
return modes[(index + 1) / 3];
|
||||
}
|
||||
|
||||
public void SetControlPointMode (int index, BezierControlPointMode mode) {
|
||||
int modeIndex = (index + 1) / 3;
|
||||
modes[modeIndex] = mode;
|
||||
if (loop) {
|
||||
if (modeIndex == 0) {
|
||||
modes[modes.Count - 1] = mode;
|
||||
}
|
||||
else if (modeIndex == modes.Count - 1) {
|
||||
modes[0] = mode;
|
||||
}
|
||||
}
|
||||
EnforceMode(index);
|
||||
}
|
||||
|
||||
private void EnforceMode (int index) {
|
||||
int modeIndex = (index+1) / 3;
|
||||
BezierControlPointMode mode = modes[modeIndex];
|
||||
if (mode == BezierControlPointMode.Free || !loop && (modeIndex == 0 || modeIndex == modes.Count - 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int middleIndex = modeIndex * 3;
|
||||
int fixedIndex, enforcedIndex;
|
||||
if (index <= middleIndex) {
|
||||
fixedIndex = middleIndex - 1;
|
||||
if (fixedIndex < 0) {
|
||||
fixedIndex = points.Count - 2;
|
||||
}
|
||||
enforcedIndex = middleIndex + 1;
|
||||
if (enforcedIndex >= points.Count) {
|
||||
enforcedIndex = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fixedIndex = middleIndex + 1;
|
||||
if (fixedIndex >= points.Count) {
|
||||
fixedIndex = 1;
|
||||
}
|
||||
enforcedIndex = middleIndex - 1;
|
||||
if (enforcedIndex < 0) {
|
||||
enforcedIndex = points.Count - 2;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 middle = GetPoint(middleIndex);
|
||||
Vector3 enforcedTangent = middle - GetPoint(fixedIndex);
|
||||
if (mode == BezierControlPointMode.Aligned) {
|
||||
enforcedTangent = enforcedTangent.normalized * Vector3.Distance(middle, GetPoint(enforcedIndex));
|
||||
}
|
||||
if (moveTransformsAsBeziers || !PointHasTransform(enforcedIndex))
|
||||
SetPoint(enforcedIndex, middle + enforcedTangent);
|
||||
}
|
||||
|
||||
public int NodeCount {
|
||||
get {
|
||||
return (points.Count - 1) / 3;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get position from time.
|
||||
/// </summary>
|
||||
/// <returns>The point in world space.</returns>
|
||||
/// <param name="t">Time.</param>
|
||||
public Vector3 GetPoint (float t) {
|
||||
int i;
|
||||
if (reverse) {
|
||||
t = 1f-t;
|
||||
t = (t-timeOffset)%1f;
|
||||
if (t<0)
|
||||
t = 1f+t;
|
||||
} else t = (t+timeOffset)%1f;
|
||||
|
||||
if (t >= 1f) {
|
||||
//t = 1f;
|
||||
i = points.Count - 4;
|
||||
}
|
||||
else {
|
||||
t = Mathf.Clamp01(t) * NodeCount;
|
||||
i = (int)t;
|
||||
t -= i;
|
||||
i *= 3;
|
||||
}
|
||||
return splineTransformMx.MultiplyPoint3x4(Bezier.GetPoint(GetInversePoint(i), GetInversePoint(i + 1), GetInversePoint(i + 2), GetInversePoint(i + 3), t)+positionOffset);
|
||||
}
|
||||
|
||||
public Vector3 GetVelocity (float t) {
|
||||
int i;
|
||||
if (reverse)
|
||||
t = 1f-t;
|
||||
t = (t+timeOffset)%1f;
|
||||
if (t >= 1f) {
|
||||
t = 1f;
|
||||
i = points.Count - 4;
|
||||
}
|
||||
else {
|
||||
t = Mathf.Clamp01(t) * NodeCount;
|
||||
i = (int)t;
|
||||
t -= i;
|
||||
i *= 3;
|
||||
}
|
||||
return splineTransformMx.MultiplyPoint3x4(Bezier.GetFirstDerivative(GetInversePoint(i), GetInversePoint(i + 1), GetInversePoint(i + 2), GetInversePoint(i + 3), t)+positionOffset) - previousPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get position from node index in the spline. If the node consists of an available transform its position will be returned, otherwise the user-specified Vector3 position.
|
||||
/// </summary>
|
||||
/// <returns>The point in world space.</returns>
|
||||
/// <param name="index">Index.</param>
|
||||
public Vector3 GetPoint (int index) {
|
||||
if (transformNodes[index].IsAvailable())
|
||||
return transformNodes[index].GetPosition();
|
||||
else return points[index];
|
||||
}
|
||||
|
||||
public Vector3 GetInversePoint (int index) {
|
||||
if (transformNodes[index].IsAvailable())
|
||||
return transformNodes[index].GetInvsersePosition();
|
||||
else return points[index];
|
||||
}
|
||||
|
||||
public Vector3 GetPointWorldSpace (int index) {
|
||||
if (transformNodes[index].IsAvailable())
|
||||
return transformNodes[index].GetPosition();
|
||||
else return splineTransformMx.MultiplyPoint3x4(points[index]+positionOffset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a point to specified position.
|
||||
/// </summary>
|
||||
/// <param name="index">Index.</param>
|
||||
/// <param name="position">Position.</param>
|
||||
void SetPoint (int index, Vector3 position) {
|
||||
if (transformNodes[index].IsAvailable())
|
||||
transformNodes[index].SetPosition(position);
|
||||
else points[index] = position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates a point.
|
||||
/// </summary>
|
||||
/// <param name="index">Index.</param>
|
||||
/// <param name="translation">Translation.</param>
|
||||
void TranslatePoint (int index, Vector3 translation) {
|
||||
if (transformNodes[index].IsAvailable())
|
||||
transformNodes[index].Translate(translation);
|
||||
else points[index] += translation;
|
||||
}
|
||||
|
||||
// Calculates the best fitting time in the given interval
|
||||
private float CPOB(Vector3 aP, float aStart, float aEnd, int aSteps)
|
||||
{
|
||||
aStart = Mathf.Clamp01(aStart);
|
||||
aEnd = Mathf.Clamp01(aEnd);
|
||||
float step = (aEnd-aStart) / (float)aSteps;
|
||||
float Res = 0;
|
||||
float Ref = float.MaxValue;
|
||||
for (int i = 0; i < aSteps; i++)
|
||||
{
|
||||
float t = aStart + step*i;
|
||||
float L = (GetPoint(t)-aP).sqrMagnitude;
|
||||
if (L < Ref)
|
||||
{
|
||||
Ref = L;
|
||||
Res = t;
|
||||
}
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
public float ClosestTimeFromPoint (Vector3 aP) {
|
||||
float t = CPOB(aP, 0, 1, 10);
|
||||
float delta = 1.0f / 10.0f;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
t = CPOB(aP, t - delta, t + delta, 10);
|
||||
delta /= 9;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public Vector3 ClosestPointFromPosition (Vector3 aP) {
|
||||
return GetPoint(ClosestTimeFromPoint(aP));
|
||||
}
|
||||
|
||||
public Vector3 GetDirection (float t) {
|
||||
return (GetPoint(t+.001f)-GetPoint(t)).normalized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a node at the last position of the node index.
|
||||
/// </summary>
|
||||
public void AddNode () {
|
||||
AddNode ((points.Count-1)/3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a node at specified node index.
|
||||
/// </summary>
|
||||
/// <param name="index">Index.</param>
|
||||
public void AddNode (int index) {
|
||||
int nodeIndex = index*3;
|
||||
Vector3 point = GetPoint(nodeIndex);
|
||||
Vector3 direction;
|
||||
if (index>0) {
|
||||
direction = GetPoint(nodeIndex)-GetPoint(nodeIndex-1);
|
||||
} else direction = GetPoint(nodeIndex+1)-GetPoint(nodeIndex);
|
||||
|
||||
direction*=fixedVelocityOnNewNode;
|
||||
|
||||
points.InsertRange(nodeIndex+1, new Vector3[3]);
|
||||
point += direction;
|
||||
points[nodeIndex+2] = point;
|
||||
point += direction;
|
||||
points[nodeIndex+1] = point;
|
||||
point += direction;
|
||||
points[nodeIndex+3] = point;
|
||||
|
||||
transformNodes.InsertRange(nodeIndex+1, new TransformNode[]{new TransformNode(), new TransformNode(), new TransformNode()});
|
||||
|
||||
BezierControlPointMode currentIndexMode = modes[index];
|
||||
modes.Insert (index, new BezierControlPointMode());
|
||||
modes[index] = currentIndexMode;
|
||||
EnforceMode(index);
|
||||
|
||||
SetControlPoint((index+1)*3, GetPoint((index+1)*3));
|
||||
|
||||
if (loop) {
|
||||
points[points.Count - 1] = points[0];
|
||||
modes[modes.Count - 1] = modes[0];
|
||||
EnforceMode(0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the first node in the node index.
|
||||
/// </summary>
|
||||
public void RemoveFirst () {
|
||||
RemoveNode(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the last node in the node index.
|
||||
/// </summary>
|
||||
public void RemoveLast () {
|
||||
RemoveNode((points.Count-1)/3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a node at specified node index.
|
||||
/// </summary>
|
||||
/// <param name="index">Index.</param>
|
||||
public void RemoveNode (int index) {
|
||||
index = Mathf.Clamp (index, 0, points.Count-1);
|
||||
int pointIndex = index*3;
|
||||
if (points.Count<=4) return;
|
||||
if (pointIndex<points.Count-1) {
|
||||
points.RemoveRange(pointIndex, 3);
|
||||
transformNodes.RemoveRange(pointIndex, 3);
|
||||
} else {
|
||||
points.RemoveRange(pointIndex-2, 3);
|
||||
transformNodes.RemoveRange(pointIndex-2, 3);
|
||||
}
|
||||
modes.RemoveAt (index);
|
||||
EnforceMode (index-1);
|
||||
if (index>0)
|
||||
SetControlPoint((index-1)*3, GetPoint((index-1)*3));
|
||||
else
|
||||
SetControlPoint(0, GetPoint(0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses all nodes in the node index.
|
||||
/// </summary>
|
||||
public void ReverseAllNodes () {
|
||||
points.Reverse();
|
||||
transformNodes.Reverse();
|
||||
modes.Reverse();
|
||||
}
|
||||
|
||||
public void SwapNodes (int from, int to) {
|
||||
Vector3[] fromPoints = points.GetRange (from, 3).ToArray();
|
||||
Vector3[] toPoints = points.GetRange (to, 3).ToArray();
|
||||
TransformNode[] fromTnode = transformNodes.GetRange (from, 3).ToArray();
|
||||
TransformNode[] toTnode = transformNodes.GetRange (to, 3).ToArray();
|
||||
BezierControlPointMode fromMode = modes[from];
|
||||
BezierControlPointMode toMode = modes[to];
|
||||
|
||||
for (int i = from; i<3; i++) {
|
||||
points[i] = toPoints[i];
|
||||
transformNodes[i] = toTnode[i];
|
||||
}
|
||||
for (int i = to; i<3; i++) {
|
||||
points[i] = fromPoints[i];
|
||||
transformNodes[i] = fromTnode[i];
|
||||
}
|
||||
modes[from] = toMode;
|
||||
modes[to] = fromMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports all nodes to Transform[]. Enable exportWithNodeStructure to parent each bezier handle to their node.
|
||||
/// </summary>
|
||||
/// <returns>A built-in array of Transforms.</returns>
|
||||
public Transform[] ExportToTransforms () {
|
||||
Transform[] transforms = new Transform[points.Count];
|
||||
for (int i = 0; i<points.Count; i++) {
|
||||
int iNode = (i+1)/3;
|
||||
int iBezier = i<3?0:(((i)%3))%2;
|
||||
bool iIsNode = i==0||i%3==0;
|
||||
transforms[i] = new GameObject(iIsNode?"Node "+iNode:"Node "+iNode+" - Bezier "+iBezier).transform;
|
||||
transforms[i].parent = splineTransform;
|
||||
transforms[i].position = splineTransform.TransformPoint(GetInversePoint(i)+positionOffset);
|
||||
}
|
||||
if (exportWithNodeStructure) {
|
||||
for (int i = 2; i<transforms.Length; i++) {
|
||||
int iBezier = i<3?0:(((i)%3))%2;
|
||||
bool iIsNode = i==0||i%3==0;
|
||||
if (!iIsNode)
|
||||
transforms[i].parent = transforms[iBezier==0?i+1:i-1];
|
||||
}
|
||||
transforms[1].parent = transforms[0];
|
||||
}
|
||||
return transforms;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports all nodes to Vector3[].
|
||||
/// </summary>
|
||||
/// <returns>A built-in array of Vector3</returns>
|
||||
public Vector3[] ExportToVector3 () {
|
||||
Vector3[] vectors = new Vector3[points.Count];
|
||||
for (int i = 0; i<points.Count; i++) {
|
||||
vectors[i] = GetPoint(i)+positionOffset;
|
||||
}
|
||||
return vectors;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset this Playground Spline. Two nodes and two bezier handles will be created.
|
||||
/// </summary>
|
||||
public void Reset () {
|
||||
points = new List<Vector3> {
|
||||
new Vector3(1f, 0f, 0f),
|
||||
new Vector3(2f, 0f, 0f),
|
||||
new Vector3(3f, 0f, 0f),
|
||||
new Vector3(4f, 0f, 0f)
|
||||
};
|
||||
modes = new List<BezierControlPointMode> {
|
||||
BezierControlPointMode.Aligned,
|
||||
BezierControlPointMode.Aligned
|
||||
};
|
||||
transformNodes = new List<TransformNode> {
|
||||
new TransformNode(),
|
||||
new TransformNode(),
|
||||
new TransformNode(),
|
||||
new TransformNode()
|
||||
};
|
||||
}
|
||||
|
||||
/*************************************************************************************************************************************************
|
||||
MonoBehaviours
|
||||
*************************************************************************************************************************************************/
|
||||
|
||||
void OnEnable () {
|
||||
isReady = false;
|
||||
splineTransform = transform;
|
||||
SetMatrix();
|
||||
}
|
||||
|
||||
void Update () {
|
||||
SetMatrix();
|
||||
for (int i = 0; i<transformNodes.Count; i++)
|
||||
transformNodes[i].Update(splineTransform);
|
||||
}
|
||||
|
||||
void SetMatrix () {
|
||||
if (previousPosition!=splineTransform.position || previousRotation!=splineTransform.rotation || previousScale!=splineTransform.localScale)
|
||||
splineTransformMx.SetTRS(splineTransform.position, splineTransform.rotation, splineTransform.localScale);
|
||||
previousPosition = splineTransform.position;
|
||||
previousRotation = splineTransform.rotation;
|
||||
previousScale = splineTransform.localScale;
|
||||
isReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class for common bezier operations on a spline.
|
||||
/// </summary>
|
||||
public static class Bezier {
|
||||
|
||||
public static Vector3 GetPoint (Vector3 p0, Vector3 p1, Vector3 p2, float t) {
|
||||
t = Mathf.Clamp01(t);
|
||||
float oneMinusT = 1f - t;
|
||||
return
|
||||
oneMinusT * oneMinusT * p0 +
|
||||
2f * oneMinusT * t * p1 +
|
||||
t * t * p2;
|
||||
}
|
||||
|
||||
public static Vector3 GetFirstDerivative (Vector3 p0, Vector3 p1, Vector3 p2, float t) {
|
||||
return
|
||||
2f * (1f - t) * (p1 - p0) +
|
||||
2f * t * (p2 - p1);
|
||||
}
|
||||
|
||||
public static Vector3 GetPoint (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
|
||||
t = Mathf.Clamp01(t);
|
||||
float OneMinusT = 1f - t;
|
||||
return
|
||||
OneMinusT * OneMinusT * OneMinusT * p0 +
|
||||
3f * OneMinusT * OneMinusT * t * p1 +
|
||||
3f * OneMinusT * t * t * p2 +
|
||||
t * t * t * p3;
|
||||
}
|
||||
|
||||
public static Vector3 GetFirstDerivative (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
|
||||
t = Mathf.Clamp01(t);
|
||||
float oneMinusT = 1f - t;
|
||||
return
|
||||
3f * oneMinusT * oneMinusT * (p1 - p0) +
|
||||
6f * oneMinusT * t * (p2 - p1) +
|
||||
3f * t * t * (p3 - p2);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class TransformNode {
|
||||
public bool enabled;
|
||||
public Transform transform;
|
||||
bool isAvailable;
|
||||
Vector3 position;
|
||||
Vector3 inversePosition;
|
||||
Vector3 previousPosition;
|
||||
|
||||
public bool Update (Transform splineTransform) {
|
||||
if (enabled && transform!=null) {
|
||||
previousPosition = position;
|
||||
position = transform.position;
|
||||
inversePosition = splineTransform.InverseTransformPoint(transform.position);
|
||||
isAvailable = true;
|
||||
return true;
|
||||
}
|
||||
isAvailable = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsAvailable () {
|
||||
return enabled&&isAvailable;
|
||||
}
|
||||
|
||||
public Vector3 GetPosition () {
|
||||
return position;
|
||||
}
|
||||
|
||||
public Vector3 GetInvsersePosition () {
|
||||
return inversePosition;
|
||||
}
|
||||
|
||||
public void SetPosition (Vector3 newPosition) {
|
||||
if (transform==null) return;
|
||||
transform.position = newPosition;
|
||||
}
|
||||
|
||||
public void Translate (Vector3 translation) {
|
||||
if (transform==null) return;
|
||||
transform.position += translation;
|
||||
}
|
||||
|
||||
public Vector3 GetPositionDelta () {
|
||||
return previousPosition-position;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SplineMode {
|
||||
Vector3,
|
||||
Transform
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The bezier mode for a spline node. This controls how one bezier handle acts in relation to the other.
|
||||
/// </summary>
|
||||
public enum BezierControlPointMode {
|
||||
/// <summary>
|
||||
/// Align the angle between the two bezier handles but keep individual lengths. Has a differential smooth in and out angle.
|
||||
/// </summary>
|
||||
Aligned,
|
||||
/// <summary>
|
||||
/// Align the angle and length between the two bezier handles. Has an equally smooth in and out angle.
|
||||
/// </summary>
|
||||
Mirrored,
|
||||
/// <summary>
|
||||
/// Bezier handles are freely aligned without consideration to the other. Ables you to have sharp angles.
|
||||
/// </summary>
|
||||
Free
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bd22d17ed7f31487db6f1305d10dfeef
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,203 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace PlaygroundSplines {
|
||||
/// <summary>
|
||||
/// The PlaygroundSplineMesh class lets you create a mesh from a Playground Spline.
|
||||
/// </summary>
|
||||
[ExecuteInEditMode()]
|
||||
public class PlaygroundSplineMesh : MonoBehaviour {
|
||||
|
||||
public PlaygroundSpline spline;
|
||||
|
||||
[Range(2,1000)]
|
||||
public int points = 100;
|
||||
|
||||
[Range(.01f, 100f)]
|
||||
public float width = 1f;
|
||||
|
||||
public bool noise = false;
|
||||
[Range(.01f, 100f)]
|
||||
public float noiseStrength = 1f;
|
||||
public Vector2 noiseScale = new Vector2(1f,1f);
|
||||
public bool noiseDistribution;
|
||||
public AnimationCurve noiseDistributionL;
|
||||
public AnimationCurve noiseDistributionR;
|
||||
|
||||
public bool followSurface = false;
|
||||
public bool followSurfaceRotation = false;
|
||||
public float surfaceOffset = .1f;
|
||||
public Vector3 meshUpDirection = Vector3.up;
|
||||
public Vector3 surfaceDirection = Vector3.down;
|
||||
|
||||
int prevPoints;
|
||||
float prevWidth;
|
||||
bool prevNoise;
|
||||
float prevNoiseStrength;
|
||||
Vector2 prevNoiseScale;
|
||||
bool prevNoiseDistribution;
|
||||
bool prevFollowSurface;
|
||||
bool prevFollowSurfaceRotation;
|
||||
float prevSurfaceOffset;
|
||||
Vector3 prevMeshUpDirection;
|
||||
Vector3 prevSurfaceDirection;
|
||||
|
||||
void OnEnable ()
|
||||
{
|
||||
if (noiseDistributionL == null || noiseDistributionL.keys.Length==0)
|
||||
SetAnimationCurveVals(ref noiseDistributionL);
|
||||
if (noiseDistributionR == null || noiseDistributionR.keys.Length==0)
|
||||
SetAnimationCurveVals(ref noiseDistributionR);
|
||||
if (GetComponent<Renderer>() == null)
|
||||
gameObject.AddComponent<MeshRenderer>();
|
||||
if (spline == null)
|
||||
spline = GetComponent<PlaygroundSpline>();
|
||||
if (spline != null)
|
||||
BuildSplineMesh(spline, points, width);
|
||||
SetVals();
|
||||
}
|
||||
|
||||
void Update ()
|
||||
{
|
||||
if (NeedsUpdate ())
|
||||
{
|
||||
if (spline != null)
|
||||
BuildSplineMesh(spline, points, width);
|
||||
SetVals ();
|
||||
}
|
||||
}
|
||||
|
||||
bool NeedsUpdate ()
|
||||
{
|
||||
return prevPoints!=points ||
|
||||
prevWidth!=width ||
|
||||
prevNoise!=noise ||
|
||||
noise && (prevNoiseScale!=noiseScale || prevNoiseStrength!=noiseStrength || prevNoiseDistribution!=noiseDistribution) ||
|
||||
prevFollowSurface!=followSurface ||
|
||||
prevFollowSurfaceRotation!=followSurfaceRotation ||
|
||||
prevSurfaceOffset!=surfaceOffset ||
|
||||
prevMeshUpDirection!=meshUpDirection ||
|
||||
prevSurfaceDirection!=surfaceDirection;
|
||||
}
|
||||
|
||||
void SetVals ()
|
||||
{
|
||||
prevPoints = points;
|
||||
prevWidth = width;
|
||||
prevNoise = noise;
|
||||
prevNoiseStrength = noiseStrength;
|
||||
prevNoiseScale = noiseScale;
|
||||
prevNoiseDistribution = noiseDistribution;
|
||||
prevFollowSurface = followSurface;
|
||||
prevFollowSurfaceRotation = followSurfaceRotation;
|
||||
prevSurfaceOffset = surfaceOffset;
|
||||
prevMeshUpDirection = meshUpDirection;
|
||||
prevSurfaceDirection = surfaceDirection;
|
||||
}
|
||||
|
||||
void SetAnimationCurveVals (ref AnimationCurve curve)
|
||||
{
|
||||
Keyframe[] reset = new Keyframe[2];
|
||||
reset[0].time = 0;
|
||||
reset[1].time = 1f;
|
||||
reset[0].value = 1f;
|
||||
reset[1].value = 1f;
|
||||
curve.keys = reset;
|
||||
}
|
||||
|
||||
public void BuildSplineMesh (PlaygroundSpline spline, int points, float width)
|
||||
{
|
||||
if (points<2)
|
||||
points = 2;
|
||||
int totalVertices = points*2;
|
||||
MeshFilter _mf = GetComponent<MeshFilter>()!=null? GetComponent<MeshFilter>() : gameObject.AddComponent<MeshFilter>();
|
||||
Mesh _m = new Mesh();
|
||||
Vector3[] verts = new Vector3[totalVertices];
|
||||
Vector2[] uvs = new Vector2[totalVertices];
|
||||
int[] tris = new int[(points-1)*6];
|
||||
|
||||
Vector3 up = meshUpDirection;
|
||||
|
||||
// Construct the mesh
|
||||
for (int i = 0; i<points; i++)
|
||||
{
|
||||
// Create a normalized time value
|
||||
float t = (i*1f)/(points-1);
|
||||
float tNext = ((i*1f)+1)/(points-1);
|
||||
if (t>=1 && !spline.Loop)
|
||||
t = .9999f;
|
||||
if (tNext>=1 && !spline.Loop)
|
||||
tNext = .99999f;
|
||||
|
||||
// Get the current and next position from the spline on time
|
||||
Vector3 currentPosition = spline.GetPoint (t);
|
||||
Vector3 nextPosition = spline.GetPoint (tNext);
|
||||
|
||||
// Raycast down to determine surface (especially practical for roads / rivers)
|
||||
if (followSurface || followSurfaceRotation)
|
||||
{
|
||||
RaycastHit hit;
|
||||
if (Physics.Raycast (currentPosition, surfaceDirection, out hit))
|
||||
{
|
||||
if (followSurfaceRotation)
|
||||
up = hit.normal;
|
||||
if (followSurface)
|
||||
currentPosition = hit.point + (hit.normal * surfaceOffset);
|
||||
}
|
||||
if (followSurface)
|
||||
{
|
||||
if (Physics.Raycast (nextPosition, surfaceDirection, out hit))
|
||||
{
|
||||
nextPosition = hit.point + (hit.normal * surfaceOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate noise (if enabled)
|
||||
float noiseAmountL = noise? Mathf.PerlinNoise((t%1f)*noiseScale.x, 0)*noiseStrength : 0;
|
||||
float noiseAmountR = noise? Mathf.PerlinNoise((t%1f)*noiseScale.y, 0)*noiseStrength : 0;
|
||||
|
||||
if (noise && noiseDistribution)
|
||||
{
|
||||
noiseAmountL *= noiseDistributionL.Evaluate(t);
|
||||
noiseAmountR *= noiseDistributionR.Evaluate(t);
|
||||
}
|
||||
|
||||
// Create two width point references based on current and next position
|
||||
Vector3 dir = (Vector3.Cross(up, nextPosition - currentPosition)).normalized;
|
||||
Vector3 lPoint = currentPosition + dir * ((width/2)+noiseAmountL);
|
||||
Vector3 rPoint = currentPosition - dir * ((width/2)+noiseAmountR);
|
||||
|
||||
// Draw debug
|
||||
Debug.DrawLine(lPoint, rPoint);
|
||||
|
||||
verts[i*2] = lPoint;
|
||||
verts[(i*2)+1] = rPoint;
|
||||
uvs[i*2] = new Vector2(t,0);
|
||||
uvs[(i*2)+1] = new Vector2(t,1f);
|
||||
|
||||
if (i>0)
|
||||
{
|
||||
int triIndex = (i-1)*6;
|
||||
int vertIndex = i*2;
|
||||
|
||||
tris[triIndex] = vertIndex-2;
|
||||
tris[triIndex+1] = vertIndex-1;
|
||||
tris[triIndex+2] = vertIndex;
|
||||
tris[triIndex+3] = vertIndex;
|
||||
tris[triIndex+4] = vertIndex-1;
|
||||
tris[triIndex+5] = vertIndex+1;
|
||||
}
|
||||
}
|
||||
|
||||
// Assign the data to the mesh
|
||||
_m.vertices = verts;
|
||||
_m.uv = uvs;
|
||||
_m.triangles = tris;
|
||||
_m.RecalculateNormals();
|
||||
|
||||
// Assign the mesh to the MeshFilter
|
||||
_mf.mesh = _m;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4531c25db4bb643a79ea6ef810dcf35a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c14f65469986a904ab38a5e365e690dd
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984948
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 189dbdd3248575540a24aa065579f63f
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984948
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c126173dfb3fe1f4fb85a5ce09cdaf26
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984949
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 88769265a64f9d04a8b3ae61fcd97460
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984949
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,174 @@
|
|||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using ParticlePlayground;
|
||||
using ParticlePlaygroundLanguage;
|
||||
|
||||
[CustomEditor (typeof(PlaygroundTrails))]
|
||||
public class PlaygroundTrailsInspector : Editor {
|
||||
|
||||
PlaygroundTrails trails;
|
||||
|
||||
SerializedObject s_trails;
|
||||
SerializedProperty s_playgroundSystem;
|
||||
SerializedProperty s_lifetimeColor;
|
||||
SerializedProperty s_material;
|
||||
SerializedProperty s_renderMode;
|
||||
SerializedProperty s_colorMode;
|
||||
SerializedProperty s_uvMode;
|
||||
SerializedProperty s_pointArrayAlpha;
|
||||
SerializedProperty s_billboardTransform;
|
||||
SerializedProperty s_customRenderScale;
|
||||
SerializedProperty s_time;
|
||||
SerializedProperty s_timeWidth;
|
||||
SerializedProperty s_widthScale;
|
||||
SerializedProperty s_minVertexDistance;
|
||||
SerializedProperty s_maxVertexDistance;
|
||||
SerializedProperty s_maxPathDeviation;
|
||||
SerializedProperty s_createPointsOnCollision;
|
||||
SerializedProperty s_maxPoints;
|
||||
SerializedProperty s_createFirstPointOnParticleBirth;
|
||||
SerializedProperty s_createLastPointOnParticleDeath;
|
||||
SerializedProperty s_multithreading;
|
||||
SerializedProperty s_receiveShadows;
|
||||
SerializedProperty s_castShadows;
|
||||
|
||||
// GUI
|
||||
public static GUIStyle boxStyle;
|
||||
public static PlaygroundSettingsC playgroundSettings;
|
||||
public static PlaygroundLanguageC playgroundLanguage;
|
||||
|
||||
public void OnEnable ()
|
||||
{
|
||||
trails = target as PlaygroundTrails;
|
||||
s_trails = new SerializedObject(trails);
|
||||
|
||||
s_time = s_trails.FindProperty("time");
|
||||
|
||||
s_material = s_trails.FindProperty("material");
|
||||
s_lifetimeColor = s_trails.FindProperty("lifetimeColor");
|
||||
s_colorMode = s_trails.FindProperty("colorMode");
|
||||
s_uvMode = s_trails.FindProperty("uvMode");
|
||||
s_pointArrayAlpha = s_trails.FindProperty("pointArrayAlpha");
|
||||
s_renderMode = s_trails.FindProperty("renderMode");
|
||||
s_billboardTransform = s_trails.FindProperty("billboardTransform");
|
||||
s_customRenderScale = s_trails.FindProperty("customRenderScale");
|
||||
|
||||
s_timeWidth = s_trails.FindProperty("timeWidth");
|
||||
s_widthScale = s_trails.FindProperty("widthScale");
|
||||
|
||||
s_minVertexDistance = s_trails.FindProperty("minVertexDistance");
|
||||
s_maxVertexDistance = s_trails.FindProperty("maxVertexDistance");
|
||||
s_maxPathDeviation = s_trails.FindProperty("maxPathDeviation");
|
||||
s_createPointsOnCollision = s_trails.FindProperty("createPointsOnCollision");
|
||||
s_maxPoints = s_trails.FindProperty("maxPoints");
|
||||
s_createFirstPointOnParticleBirth = s_trails.FindProperty("createFirstPointOnParticleBirth");
|
||||
s_createLastPointOnParticleDeath = s_trails.FindProperty("createLastPointOnParticleDeath");
|
||||
|
||||
s_playgroundSystem = s_trails.FindProperty("playgroundSystem");
|
||||
s_multithreading = s_trails.FindProperty("multithreading");
|
||||
|
||||
s_receiveShadows = s_trails.FindProperty("receiveShadows");
|
||||
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6
|
||||
s_castShadows = s_trails.FindProperty("castShadows");
|
||||
#else
|
||||
s_castShadows = s_trails.FindProperty("shadowCastingMode");
|
||||
#endif
|
||||
playgroundSettings = PlaygroundSettingsC.GetReference();
|
||||
playgroundLanguage = PlaygroundSettingsC.GetLanguage();
|
||||
|
||||
// Issue a quick refresh
|
||||
if (!EditorApplication.isPlaying && Selection.activeTransform!=null)
|
||||
{
|
||||
trails.ResetTrails();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI ()
|
||||
{
|
||||
if (boxStyle==null)
|
||||
boxStyle = GUI.skin.FindStyle("box");
|
||||
|
||||
s_trails.UpdateIfDirtyOrScript();
|
||||
|
||||
bool hasParticleSystem = trails.playgroundSystem != null;
|
||||
if (!hasParticleSystem)
|
||||
EditorGUILayout.HelpBox(playgroundLanguage.missingParticleSystemWarning, MessageType.Warning);
|
||||
|
||||
EditorGUILayout.BeginVertical (boxStyle);
|
||||
playgroundSettings.playgroundTrailsFoldout = GUILayout.Toggle(playgroundSettings.playgroundTrailsFoldout, playgroundLanguage.playgroundTrails, EditorStyles.foldout);
|
||||
if (playgroundSettings.playgroundTrailsFoldout)
|
||||
{
|
||||
EditorGUILayout.BeginVertical (boxStyle);
|
||||
|
||||
// Time foldout
|
||||
if (GUILayout.Button(playgroundLanguage.time+" ("+s_time.floatValue.ToString ("F1")+")", EditorStyles.toolbarDropDown)) playgroundSettings.trailsTimeFoldout=!playgroundSettings.trailsTimeFoldout;
|
||||
if (playgroundSettings.trailsTimeFoldout)
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.PropertyField(s_time, new GUIContent(playgroundLanguage.time));
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
// Width foldout
|
||||
if (GUILayout.Button(playgroundLanguage.width+" ("+s_widthScale.floatValue.ToString ("F1")+")", EditorStyles.toolbarDropDown)) playgroundSettings.trailsWidthFoldout=!playgroundSettings.trailsWidthFoldout;
|
||||
if (playgroundSettings.trailsWidthFoldout)
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.PropertyField(s_timeWidth, new GUIContent(playgroundLanguage.timeWidth));
|
||||
EditorGUILayout.PropertyField(s_widthScale, new GUIContent(playgroundLanguage.widthScale));
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
// Rendering foldout
|
||||
if (GUILayout.Button(playgroundLanguage.rendering+" ("+trails.renderMode+")", EditorStyles.toolbarDropDown)) playgroundSettings.trailsRenderingFoldout=!playgroundSettings.trailsRenderingFoldout;
|
||||
if (playgroundSettings.trailsRenderingFoldout)
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.PropertyField(s_material, new GUIContent(playgroundLanguage.material));
|
||||
EditorGUILayout.PropertyField(s_lifetimeColor, new GUIContent(playgroundLanguage.lifetimeColor));
|
||||
EditorGUILayout.PropertyField(s_colorMode, new GUIContent(playgroundLanguage.colorMode));
|
||||
if (trails.colorMode == TrailColorMode.Lifetime)
|
||||
EditorGUILayout.PropertyField(s_pointArrayAlpha, new GUIContent(playgroundLanguage.pointArrayAlpha));
|
||||
EditorGUILayout.PropertyField(s_uvMode, new GUIContent(playgroundLanguage.uvMode));
|
||||
EditorGUILayout.PropertyField(s_renderMode, new GUIContent(playgroundLanguage.renderMode));
|
||||
if (trails.renderMode == TrailRenderMode.Billboard)
|
||||
EditorGUILayout.PropertyField(s_billboardTransform, new GUIContent(playgroundLanguage.billboardTransform));
|
||||
else if (trails.renderMode == TrailRenderMode.CustomRenderScale)
|
||||
EditorGUILayout.PropertyField(s_customRenderScale, new GUIContent(playgroundLanguage.customRenderScale));
|
||||
EditorGUILayout.PropertyField(s_castShadows, new GUIContent(playgroundLanguage.castShadows));
|
||||
EditorGUILayout.PropertyField(s_receiveShadows, new GUIContent(playgroundLanguage.receiveShadows));
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
// Point creation foldout
|
||||
if (GUILayout.Button(playgroundLanguage.pointCreation+" ("+s_maxPoints.intValue+")", EditorStyles.toolbarDropDown)) playgroundSettings.trailsPointCreationFoldout=!playgroundSettings.trailsPointCreationFoldout;
|
||||
if (playgroundSettings.trailsPointCreationFoldout)
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.PropertyField(s_maxPoints, new GUIContent(playgroundLanguage.maximumPoints));
|
||||
EditorGUILayout.PropertyField(s_minVertexDistance, new GUIContent(playgroundLanguage.minimumVertexDistance));
|
||||
EditorGUILayout.PropertyField(s_maxVertexDistance, new GUIContent(playgroundLanguage.maximumVertexDistance));
|
||||
EditorGUILayout.PropertyField(s_maxPathDeviation, new GUIContent(playgroundLanguage.maximumPathDeviation));
|
||||
EditorGUILayout.PropertyField(s_createFirstPointOnParticleBirth, new GUIContent(playgroundLanguage.createFirstPointOnParticleBirth));
|
||||
EditorGUILayout.PropertyField(s_createLastPointOnParticleDeath, new GUIContent(playgroundLanguage.createLastPointOnParticleDeath));
|
||||
EditorGUILayout.PropertyField(s_createPointsOnCollision, new GUIContent(playgroundLanguage.createPointsOnCollision));
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
// Advanced foldout
|
||||
if (GUILayout.Button(playgroundLanguage.advanced, EditorStyles.toolbarDropDown)) playgroundSettings.trailsAdvancedFoldout=!playgroundSettings.trailsAdvancedFoldout;
|
||||
if (playgroundSettings.trailsAdvancedFoldout)
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.PropertyField(s_playgroundSystem, new GUIContent(playgroundLanguage.particleSystem));
|
||||
EditorGUILayout.PropertyField(s_multithreading, new GUIContent(playgroundLanguage.multithreading));
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
s_trails.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 302cc09ed3fd7488693e16d806a7665f
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,425 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ParticlePlayground {
|
||||
|
||||
[Serializable]
|
||||
public class ParticlePlaygroundTrail
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if this ParticlePlaygroundTrail should update.
|
||||
/// </summary>
|
||||
[HideInInspector] public bool update = true;
|
||||
/// <summary>
|
||||
/// The GameObject of this trail.
|
||||
/// </summary>
|
||||
[HideInInspector] public GameObject trailGameObject;
|
||||
/// <summary>
|
||||
/// The Transform of this trail.
|
||||
/// </summary>
|
||||
[HideInInspector] public Transform trailTransform;
|
||||
/// <summary>
|
||||
/// The Mesh Renderer component of this trail.
|
||||
/// </summary>
|
||||
[HideInInspector] public MeshRenderer trailRenderer;
|
||||
/// <summary>
|
||||
/// The Mesh Filter component of this trail.
|
||||
/// </summary>
|
||||
[HideInInspector] public MeshFilter trailMeshFilter;
|
||||
/// <summary>
|
||||
/// The Mesh component of this trail.
|
||||
/// </summary>
|
||||
[HideInInspector] public Mesh trailMesh;
|
||||
/// <summary>
|
||||
/// The particle this trail is following.
|
||||
/// </summary>
|
||||
[HideInInspector] public int particleId;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum point cache limit.
|
||||
/// </summary>
|
||||
[HideInInspector] public int minPointCache = 2;
|
||||
/// <summary>
|
||||
/// The maximum point cache limit.
|
||||
/// </summary>
|
||||
[HideInInspector] public int maxPointCache = 32767;
|
||||
|
||||
[NonSerialized] public List<TrailPoint> trailPoints = new List<TrailPoint>();
|
||||
[NonSerialized] public Vector3[] meshVerticesCache;
|
||||
[NonSerialized] public Vector3[] meshNormalsCache;
|
||||
[NonSerialized] public Vector2[] meshUvsCache;
|
||||
[NonSerialized] public int[] meshTrianglesCache;
|
||||
[NonSerialized] public Color32[] meshColorsCache;
|
||||
|
||||
private int _pointCache = 200;
|
||||
private int _birthIterator;
|
||||
private int _deathIterator;
|
||||
private float _particleTime;
|
||||
private Vector3 _particlePosition;
|
||||
private Vector3 _previousParticlePosition;
|
||||
private Vector3 _particleDirection;
|
||||
private Vector3 _lastAddedPointPosition;
|
||||
private Vector3 _lastAddedPointDirection;
|
||||
private bool _isDead = false;
|
||||
private bool _isReady = false;
|
||||
|
||||
private float _timeCached;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ParticlePlayground.ParticlePlaygroundTrail"/> class.
|
||||
/// </summary>
|
||||
public ParticlePlaygroundTrail ()
|
||||
{
|
||||
UpdateCache();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ParticlePlayground.ParticlePlaygroundTrail"/> class and specifies the available point cache.
|
||||
/// The mesh's available vertices, normals, uvs, triangles and colors will be based on the specified point cache.
|
||||
/// </summary>
|
||||
/// <param name="pointCache">Mesh point cache (vertices, normals and uvs will be multiplied by two, triangles by six).</param>
|
||||
public ParticlePlaygroundTrail (int pointCache)
|
||||
{
|
||||
_pointCache = Mathf.Clamp (pointCache, minPointCache, maxPointCache);
|
||||
UpdateCache();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the mesh cache. This is done upon creation where cache lengths will be based on the point cache.
|
||||
/// </summary>
|
||||
public void UpdateCache ()
|
||||
{
|
||||
_timeCached = PlaygroundC.globalTime;
|
||||
meshVerticesCache = new Vector3[_pointCache*2];
|
||||
meshNormalsCache = new Vector3[_pointCache*2];
|
||||
meshUvsCache = new Vector2[_pointCache*2];
|
||||
meshTrianglesCache = new int[(_pointCache-1)*6];
|
||||
meshColorsCache = new Color32[_pointCache*2];
|
||||
_isReady = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the trail mesh. This is done each frame from the main-thread.
|
||||
/// </summary>
|
||||
public void UpdateMesh ()
|
||||
{
|
||||
trailMesh.Clear();
|
||||
trailMesh.vertices = meshVerticesCache;
|
||||
trailMesh.uv = meshUvsCache;
|
||||
trailMesh.triangles = meshTrianglesCache;
|
||||
trailMesh.colors32 = meshColorsCache;
|
||||
trailMesh.normals = meshNormalsCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recalculates the bounds on the trail mesh. This is done automatically when triangles are set into a mesh.
|
||||
/// </summary>
|
||||
public void RecalculateBounds ()
|
||||
{
|
||||
trailMesh.RecalculateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the trail mesh.
|
||||
/// </summary>
|
||||
public void ClearMesh ()
|
||||
{
|
||||
_birthIterator = 0;
|
||||
_deathIterator = 0;
|
||||
meshVerticesCache = new Vector3[0];
|
||||
meshNormalsCache = new Vector3[0];
|
||||
meshUvsCache = new Vector2[0];
|
||||
meshTrianglesCache = new int[0];
|
||||
meshColorsCache = new Color32[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the first point in the trail. This will add two initial points, one starting point and one ending point which will follow the assigned particle.
|
||||
/// </summary>
|
||||
/// <param name="pos">Position.</param>
|
||||
/// <param name="dir">Direction.</param>
|
||||
/// <param name="startWidth">Start width.</param>
|
||||
/// <param name="lifetime">Lifetime.</param>
|
||||
public void SetFirstPoint (Vector3 pos, Vector3 dir, float startWidth, float lifetime, float creationTime)
|
||||
{
|
||||
_particleDirection = dir;
|
||||
AddPoint (pos, startWidth, lifetime, creationTime);
|
||||
AddPoint (pos, startWidth, lifetime, creationTime);
|
||||
_birthIterator = 2;
|
||||
_deathIterator = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the last point in the trail and then kills it. This will add one last point which won't follow the assigned particle.
|
||||
/// </summary>
|
||||
/// <param name="pos">Position.</param>
|
||||
/// <param name="dir">Direction.</param>
|
||||
/// <param name="startWidth">Start width.</param>
|
||||
/// <param name="lifetime">Lifetime.</param>
|
||||
public void SetLastPoint (Vector3 pos, Vector3 dir, float startWidth, float lifetime, float creationTime)
|
||||
{
|
||||
_particleDirection = dir;
|
||||
AddPoint (pos, startWidth, lifetime, creationTime);
|
||||
Die ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a point into the end of the trail.
|
||||
/// </summary>
|
||||
/// <param name="position">Position.</param>
|
||||
/// <param name="width">Width.</param>
|
||||
/// <param name="lifetime">Lifetime.</param>
|
||||
public void AddPoint (Vector3 position, float width, float lifetime, float creationTime)
|
||||
{
|
||||
if (_birthIterator >= _pointCache || _isDead)
|
||||
return;
|
||||
trailPoints.Add (new TrailPoint(position, lifetime, width, creationTime));
|
||||
AddPoint(position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a point into the end of the trail.
|
||||
/// </summary>
|
||||
/// <param name="position">Position.</param>
|
||||
/// <param name="velocity">Initial Velocity.</param>
|
||||
/// <param name="width">Width.</param>
|
||||
/// <param name="lifetime">Lifetime.</param>
|
||||
public void AddPoint (Vector3 position, Vector3 velocity, float width, float lifetime, float creationTime)
|
||||
{
|
||||
if (_birthIterator >= _pointCache || _isDead)
|
||||
return;
|
||||
trailPoints.Add (new TrailPoint(position, velocity, lifetime, width, creationTime));
|
||||
AddPoint(position);
|
||||
}
|
||||
|
||||
|
||||
void AddPoint (Vector3 position)
|
||||
{
|
||||
_lastAddedPointDirection = position-_previousParticlePosition;
|
||||
_lastAddedPointPosition = position;
|
||||
|
||||
meshVerticesCache[_birthIterator*2] = position;
|
||||
meshVerticesCache[(_birthIterator*2)+1] = position;
|
||||
|
||||
meshNormalsCache[_birthIterator*2] = -Vector3.forward;
|
||||
meshNormalsCache[(_birthIterator*2)+1] = -Vector3.forward;
|
||||
|
||||
meshUvsCache[_birthIterator*2] = new Vector2(1f, 0f);
|
||||
meshUvsCache[(_birthIterator*2)+1] = new Vector2(0f, 1f);
|
||||
|
||||
meshColorsCache[_birthIterator*2] = new Color32();
|
||||
meshColorsCache[(_birthIterator*2)+1] = new Color32();
|
||||
|
||||
|
||||
if (trailPoints.Count>1) {
|
||||
int vertexIndex = (_birthIterator)*2;
|
||||
int triIndex = (_birthIterator-1)*6;
|
||||
|
||||
meshTrianglesCache[triIndex] = vertexIndex -2;
|
||||
meshTrianglesCache[triIndex+1] = vertexIndex -1;
|
||||
meshTrianglesCache[triIndex+2] = vertexIndex;
|
||||
meshTrianglesCache[triIndex+3] = vertexIndex;
|
||||
meshTrianglesCache[triIndex+4] = vertexIndex -1;
|
||||
meshTrianglesCache[triIndex+5] = vertexIndex +1;
|
||||
}
|
||||
|
||||
NextPoint();
|
||||
}
|
||||
|
||||
public void RemovePoint (int index)
|
||||
{
|
||||
if (_deathIterator < _birthIterator-2)
|
||||
{
|
||||
meshVerticesCache[_deathIterator*2] = meshVerticesCache[(_deathIterator*2)+2];
|
||||
meshVerticesCache[(_deathIterator*2)+1] = meshVerticesCache[(_deathIterator*2)+3];
|
||||
meshColorsCache[_deathIterator*2] = new Color32();
|
||||
meshColorsCache[(_deathIterator*2)+1] = new Color32();
|
||||
|
||||
_deathIterator++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the color at specified index. This is done automatically through the trail calculation loop.
|
||||
/// </summary>
|
||||
/// <param name="index">Index.</param>
|
||||
/// <param name="color">Color.</param>
|
||||
public void SetColor (int index, Color32 color)
|
||||
{
|
||||
meshColorsCache[index*2] = color;
|
||||
meshColorsCache[(index*2)+1] = color;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the iterator jump to next point. The iterator controls which point is following the particle.
|
||||
/// </summary>
|
||||
public void NextPoint ()
|
||||
{
|
||||
_birthIterator++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the paired particle's current time.
|
||||
/// </summary>
|
||||
/// <returns>The paired particle's current time.</returns>
|
||||
public float GetParticleTime ()
|
||||
{
|
||||
return _particleTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the paired particle's current time.
|
||||
/// </summary>
|
||||
/// <param name="time">Time.</param>
|
||||
public void SetParticleTime (float time)
|
||||
{
|
||||
_particleTime = time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the paired particle's current position.
|
||||
/// </summary>
|
||||
/// <returns>The paired particle's position.</returns>
|
||||
public Vector3 GetParticlePosition ()
|
||||
{
|
||||
return _particlePosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the paired particle's position.
|
||||
/// </summary>
|
||||
/// <param name="position">Position.</param>
|
||||
public void SetParticlePosition (Vector3 position)
|
||||
{
|
||||
if (_isDead)
|
||||
return;
|
||||
_previousParticlePosition = _particlePosition;
|
||||
_particlePosition = position;
|
||||
_particleDirection = (position-_previousParticlePosition).normalized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the paired particle's direction.
|
||||
/// </summary>
|
||||
/// <param name="direction">Direction.</param>
|
||||
public void SetParticleDirection (Vector3 direction)
|
||||
{
|
||||
_particleDirection = direction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last added point position.
|
||||
/// </summary>
|
||||
/// <returns>The last added point position.</returns>
|
||||
public Vector3 GetLastAddedPointPosition ()
|
||||
{
|
||||
return _lastAddedPointPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the direction of the particle.
|
||||
/// </summary>
|
||||
/// <returns>The particle direction.</returns>
|
||||
public Vector3 GetParticleDirection ()
|
||||
{
|
||||
return _particleDirection;
|
||||
}
|
||||
|
||||
public Vector3 GetLastAddedPointDirection ()
|
||||
{
|
||||
return _lastAddedPointDirection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current path deviation angle based on the last added point direction and the current direction of the particle.
|
||||
/// </summary>
|
||||
/// <returns>The path deviation angle.</returns>
|
||||
public float GetPathDeviation () {
|
||||
return Vector3.Angle(_lastAddedPointDirection, _particleDirection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the birth iterator used for iterating through the mesh arrays to set new vertex positions.
|
||||
/// </summary>
|
||||
/// <returns>The birth iterator.</returns>
|
||||
public int GetBirthIterator ()
|
||||
{
|
||||
return _birthIterator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the death iterator used for iterating through the mesh arrays to remove old vertex positions.
|
||||
/// </summary>
|
||||
/// <returns>The death iterator.</returns>
|
||||
public int GetDeathIterator ()
|
||||
{
|
||||
return _deathIterator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the point cache amount. The point cache is set at the trail's creation and determines how many vertices, triangles, uvs, normals and colors the trail mesh can have.
|
||||
/// </summary>
|
||||
/// <returns>The point cache amount.</returns>
|
||||
public int GetPointCache ()
|
||||
{
|
||||
return _pointCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time this trail was cached.
|
||||
/// </summary>
|
||||
/// <returns>The cached time.</returns>
|
||||
public float TimeCached ()
|
||||
{
|
||||
return _timeCached;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this trail can remove a point at specified index.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this trail can remove a point at the specified index; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="point">Point.</param>
|
||||
public bool CanRemovePoint (int point)
|
||||
{
|
||||
return trailPoints[point].CanRemove();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this trail can be removed. This will check if the last point in the trail has reached the end of its lifetime.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this trail can be removed; otherwise, <c>false</c>.</returns>
|
||||
public bool CanRemoveTrail ()
|
||||
{
|
||||
if (trailPoints.Count == 0 || !_isReady)
|
||||
return false;
|
||||
return trailPoints[trailPoints.Count-1].CanRemove();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wakes up the trail from being dead.
|
||||
/// </summary>
|
||||
public void WakeUp ()
|
||||
{
|
||||
_isDead = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the trail stop following its assigned particle.
|
||||
/// </summary>
|
||||
public void Die ()
|
||||
{
|
||||
_isDead = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this trail is dead.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this trail is dead; otherwise, <c>false</c>.</returns>
|
||||
public bool IsDead ()
|
||||
{
|
||||
return _isDead;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 69a95d91e31314835b480a1e0e499ed5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,77 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ParticlePlayground {
|
||||
public class TrailPoint
|
||||
{
|
||||
public Vector3 position;
|
||||
public Vector3 velocity;
|
||||
public float lifetime;
|
||||
public float startLifetime;
|
||||
public float width;
|
||||
|
||||
bool _canRemove = false;
|
||||
float _lastTimeUpdated;
|
||||
|
||||
public TrailPoint (Vector3 position, float startLifetime, float creationTime)
|
||||
{
|
||||
this.position = position;
|
||||
this.lifetime = startLifetime;
|
||||
this.startLifetime = startLifetime;
|
||||
this.width = 0;
|
||||
|
||||
_lastTimeUpdated = creationTime;
|
||||
}
|
||||
|
||||
public TrailPoint (Vector3 position, float startLifetime, float width, float creationTime)
|
||||
{
|
||||
this.position = position;
|
||||
this.lifetime = startLifetime;
|
||||
this.startLifetime = startLifetime;
|
||||
this.width = width;
|
||||
|
||||
_lastTimeUpdated = creationTime;
|
||||
}
|
||||
|
||||
public TrailPoint (Vector3 position, Vector3 velocity, float startLifetime, float width, float creationTime)
|
||||
{
|
||||
this.position = position;
|
||||
this.lifetime = startLifetime;
|
||||
this.startLifetime = startLifetime;
|
||||
this.width = width;
|
||||
this.velocity = velocity;
|
||||
|
||||
_lastTimeUpdated = creationTime;
|
||||
}
|
||||
|
||||
public void Update (float updateTime, float width)
|
||||
{
|
||||
lifetime -= updateTime-_lastTimeUpdated;
|
||||
if (lifetime <= 0)
|
||||
{
|
||||
_canRemove = true;
|
||||
lifetime = 0;
|
||||
}
|
||||
this.width = width;
|
||||
_lastTimeUpdated = updateTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the normalized lifetime of this trail point.
|
||||
/// </summary>
|
||||
/// <returns>The normalized lifetime.</returns>
|
||||
public float GetNormalizedLifetime () {
|
||||
return 1f-(lifetime/startLifetime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this point can be removed.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this point can be removed; otherwise, <c>false</c>.</returns>
|
||||
public bool CanRemove () {
|
||||
return _canRemove;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d13961b3ce5d04e079a2f25f5b542a50
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using ParticlePlayground;
|
||||
|
||||
[ExecuteInEditMode()]
|
||||
public class PlaygroundTrailParent : MonoBehaviour {
|
||||
|
||||
public PlaygroundTrails trailsReference;
|
||||
|
||||
private GameObject _gameObject;
|
||||
|
||||
void Awake () {
|
||||
_gameObject = gameObject;
|
||||
}
|
||||
|
||||
void Update () {
|
||||
if (_gameObject != trailsReference.GetParentGameObject())
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
Destroy (_gameObject);
|
||||
else
|
||||
DestroyImmediate(_gameObject);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 500796a8d01a74b6aae149cd39a714f8
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,853 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ParticlePlayground {
|
||||
|
||||
[ExecuteInEditMode()]
|
||||
public class PlaygroundTrails : MonoBehaviour {
|
||||
|
||||
/// <summary>
|
||||
/// The particle system this Playground Trail will follow.
|
||||
/// </summary>
|
||||
[HideInInspector] public PlaygroundParticlesC playgroundSystem;
|
||||
|
||||
/// <summary>
|
||||
/// The material of each trail.
|
||||
/// </summary>
|
||||
[HideInInspector] public Material material;
|
||||
/// <summary>
|
||||
/// The lifetime color of all trails.
|
||||
/// </summary>
|
||||
[HideInInspector] public Gradient lifetimeColor = new Gradient();
|
||||
/// <summary>
|
||||
/// The point array alpha determines the alpha level over the trail points. This is a normalized value where 1 on the x-axis means all points, 1 on the y-axis means full alpha.
|
||||
/// </summary>
|
||||
[HideInInspector] public AnimationCurve pointArrayAlpha;
|
||||
/// <summary>
|
||||
/// The mode to color the trails with. If TrailColorMode.Lifetime is selected the coloring will be based on each point's lifetime. If TrailColorMode.PointArray is selected the coloring will be based on the points in the array.
|
||||
/// </summary>
|
||||
[HideInInspector] public TrailColorMode colorMode;
|
||||
/// <summary>
|
||||
/// The uv mode.
|
||||
/// </summary>
|
||||
[HideInInspector] public TrailUvMode uvMode;
|
||||
/// <summary>
|
||||
/// Determines the render mode of the trail. This sets the rotation direction of the trail points.
|
||||
/// </summary>
|
||||
[HideInInspector] public TrailRenderMode renderMode;
|
||||
/// <summary>
|
||||
/// The transform to billboard towards if renderMode is set to TrailRenderMode.Billboard. If none is set this will default to the Main Camera transform.
|
||||
/// </summary>
|
||||
[HideInInspector] public Transform billboardTransform;
|
||||
/// <summary>
|
||||
/// The custom render scale if renderMode is set to TrailRenderMode.CustomRenderScale. This ables you to set the normal direction (with multiplier) of the trails.
|
||||
/// </summary>
|
||||
[HideInInspector] public Vector3 customRenderScale = Vector3.one;
|
||||
/// <summary>
|
||||
/// Determines if the trails should receive shadows. Note that the shader of the material needs to support this.
|
||||
/// </summary>
|
||||
[HideInInspector] public bool receiveShadows;
|
||||
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6
|
||||
/// <summary>
|
||||
/// Determines if the trails should cast shadows (Unity 4). Note that the shader of the material needs to support this.
|
||||
/// </summary>
|
||||
[HideInInspector] public bool castShadows = false;
|
||||
#else
|
||||
/// <summary>
|
||||
/// Determines if the trails should cast shadows. Note that the shader of the material needs to support this.
|
||||
/// </summary>
|
||||
[HideInInspector] public UnityEngine.Rendering.ShadowCastingMode shadowCastingMode;
|
||||
#endif
|
||||
/// <summary>
|
||||
/// The time vertices is living on the trail (determines length).
|
||||
/// </summary>
|
||||
[HideInInspector] public float time = 3f;
|
||||
/// <summary>
|
||||
/// The width over normalized lifetime.
|
||||
/// </summary>
|
||||
public AnimationCurve timeWidth;
|
||||
/// <summary>
|
||||
/// The scale of start- and end width.
|
||||
/// </summary>
|
||||
public float widthScale = .1f;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum distance before new vertices can be created.
|
||||
/// </summary>
|
||||
public float minVertexDistance = .1f;
|
||||
/// <summary>
|
||||
/// The maximum distance before forcing new vertices.
|
||||
/// </summary>
|
||||
public float maxVertexDistance = 100f;
|
||||
/// <summary>
|
||||
/// The maximum forward path deviation before forcing new vertices.
|
||||
/// </summary>
|
||||
public float maxPathDeviation = 1f;
|
||||
/// <summary>
|
||||
/// Determines if points should be created upon particle collision.
|
||||
/// </summary>
|
||||
public bool createPointsOnCollision = false;
|
||||
/// <summary>
|
||||
/// The maximum available points able to be created by this Playground Trail. This will determine the generation of built-in arrays needed to remain efficient in memory consumption.
|
||||
/// The trail is made out of points where vertices are drawn in between, two points is the minimum to be able to draw a trail, this represents 4 vertices and 6 triangles.
|
||||
/// </summary>
|
||||
public int maxPoints = 100;
|
||||
/// <summary>
|
||||
/// Determines if first point should be created immediately on particle birth, otherwise this will be created during the trail calculation routine.
|
||||
/// This has affect on when the trail starts as the particle may have moved when the first point is created. If your particle source is moving you may want to leave this setting off to not create a first skewed trail point.
|
||||
/// </summary>
|
||||
public bool createFirstPointOnParticleBirth = false;
|
||||
/// <summary>
|
||||
/// Determines if a last point on the trail should be created when its assigned particle dies.
|
||||
/// </summary>
|
||||
public bool createLastPointOnParticleDeath = false;
|
||||
/// <summary>
|
||||
/// Determines if the Playground Trails should run asynchronously on a separate thread. This will go through the selected Thread Pool Method in the Playground Manager (PlaygroundC).
|
||||
/// </summary>
|
||||
public bool multithreading = true;
|
||||
|
||||
/// <summary>
|
||||
/// The reference to the birth event on the assigned Particle Playground system.
|
||||
/// </summary>
|
||||
[HideInInspector] public PlaygroundEventC birthEvent;
|
||||
/// <summary>
|
||||
/// The reference to the death event on the assigned Particle Playground system.
|
||||
/// </summary>
|
||||
[HideInInspector] public PlaygroundEventC deathEvent;
|
||||
/// <summary>
|
||||
/// The reference to the collision event on the assigned Particle Playground system.
|
||||
/// </summary>
|
||||
[HideInInspector] public PlaygroundEventC collisionEvent;
|
||||
|
||||
/// <summary>
|
||||
/// The list of trails following each particle.
|
||||
/// </summary>
|
||||
private List<ParticlePlaygroundTrail> _trails = new List<ParticlePlaygroundTrail>();
|
||||
|
||||
private Transform _parentTransform;
|
||||
private GameObject _parentGameObject;
|
||||
private Material _materialCache;
|
||||
private float _calculationStartTime;
|
||||
private int _currentParticleCount;
|
||||
private float _currentParticleMinLifetime;
|
||||
private float _currentParticleMaxLifetime;
|
||||
private bool _localSpace;
|
||||
private Vector3 _billboardTransformPosition;
|
||||
private object _locker = new object();
|
||||
private bool _isDoneThread = true;
|
||||
private Matrix4x4 _localMatrix;
|
||||
|
||||
/// <summary>
|
||||
/// The birth queue of trails. This will be added to whenever a particle births. As a Particle Playground system can birth particles and send particle events asynchronously a thread safe queue is needed to create the trails.
|
||||
/// </summary>
|
||||
readonly Queue<TrailParticleInfo> _birthQueue = new Queue<TrailParticleInfo>();
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Monobehaviours
|
||||
****************************************************************************/
|
||||
|
||||
void OnEnable ()
|
||||
{
|
||||
// Cache reference to the Particle Playground system
|
||||
if (playgroundSystem == null)
|
||||
playgroundSystem = GetComponent<PlaygroundParticlesC>();
|
||||
|
||||
// Cache a reference to the Main Camera if billboardTransform isn't assigned
|
||||
if (billboardTransform == null)
|
||||
billboardTransform = Camera.main.transform;
|
||||
|
||||
// Set the initial material
|
||||
if (material == null)
|
||||
{
|
||||
material = new Material(Shader.Find("Playground/Vertex Color"));
|
||||
_materialCache = material;
|
||||
}
|
||||
|
||||
// Reset the trails
|
||||
ResetTrails();
|
||||
|
||||
// Add the required birth/death/collision events
|
||||
AddRequiredParticleEvents();
|
||||
|
||||
// Setup default time width keys
|
||||
if (timeWidth == null)
|
||||
timeWidth = new AnimationCurve(DefaultWidthKeys());
|
||||
|
||||
// Setup default point array alpha keys
|
||||
if (pointArrayAlpha == null)
|
||||
pointArrayAlpha = new AnimationCurve(DefaultWidthKeys());
|
||||
|
||||
_isDoneThread = true;
|
||||
}
|
||||
|
||||
void OnDisable ()
|
||||
{
|
||||
// Destroy all trails
|
||||
DestroyAllTrails();
|
||||
|
||||
// Remove the required events
|
||||
RemoveRequiredEvents();
|
||||
}
|
||||
|
||||
void OnDestroy ()
|
||||
{
|
||||
// Destroy all trails
|
||||
DestroyAllTrails();
|
||||
|
||||
// Remove the required events
|
||||
RemoveRequiredEvents();
|
||||
}
|
||||
|
||||
void Update ()
|
||||
{
|
||||
// Clamp values
|
||||
maxPoints = Mathf.Clamp (maxPoints, 2, 32767);
|
||||
|
||||
// Set asynchronous available values
|
||||
if (billboardTransform != null)
|
||||
_billboardTransformPosition = billboardTransform.position;
|
||||
|
||||
// Early out if no particles exist yet
|
||||
if (playgroundSystem == null || !playgroundSystem.IsReady() || playgroundSystem.IsSettingParticleCount() || playgroundSystem.IsSettingLifetime() || playgroundSystem.particleCache == null || playgroundSystem.particleCache.Length == 0)
|
||||
return;
|
||||
|
||||
// Reset trails if a crucial state is changed
|
||||
if (_currentParticleCount != playgroundSystem.particleCount || _currentParticleMinLifetime != playgroundSystem.lifetimeMin || _currentParticleMaxLifetime != playgroundSystem.lifetime || _localSpace != (playgroundSystem.shurikenParticleSystem.simulationSpace == ParticleSystemSimulationSpace.Local))
|
||||
ResetTrails();
|
||||
|
||||
// Set calculation matrix if this is local space
|
||||
if (_localSpace)
|
||||
_localMatrix.SetTRS(playgroundSystem.particleSystemTransform.position, playgroundSystem.particleSystemTransform.rotation, playgroundSystem.particleSystemTransform.lossyScale);
|
||||
|
||||
// Check material
|
||||
if (material != _materialCache)
|
||||
SetMaterial(material);
|
||||
|
||||
// Remove any trails that has ended
|
||||
if (_isDoneThread)
|
||||
{
|
||||
for (int i = 0; i<_trails.Count; i++)
|
||||
{
|
||||
if (_trails[i].trailPoints != null && _trails[i].trailPoints.Count > 1 && _trails[i].trailPoints[_trails[i].trailPoints.Count-1] != null && _trails[i].CanRemoveTrail())
|
||||
{
|
||||
RemoveTrail(i);
|
||||
i--;
|
||||
if (i<0) i = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Consume the particle birth queue
|
||||
while (_birthQueue.Count>0)
|
||||
AddTrail(_birthQueue.Dequeue());
|
||||
|
||||
// Update all trail meshes and their render settings
|
||||
for (int i = 0; i<_trails.Count; i++)
|
||||
{
|
||||
ParticlePlaygroundTrail trail = _trails[i];
|
||||
// Set shadow casting/receiving
|
||||
trail.trailRenderer.receiveShadows = receiveShadows;
|
||||
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6
|
||||
trail.trailRenderer.castShadows = castShadows;
|
||||
#else
|
||||
trail.trailRenderer.shadowCastingMode = shadowCastingMode;
|
||||
#endif
|
||||
if (_isDoneThread)
|
||||
trail.UpdateMesh();
|
||||
}
|
||||
// Finally calculate all trails
|
||||
if (multithreading)
|
||||
{
|
||||
if (_isDoneThread)
|
||||
{
|
||||
_calculationStartTime = Application.isPlaying? Time.time : Time.realtimeSinceStartup;
|
||||
_isDoneThread = false;
|
||||
PlaygroundC.RunAsync(()=>{
|
||||
lock (_locker)
|
||||
{
|
||||
if (_isDoneThread) return;
|
||||
CalculateTrail();
|
||||
_isDoneThread = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_calculationStartTime = Application.isPlaying? Time.time : Time.realtimeSinceStartup;
|
||||
CalculateTrail();
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent build-up of the birth queue while Editor is out of focus
|
||||
#if UNITY_EDITOR
|
||||
public void OnApplicationPause (bool pauseStatus)
|
||||
{
|
||||
if (!pauseStatus && !UnityEditor.EditorApplication.isPlaying)
|
||||
{
|
||||
_birthQueue.Clear();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
Event Listeners
|
||||
****************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// This function will be called whenever a particle is birthed.
|
||||
/// </summary>
|
||||
/// <param name="particle">The birthed particle.</param>
|
||||
void OnParticleBirthEvent (PlaygroundEventParticle particle)
|
||||
{
|
||||
_birthQueue.Enqueue (new TrailParticleInfo(particle.particleId, particle.position, particle.velocity));
|
||||
}
|
||||
/// <summary>
|
||||
/// This function will be called whenever a particle has died.
|
||||
/// </summary>
|
||||
/// <param name="particle">The particle which died.</param>
|
||||
void OnParticleDeathEvent (PlaygroundEventParticle particle)
|
||||
{
|
||||
int trailIndex = GetOldestTrailWithParticleId(particle.particleId);
|
||||
if (trailIndex > -1)
|
||||
{
|
||||
if (createLastPointOnParticleDeath)
|
||||
{
|
||||
_trails[trailIndex].SetLastPoint(particle.position, particle.velocity, EvaluateWidth(0), time, _calculationStartTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
_trails[trailIndex].SetParticlePosition(particle.position);
|
||||
_trails[trailIndex].Die();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// This function will be called whenever a particle is colliding.
|
||||
/// </summary>
|
||||
/// <param name="particle">The collided particle.</param>
|
||||
void OnParticleCollisionEvent (PlaygroundEventParticle particle)
|
||||
{
|
||||
if (createPointsOnCollision)
|
||||
{
|
||||
int trailIndex = GetNewestTrailWithParticleId (particle.particleId);
|
||||
if (trailIndex < 0)
|
||||
return;
|
||||
ParticlePlaygroundTrail trailAtIndex = _trails[trailIndex];
|
||||
trailAtIndex.AddPoint (playgroundSystem.particleCache[particle.particleId].position, EvaluateWidth(0), time, _calculationStartTime);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the birth event this Playground Trail is listening to.
|
||||
/// </summary>
|
||||
/// <returns>The particle birth event.</returns>
|
||||
public PlaygroundEventC GetBirthEvent () {return birthEvent;}
|
||||
/// <summary>
|
||||
/// Gets the death event this Playground Trail is listening to.
|
||||
/// </summary>
|
||||
/// <returns>The particle death event.</returns>
|
||||
public PlaygroundEventC GetDeathEvent () {return deathEvent;}
|
||||
/// <summary>
|
||||
/// Gets the collision event this Playground Trail is listening to.
|
||||
/// </summary>
|
||||
/// <returns>The particle collision event.</returns>
|
||||
public PlaygroundEventC GetCollisionEvent () {return collisionEvent;}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the required particle events to track particles.
|
||||
/// </summary>
|
||||
public void AddRequiredParticleEvents ()
|
||||
{
|
||||
if (playgroundSystem != null)
|
||||
{
|
||||
// Hookup events
|
||||
birthEvent = GetEventFromType(EVENTTYPEC.Birth);
|
||||
if (birthEvent == null)
|
||||
{
|
||||
birthEvent = PlaygroundC.CreateEvent(playgroundSystem);
|
||||
birthEvent.broadcastType = EVENTBROADCASTC.EventListeners;
|
||||
birthEvent.eventType = EVENTTYPEC.Birth;
|
||||
}
|
||||
birthEvent.particleEvent += OnParticleBirthEvent;
|
||||
|
||||
deathEvent = GetEventFromType(EVENTTYPEC.Death);
|
||||
if (deathEvent == null)
|
||||
{
|
||||
deathEvent = PlaygroundC.CreateEvent(playgroundSystem);
|
||||
deathEvent.broadcastType = EVENTBROADCASTC.EventListeners;
|
||||
deathEvent.eventType = EVENTTYPEC.Death;
|
||||
}
|
||||
deathEvent.particleEvent += OnParticleDeathEvent;
|
||||
|
||||
collisionEvent = GetEventFromType(EVENTTYPEC.Collision);
|
||||
if (collisionEvent == null)
|
||||
{
|
||||
collisionEvent = PlaygroundC.CreateEvent(playgroundSystem);
|
||||
collisionEvent.broadcastType = EVENTBROADCASTC.EventListeners;
|
||||
collisionEvent.eventType = EVENTTYPEC.Collision;
|
||||
}
|
||||
collisionEvent.particleEvent += OnParticleCollisionEvent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the required events to track particles.
|
||||
/// </summary>
|
||||
public void RemoveRequiredEvents ()
|
||||
{
|
||||
if (playgroundSystem != null)
|
||||
{
|
||||
if (birthEvent != null)
|
||||
{
|
||||
birthEvent.particleEvent -= OnParticleBirthEvent;
|
||||
birthEvent = null;
|
||||
}
|
||||
if (deathEvent != null)
|
||||
{
|
||||
deathEvent.particleEvent -= OnParticleDeathEvent;
|
||||
deathEvent = null;
|
||||
}
|
||||
if (collisionEvent != null)
|
||||
{
|
||||
collisionEvent.particleEvent -= OnParticleCollisionEvent;
|
||||
collisionEvent = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of event based on the passed in EVETTTYPEC.
|
||||
/// </summary>
|
||||
/// <returns>The event of type specified.</returns>
|
||||
/// <param name="eventType">The event type.</param>
|
||||
public PlaygroundEventC GetEventFromType (EVENTTYPEC eventType)
|
||||
{
|
||||
for (int i = 0; i<playgroundSystem.events.Count; i++)
|
||||
if (playgroundSystem.events[i].eventType == eventType)
|
||||
return playgroundSystem.events[i];
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Misc functions
|
||||
****************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Returns a default pair of AnimationCurve Keyframes in X 0 and X 1 at value Y 1.
|
||||
/// </summary>
|
||||
/// <returns>The default width keys.</returns>
|
||||
public Keyframe[] DefaultWidthKeys () {
|
||||
Keyframe[] keys = new Keyframe[2];
|
||||
keys[0].time = 0;
|
||||
keys[1].time = 1f;
|
||||
keys[0].value = 1f;
|
||||
keys[1].value = 1f;
|
||||
return keys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the material of all trails.
|
||||
/// </summary>
|
||||
/// <param name="material">The material all trails should get.</param>
|
||||
public void SetMaterial (Material material) {
|
||||
for (int i = 0; i<_trails.Count; i++) {
|
||||
if (_trails[i] != null && _trails[i].trailRenderer != null)
|
||||
_trails[i].trailRenderer.sharedMaterial = material;
|
||||
}
|
||||
_materialCache = material;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the width at normalized trail time.
|
||||
/// </summary>
|
||||
/// <returns>The width at normalized trail time.</returns>
|
||||
/// <param name="normalizedTime">Normalized time.</param>
|
||||
public float EvaluateWidth (float normalizedTime) {
|
||||
return timeWidth.Evaluate(normalizedTime)*widthScale;
|
||||
}
|
||||
|
||||
|
||||
public Color32 EvaluateColor (float normalizedTime)
|
||||
{
|
||||
return lifetimeColor.Evaluate(normalizedTime);
|
||||
}
|
||||
|
||||
public Color32 EvaluateColor (int trailIndex, int trailPointIndex)
|
||||
{
|
||||
return lifetimeColor.Evaluate((trailPointIndex*1f) / (_trails[trailIndex].GetBirthIterator()-1));
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Trail functions
|
||||
****************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Creates a trail and assigns it to a particle.
|
||||
/// </summary>
|
||||
/// <param name="particleInfo">Information about the particle.</param>
|
||||
public void AddTrail (TrailParticleInfo particleInfo)
|
||||
{
|
||||
// Check parent object
|
||||
if (_parentGameObject == null)
|
||||
{
|
||||
_parentGameObject = new GameObject("Playground Trails ("+playgroundSystem.name+")", typeof(PlaygroundTrailParent));
|
||||
_parentTransform = _parentGameObject.transform;
|
||||
_parentGameObject.GetComponent<PlaygroundTrailParent>().trailsReference = this;
|
||||
}
|
||||
|
||||
ParticlePlaygroundTrail newTrail = new ParticlePlaygroundTrail(maxPoints);
|
||||
newTrail.trailGameObject = new GameObject("Playground Trail "+particleInfo.particleId);
|
||||
newTrail.trailTransform = newTrail.trailGameObject.transform;
|
||||
newTrail.trailTransform.parent = _parentTransform;
|
||||
newTrail.trailRenderer = newTrail.trailGameObject.AddComponent<MeshRenderer>();
|
||||
newTrail.trailMeshFilter = newTrail.trailGameObject.AddComponent<MeshFilter>();
|
||||
newTrail.trailMesh = new Mesh();
|
||||
newTrail.trailMesh.MarkDynamic();
|
||||
newTrail.trailMeshFilter.sharedMesh = newTrail.trailMesh;
|
||||
newTrail.trailRenderer.sharedMaterial = material;
|
||||
|
||||
newTrail.particleId = particleInfo.particleId;
|
||||
|
||||
if (createFirstPointOnParticleBirth)
|
||||
newTrail.SetFirstPoint(particleInfo.position, particleInfo.velocity, EvaluateWidth(0), time, _calculationStartTime);
|
||||
|
||||
_trails.Add (newTrail);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the oldest trail following the particle id. If the trail is already dead or doesn't contain the particle id -1 will be returned.
|
||||
/// </summary>
|
||||
/// <returns>The trail with particle id (-1 if not found).</returns>
|
||||
/// <param name="particleId">Particle identifier.</param>
|
||||
public int GetOldestTrailWithParticleId (int particleId)
|
||||
{
|
||||
for (int i = 0; i<_trails.Count; i++)
|
||||
if (_trails[i].particleId == particleId && !_trails[i].IsDead())
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the newest trail following the particle id. If the trail is already dead or doesn't contain the particle id -1 will be returned.
|
||||
/// </summary>
|
||||
/// <returns>The trail with particle id (-1 if not found).</returns>
|
||||
/// <param name="particleId">Particle identifier.</param>
|
||||
public int GetNewestTrailWithParticleId (int particleId)
|
||||
{
|
||||
for (int i = _trails.Count-1; i>=0; --i)
|
||||
if (_trails[i].particleId == particleId && !_trails[i].IsDead())
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cached parent transform of the trails.
|
||||
/// </summary>
|
||||
/// <returns>The parent transform.</returns>
|
||||
public Transform GetParentTransform ()
|
||||
{
|
||||
return _parentTransform;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cached parent game object of the trails.
|
||||
/// </summary>
|
||||
/// <returns>The parent game object.</returns>
|
||||
public GameObject GetParentGameObject ()
|
||||
{
|
||||
return _parentGameObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stopping the trail will make the trail stop following its assigned particle.
|
||||
/// </summary>
|
||||
/// <param name="trailNumber">Trail number.</param>
|
||||
public void StopTrail (int trailNumber)
|
||||
{
|
||||
if (trailNumber < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_trails[trailNumber].Die();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the oldest trail with particle identifier.
|
||||
/// </summary>
|
||||
/// <param name="particleId">Particle identifier.</param>
|
||||
public void StopOldestTrailWithParticleId (int particleId)
|
||||
{
|
||||
StopTrail (GetOldestTrailWithParticleId (particleId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the newest trail with particle identifier.
|
||||
/// </summary>
|
||||
/// <param name="particleId">Particle identifier.</param>
|
||||
public void StopNewestTrailWithParticleId (int particleId)
|
||||
{
|
||||
StopTrail (GetNewestTrailWithParticleId (particleId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets all trails.
|
||||
/// </summary>
|
||||
public void ResetTrails () {
|
||||
DestroyAllTrails();
|
||||
if (playgroundSystem != null && gameObject.activeInHierarchy)
|
||||
{
|
||||
_currentParticleCount = playgroundSystem.particleCount;
|
||||
_currentParticleMinLifetime = playgroundSystem.lifetimeMin;
|
||||
_currentParticleMaxLifetime = playgroundSystem.lifetime;
|
||||
_localSpace = playgroundSystem.shurikenParticleSystem.simulationSpace == ParticleSystemSimulationSpace.Local;
|
||||
}
|
||||
|
||||
_isDoneThread = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the trail at index.
|
||||
/// </summary>
|
||||
/// <param name="index">The trail index.</param>
|
||||
public void RemoveTrail (int index) {
|
||||
if (Application.isPlaying)
|
||||
Destroy(_trails[index].trailGameObject);
|
||||
else
|
||||
DestroyImmediate(_trails[index].trailGameObject);
|
||||
|
||||
_trails.RemoveAt(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys all trails and clears out trail list.
|
||||
/// </summary>
|
||||
public void DestroyAllTrails () {
|
||||
|
||||
foreach (ParticlePlaygroundTrail trail in _trails)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
Destroy(trail.trailGameObject);
|
||||
else
|
||||
DestroyImmediate(trail.trailGameObject);
|
||||
}
|
||||
|
||||
if (_parentGameObject != null)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
Destroy (_parentGameObject);
|
||||
else
|
||||
DestroyImmediate(_parentGameObject);
|
||||
}
|
||||
|
||||
_trails.Clear();
|
||||
_birthQueue.Clear();
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Internal
|
||||
****************************************************************************/
|
||||
|
||||
void CalculateTrail ()
|
||||
{
|
||||
// Iterate through all trails
|
||||
for (int i = 0; i<_trails.Count; i++)
|
||||
{
|
||||
ParticlePlaygroundTrail trail = _trails[i];
|
||||
|
||||
// Skip this trail if it's prepared to be removed
|
||||
if (trail.CanRemoveTrail())
|
||||
continue;
|
||||
|
||||
if (trail.particleId >= 0 && !trail.IsDead())
|
||||
{
|
||||
if (trail.GetBirthIterator()>0)
|
||||
{
|
||||
// New point creation
|
||||
float pointDistance = Vector3.Distance(trail.GetParticlePosition(), trail.GetLastAddedPointPosition());
|
||||
if (pointDistance>minVertexDistance) {
|
||||
float pathDeviationAngle = trail.GetPathDeviation();
|
||||
if (pointDistance>maxVertexDistance || pathDeviationAngle>maxPathDeviation) {
|
||||
trail.AddPoint(playgroundSystem.particleCache[trail.particleId].position, EvaluateWidth(0), time, _calculationStartTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// First point creation
|
||||
trail.SetFirstPoint(playgroundSystem.particleCache[trail.particleId].position, playgroundSystem.particleCache[trail.particleId].velocity, EvaluateWidth(0), time, _calculationStartTime);
|
||||
}
|
||||
|
||||
// Set the particle position info
|
||||
trail.SetParticlePosition(playgroundSystem.particleCache[trail.particleId].position);
|
||||
}
|
||||
|
||||
// Update the trail points
|
||||
for (int x = 0; x<trail.trailPoints.Count; x++)
|
||||
{
|
||||
TrailPoint trailPoint = trail.trailPoints[x];
|
||||
|
||||
if (trailPoint.CanRemove())
|
||||
{
|
||||
trail.RemovePoint(x);
|
||||
|
||||
if (!_localSpace)
|
||||
continue;
|
||||
}
|
||||
|
||||
float normalizedLifetime = trailPoint.GetNormalizedLifetime();
|
||||
|
||||
// Update trail points data
|
||||
trailPoint.Update (
|
||||
_calculationStartTime,
|
||||
EvaluateWidth(normalizedLifetime)
|
||||
);
|
||||
|
||||
// Set end point to follow particle
|
||||
if (!trail.IsDead() && x==trail.trailPoints.Count-1)
|
||||
trailPoint.position = trail.GetParticlePosition();
|
||||
|
||||
// Rotation of trail points
|
||||
Vector3 currentPosition = trailPoint.position;
|
||||
Vector3 nextPosition = x<trail.trailPoints.Count-1? trail.trailPoints[x+1].position : currentPosition + (currentPosition - trail.trailPoints[x-1].position);
|
||||
|
||||
Vector3 lookDirection = Vector3.up;
|
||||
switch (renderMode)
|
||||
{
|
||||
case TrailRenderMode.Vertical:
|
||||
lookDirection = Vector3.forward;
|
||||
break;
|
||||
case TrailRenderMode.Billboard:
|
||||
lookDirection = (_billboardTransformPosition - currentPosition).normalized;
|
||||
break;
|
||||
}
|
||||
|
||||
// If this is local space then recompute current & next position based on the local matrix
|
||||
if (_localSpace)
|
||||
{
|
||||
currentPosition = _localMatrix.MultiplyPoint3x4(currentPosition);
|
||||
nextPosition = _localMatrix.MultiplyPoint3x4(nextPosition);
|
||||
}
|
||||
|
||||
Vector3 dir = renderMode != TrailRenderMode.CustomRenderScale? (Vector3.Cross(lookDirection, nextPosition - currentPosition)).normalized : customRenderScale;
|
||||
Vector3 lPoint = currentPosition + (dir * (trailPoint.width*.5f));
|
||||
Vector3 rPoint = currentPosition - (dir * (trailPoint.width*.5f));
|
||||
|
||||
// Set mesh vertices into the rotated position
|
||||
trail.meshVerticesCache[x*2] = lPoint;
|
||||
trail.meshVerticesCache[(x*2)+1] = rPoint;
|
||||
|
||||
// Set uv
|
||||
float uvRatio = uvMode == TrailUvMode.Lifetime? normalizedLifetime : (x*1f) / (trail.GetBirthIterator()-1);
|
||||
trail.meshUvsCache[x*2] = new Vector2(uvRatio, 0);
|
||||
trail.meshUvsCache[(x*2)+1] = new Vector2(uvRatio, 1f);
|
||||
|
||||
// Update colors
|
||||
if (colorMode == TrailColorMode.Lifetime)
|
||||
{
|
||||
Color32 color = EvaluateColor(normalizedLifetime);
|
||||
color.a = (byte)(color.a*(pointArrayAlpha.Evaluate((x*1f) / (trail.GetBirthIterator()-1))));
|
||||
trail.SetColor(x, color);
|
||||
}
|
||||
else
|
||||
trail.SetColor(x, EvaluateColor(i, x));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The trail render mode determines how the trail will be rotated.
|
||||
/// Using billboard will rotate towards the assigned transform position, this is by default the main camera.
|
||||
/// Horizontal will rotate the points flat on X-Z axis.
|
||||
/// Vertical will rotate the points flat on X-Y axis.
|
||||
/// CustomRenderScale is a global world space normal which will multiply the scale on each axis.
|
||||
/// </summary>
|
||||
public enum TrailRenderMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Rotate points towards assigned billboard transform.
|
||||
/// </summary>
|
||||
Billboard,
|
||||
/// <summary>
|
||||
/// Rotate points flat X-Z.
|
||||
/// </summary>
|
||||
Horizontal,
|
||||
/// <summary>
|
||||
/// Rotate points flat X-Y.
|
||||
/// </summary>
|
||||
Vertical,
|
||||
/// <summary>
|
||||
/// Creates a custom render rotation/scale.
|
||||
/// </summary>
|
||||
CustomRenderScale
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The trail color mode determines how color should be distributed over a trail.
|
||||
/// </summary>
|
||||
public enum TrailColorMode
|
||||
{
|
||||
/// <summary>
|
||||
/// When using TrailColorMode.Lifetime the colors will be set depending on each point's normalized lifetime.
|
||||
/// </summary>
|
||||
Lifetime,
|
||||
/// <summary>
|
||||
/// When using TrailColorMode.PointArray the colors will be set depending on all the points within the trail, where each point is a normalized value linearly towards the total points.
|
||||
/// </summary>
|
||||
PointArray
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The trail uv mode determines how uv will be distributed over a trail.
|
||||
/// </summary>
|
||||
public enum TrailUvMode
|
||||
{
|
||||
/// <summary>
|
||||
/// When using TrailUvMode.Lifetime the uvs will be set depending on each point's normalized lifetime.
|
||||
/// </summary>
|
||||
Lifetime,
|
||||
/// <summary>
|
||||
/// When using TrailUvMode.PointArray the uvs will be set depending on all the points within the trail, where each point is a normalized value linearly towards the total points.
|
||||
/// </summary>
|
||||
PointArray
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The trail particle info struct contains data about particles to be read by a Playground Trail.
|
||||
/// </summary>
|
||||
public struct TrailParticleInfo {
|
||||
/// <summary>
|
||||
/// The particle identifier linearly towards the particle system's cached particles.
|
||||
/// </summary>
|
||||
public int particleId;
|
||||
/// <summary>
|
||||
/// The position of this trail particle.
|
||||
/// </summary>
|
||||
public Vector3 position;
|
||||
/// <summary>
|
||||
/// The velocity of this trail particle.
|
||||
/// </summary>
|
||||
public Vector3 velocity;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ParticlePlayground.TrailParticleInfo"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="particleId">Particle identifier.</param>
|
||||
/// <param name="position">Particle position.</param>
|
||||
/// <param name="velocity">Particle velocity.</param>
|
||||
public TrailParticleInfo (int particleId, Vector3 position, Vector3 velocity)
|
||||
{
|
||||
this.particleId = particleId;
|
||||
this.position = position;
|
||||
this.velocity = velocity;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 76bc001fa44a547bb86aea579a67ae0d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/Particle Playground/Graphics.meta
Normal file
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0a27dd1d06c3c504583ba9a6fc31f673
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984948
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/Particle Playground/Graphics/Editor.meta
Normal file
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fb31e28e5e0963e428467e92c4c48753
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984948
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/Particle Playground/Graphics/Editor/Icons.meta
Normal file
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cb29d5dac6f2c2048bfd3819df6838b2
|
||||
folderAsset: yes
|
||||
timeCreated: 1451984949
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 7.1 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e25eb56ec99894d6f8f83d963d324f78
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 7.6 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b7efd61b3c21e45fc9510abf1dd559bf
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ea83db8bf09b741a1a203571af766f5f
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6e01041934bf04f5a88b0272165bf725
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 8 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cb8fe57cd63cd47b78c512b6cb3828f9
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Particle Playground/Graphics/Editor/Icons/Default.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3dbf42a686ef44cbd8525bda4eb6723d
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 8.6 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: eb30b1d0e444c4556960c7042d29784f
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 17ed52b4e246743928ec1ec2ef8a5699
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 8.2 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bb3878536081d40a1970f04bcbeb5a1e
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 87036563b73f24d38b515d892cb425ee
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 7.9 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 16c18ec21693744eab6afd5b60915147
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 5.8 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 993cf971063fd48c1843623b82a29438
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 8.6 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e9116afcaef00450a949d2d983af28cd
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 9.9 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1824ae714e5244646ad99c05eda63a63
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 8.4 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c9151beffdd374add86203bb3703c0ce
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 4.5 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9d653a4f8784a4dc386f5c1cdf37248e
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 32
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5526d326b5fd746a8835ff5a83332dfb
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 32
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 4.9 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 672fadd0d1245444dba30066ebed196d
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 32
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 4.1 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 866f85a4a947341e79b24a5c788a02ee
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 32
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7cbc9b4a9effd4fe9ac8af6a21456512
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 32
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 4.6 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: caf46de47c6d8429e976d93964bf5eac
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 32
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e9e9e5dc11a3347b08009756a9d60739
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -3
|
||||
maxTextureSize: 32
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 3.7 KiB |