/****************************************************************************
        *       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>
 /// 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);
     }
 }
Beispiel #3
0
        /// <summary>
        /// Creates a trail and assigns it to a particle.
        /// </summary>
        /// <param name="particleInfo">Information about the particle.</param>
        public void CreateTrail(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 " + trails.Count);
            layer = Mathf.Clamp(layer, 0, 32);
            newTrail.trailGameObject.layer = layer;
            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)
            {
                float w = EvaluateWidth(0);
                newTrail.SetFirstPoint(particleInfo.position, particleInfo.velocity, w, time, _calculationStartTime);

                // Send trail point event to listeners
                if (_hasTrailPointEventListener)
                {
                    _eventTrailPoint.Update(
                        trails.Count,
                        0,
                        particleInfo.position,
                        w,
                        time,
                        _calculationStartTime
                        );
                    trailPointEvent(_eventTrailPoint);
                }
            }

            trails.Add(newTrail);
        }
		/****************************************************************************
			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);
		}
        /****************************************************************************
        *       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));
                    }
                }
            }
        }
        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();
            }
        }
Beispiel #7
0
        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 || _currentLoopValue != playgroundSystem.loop || _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);
            }

            // Consume the particle birth queue
            while (_isDoneThread && _birthQueue.Count > 0)
            {
                // Reuse or create new trails
                bool canReuseTrail       = trails.Count > 0 && _trailReuseQueue.Count > 0;
                int  reuseQueuePeekValue = canReuseTrail? _trailReuseQueue.Peek() : 0;
                if (canReuseTrail && (reuseQueuePeekValue < 0 || reuseQueuePeekValue > trails.Count - 1 || !trails[reuseQueuePeekValue].IsQueuedForReuse()))
                {
                    _trailReuseQueue.Dequeue();
                    canReuseTrail = false;
                }
                if (canReuseTrail)
                {
                    ReuseTrail(_trailReuseQueue.Dequeue(), _birthQueue.Dequeue());
                }
                else
                {
                    CreateTrail(_birthQueue.Dequeue());
                }
            }

            // 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())
                    {
                        if (!trails[i].IsQueuedForReuse())
                        {
                            _trailReuseQueue.Enqueue(i);
                            trails[i].QueueForReuse();
                        }
                    }
                }
            }

            // 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.IsQueuedForReuse())
                {
                    trail.UpdateMesh();
                }
            }

            // Check if there's any event listeners
            _hasTrailPointEventListener = trailPointEvent != null;

            // Check that the calculation delegate is assigned
            if (_trailsCalculationAction == null)
            {
                _trailsCalculationAction = CalculationDelegate;
            }

            _calculationStartTime = Application.isPlaying? Time.time : Time.realtimeSinceStartup;

            // Finally calculate all trails
            if (multithreading)
            {
                if (_isDoneThread)
                {
                    _isDoneThread = false;
                    PlaygroundC.RunAsync(_trailsCalculationAction);
                }
            }
            else
            {
                _isDoneThread = false;
                _trailsCalculationAction();
            }
        }