void OnGUI()
 {
     scaleMode = (ParticleSystemScalingMode)GUI.SelectionGrid(new Rect(25, 25, 300, 30), (int)scaleMode, new GUIContent[] { new GUIContent("Hierarchy"), new GUIContent("Local"), new GUIContent("Shape") }, 3);
     GUI.Label(new Rect(25, 80, 100, 30), "Scale");
     sliderValue = GUI.HorizontalSlider(new Rect(125, 85, 100, 30), sliderValue, 0.0F, 5.0F);
     GUI.Label(new Rect(25, 120, 100, 30), "Parent Scale");
     parentSliderValue = GUI.HorizontalSlider(new Rect(125, 125, 100, 30), parentSliderValue, 0.0F, 5.0F);
 }
Пример #2
0
                // ...

                void setScalingModeForAll(ParticleSystemScalingMode mode)
                {
                    saveUndo();

                    for (int i = 0; i < particleSystems.Count; i++)
                    {
                        ParticleSystem.MainModule m = particleSystems[i].main;
                        m.scalingMode = mode;
                    }
                }
 protected override void ReadFromImpl(object obj)
 {
     base.ReadFromImpl(obj);
     ParticleSystem.MainModule uo = (ParticleSystem.MainModule)obj;
     duration                  = uo.duration;
     loop                      = uo.loop;
     prewarm                   = uo.prewarm;
     startDelay                = uo.startDelay;
     startDelayMultiplier      = uo.startDelayMultiplier;
     startLifetime             = uo.startLifetime;
     startLifetimeMultiplier   = uo.startLifetimeMultiplier;
     startSpeed                = uo.startSpeed;
     startSpeedMultiplier      = uo.startSpeedMultiplier;
     startSize3D               = uo.startSize3D;
     startSize                 = uo.startSize;
     startSizeMultiplier       = uo.startSizeMultiplier;
     startSizeX                = uo.startSizeX;
     startSizeXMultiplier      = uo.startSizeXMultiplier;
     startSizeY                = uo.startSizeY;
     startSizeYMultiplier      = uo.startSizeYMultiplier;
     startSizeZ                = uo.startSizeZ;
     startSizeZMultiplier      = uo.startSizeZMultiplier;
     startRotation3D           = uo.startRotation3D;
     startRotation             = uo.startRotation;
     startRotationMultiplier   = uo.startRotationMultiplier;
     startRotationX            = uo.startRotationX;
     startRotationXMultiplier  = uo.startRotationXMultiplier;
     startRotationY            = uo.startRotationY;
     startRotationYMultiplier  = uo.startRotationYMultiplier;
     startRotationZ            = uo.startRotationZ;
     startRotationZMultiplier  = uo.startRotationZMultiplier;
     flipRotation              = uo.flipRotation;
     startColor                = uo.startColor;
     gravityModifier           = uo.gravityModifier;
     gravityModifierMultiplier = uo.gravityModifierMultiplier;
     simulationSpace           = uo.simulationSpace;
     customSimulationSpace     = ToID(uo.customSimulationSpace);
     simulationSpeed           = uo.simulationSpeed;
     useUnscaledTime           = uo.useUnscaledTime;
     scalingMode               = uo.scalingMode;
     playOnAwake               = uo.playOnAwake;
     maxParticles              = uo.maxParticles;
     emitterVelocityMode       = uo.emitterVelocityMode;
     stopAction                = uo.stopAction;
     cullingMode               = uo.cullingMode;
     ringBufferMode            = uo.ringBufferMode;
     ringBufferLoopRange       = uo.ringBufferLoopRange;
 }
Пример #4
0
    static void UpdateScaleMode(ParticleSystemScalingMode mode)
    {
        ParticleSystemProcess((particleSystem) => {
            if (particleSystem.main.scalingMode != mode)
            {
                particleSystem.scalingMode = mode;

                /*
                 * SerializedObject so = new SerializedObject(particleSystem);
                 *
                 * so.FindProperty(" ParticleSystem.MainModule.scalingMode").enumValueIndex = 1;
                 *
                 * so.ApplyModifiedProperties();
                 * particleSystem.main.scalingMode = mode;
                 */
                return(true);
            }
            return(false);
        });
    }
Пример #5
0
                // ...

                void LateUpdate()
                {
                    if (trianglesMeshFilter)
                    {
                        switch (particleSystemMainModule.simulationSpace)
                        {
                        case ParticleSystemSimulationSpace.World:
                        {
                            // Make sure this is always at origin, or triangle mesh moves out of sync since
                            // the mesh triangle vertices are already set to the world space particle positions.

                            trianglesMeshFilter.transform.position = Vector3.zero;

                            break;
                        }

                        case ParticleSystemSimulationSpace.Local:
                        {
                            // In local space it should follow me.

                            trianglesMeshFilter.transform.position = transform.position;
                            trianglesMeshFilter.transform.rotation = transform.rotation;

                            break;
                        }

                        case ParticleSystemSimulationSpace.Custom:
                        {
                            // In custom space it should follow the custom transform.

                            trianglesMeshFilter.transform.position = particleSystemMainModule.customSimulationSpace.position;
                            trianglesMeshFilter.transform.rotation = particleSystemMainModule.customSimulationSpace.rotation;

                            break;
                        }
                        }
                    }

                    // Filter doesn't exist but mesh is there? That means the filter reference was lost. Clear the mesh.
                    // AKA... If mesh filter is gone (deleted and/or reference nulled), clear the mesh.

                    else if (trianglesMesh)
                    {
                        trianglesMesh.Clear();
                    }

                    int lineRenderersCount = lineRenderers.Count;

                    // In case max line renderers value is changed at runtime -> destroy extra.

                    if (lineRenderersCount > maxLineRenderers)
                    {
                        for (int i = maxLineRenderers; i < lineRenderersCount; i++)
                        {
                            Destroy(lineRenderers[i].gameObject);
                        }

                        lineRenderers.RemoveRange(maxLineRenderers, lineRenderersCount - maxLineRenderers);
                        //lineRendererData.RemoveRange(maxLineRenderers, lineRenderersCount - maxLineRenderers);

                        lineRenderersCount -= lineRenderersCount - maxLineRenderers;
                    }

                    if (alwaysUpdate || visible)
                    {
                        // Prevent constant allocations so long as max particle count doesn't change.

                        int maxParticles = particleSystemMainModule.maxParticles;

                        if (particles == null || particles.Length < maxParticles)
                        {
                            particles = new ParticleSystem.Particle[maxParticles];

                            particlePositions = new Vector3[maxParticles];

                            particleColours = new Color[maxParticles];
                            particleSizes   = new float[maxParticles];
                        }

                        float deltaTime = Time.deltaTime;

                        timer += deltaTime;

                        if (timer >= delay)
                        {
                            timer = 0.0f;

                            int lrIndex = 0;

                            allConnectedParticles.Clear();

                            // Only update if drawing/making connections.

                            if (maxConnections > 0 && maxLineRenderers > 0)
                            {
                                particleSystem.GetParticles(particles);
                                //particleSystem.GetCustomParticleData(customParticleData, ParticleSystemCustomData.Custom1);

                                int particleCount = particleSystem.particleCount;

                                float maxDistanceSqr = maxDistance * maxDistance;

                                ParticleSystemSimulationSpace simulationSpace = particleSystemMainModule.simulationSpace;
                                ParticleSystemScalingMode     scalingMode     = particleSystemMainModule.scalingMode;

                                Transform customSimulationSpaceTransform = particleSystemMainModule.customSimulationSpace;

                                Color lineRendererStartColour = lineRendererTemplate.startColor;
                                Color lineRendererEndColour   = lineRendererTemplate.endColor;

                                float lineRendererStartWidth = lineRendererTemplate.startWidth * lineRendererTemplate.widthMultiplier;
                                float lineRendererEndWidth   = lineRendererTemplate.endWidth * lineRendererTemplate.widthMultiplier;

                                // Save particle properties in a quick loop (accessing these is expensive and loops significantly more later, so it's better to save them once now).

                                for (int i = 0; i < particleCount; i++)
                                {
                                    particlePositions[i] = particles[i].position;

                                    particleColours[i] = particles[i].GetCurrentColor(particleSystem);
                                    particleSizes[i]   = particles[i].GetCurrentSize(particleSystem);

                                    // Default is 0.0f, so if default, this is a new particle and I need to assign a custom ID.

                                    //if (customParticleData[i].x == 0.0f)
                                    //{
                                    //    // ++value -> increment first, then return that value.
                                    //    // That way it won't be zero (default) the first time I use it.

                                    //    customParticleData[i] = new Vector4(++uniqueParticleID, 0, 0, 0);
                                    //}
                                }

                                //particleSystem.SetCustomParticleData(customParticleData, ParticleSystemCustomData.Custom1);

                                Vector3 p1p2_difference;

                                // If in world space, there's no need to do any of the extra calculations... simplify the loop!

                                if (simulationSpace == ParticleSystemSimulationSpace.World)
                                {
                                    for (int i = 0; i < particleCount; i++)
                                    {
                                        if (lrIndex == maxLineRenderers)
                                        {
                                            break;
                                        }

                                        Color particleColour = particleColours[i];

                                        Color lineStartColour = Color.LerpUnclamped(lineRendererStartColour, particleColour, colourFromParticle);
                                        float lineStartColourOriginalAlpha = Mathf.LerpUnclamped(lineRendererStartColour.a, particleColour.a, alphaFromParticle);

                                        lineStartColour.a = lineStartColourOriginalAlpha;

                                        float lineStartWidth = Mathf.LerpUnclamped(lineRendererStartWidth, particleSizes[i], widthFromParticle);

                                        int   connections        = 0;
                                        int[] connectedParticles = new int[maxConnections + 1];

                                        for (int j = i + 1; j < particleCount; j++)
                                        {
                                            p1p2_difference.x = particlePositions[i].x - particlePositions[j].x;
                                            p1p2_difference.y = particlePositions[i].y - particlePositions[j].y;
                                            p1p2_difference.z = particlePositions[i].z - particlePositions[j].z;

                                            //float distanceSqr = Vector3.SqrMagnitude(p1p2_difference);

                                            float distanceSqr =

                                                p1p2_difference.x * p1p2_difference.x +
                                                p1p2_difference.y * p1p2_difference.y +
                                                p1p2_difference.z * p1p2_difference.z;

                                            if (distanceSqr <= maxDistanceSqr)
                                            {
                                                LineRenderer lr;

                                                if (lrIndex == lineRenderersCount)
                                                {
                                                    lr = Instantiate(lineRendererTemplate, _transform, false);

                                                    lineRenderers.Add(lr);
                                                    lineRenderersCount++;
                                                }

                                                lr = lineRenderers[lrIndex]; lr.enabled = true;

                                                lr.SetPosition(0, particlePositions[i]);
                                                lr.SetPosition(1, particlePositions[j]);

                                                float alphaAttenuation = alphaOverNormalizedDistance.Evaluate(distanceSqr / maxDistanceSqr);
                                                lineStartColour.a = lineStartColourOriginalAlpha * alphaAttenuation;

                                                lr.startColor = lineStartColour;

                                                particleColour = particleColours[j];

                                                Color lineEndColour = Color.LerpUnclamped(lineRendererEndColour, particleColour, colourFromParticle);
                                                lineEndColour.a = Mathf.LerpUnclamped(lineRendererEndColour.a, particleColour.a, alphaFromParticle);

                                                lr.endColor = lineEndColour;

                                                lr.startWidth = lineStartWidth;
                                                lr.endWidth   = Mathf.LerpUnclamped(lineRendererEndWidth, particleSizes[j], widthFromParticle);

                                                lrIndex++;
                                                connections++;

                                                // Intentionally taken AFTER connections++ (because index = 0 is the i'th / line origin particle).

                                                connectedParticles[connections] = j;

                                                if (connections == maxConnections || lrIndex == maxLineRenderers)
                                                {
                                                    break;
                                                }
                                            }
                                        }

                                        if (connections >= 2)
                                        {
                                            connectedParticles[0] = i;
                                            allConnectedParticles.Add(connectedParticles);
                                        }
                                    }
                                }
                                else
                                {
                                    Vector3    position   = Vector3.zero;
                                    Quaternion rotation   = Quaternion.identity;
                                    Vector3    localScale = Vector3.one;

                                    Transform simulationSpaceTransform = _transform;

                                    switch (simulationSpace)
                                    {
                                    case ParticleSystemSimulationSpace.Local:
                                    {
                                        position   = simulationSpaceTransform.position;
                                        rotation   = simulationSpaceTransform.rotation;
                                        localScale = simulationSpaceTransform.localScale;

                                        break;
                                    }

                                    case ParticleSystemSimulationSpace.Custom:
                                    {
                                        simulationSpaceTransform = customSimulationSpaceTransform;

                                        position   = simulationSpaceTransform.position;
                                        rotation   = simulationSpaceTransform.rotation;
                                        localScale = simulationSpaceTransform.localScale;

                                        break;
                                    }

                                    default:
                                    {
                                        throw new System.NotSupportedException(

                                                  string.Format("Unsupported scaling mode '{0}'.", simulationSpace));
                                    }
                                    }

                                    // I put these here so I can take out the default exception case.
                                    // Else I'd have a compiler error for potentially unassigned variables.

                                    Vector3 p1_position = Vector3.zero;
                                    Vector3 p2_position = Vector3.zero;

                                    for (int i = 0; i < particleCount; i++)
                                    {
                                        if (lrIndex == maxLineRenderers)
                                        {
                                            break;
                                        }

                                        switch (simulationSpace)
                                        {
                                        case ParticleSystemSimulationSpace.Local:
                                        case ParticleSystemSimulationSpace.Custom:
                                        {
                                            switch (scalingMode)
                                            {
                                            case ParticleSystemScalingMode.Hierarchy:
                                            {
                                                p1_position = simulationSpaceTransform.TransformPoint(particlePositions[i]);

                                                break;
                                            }

                                            case ParticleSystemScalingMode.Local:
                                            {
                                                // Order is important.

                                                //p1_position = Vector3.Scale(particlePositions[i], localScale);

                                                p1_position.x = particlePositions[i].x * localScale.x;
                                                p1_position.y = particlePositions[i].y * localScale.y;
                                                p1_position.z = particlePositions[i].z * localScale.z;

                                                p1_position = rotation * p1_position;
                                                //p1_position += position;

                                                p1_position.x += position.x;
                                                p1_position.y += position.y;
                                                p1_position.z += position.z;

                                                break;
                                            }

                                            case ParticleSystemScalingMode.Shape:
                                            {
                                                // Order is important.

                                                p1_position = rotation * particlePositions[i];
                                                //p1_position += position;

                                                p1_position.x += position.x;
                                                p1_position.y += position.y;
                                                p1_position.z += position.z;

                                                break;
                                            }

                                            default:
                                            {
                                                throw new System.NotSupportedException(

                                                          string.Format("Unsupported scaling mode '{0}'.", scalingMode));
                                            }
                                            }

                                            break;
                                        }
                                        }

                                        Color particleColour = particleColours[i];

                                        Color lineStartColour = Color.LerpUnclamped(lineRendererStartColour, particleColour, colourFromParticle);
                                        float lineStartColourOriginalAlpha = Mathf.LerpUnclamped(lineRendererStartColour.a, particleColour.a, alphaFromParticle);

                                        lineStartColour.a = lineStartColourOriginalAlpha;

                                        float lineStartWidth = Mathf.LerpUnclamped(lineRendererStartWidth, particleSizes[i], widthFromParticle);

                                        int   connections        = 0;
                                        int[] connectedParticles = new int[maxConnections + 1];

                                        for (int j = i + 1; j < particleCount; j++)
                                        {
                                            // Note that because particles array is not sorted by distance,
                                            // but rather by spawn time (I think), the connections made are
                                            // not necessarily the closest.

                                            switch (simulationSpace)
                                            {
                                            case ParticleSystemSimulationSpace.Local:
                                            case ParticleSystemSimulationSpace.Custom:
                                            {
                                                switch (scalingMode)
                                                {
                                                case ParticleSystemScalingMode.Hierarchy:
                                                {
                                                    p2_position = simulationSpaceTransform.TransformPoint(particlePositions[j]);

                                                    break;
                                                }

                                                case ParticleSystemScalingMode.Local:
                                                {
                                                    // Order is important.

                                                    //p2_position = Vector3.Scale(particlePositions[j], localScale);

                                                    p2_position.x = particlePositions[j].x * localScale.x;
                                                    p2_position.y = particlePositions[j].y * localScale.y;
                                                    p2_position.z = particlePositions[j].z * localScale.z;

                                                    p2_position = rotation * p2_position;
                                                    //p2_position += position;

                                                    p2_position.x += position.x;
                                                    p2_position.y += position.y;
                                                    p2_position.z += position.z;

                                                    break;
                                                }

                                                case ParticleSystemScalingMode.Shape:
                                                {
                                                    // Order is important.

                                                    p2_position = rotation * particlePositions[j];
                                                    //p2_position += position;

                                                    p2_position.x += position.x;
                                                    p2_position.y += position.y;
                                                    p2_position.z += position.z;

                                                    break;
                                                }

                                                default:
                                                {
                                                    throw new System.NotSupportedException(

                                                              string.Format("Unsupported scaling mode '{0}'.", scalingMode));
                                                }
                                                }

                                                break;
                                            }
                                            }

                                            p1p2_difference.x = particlePositions[i].x - particlePositions[j].x;
                                            p1p2_difference.y = particlePositions[i].y - particlePositions[j].y;
                                            p1p2_difference.z = particlePositions[i].z - particlePositions[j].z;

                                            // Note that distance is always calculated in WORLD SPACE.
                                            // Scaling the particle system will stretch the distances
                                            // and may require adjusting the maxDistance value.

                                            // I could also do it in local space (which may actually make more
                                            // sense) by just getting the difference of the positions without
                                            // all the transformations. This also provides opportunity for
                                            // optimization as I can limit the world space transform calculations
                                            // to only happen if a particle is within range.

                                            // Think about: Putting in a bool to switch between the two?

                                            //float distanceSqr = Vector3.SqrMagnitude(p1p2_difference);

                                            float distanceSqr =

                                                p1p2_difference.x * p1p2_difference.x +
                                                p1p2_difference.y * p1p2_difference.y +
                                                p1p2_difference.z * p1p2_difference.z;

                                            // If distance to particle within range, add new vertex position.

                                            // The larger the max distance, the quicker connections will
                                            // reach its max, terminating the loop earlier. So even though more lines have
                                            // to be drawn, it's still faster to have a larger maxDistance value because
                                            // the call to Vector3.Distance() is expensive.

                                            if (distanceSqr <= maxDistanceSqr)
                                            {
                                                LineRenderer lr;

                                                if (lrIndex == lineRenderersCount)
                                                {
                                                    lr = Instantiate(lineRendererTemplate, _transform, false);

                                                    lineRenderers.Add(lr);
                                                    lineRenderersCount++;

                                                    //lineRendererData.Add(new LineRendererData());
                                                }

                                                lr = lineRenderers[lrIndex];
                                                //LineRendererData lrd = lineRendererData[lrIndex];

                                                lr.enabled = true;

                                                //lrd.previousStartParticleID = lrd.currentStartParticleID;
                                                //lrd.previousEndParticleID = lrd.currentEndParticleID;

                                                //lrd.currentStartParticleID = customParticleData[i].x;
                                                //lrd.currentEndParticleID = customParticleData[j].x;

                                                lr.SetPosition(0, p1_position);
                                                lr.SetPosition(1, p2_position);

                                                //if (lrd.currentStartParticleID != lrd.previousStartParticleID || lrd.currentEndParticleID != lrd.previousEndParticleID)
                                                //{
                                                //    lrd.timer = 0.0f;
                                                //}

                                                //if (lrd.timer < 1.0f)
                                                //{
                                                //    lrd.timer += deltaTime / fadeInTime;
                                                //}

                                                //if (lrd.timer > 1.0f)
                                                //{
                                                //    lrd.timer = 1.0f;
                                                //}

                                                float alphaAttenuation = alphaOverNormalizedDistance.Evaluate(distanceSqr / maxDistanceSqr);
                                                //float alphaAttenuation = lrd.timer * alphaOverNormalizedDistance.Evaluate(distanceSqr / maxDistanceSqr);

                                                lineStartColour.a = lineStartColourOriginalAlpha * alphaAttenuation;

                                                lr.startColor = lineStartColour;

                                                particleColour = particleColours[j];

                                                Color lineEndColour = Color.LerpUnclamped(lineRendererEndColour, particleColour, colourFromParticle);
                                                lineEndColour.a = Mathf.LerpUnclamped(lineRendererEndColour.a, particleColour.a, alphaFromParticle) * alphaAttenuation;

                                                lr.endColor = lineEndColour;

                                                lr.startWidth = lineStartWidth;
                                                lr.endWidth   = Mathf.LerpUnclamped(lineRendererEndWidth, particleSizes[j], widthFromParticle);

                                                //lineRendererData[lrIndex] = lrd;

                                                lrIndex++;
                                                connections++;

                                                // Intentionally taken AFTER connections++ (because index = 0 is the i'th / line origin particle).

                                                connectedParticles[connections] = j;

                                                if (connections == maxConnections || lrIndex == maxLineRenderers)
                                                {
                                                    break;
                                                }
                                            }
                                        }

                                        if (connections >= 2)
                                        {
                                            connectedParticles[0] = i;
                                            allConnectedParticles.Add(connectedParticles);
                                        }
                                    }
                                }
                            }

                            // Disable remaining line renderers from the pool that weren't used.

                            for (int i = lrIndex; i < lineRenderersCount; i++)
                            {
                                if (lineRenderers[i].enabled)
                                {
                                    lineRenderers[i].enabled = false;
                                }
                            }

                            // I check against the filter rather than the mesh because the mesh should always exist as long as the filter reference is there.
                            // This way I can stop drawing/updating should the filter reference be lost.

                            if (trianglesMeshFilter)
                            {
                                // Triangles mesh.

                                // For efficiency (and my own general laziness), I only bother taking the first triangle formed.
                                // It doesn't matter all that much since this is an abstract effect anyway.

                                int vertexCount = allConnectedParticles.Count * 3;

                                Vector3[] vertices  = new Vector3[vertexCount];
                                int[]     triangles = new int[vertexCount];

                                Vector2[] uv = new Vector2[vertexCount];

                                Color[] colours = new Color[vertexCount];

                                float maxDistanceSqr = (maxDistance * maxDistance) * maxDistanceTriangleBias;

                                for (int i = 0; i < allConnectedParticles.Count; i++)
                                {
                                    int[] connectedParticles = allConnectedParticles[i];

                                    float distanceSqr = 0.0f;

                                    if (trianglesDistanceCheck)
                                    {
                                        Vector3 particlePositionA = particlePositions[connectedParticles[1]];
                                        Vector3 particlePositionB = particlePositions[connectedParticles[2]];

                                        //distance = Vector3.Distance(particlePositionA, particlePositionB);

                                        Vector3 difference;

                                        difference.x = particlePositionA.x - particlePositionB.x;
                                        difference.y = particlePositionA.y - particlePositionB.y;
                                        difference.z = particlePositionA.z - particlePositionB.z;

                                        distanceSqr =

                                            difference.x * difference.x +
                                            difference.y * difference.y +
                                            difference.z * difference.z;
                                    }

                                    if (distanceSqr < maxDistanceSqr)
                                    {
                                        int i3 = i * 3;

                                        vertices[i3 + 0] = particlePositions[connectedParticles[0]];
                                        vertices[i3 + 1] = particlePositions[connectedParticles[1]];
                                        vertices[i3 + 2] = particlePositions[connectedParticles[2]];

                                        uv[i3 + 0] = new Vector2(0.0f, 0.0f);
                                        uv[i3 + 1] = new Vector2(0.0f, 1.0f);
                                        uv[i3 + 2] = new Vector2(1.0f, 1.0f);

                                        triangles[i3 + 0] = i3 + 0;
                                        triangles[i3 + 1] = i3 + 1;
                                        triangles[i3 + 2] = i3 + 2;

                                        colours[i3 + 0] = particleColours[connectedParticles[0]];
                                        colours[i3 + 1] = particleColours[connectedParticles[1]];
                                        colours[i3 + 2] = particleColours[connectedParticles[2]];

                                        colours[i3 + 0] = Color.LerpUnclamped(Color.white, particleColours[connectedParticles[0]], triangleColourFromParticle);
                                        colours[i3 + 1] = Color.LerpUnclamped(Color.white, particleColours[connectedParticles[1]], triangleColourFromParticle);
                                        colours[i3 + 2] = Color.LerpUnclamped(Color.white, particleColours[connectedParticles[2]], triangleColourFromParticle);

                                        colours[i3 + 0].a = Mathf.LerpUnclamped(1.0f, particleColours[connectedParticles[0]].a, triangleAlphaFromParticle);
                                        colours[i3 + 1].a = Mathf.LerpUnclamped(1.0f, particleColours[connectedParticles[1]].a, triangleAlphaFromParticle);
                                        colours[i3 + 2].a = Mathf.LerpUnclamped(1.0f, particleColours[connectedParticles[2]].a, triangleAlphaFromParticle);
                                    }
                                }

                                trianglesMesh.Clear();

                                trianglesMesh.vertices = vertices;

                                trianglesMesh.uv = uv;

                                trianglesMesh.triangles = triangles;
                                trianglesMesh.colors    = colours;
                            }
                        }
                    }
                }
Пример #6
0
                // ...

                void LateUpdate()
                {
                    int lineRenderersCount = lineRenderers.Count;

                    // In case max line renderers value is changed at runtime -> destroy extra.

                    if (lineRenderersCount > maxLineRenderers)
                    {
                        for (int i = maxLineRenderers; i < lineRenderersCount; i++)
                        {
                            Destroy(lineRenderers[i].gameObject);
                        }

                        lineRenderers.RemoveRange(maxLineRenderers, lineRenderersCount - maxLineRenderers);
                        lineRenderersCount -= lineRenderersCount - maxLineRenderers;
                    }

                    if (alwaysUpdate || visible)
                    {
                        // Prevent constant allocations so long as max particle count doesn't change.

                        int maxParticles = particleSystemMainModule.maxParticles;

                        if (particles == null || particles.Length < maxParticles)
                        {
                            particles = new ParticleSystem.Particle[maxParticles];

                            particlePositions = new Vector3[maxParticles];

                            particleColours = new Color[maxParticles];
                            particleSizes   = new float[maxParticles];
                        }

                        timer += Time.deltaTime;

                        if (timer >= delay)
                        {
                            timer = 0.0f;

                            int lrIndex = 0;

                            // Only update if drawing/making connections.

                            if (maxConnections > 0 && maxLineRenderers > 0)
                            {
                                particleSystem.GetParticles(particles);
                                int particleCount = particleSystem.particleCount;

                                float maxDistanceSqr = maxDistance * maxDistance;

                                ParticleSystemSimulationSpace simulationSpace = particleSystemMainModule.simulationSpace;
                                ParticleSystemScalingMode     scalingMode     = particleSystemMainModule.scalingMode;

                                Transform customSimulationSpaceTransform = particleSystemMainModule.customSimulationSpace;

                                Color lineRendererStartColour = lineRendererTemplate.startColor;
                                Color lineRendererEndColour   = lineRendererTemplate.endColor;

                                float lineRendererStartWidth = lineRendererTemplate.startWidth * lineRendererTemplate.widthMultiplier;
                                float lineRendererEndWidth   = lineRendererTemplate.endWidth * lineRendererTemplate.widthMultiplier;

                                // Save particle properties in a quick loop (accessing these is expensive and loops significantly more later, so it's better to save them once now).

                                for (int i = 0; i < particleCount; i++)
                                {
                                    particlePositions[i] = particles[i].position;

                                    particleColours[i] = particles[i].GetCurrentColor(particleSystem);
                                    particleSizes[i]   = particles[i].GetCurrentSize(particleSystem);
                                }

                                Vector3 p1p2_difference;

                                // If in world space, there's no need to do any of the extra calculations... simplify the loop!

                                if (simulationSpace == ParticleSystemSimulationSpace.World)
                                {
                                    for (int i = 0; i < particleCount; i++)
                                    {
                                        if (lrIndex == maxLineRenderers)
                                        {
                                            break;
                                        }

                                        Color particleColour = particleColours[i];

                                        Color lineStartColour = Color.LerpUnclamped(lineRendererStartColour, particleColour, colourFromParticle);
                                        lineStartColour.a = Mathf.LerpUnclamped(lineRendererStartColour.a, particleColour.a, alphaFromParticle);

                                        float lineStartWidth = Mathf.LerpUnclamped(lineRendererStartWidth, particleSizes[i], widthFromParticle);

                                        int connections = 0;

                                        for (int j = i + 1; j < particleCount; j++)
                                        {
                                            p1p2_difference.x = particlePositions[i].x - particlePositions[j].x;
                                            p1p2_difference.y = particlePositions[i].y - particlePositions[j].y;
                                            p1p2_difference.z = particlePositions[i].z - particlePositions[j].z;

                                            //float distanceSqr = Vector3.SqrMagnitude(p1p2_difference);

                                            float distanceSqr =

                                                p1p2_difference.x * p1p2_difference.x +
                                                p1p2_difference.y * p1p2_difference.y +
                                                p1p2_difference.z * p1p2_difference.z;

                                            if (distanceSqr <= maxDistanceSqr)
                                            {
                                                LineRenderer lr;

                                                if (lrIndex == lineRenderersCount)
                                                {
                                                    lr = Instantiate(lineRendererTemplate, _transform, false);

                                                    lineRenderers.Add(lr);
                                                    lineRenderersCount++;
                                                }

                                                lr = lineRenderers[lrIndex]; lr.enabled = true;

                                                lr.SetPosition(0, particlePositions[i]);
                                                lr.SetPosition(1, particlePositions[j]);

                                                lr.startColor = lineStartColour;

                                                particleColour = particleColours[j];

                                                Color lineEndColour = Color.LerpUnclamped(lineRendererEndColour, particleColour, colourFromParticle);
                                                lineEndColour.a = Mathf.LerpUnclamped(lineRendererEndColour.a, particleColour.a, alphaFromParticle);

                                                lr.endColor = lineEndColour;

                                                lr.startWidth = lineStartWidth;
                                                lr.endWidth   = Mathf.LerpUnclamped(lineRendererEndWidth, particleSizes[j], widthFromParticle);

                                                lrIndex++;
                                                connections++;

                                                if (connections == maxConnections || lrIndex == maxLineRenderers)
                                                {
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    Vector3    position   = Vector3.zero;
                                    Quaternion rotation   = Quaternion.identity;
                                    Vector3    localScale = Vector3.one;

                                    Transform simulationSpaceTransform = _transform;

                                    switch (simulationSpace)
                                    {
                                    case ParticleSystemSimulationSpace.Local:
                                    {
                                        position   = simulationSpaceTransform.position;
                                        rotation   = simulationSpaceTransform.rotation;
                                        localScale = simulationSpaceTransform.localScale;

                                        break;
                                    }

                                    case ParticleSystemSimulationSpace.Custom:
                                    {
                                        simulationSpaceTransform = customSimulationSpaceTransform;

                                        position   = simulationSpaceTransform.position;
                                        rotation   = simulationSpaceTransform.rotation;
                                        localScale = simulationSpaceTransform.localScale;

                                        break;
                                    }

                                    default:
                                    {
                                        throw new System.NotSupportedException(

                                                  string.Format("Unsupported scaling mode '{0}'.", simulationSpace));
                                    }
                                    }

                                    // I put these here so I can take out the default exception case.
                                    // Else I'd have a compiler error for potentially unassigned variables.

                                    Vector3 p1_position = Vector3.zero;
                                    Vector3 p2_position = Vector3.zero;

                                    for (int i = 0; i < particleCount; i++)
                                    {
                                        if (lrIndex == maxLineRenderers)
                                        {
                                            break;
                                        }

                                        switch (simulationSpace)
                                        {
                                        case ParticleSystemSimulationSpace.Local:
                                        case ParticleSystemSimulationSpace.Custom:
                                        {
                                            switch (scalingMode)
                                            {
                                            case ParticleSystemScalingMode.Hierarchy:
                                            {
                                                p1_position = simulationSpaceTransform.TransformPoint(particlePositions[i]);

                                                break;
                                            }

                                            case ParticleSystemScalingMode.Local:
                                            {
                                                // Order is important.

                                                //p1_position = Vector3.Scale(particlePositions[i], localScale);

                                                p1_position.x = particlePositions[i].x * localScale.x;
                                                p1_position.y = particlePositions[i].y * localScale.y;
                                                p1_position.z = particlePositions[i].z * localScale.z;

                                                p1_position = rotation * p1_position;
                                                //p1_position += position;

                                                p1_position.x += position.x;
                                                p1_position.y += position.y;
                                                p1_position.z += position.z;

                                                break;
                                            }

                                            case ParticleSystemScalingMode.Shape:
                                            {
                                                // Order is important.

                                                p1_position = rotation * particlePositions[i];
                                                //p1_position += position;

                                                p1_position.x += position.x;
                                                p1_position.y += position.y;
                                                p1_position.z += position.z;

                                                break;
                                            }

                                            default:
                                            {
                                                throw new System.NotSupportedException(

                                                          string.Format("Unsupported scaling mode '{0}'.", scalingMode));
                                            }
                                            }

                                            break;
                                        }
                                        }

                                        Color particleColour = particleColours[i];

                                        Color lineStartColour = Color.LerpUnclamped(lineRendererStartColour, particleColour, colourFromParticle);
                                        lineStartColour.a = Mathf.LerpUnclamped(lineRendererStartColour.a, particleColour.a, alphaFromParticle);

                                        float lineStartWidth = Mathf.LerpUnclamped(lineRendererStartWidth, particleSizes[i], widthFromParticle);

                                        int connections = 0;

                                        for (int j = i + 1; j < particleCount; j++)
                                        {
                                            // Note that because particles array is not sorted by distance,
                                            // but rather by spawn time (I think), the connections made are
                                            // not necessarily the closest.

                                            switch (simulationSpace)
                                            {
                                            case ParticleSystemSimulationSpace.Local:
                                            case ParticleSystemSimulationSpace.Custom:
                                            {
                                                switch (scalingMode)
                                                {
                                                case ParticleSystemScalingMode.Hierarchy:
                                                {
                                                    p2_position = simulationSpaceTransform.TransformPoint(particlePositions[j]);

                                                    break;
                                                }

                                                case ParticleSystemScalingMode.Local:
                                                {
                                                    // Order is important.

                                                    //p2_position = Vector3.Scale(particlePositions[j], localScale);

                                                    p2_position.x = particlePositions[j].x * localScale.x;
                                                    p2_position.y = particlePositions[j].y * localScale.y;
                                                    p2_position.z = particlePositions[j].z * localScale.z;

                                                    p2_position = rotation * p2_position;
                                                    //p2_position += position;

                                                    p2_position.x += position.x;
                                                    p2_position.y += position.y;
                                                    p2_position.z += position.z;

                                                    break;
                                                }

                                                case ParticleSystemScalingMode.Shape:
                                                {
                                                    // Order is important.

                                                    p2_position = rotation * particlePositions[j];
                                                    //p2_position += position;

                                                    p2_position.x += position.x;
                                                    p2_position.y += position.y;
                                                    p2_position.z += position.z;

                                                    break;
                                                }

                                                default:
                                                {
                                                    throw new System.NotSupportedException(

                                                              string.Format("Unsupported scaling mode '{0}'.", scalingMode));
                                                }
                                                }

                                                break;
                                            }
                                            }

                                            p1p2_difference.x = particlePositions[i].x - particlePositions[j].x;
                                            p1p2_difference.y = particlePositions[i].y - particlePositions[j].y;
                                            p1p2_difference.z = particlePositions[i].z - particlePositions[j].z;

                                            // Note that distance is always calculated in WORLD SPACE.
                                            // Scaling the particle system will stretch the distances
                                            // and may require adjusting the maxDistance value.

                                            // I could also do it in local space (which may actually make more
                                            // sense) by just getting the difference of the positions without
                                            // all the transformations. This also provides opportunity for
                                            // optimization as I can limit the world space transform calculations
                                            // to only happen if a particle is within range.

                                            // Think about: Putting in a bool to switch between the two?

                                            //float distanceSqr = Vector3.SqrMagnitude(p1p2_difference);

                                            float distanceSqr =

                                                p1p2_difference.x * p1p2_difference.x +
                                                p1p2_difference.y * p1p2_difference.y +
                                                p1p2_difference.z * p1p2_difference.z;

                                            // If distance to particle within range, add new vertex position.

                                            // The larger the max distance, the quicker connections will
                                            // reach its max, terminating the loop earlier. So even though more lines have
                                            // to be drawn, it's still faster to have a larger maxDistance value because
                                            // the call to Vector3.Distance() is expensive.

                                            if (distanceSqr <= maxDistanceSqr)
                                            {
                                                LineRenderer lr;

                                                if (lrIndex == lineRenderersCount)
                                                {
                                                    lr = Instantiate(lineRendererTemplate, _transform, false);

                                                    lineRenderers.Add(lr);
                                                    lineRenderersCount++;
                                                }

                                                lr = lineRenderers[lrIndex]; lr.enabled = true;

                                                lr.SetPosition(0, p1_position);
                                                lr.SetPosition(1, p2_position);

                                                lr.startColor = lineStartColour;

                                                particleColour = particleColours[j];

                                                Color lineEndColour = Color.LerpUnclamped(lineRendererEndColour, particleColour, colourFromParticle);
                                                lineEndColour.a = Mathf.LerpUnclamped(lineRendererEndColour.a, particleColour.a, alphaFromParticle);

                                                lr.endColor = lineEndColour;

                                                lr.startWidth = lineStartWidth;
                                                lr.endWidth   = Mathf.LerpUnclamped(lineRendererEndWidth, particleSizes[j], widthFromParticle);

                                                lrIndex++;
                                                connections++;

                                                if (connections == maxConnections || lrIndex == maxLineRenderers)
                                                {
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }

                            // Disable remaining line renderers from the pool that weren't used.

                            for (int i = lrIndex; i < lineRenderersCount; i++)
                            {
                                if (lineRenderers[i].enabled)
                                {
                                    lineRenderers[i].enabled = false;
                                }
                            }
                        }
                    }
                }
                // ...

                protected virtual void LateUpdate()
                {
                    _radius   = scaledRadius;
                    radiusSqr = _radius * _radius;

                    forceDeltaTime    = force * Time.deltaTime;
                    transformPosition = transform.position + offset;

                    // SELECTIVE.
                    // If manually assigned a set of systems, use those no matter what.

                    if (_particleSystems.Count != 0)
                    {
                        // If editor array size changed, clear and add again.

                        if (particleSystems.Count != _particleSystems.Count)
                        {
                            particleSystems.Clear();
                            particleSystems.AddRange(_particleSystems);
                        }

                        // Else if array size is the same, then re-assign from
                        // the editor array. I do this in case the elements are different
                        // even though the size is the same.

                        else
                        {
                            for (int i = 0; i < _particleSystems.Count; i++)
                            {
                                particleSystems[i] = _particleSystems[i];
                            }
                        }
                    }

                    // LOCAL.
                    // Else if attached to particle system, use only that.
                    // Obviously, this will only happen if there are no systems specified in the array.

                    else if (particleSystem)
                    {
                        // If just one element, assign as local PS component.

                        if (particleSystems.Count == 1)
                        {
                            particleSystems[0] = particleSystem;
                        }

                        // Else, clear entire array and add only the one.

                        else
                        {
                            particleSystems.Clear();
                            particleSystems.Add(particleSystem);
                        }
                    }

                    // GLOBAL.
                    // Else, take all the ones from the entire scene.

                    // This is the most expensive since it searches the entire scene
                    // and also requires an allocation for every frame due to not knowing
                    // if the particle systems are all the same from the last frame unless
                    // I had a list to compare to from last frame. In that case, I'm not sure
                    // if the performance would be better or worse. Do a test later?

                    else
                    {
                        particleSystems.Clear();
                        particleSystems.AddRange(FindObjectsOfType <ParticleSystem>());
                    }

                    parameters = new GetForceParameters();

                    particleSystemsCount = particleSystems.Count;

                    // If first frame (array is null) or length is less than the number of systems, initialize size of array.
                    // I never shrink the array. Not sure if that's potentially super bad? I could always throw in a public
                    // bool as an option to allow shrinking since there's a performance benefit for each, but depends on the
                    // implementation case.

                    if (particleSystemParticles == null || particleSystemParticles.Length < particleSystemsCount)
                    {
                        particleSystemParticles   = new ParticleSystem.Particle[particleSystemsCount][];
                        particleSystemMainModules = new ParticleSystem.MainModule[particleSystemsCount];

                        particleSystemRenderers = new Renderer[particleSystemsCount];
                        particleSystemExternalForcesMultipliers = new float[particleSystemsCount];

                        for (int i = 0; i < particleSystemsCount; i++)
                        {
                            particleSystemMainModules[i] = particleSystems[i].main;
                            particleSystemRenderers[i]   = particleSystems[i].GetComponent <Renderer>();

                            particleSystemExternalForcesMultipliers[i] = particleSystems[i].externalForces.multiplier;
                        }
                    }

                    for (int i = 0; i < particleSystemsCount; i++)
                    {
                        if (!particleSystemRenderers[i].isVisible && !alwaysUpdate)
                        {
                            continue;
                        }

                        int maxParticles = particleSystemMainModules[i].maxParticles;

                        if (particleSystemParticles[i] == null || particleSystemParticles[i].Length < maxParticles)
                        {
                            particleSystemParticles[i] = new ParticleSystem.Particle[maxParticles];
                        }

                        currentParticleSystem = particleSystems[i];

                        PerParticleSystemSetup();

                        int particleCount = currentParticleSystem.GetParticles(particleSystemParticles[i]);

                        ParticleSystemSimulationSpace simulationSpace = particleSystemMainModules[i].simulationSpace;
                        ParticleSystemScalingMode     scalingMode     = particleSystemMainModules[i].scalingMode;

                        // I could also store the transforms in an array similar to what I do with modules.
                        // Or, put all of those together into a struct and make an array out of that since
                        // they'll always be assigned/updated at the same time.

                        Transform currentParticleSystemTransform = currentParticleSystem.transform;
                        Transform customSimulationSpaceTransform = particleSystemMainModules[i].customSimulationSpace;

                        // If in world space, there's no need to do any of the extra calculations... simplify the loop!

                        if (simulationSpace == ParticleSystemSimulationSpace.World)
                        {
                            for (int j = 0; j < particleCount; j++)
                            {
                                parameters.particlePosition = particleSystemParticles[i][j].position;

                                parameters.scaledDirectionToAffectorCenter.x = transformPosition.x - parameters.particlePosition.x;
                                parameters.scaledDirectionToAffectorCenter.y = transformPosition.y - parameters.particlePosition.y;
                                parameters.scaledDirectionToAffectorCenter.z = transformPosition.z - parameters.particlePosition.z;

                                parameters.distanceToAffectorCenterSqr = parameters.scaledDirectionToAffectorCenter.sqrMagnitude;

                                if (parameters.distanceToAffectorCenterSqr < radiusSqr)
                                {
                                    float distanceToCenterNormalized = parameters.distanceToAffectorCenterSqr / radiusSqr;
                                    float distanceScale = scaleForceByDistance.Evaluate(distanceToCenterNormalized);

                                    Vector3 force      = GetForce();
                                    float   forceScale = (forceDeltaTime * distanceScale) * particleSystemExternalForcesMultipliers[i];

                                    force.x *= forceScale;
                                    force.y *= forceScale;
                                    force.z *= forceScale;

                                    Vector3 particleVelocity = particleSystemParticles[i][j].velocity;

                                    particleVelocity.x += force.x;
                                    particleVelocity.y += force.y;
                                    particleVelocity.z += force.z;

                                    particleSystemParticles[i][j].velocity = particleVelocity;
                                }
                            }
                        }
                        else
                        {
                            Vector3    particleSystemPosition   = Vector3.zero;
                            Quaternion particleSystemRotation   = Quaternion.identity;
                            Vector3    particleSystemLocalScale = Vector3.one;

                            Transform simulationSpaceTransform = currentParticleSystemTransform;

                            switch (simulationSpace)
                            {
                            case ParticleSystemSimulationSpace.Local:
                            {
                                particleSystemPosition   = simulationSpaceTransform.position;
                                particleSystemRotation   = simulationSpaceTransform.rotation;
                                particleSystemLocalScale = simulationSpaceTransform.localScale;

                                break;
                            }

                            case ParticleSystemSimulationSpace.Custom:
                            {
                                simulationSpaceTransform = customSimulationSpaceTransform;

                                particleSystemPosition   = simulationSpaceTransform.position;
                                particleSystemRotation   = simulationSpaceTransform.rotation;
                                particleSystemLocalScale = simulationSpaceTransform.localScale;

                                break;
                            }

                            default:
                            {
                                throw new System.NotSupportedException(

                                          string.Format("Unsupported scaling mode '{0}'.", simulationSpace));
                            }
                            }

                            for (int j = 0; j < particleCount; j++)
                            {
                                parameters.particlePosition = particleSystemParticles[i][j].position;

                                switch (simulationSpace)
                                {
                                case ParticleSystemSimulationSpace.Local:
                                case ParticleSystemSimulationSpace.Custom:
                                {
                                    switch (scalingMode)
                                    {
                                    case ParticleSystemScalingMode.Hierarchy:
                                    {
                                        parameters.particlePosition = simulationSpaceTransform.TransformPoint(particleSystemParticles[i][j].position);

                                        break;
                                    }

                                    case ParticleSystemScalingMode.Local:
                                    {
                                        // Order is important.

                                        parameters.particlePosition = Vector3.Scale(parameters.particlePosition, particleSystemLocalScale);
                                        parameters.particlePosition = particleSystemRotation * parameters.particlePosition;
                                        parameters.particlePosition = parameters.particlePosition + particleSystemPosition;

                                        break;
                                    }

                                    case ParticleSystemScalingMode.Shape:
                                    {
                                        parameters.particlePosition = particleSystemRotation * parameters.particlePosition;
                                        parameters.particlePosition = parameters.particlePosition + particleSystemPosition;

                                        break;
                                    }

                                    default:
                                    {
                                        throw new System.NotSupportedException(

                                                  string.Format("Unsupported scaling mode '{0}'.", scalingMode));
                                    }
                                    }

                                    break;
                                }
                                }

                                parameters.scaledDirectionToAffectorCenter.x = transformPosition.x - parameters.particlePosition.x;
                                parameters.scaledDirectionToAffectorCenter.y = transformPosition.y - parameters.particlePosition.y;
                                parameters.scaledDirectionToAffectorCenter.z = transformPosition.z - parameters.particlePosition.z;

                                parameters.distanceToAffectorCenterSqr = parameters.scaledDirectionToAffectorCenter.sqrMagnitude;

                                //particleSystemParticles[i][j].velocity += forceDeltaTime * Vector3.Normalize(parameters.scaledDirectionToAffectorCenter);

                                if (parameters.distanceToAffectorCenterSqr < radiusSqr)
                                {
                                    // 0.0f -> 0.99...f;

                                    float distanceToCenterNormalized = parameters.distanceToAffectorCenterSqr / radiusSqr;

                                    // Evaluating a curve within a loop which is very likely to exceed a few thousand
                                    // iterations produces a noticeable FPS drop (around minus 2 - 5). Might be a worthwhile
                                    // optimization to check outside all loops if the curve is constant (all keyframes same value),
                                    // and then run a different block of code if true that uses that value as a stored float without
                                    // having to call Evaluate(t).

                                    float distanceScale = scaleForceByDistance.Evaluate(distanceToCenterNormalized);

                                    // Expanded vector operations for optimization. I think this is already done by
                                    // the compiler, but it's nice to have for the editor anyway.

                                    Vector3 force      = GetForce();
                                    float   forceScale = (forceDeltaTime * distanceScale) * particleSystemExternalForcesMultipliers[i];

                                    force.x *= forceScale;
                                    force.y *= forceScale;
                                    force.z *= forceScale;

                                    switch (simulationSpace)
                                    {
                                    case ParticleSystemSimulationSpace.Local:
                                    case ParticleSystemSimulationSpace.Custom:
                                    {
                                        switch (scalingMode)
                                        {
                                        case ParticleSystemScalingMode.Hierarchy:
                                        {
                                            force = simulationSpaceTransform.InverseTransformVector(force);

                                            break;
                                        }

                                        case ParticleSystemScalingMode.Local:
                                        {
                                            // Order is important.
                                            // Notice how rotation and scale orders are reversed.

                                            force = Quaternion.Inverse(particleSystemRotation) * force;
                                            force = Vector3.Scale(force, new Vector3(

                                                                      1.0f / particleSystemLocalScale.x,
                                                                      1.0f / particleSystemLocalScale.y,
                                                                      1.0f / particleSystemLocalScale.z));

                                            break;
                                        }

                                        case ParticleSystemScalingMode.Shape:
                                        {
                                            force = Quaternion.Inverse(particleSystemRotation) * force;

                                            break;
                                        }

                                        // This would technically never execute since it's checked earlier (above).

                                        default:
                                        {
                                            throw new System.NotSupportedException(

                                                      string.Format("Unsupported scaling mode '{0}'.", scalingMode));
                                        }
                                        }

                                        break;
                                    }
                                    }

                                    Vector3 particleVelocity = particleSystemParticles[i][j].velocity;

                                    particleVelocity.x += force.x;
                                    particleVelocity.y += force.y;
                                    particleVelocity.z += force.z;

                                    particleSystemParticles[i][j].velocity = particleVelocity;
                                }
                            }
                        }

                        currentParticleSystem.SetParticles(particleSystemParticles[i], particleCount);
                    }
                }
        protected override JSONObject ToJSON(WXHierarchyContext context)
        {
            ParticleSystemRenderer particleSystemRenderer = particleSys.GetComponent <ParticleSystemRenderer>();

            JSONObject json = new JSONObject(JSONObject.Type.OBJECT);
            JSONObject data = new JSONObject(JSONObject.Type.OBJECT);

            json.AddField("type", getTypeName());
            json.AddField("data", data);

            JSONObject materials = new JSONObject(JSONObject.Type.ARRAY);

            data.AddField("materials", materials);
            Material[] mats = particleSystemRenderer.sharedMaterials;
            foreach (Material material in mats)
            {
                if (material != null)
                {
                    WXMaterial materialConverter = new WXMaterial(material, particleSystemRenderer);
                    string     materialPath      = materialConverter.Export(context.preset);
                    materials.Add(materialPath);
                    context.AddResource(materialPath);
                }
            }

            JSONObject modCommon     = new JSONObject(JSONObject.Type.OBJECT);
            JSONObject modCommonData = new JSONObject(JSONObject.Type.OBJECT);

            data.AddField("common", modCommonData);

            modCommonData.AddField("startSize3D", particleSys.main.startSize3D);
            if (particleSys.main.startSize3D)
            {
                modCommonData.AddField("startSizeX", ParseMinMaxCurve(particleSys.main.startSizeX));
                modCommonData.AddField("startSizeY", ParseMinMaxCurve(particleSys.main.startSizeY));
                modCommonData.AddField("startSizeZ", ParseMinMaxCurve(particleSys.main.startSizeZ));
            }
            else
            {
                modCommonData.AddField("startSize", ParseMinMaxCurve(particleSys.main.startSize));
            }
            modCommonData.AddField("startColor", ParseMinMaxGradient(particleSys.main.startColor));
            modCommonData.AddField("startLifetime", ParseMinMaxCurve(particleSys.main.startLifetime));
            modCommonData.AddField("startRotation3D", particleSys.main.startRotation3D);
            if (particleSys.main.startRotation3D)
            {
                modCommonData.AddField("startRotationX", ParseMinMaxCurve(particleSys.main.startRotationX, (float)(180 / Math.PI)));
                modCommonData.AddField("startRotationY", ParseMinMaxCurve(particleSys.main.startRotationY, (float)(180 / Math.PI)));
                modCommonData.AddField("startRotationZ", ParseMinMaxCurve(particleSys.main.startRotationZ, (float)(180 / Math.PI)));
            }
            else
            {
                modCommonData.AddField("startRotationZ", ParseMinMaxCurve(particleSys.main.startRotation, (float)(180 / Math.PI)));
            }
            modCommonData.AddField("startSpeed", ParseMinMaxCurve(particleSys.main.startSpeed));
            modCommonData.AddField("gravityModifier", ParseMinMaxCurve(particleSys.main.gravityModifier));
#if UNITY_2018_1_OR_NEWER
            modCommonData.AddField("randomizeRotation", particleSys.main.flipRotation);
#endif
            modCommonData.AddField("randomSeed", particleSys.randomSeed);
            modCommonData.AddField("autoRandomSeed", particleSys.useAutoRandomSeed);

            ParticleSystemScalingMode pScalingMode = particleSys.main.scalingMode;
            int pScalingModeNum = 0;
            switch (pScalingMode)
            {
            case ParticleSystemScalingMode.Hierarchy:
                pScalingModeNum = 0;
                break;

            case ParticleSystemScalingMode.Local:
                pScalingModeNum = 1;
                break;

            case ParticleSystemScalingMode.Shape:
                pScalingModeNum = 2;
                break;
            }
            modCommonData.AddField("scalingMode", pScalingModeNum);

            ParticleSystemSimulationSpace simulationSpace = particleSys.main.simulationSpace;
            int simulationSpaceNum = 0;
            switch (simulationSpace)
            {
            case ParticleSystemSimulationSpace.Local:
                simulationSpaceNum = 0;
                break;

            case ParticleSystemSimulationSpace.World:
                simulationSpaceNum = 1;
                break;

            case ParticleSystemSimulationSpace.Custom:
                simulationSpaceNum = 2;
                break;
            }
            modCommonData.AddField("simulationSpace", simulationSpaceNum);

            JSONObject emitter     = new JSONObject(JSONObject.Type.OBJECT);
            JSONObject emitterData = new JSONObject(JSONObject.Type.OBJECT);
            data.AddField("emitter", emitterData);
            emitterData.AddField("playOnAwake", particleSys.main.playOnAwake);
            emitterData.AddField("looping", particleSys.main.loop);
            emitterData.AddField("duration", particleSys.main.duration);
            emitterData.AddField("startDelay", ParseMinMaxCurve(particleSys.main.startDelay));


            if (particleSys.emission.enabled)
            {
                JSONObject burst = new JSONObject(JSONObject.Type.ARRAY);
                emitterData.AddField("bursts", burst);
                int count = particleSys.emission.burstCount;
                ParticleSystem.Burst[] bursts = new ParticleSystem.Burst[count];
                particleSys.emission.GetBursts(bursts);
                for (int i = 0; i < count; i++)
                {
                    //burst.Add(ParseBurst(particleSys.emission.GetBurst(i)));
                    burst.Add(ParseBurst(bursts[i]));
                }

                emitterData.AddField("rateOverTime", ParseMinMaxCurve(particleSys.emission.rateOverTime));
            }
            emitterData.AddField("maxParticles", particleSys.main.maxParticles);

            if (particleSystemRenderer.enabled)
            {
                JSONObject renderer     = new JSONObject(JSONObject.Type.OBJECT);
                JSONObject rendererData = new JSONObject(JSONObject.Type.OBJECT);
                data.AddField("renderer", rendererData);
                ParticleSystemRenderMode pRenderMode = particleSystemRenderer.renderMode;
                int pRenderModeNum = 0;
                switch (pRenderMode)
                {
                case ParticleSystemRenderMode.Billboard:
                    pRenderModeNum = 1;
                    break;

                case ParticleSystemRenderMode.Stretch:
                    pRenderModeNum = 2;
                    rendererData.AddField("cameraScale", particleSystemRenderer.cameraVelocityScale);
                    rendererData.AddField("speedScale", particleSystemRenderer.velocityScale);
                    rendererData.AddField("lengthScale", particleSystemRenderer.lengthScale);
                    break;

                case ParticleSystemRenderMode.HorizontalBillboard:
                    pRenderModeNum = 3;
                    break;

                case ParticleSystemRenderMode.VerticalBillboard:
                    pRenderModeNum = 4;
                    break;

                case ParticleSystemRenderMode.Mesh:
                    Mesh mesh = particleSystemRenderer.mesh;
                    if (mesh != null)
                    {
                        WXMesh meshConverter = new WXMesh(mesh);
                        string meshPath      = meshConverter.Export(context.preset);
                        rendererData.AddField("mesh", meshPath);
                        rendererData.AddField("meshCount", particleSystemRenderer.meshCount);
                        context.AddResource(meshPath);
                    }
                    else
                    {
                        Debug.LogError(string.Format("{0} mesh is null", particleSys.name));
                    }
                    pRenderModeNum = 5;
                    break;

                case ParticleSystemRenderMode.None:
                    pRenderModeNum = 0;
                    break;

                default:
                    pRenderModeNum = 1;
                    break;
                }
                rendererData.AddField("renderMode", pRenderModeNum);

                int mode = 1;
                switch (particleSystemRenderer.alignment)
                {
                case ParticleSystemRenderSpace.View:
                    mode = 1;
                    break;

                case ParticleSystemRenderSpace.World:
                    mode = 2;
                    break;

                case ParticleSystemRenderSpace.Local:
                    mode = 3;
                    break;

                case ParticleSystemRenderSpace.Facing:
                    mode = 4;
                    break;

#if UNITY_2017_1_OR_NEWER
                case ParticleSystemRenderSpace.Velocity:
                    mode = 5;
                    break;
#endif
                default:
                    break;
                }
                rendererData.AddField("renderAlignment", mode);


                mode = 0;
                switch (particleSystemRenderer.sortMode)
                {
                case ParticleSystemSortMode.None:
                    mode = 0;
                    break;

                case ParticleSystemSortMode.Distance:
                    mode = 1;
                    break;

                case ParticleSystemSortMode.OldestInFront:
                    mode = 2;
                    break;

                case ParticleSystemSortMode.YoungestInFront:
                    mode = 3;
                    break;

                default:
                    break;
                }
                rendererData.AddField("sortMode", mode);
                rendererData.AddField("sortingFudge", particleSystemRenderer.sortingFudge);
                rendererData.AddField("normalDirection", particleSystemRenderer.normalDirection);
                rendererData.AddField("minParticleSize", particleSystemRenderer.minParticleSize);
                rendererData.AddField("maxParticleSize", particleSystemRenderer.maxParticleSize);

                var flipValue = TryGetContainProperty(particleSystemRenderer, "flip");
                if (flipValue != null)
                {
                    rendererData.AddField("flip", GetVect3((Vector3)flipValue));
                }
                else
                {
                    renderer.AddField("flip", GetVect3(new Vector3(0, 0, 0)));
                }
                //rendererData.AddField("flip", GetVect3(particleSystemRenderer.flip));
                rendererData.AddField("pivot", GetVect3(particleSystemRenderer.pivot));

                var allowRollData = TryGetContainProperty(particleSystemRenderer, "allowRoll");
                if (allowRollData != null)
                {
                    rendererData.AddField("allowRoll", (bool)allowRollData);
                }
                else
                {
                    rendererData.AddField("allowRoll", false);
                }
            }
            else
            {
                String info = "entity: " + particleSys.gameObject.name + " 的粒子组件没有renderer模块,不可导出;请加上renderer模块,或删除该粒子组件";

                ErrorUtil.ExportErrorReporter.create()
                .setGameObject(particleSys.gameObject)
                .setHierarchyContext(context)
                .error(0, "粒子组件没有renderer模块,不可导出;请加上renderer模块,或删除该粒子组件");
            }

            if (particleSys.rotationOverLifetime.enabled)
            {
                JSONObject rotationByLife     = new JSONObject(JSONObject.Type.OBJECT);
                JSONObject rotationByLifeData = new JSONObject(JSONObject.Type.OBJECT);
                data.AddField("rotationByLife", rotationByLifeData);

                rotationByLifeData.AddField("separateAxes", particleSys.rotationOverLifetime.separateAxes);
                if (particleSys.rotationOverLifetime.separateAxes)
                {
                    rotationByLifeData.AddField("x", ParseMinMaxCurve(particleSys.rotationOverLifetime.x, (float)(180 / Math.PI)));
                    rotationByLifeData.AddField("y", ParseMinMaxCurve(particleSys.rotationOverLifetime.y, (float)(180 / Math.PI)));
                    rotationByLifeData.AddField("z", ParseMinMaxCurve(particleSys.rotationOverLifetime.z, (float)(180 / Math.PI)));
                }
                else
                {
                    rotationByLifeData.AddField("z", ParseMinMaxCurve(particleSys.rotationOverLifetime.z, (float)(180 / Math.PI)));
                }
            }

            if (particleSys.sizeOverLifetime.enabled)
            {
                JSONObject sizeOverLifetime     = new JSONObject(JSONObject.Type.OBJECT);
                JSONObject sizeOverLifetimeData = new JSONObject(JSONObject.Type.OBJECT);
                data.AddField("sizeByLife", sizeOverLifetimeData);

                sizeOverLifetimeData.AddField("separateAxes", particleSys.sizeOverLifetime.separateAxes);
                if (particleSys.sizeOverLifetime.separateAxes)
                {
                    sizeOverLifetimeData.AddField("x", ParseMinMaxCurve(particleSys.sizeOverLifetime.x));
                    sizeOverLifetimeData.AddField("y", ParseMinMaxCurve(particleSys.sizeOverLifetime.y));
                    sizeOverLifetimeData.AddField("z", ParseMinMaxCurve(particleSys.sizeOverLifetime.z));
                }
                else
                {
                    sizeOverLifetimeData.AddField("x", ParseMinMaxCurve(particleSys.sizeOverLifetime.size));
                }
            }

            if (particleSys.velocityOverLifetime.enabled)
            {
                JSONObject speedByLifeData = new JSONObject(JSONObject.Type.OBJECT);
                data.AddField("speedByLife", speedByLifeData);
                switch (particleSys.velocityOverLifetime.space)
                {
                case ParticleSystemSimulationSpace.Local:
                    speedByLifeData.AddField("space", 1);
                    break;

                case ParticleSystemSimulationSpace.World:
                    speedByLifeData.AddField("space", 2);
                    break;

                case ParticleSystemSimulationSpace.Custom:
                    break;

                default:
                    break;
                }

                speedByLifeData.AddField("x", ParseMinMaxCurve(particleSys.velocityOverLifetime.x));
                speedByLifeData.AddField("y", ParseMinMaxCurve(particleSys.velocityOverLifetime.y));
                speedByLifeData.AddField("z", ParseMinMaxCurve(particleSys.velocityOverLifetime.z));
#if UNITY_2018_1_OR_NEWER
                speedByLifeData.AddField("orbitalX", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalX));
                speedByLifeData.AddField("orbitalY", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalY));
                speedByLifeData.AddField("orbitalZ", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalZ));
                speedByLifeData.AddField("orbitalOffsetX", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalOffsetX));
                speedByLifeData.AddField("orbitalOffsetY", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalOffsetY));
                speedByLifeData.AddField("orbitalOffsetZ", ParseMinMaxCurve(particleSys.velocityOverLifetime.orbitalOffsetZ));
                speedByLifeData.AddField("radial", ParseMinMaxCurve(particleSys.velocityOverLifetime.radial));
#endif
#if UNITY_2017_1_OR_NEWER
                speedByLifeData.AddField("speedScale", ParseMinMaxCurve(particleSys.velocityOverLifetime.speedModifier));
#endif
            }

            if (particleSys.limitVelocityOverLifetime.enabled)
            {
                JSONObject speedLimitByLifeData = new JSONObject(JSONObject.Type.OBJECT);
                data.AddField("speedLimitByLife", speedLimitByLifeData);
                speedLimitByLifeData.AddField("separateAxes", particleSys.limitVelocityOverLifetime.separateAxes);
                if (particleSys.limitVelocityOverLifetime.separateAxes)
                {
                    speedLimitByLifeData.AddField("x", ParseMinMaxCurve(particleSys.limitVelocityOverLifetime.limitX, particleSys.limitVelocityOverLifetime.limitXMultiplier));
                    speedLimitByLifeData.AddField("y", ParseMinMaxCurve(particleSys.limitVelocityOverLifetime.limitY, particleSys.limitVelocityOverLifetime.limitYMultiplier));
                    speedLimitByLifeData.AddField("z", ParseMinMaxCurve(particleSys.limitVelocityOverLifetime.limitZ, particleSys.limitVelocityOverLifetime.limitZMultiplier));
                }
                else
                {
                    speedLimitByLifeData.AddField("x", ParseMinMaxCurve(particleSys.limitVelocityOverLifetime.limit, particleSys.limitVelocityOverLifetime.limitMultiplier));
                }
                speedLimitByLifeData.AddField("dampen", particleSys.limitVelocityOverLifetime.dampen);
                switch (particleSys.limitVelocityOverLifetime.space)
                {
                case ParticleSystemSimulationSpace.Local:
                    speedLimitByLifeData.AddField("space", 1);
                    break;

                case ParticleSystemSimulationSpace.World:
                    speedLimitByLifeData.AddField("space", 2);
                    break;

                case ParticleSystemSimulationSpace.Custom:
                    break;

                default:
                    break;
                }
#if UNITY_2017_1_OR_NEWER
                speedLimitByLifeData.AddField("drag", ParseMinMaxCurve(particleSys.limitVelocityOverLifetime.drag));
                speedLimitByLifeData.AddField("dragMultiplyBySize", particleSys.limitVelocityOverLifetime.multiplyDragByParticleSize);
                speedLimitByLifeData.AddField("dragMultiplyBySpeed", particleSys.limitVelocityOverLifetime.multiplyDragByParticleVelocity);
#endif
            }

            if (particleSys.colorOverLifetime.enabled)
            {
                JSONObject colorOverLifetime     = new JSONObject(JSONObject.Type.OBJECT);
                JSONObject colorOverLifetimeData = new JSONObject(JSONObject.Type.OBJECT);
                data.AddField("colorByLife", colorOverLifetimeData);
                colorOverLifetimeData.AddField("gColor", ParseMinMaxGradient(particleSys.colorOverLifetime.color));
            }

            if (particleSys.shape.enabled)
            {
                JSONObject shapeData = new JSONObject(JSONObject.Type.OBJECT);
                var        haveShape = true;
                if (particleSys.shape.shapeType == ParticleSystemShapeType.Cone || particleSys.shape.shapeType == ParticleSystemShapeType.ConeVolume || particleSys.shape.shapeType == ParticleSystemShapeType.ConeVolumeShell || particleSys.shape.shapeType == ParticleSystemShapeType.ConeShell)
                {
                    shapeData.AddField("shape", ParseConeShape(particleSys.shape));
                }
                else if (particleSys.shape.shapeType == ParticleSystemShapeType.Sphere || particleSys.shape.shapeType == ParticleSystemShapeType.SphereShell)
                {
                    shapeData.AddField("shape", ParseSphereShape(particleSys.shape));
                }
                else if (particleSys.shape.shapeType == ParticleSystemShapeType.Circle || particleSys.shape.shapeType == ParticleSystemShapeType.CircleEdge)
                {
                    shapeData.AddField("shape", ParseCircleShape(particleSys.shape));
                }
                else if (particleSys.shape.shapeType == ParticleSystemShapeType.Box || particleSys.shape.shapeType == ParticleSystemShapeType.BoxEdge || particleSys.shape.shapeType == ParticleSystemShapeType.BoxShell)
                {
                    shapeData.AddField("shape", ParseBox(particleSys.shape));
                }
                else if (particleSys.shape.shapeType == ParticleSystemShapeType.Hemisphere || particleSys.shape.shapeType == ParticleSystemShapeType.HemisphereShell)
                {
                    shapeData.AddField("shape", ParseHemisphere(particleSys.shape));
                }
                // else if (particleSys.shape.shapeType == ParticleSystemShapeType.SingleSidedEdge) {
                //     shapeData.AddField("shape", ParseSingleSidedEdge(particleSys.shape));
                // }
                else
                {
                    var parentChain = go.name;
                    var parent      = go.transform.parent;
                    while (parent)
                    {
                        parentChain += " -> " + parent.gameObject.name;
                        parent       = parent.parent;
                    }
                    Debug.LogError("unSupport shape (" + particleSys.shape.shapeType.ToString() + ") at: " + parentChain);
                    haveShape = false;
                }
                if (haveShape)
                {
                    data.AddField("emitterShape", shapeData);
                }
            }

            if (particleSys.textureSheetAnimation.enabled)
            {
                JSONObject textureSheetAnimationData = new JSONObject(JSONObject.Type.OBJECT);
                data.AddField("textureSheetAnimation", textureSheetAnimationData);
                int mode = 1;
#if UNITY_2017_1_OR_NEWER
                mode = 1;
                switch (particleSys.textureSheetAnimation.mode)
                {
                case ParticleSystemAnimationMode.Grid:
                    mode = 1;
                    break;

                case ParticleSystemAnimationMode.Sprites:
                    mode = 2;
                    break;

                default:
                    break;
                }
                textureSheetAnimationData.AddField("mode", mode);
#endif
                JSONObject vec2 = new JSONObject(JSONObject.Type.ARRAY);
                vec2.Add(particleSys.textureSheetAnimation.numTilesX);
                vec2.Add(particleSys.textureSheetAnimation.numTilesY);
                textureSheetAnimationData.AddField("tiles", vec2);
                mode = 1;
                switch (particleSys.textureSheetAnimation.animation)
                {
                case ParticleSystemAnimationType.WholeSheet:
                    mode = 1;
                    break;

                case ParticleSystemAnimationType.SingleRow:
                    mode = 2;
                    break;

                default:
                    break;
                }
                textureSheetAnimationData.AddField("animationType", mode);
                textureSheetAnimationData.AddField("randomRow", particleSys.textureSheetAnimation.useRandomRow);
                textureSheetAnimationData.AddField("row", particleSys.textureSheetAnimation.rowIndex);

                //mode = 1;
                //switch (particleSys.textureSheetAnimation.timeMode)
                //{
                //    case ParticleSystemAnimationTimeMode.Lifetime:
                //        mode = 1;
                //        break;
                //    case ParticleSystemAnimationTimeMode.Speed:
                //        mode = 2;
                //        break;
                //    case ParticleSystemAnimationTimeMode.FPS:
                //        mode = 3;
                //        break;
                //    default:
                //        break;
                //}
                textureSheetAnimationData.AddField("timeMode", 1);
                if (mode == 1)
                {
                    textureSheetAnimationData.AddField("frameOverTime", ParseMinMaxCurve(particleSys.textureSheetAnimation.frameOverTime, particleSys.textureSheetAnimation.numTilesX * particleSys.textureSheetAnimation.numTilesY));
                }
                else
                {
                    textureSheetAnimationData.AddField("frameOverTime", ParseMinMaxCurve(particleSys.textureSheetAnimation.frameOverTime, particleSys.textureSheetAnimation.numTilesX));
                }
                textureSheetAnimationData.AddField("startFrame", ParseMinMaxCurve(particleSys.textureSheetAnimation.startFrame));
                textureSheetAnimationData.AddField("cycles", particleSys.textureSheetAnimation.cycleCount);
                mode = 0;
                var a = particleSys.textureSheetAnimation.uvChannelMask;
                var b = a & UVChannelFlags.UV0;
                if ((a & UVChannelFlags.UV0) != 0)
                {
                    mode += 1;
                }
                if ((a & UVChannelFlags.UV1) != 0)
                {
                    mode += 2;
                }
                if ((a & UVChannelFlags.UV2) != 0)
                {
                    mode += 3;
                }
                if ((a & UVChannelFlags.UV3) != 0)
                {
                    mode += 4;
                }

                textureSheetAnimationData.AddField("affectedUVChannels", mode);
            }

            if (particleSys.subEmitters.enabled)
            {
                JSONObject subEmittersData = new JSONObject(JSONObject.Type.ARRAY);
                data.AddField("subEmitters", subEmittersData);

                int count = particleSys.subEmitters.subEmittersCount;
                for (int i = 0; i < count; i++)
                {
                    ParticleSystemSubEmitterProperties properties = particleSys.subEmitters.GetSubEmitterProperties(i);
                    ParticleSystemSubEmitterType       type       = particleSys.subEmitters.GetSubEmitterType(i);
                    JSONObject res     = new JSONObject(JSONObject.Type.OBJECT);
                    int        typeNum = 0;
                    switch (type)
                    {
                    case ParticleSystemSubEmitterType.Birth:
                        typeNum = 0;
                        break;

                    case ParticleSystemSubEmitterType.Collision:
                        typeNum = 1;
                        break;

                    case ParticleSystemSubEmitterType.Death:
                        typeNum = 2;
                        break;

                    default:
                        break;
                    }
                    res.AddField("type", typeNum);
                    int propertiesNum = 0;
                    switch (properties)
                    {
                    case ParticleSystemSubEmitterProperties.InheritNothing:
                        propertiesNum = 0;
                        break;

                    case ParticleSystemSubEmitterProperties.InheritEverything:
                        propertiesNum = 1;
                        break;

                    case ParticleSystemSubEmitterProperties.InheritColor:
                        propertiesNum = 2;
                        break;

                    case ParticleSystemSubEmitterProperties.InheritSize:
                        propertiesNum = 3;
                        break;

                    case ParticleSystemSubEmitterProperties.InheritRotation:
                        propertiesNum = 4;
                        break;

                    default:
                        break;
                    }
                    res.AddField("properties", propertiesNum);

                    subEmittersData.Add(res);
                }
            }

            return(json);
        }