Beispiel #1
0
 // ACCUMULATE ROTATION RATE //
 //
 public void AccumulateRotationRate()
 {
     foreach (Pool <ParticleMarker> .Node node in particleMarkers.ActiveNodes)
     {
         rotationRateAccumulators[node.NodeIndex] += AmpsHelpers.ConvertVector4Vector3(blueprint.rotationRateStack.values[node.NodeIndex])
                                                     * deltaTime;
     }
 }
Beispiel #2
0
 // ACCUMULATE VELOCITY //
 //
 public void AccumulateVelocity()
 {
     foreach (Pool <ParticleMarker> .Node node in particleMarkers.ActiveNodes)
     {
         blueprint.velocityStack.values[node.NodeIndex] += AmpsHelpers.ConvertVector3Vector4(accelerationAccumulators[node.NodeIndex], 0);
         velocityAccumulators[node.NodeIndex]           += AmpsHelpers.ConvertVector4Vector3(blueprint.velocityStack.values[node.NodeIndex]) * deltaTime;
     }
 }
Beispiel #3
0
        public int randomSeed            = 0;                           // A curve specific random seed;

        // GET CURVE INPUT //
        //
        public float GetCurveInput(AmpsBlueprint ownerBlueprint, int particleIndex)
        {
            float   returnValue = 0;
            Vector3 v3          = Vector3.zero;
            Vector4 v4          = Vector4.zero;

            //Matrix4x4 toMatrix = AmpsHelpers.identityMatrix; // Slightly faster than Matrix4x4.identity;

            v4 = AmpsHelpers.GetSystemProperty(ownerBlueprint, particleIndex, curveInput);

            // The only need to work with conversion to emitter space as everything
            // is world relative by default.
            if (curveInputCoordSystem == AmpsHelpers.eCoordSystems.Emitter)
            {
                //toMatrix = ownerBlueprint.ownerEmitter.emitterMatrixFull;
                if (AmpsHelpers.isPositionInput(curveInput))
                {
                    v3  = AmpsHelpers.ConvertVector4Vector3(v4);
                    v3 -= ownerBlueprint.ownerEmitter.transform.position;
                    v3  = AmpsHelpers.RotateAroundPoint(v3, ownerBlueprint.ownerEmitter.emitterPosition, ownerBlueprint.ownerEmitter.transform.rotation);
                    v4  = AmpsHelpers.ConvertVector3Vector4(v3, 0);
                }
                else if (AmpsHelpers.isRotationInput(curveInput))
                {
                    v3  = AmpsHelpers.ConvertVector4Vector3(v4);
                    v3 += ownerBlueprint.ownerEmitter.transform.rotation.eulerAngles;
                    v4  = AmpsHelpers.ConvertVector3Vector4(v3, 0);
                }
                else if (AmpsHelpers.isVelocityInput(curveInput))
                {
                    v3  = AmpsHelpers.ConvertVector4Vector3(v4);
                    v3 += ownerBlueprint.ownerEmitter.emitterMatrixPositionZero.MultiplyPoint3x4(v3);
                    v4  = AmpsHelpers.ConvertVector3Vector4(v3, 0);
                }
                else if (AmpsHelpers.isScaleInput(curveInput))
                {
                    v3    = AmpsHelpers.ConvertVector4Vector3(v4);
                    v3.x *= ownerBlueprint.ownerEmitter.transform.lossyScale.x;
                    v3.y *= ownerBlueprint.ownerEmitter.transform.lossyScale.y;
                    v3.z *= ownerBlueprint.ownerEmitter.transform.lossyScale.z;
                    v4    = AmpsHelpers.ConvertVector3Vector4(v3, 0);
                }
            }

            if (AmpsHelpers.isFloatInput(curveInput))
            {
                returnValue = v4.x;
            }
            else
            {
                //if (AmpsHelpers.isPositionInput(curveInput)) v = toMatrix.MultiplyPoint3x4(v);
                //else v = toMatrix.MultiplyVector(v);

                switch (curveInputVectorComponent)
                {
                case AmpsHelpers.eVectorComponents.X:
                    returnValue = v4.x;
                    break;

                case AmpsHelpers.eVectorComponents.Y:
                    returnValue = v4.y;
                    break;

                case AmpsHelpers.eVectorComponents.Z:
                    returnValue = v4.z;
                    break;

                case AmpsHelpers.eVectorComponents.W:
                    returnValue = v4.w;
                    break;

                case AmpsHelpers.eVectorComponents.Mag:
                    returnValue = new Vector3(v4.x, v4.y, v4.z).magnitude;
                    break;
                }
                // TODO: Handle Color.
            }

            // Normalize input.
            float finalInputRangeMin = inputRangeMin;
            float finalInputRangeMax = inputRangeMax;

            if (isInputRangeRandom)
            {
                System.Random theRandom = new System.Random(ownerBlueprint.ownerEmitter.randomSeed + randomSeed + ownerBlueprint.ownerEmitter.particleIds[particleIndex]);
                finalInputRangeMin = Mathf.Lerp(inputRangeMin, inputRangeRandomMin, (float)theRandom.NextDouble());
                finalInputRangeMax = Mathf.Lerp(inputRangeMax, inputRangeRandomMax, (float)theRandom.NextDouble());
            }

            if (finalInputRangeMax - finalInputRangeMin == 0)
            {
                returnValue = 0;
            }
            else
            {
                returnValue = (returnValue - finalInputRangeMin) / (finalInputRangeMax - finalInputRangeMin);
            }

            return(returnValue);
        }
        // EVALUATE //
        //
        override public void Evaluate()
        {
            Vector4    customVector;
            Vector3    position;
            Vector3    pivotOffset;
            Vector3    rotation;
            Quaternion quaternionRotation;
            Vector3    scale;
            Color      color;
            bool       shouldRecreateMesh;
            bool       shouldBeDoubleSided;
            Quaternion camFacingRotation;
            int        vertexIndexSteps;
            int        triangleIndexSteps;

            if (ownerBlueprint == null ||
                ownerBlueprint.ownerEmitter == null ||
                ownerBlueprint.ownerEmitter.particleMarkers == null)
            {
                return;                                                                                 // To fix null ref log spam after script rebuild.
            }
            if (finalMesh == null)
            {
                SoftReset();
            }

            ownerBlueprint.ownerEmitter.activeParticleIndices = ownerBlueprint.ownerEmitter.particleMarkers.GetActiveIndices();
            particleCount       = ownerBlueprint.ownerEmitter.activeParticleIndices.Length;
            shouldRecreateMesh  = (particleCount != lastParticleCount);
            shouldBeDoubleSided = isDoubleSided.GetValue();
            if (shouldBeDoubleSided)
            {
                vertexIndexSteps   = 8;
                triangleIndexSteps = 12;
            }
            else
            {
                vertexIndexSteps   = 4;
                triangleIndexSteps = 6;
            }
            // TODO: Investigate why this line fails at runtime around 2 * 4:
            //shouldRecreateMesh = triangles.Length != particleCount * vertexIndexSteps;

            if (shouldRecreateMesh)
            {
                finalMesh.Clear();

                vertices  = new Vector3[particleCount * vertexIndexSteps];
                normals   = new Vector3[particleCount * vertexIndexSteps];
                tangents  = new Vector4[particleCount * vertexIndexSteps];
                uvs       = new Vector2[particleCount * vertexIndexSteps];
                uv2s      = new Vector2[particleCount * vertexIndexSteps];
                colors    = new Color[particleCount * vertexIndexSteps];
                triangles = new int[particleCount * triangleIndexSteps];

                lastParticleCount = particleCount;
            }

            int particleIndex;

            for (int i = 0; i < ownerBlueprint.ownerEmitter.activeParticleIndices.Length; i++)
            {
                particleIndex = ownerBlueprint.ownerEmitter.activeParticleIndices[i];
                customVector  = ownerBlueprint.customVectorStack.values[particleIndex];

                position  = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.ownerEmitter.blueprint.positionStack.values[particleIndex]); // Raw position stack result.
                position  = AmpsHelpers.RotateAroundPoint(position, ownerBlueprint.ownerEmitter.transform.position, Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation));
                position -= ownerBlueprint.ownerEmitter.emitterPosition;                                                                  // Compensating for emitter position, turning position world relative.

                pivotOffset = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.pivotOffsetStack.values[particleIndex]);

                rotation           = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.rotationStack.values[particleIndex]);       // Raw particle stack result.
                quaternionRotation = Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation) * Quaternion.Euler(rotation);

                scale = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.scaleStack.values[particleIndex]);

                color = ownerBlueprint.colorStack.values[particleIndex];

                // Setting up the quad, particle is at the center.
                vertices[i * vertexIndexSteps]     = (position + pivotOffset) + (new Vector3(scale.x, scale.y, 0) / 2);
                vertices[i * vertexIndexSteps + 1] = (position + pivotOffset) + (new Vector3(-scale.x, scale.y, 0) / 2);
                vertices[i * vertexIndexSteps + 2] = (position + pivotOffset) + (new Vector3(-scale.x, -scale.y, 0) / 2);
                vertices[i * vertexIndexSteps + 3] = (position + pivotOffset) + (new Vector3(scale.x, -scale.y, 0) / 2);

                switch (orientation.GetValue())
                {
                case (int)eOrientation.Rotated:
                    // Rotating the (pivot offset) vertices around particle position.
                    vertices[i * vertexIndexSteps]     = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps], position, quaternionRotation);
                    vertices[i * vertexIndexSteps + 1] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 1], position, quaternionRotation);
                    vertices[i * vertexIndexSteps + 2] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 2], position, quaternionRotation);
                    vertices[i * vertexIndexSteps + 3] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 3], position, quaternionRotation);
                    break;

                case (int)eOrientation.CameraFacing:
                    camFacingRotation = Quaternion.LookRotation(ownerBlueprint.ownerEmitter.currentCameraTransform.forward, ownerBlueprint.ownerEmitter.currentCameraTransform.up);
                    camFacingRotation = Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation) * camFacingRotation;
                    // TODO: Research if camera-particle position diff vector is better.

                    // Rotating all vertices around the center so the quad faces the camera.
                    vertices[i * vertexIndexSteps]     = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps], position, camFacingRotation);
                    vertices[i * vertexIndexSteps + 1] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 1], position, camFacingRotation);
                    vertices[i * vertexIndexSteps + 2] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 2], position, camFacingRotation);
                    vertices[i * vertexIndexSteps + 3] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 3], position, camFacingRotation);
                    break;

                case (int)eOrientation.RotatedCameraFacing:
                    camFacingRotation = Quaternion.LookRotation(ownerBlueprint.ownerEmitter.currentCameraTransform.forward, ownerBlueprint.ownerEmitter.currentCameraTransform.up);
                    camFacingRotation = Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation) * camFacingRotation;
                    camFacingRotation = camFacingRotation * Quaternion.Euler(rotation);

                    // Rotating all vertices around the center so the quad faces the camera.
                    vertices[i * vertexIndexSteps]     = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps], position, camFacingRotation);
                    vertices[i * vertexIndexSteps + 1] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 1], position, camFacingRotation);
                    vertices[i * vertexIndexSteps + 2] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 2], position, camFacingRotation);
                    vertices[i * vertexIndexSteps + 3] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 3], position, camFacingRotation);
                    break;

                case (int)eOrientation.VectorAlignedCameraFacing:
                    //Vector3 upVector = Vector3.Normalize(alignmentVector.GetValue());
                    //Vector3 forwardVector = ownerBlueprint.ownerEmitter.currentCameraTransform.forward;
                    ////ownerBlueprint.ownerEmitter.currentCameraTransform.up;
                    //camFacingRotation = Quaternion.LookRotation(forwardVector, upVector);
                    ////camFacingRotation = Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation) * camFacingRotation;

                    camFacingRotation = Quaternion.LookRotation(ownerBlueprint.ownerEmitter.currentCameraTransform.forward, Vector3.up);
                    Vector3 eulerRotation = camFacingRotation.eulerAngles;
                    eulerRotation.x   = 0;                              // Discard rotation around x.
                    eulerRotation.z   = 0;                              // Discard rotation around z.
                    camFacingRotation = Quaternion.Euler(eulerRotation);

                    // Rotating all vertices around the center so the quad faces the camera.
                    vertices[i * vertexIndexSteps]     = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps], position, camFacingRotation);
                    vertices[i * vertexIndexSteps + 1] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 1], position, camFacingRotation);
                    vertices[i * vertexIndexSteps + 2] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 2], position, camFacingRotation);
                    vertices[i * vertexIndexSteps + 3] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 3], position, camFacingRotation);
                    break;
                }

                if (shouldBeDoubleSided)
                {
                    vertices[i * vertexIndexSteps + 4] = vertices[i * vertexIndexSteps];
                    vertices[i * vertexIndexSteps + 5] = vertices[i * vertexIndexSteps + 1];
                    vertices[i * vertexIndexSteps + 6] = vertices[i * vertexIndexSteps + 2];
                    vertices[i * vertexIndexSteps + 7] = vertices[i * vertexIndexSteps + 3];
                }

                colors[i * vertexIndexSteps]     = color;
                colors[i * vertexIndexSteps + 1] = color;
                colors[i * vertexIndexSteps + 2] = color;
                colors[i * vertexIndexSteps + 3] = color;
                if (shouldBeDoubleSided)
                {
                    if ((eDoubleSidedColorMode)doubleSidedColorMode.GetValue() == eDoubleSidedColorMode.ColorStack)
                    {
                        colors[i * vertexIndexSteps + 4] = colors[i * vertexIndexSteps];
                        colors[i * vertexIndexSteps + 5] = colors[i * vertexIndexSteps + 1];
                        colors[i * vertexIndexSteps + 6] = colors[i * vertexIndexSteps + 2];
                        colors[i * vertexIndexSteps + 7] = colors[i * vertexIndexSteps + 3];
                    }
                    else
                    {
                        colors[i * vertexIndexSteps + 4] = customVector;
                        colors[i * vertexIndexSteps + 5] = customVector;
                        colors[i * vertexIndexSteps + 6] = customVector;
                        colors[i * vertexIndexSteps + 7] = customVector;
                    }
                }

                switch (normalMode.GetValue())
                {
                case (int)eNormalMode.Skip:
                    break;

                case (int)eNormalMode.Flat:
                    Vector3 calculatedNormal = Vector3.Cross((vertices[i * vertexIndexSteps + 2] - vertices[i * vertexIndexSteps]), (vertices[i * vertexIndexSteps + 1] - vertices[i * vertexIndexSteps]));
                    calculatedNormal = Vector3.Normalize(calculatedNormal);
                    normals[i * vertexIndexSteps]     = calculatedNormal;
                    normals[i * vertexIndexSteps + 1] = calculatedNormal;
                    normals[i * vertexIndexSteps + 2] = calculatedNormal;
                    normals[i * vertexIndexSteps + 3] = calculatedNormal;
                    break;
                }
                if (shouldBeDoubleSided)
                {
                    normals[i * vertexIndexSteps + 4] = normals[i * vertexIndexSteps] * -1;
                    normals[i * vertexIndexSteps + 5] = normals[i * vertexIndexSteps + 1] * -1;
                    normals[i * vertexIndexSteps + 6] = normals[i * vertexIndexSteps + 2] * -1;
                    normals[i * vertexIndexSteps + 7] = normals[i * vertexIndexSteps + 3] * -1;
                }

                switch (uv2Mode.GetValue())
                {
                case (int)eUV2Mode.Skip:
                    break;

                case (int)eUV2Mode.CustomVectorXY:
                    uv2s[i * vertexIndexSteps]     = new Vector2(customVector.x, customVector.y);
                    uv2s[i * vertexIndexSteps + 1] = new Vector2(customVector.x, customVector.y);
                    uv2s[i * vertexIndexSteps + 2] = new Vector2(customVector.x, customVector.y);
                    uv2s[i * vertexIndexSteps + 3] = new Vector2(customVector.x, customVector.y);
                    break;

                case (int)eUV2Mode.CustomVectorXYZW:                            // BUG: Doesn't really work...
                    Vector2 calculatedUv2 = Vector2.zero;
                    calculatedUv2.x                = AmpsHelpers.PackVector2(new Vector2(customVector.x, customVector.y));
                    calculatedUv2.y                = AmpsHelpers.PackVector2(new Vector2(customVector.z, customVector.w));
                    uv2s[i * vertexIndexSteps]     = calculatedUv2;
                    uv2s[i * vertexIndexSteps + 1] = calculatedUv2;
                    uv2s[i * vertexIndexSteps + 2] = calculatedUv2;
                    uv2s[i * vertexIndexSteps + 3] = calculatedUv2;
                    break;
                }
                if (shouldBeDoubleSided)
                {
                    uv2s[i * vertexIndexSteps + 4] = uv2s[i * vertexIndexSteps];
                    uv2s[i * vertexIndexSteps + 5] = uv2s[i * vertexIndexSteps + 1];
                    uv2s[i * vertexIndexSteps + 6] = uv2s[i * vertexIndexSteps + 2];
                    uv2s[i * vertexIndexSteps + 7] = uv2s[i * vertexIndexSteps + 3];
                }

                switch (tangentMode.GetValue())
                {
                case (int)eTangentMode.Skip:
                    break;

                case (int)eTangentMode.Generate:
                    //Vector3 rawTangent = Vector3.Normalize(vertices[i * 4 + 3] - vertices[i * 4 + 1]);
                    Vector3 rawTangent        = Vector3.Normalize(vertices[i * 4 + 0] - vertices[i * 4 + 1]);
                    Vector4 calculatedTangent = new Vector4(rawTangent.x, rawTangent.y, rawTangent.z, -1);
                    tangents[i * vertexIndexSteps]     = calculatedTangent;
                    tangents[i * vertexIndexSteps + 1] = calculatedTangent;
                    tangents[i * vertexIndexSteps + 2] = calculatedTangent;
                    tangents[i * vertexIndexSteps + 3] = calculatedTangent;
                    break;

                case (int)eTangentMode.CustomVectorXYZW:
                    tangents[i * vertexIndexSteps]     = customVector;
                    tangents[i * vertexIndexSteps + 1] = customVector;
                    tangents[i * vertexIndexSteps + 2] = customVector;
                    tangents[i * vertexIndexSteps + 3] = customVector;
                    break;
                }
                if (shouldBeDoubleSided)
                {
                    // TODO: Should it be multiplied by -1?
                    tangents[i * vertexIndexSteps + 4] = tangents[i * vertexIndexSteps];
                    tangents[i * vertexIndexSteps + 5] = tangents[i * vertexIndexSteps + 1];
                    tangents[i * vertexIndexSteps + 6] = tangents[i * vertexIndexSteps + 2];
                    tangents[i * vertexIndexSteps + 7] = tangents[i * vertexIndexSteps + 3];
                }


                if (shouldRecreateMesh)                 // Things go in here which don't change unless particle count changes.
                {
                    uvs[i * vertexIndexSteps]     = new Vector2(1, 1);
                    uvs[i * vertexIndexSteps + 1] = new Vector2(0, 1);
                    uvs[i * vertexIndexSteps + 2] = new Vector2(0, 0);
                    uvs[i * vertexIndexSteps + 3] = new Vector2(1, 0);
                    if (shouldBeDoubleSided)
                    {
                        uvs[i * vertexIndexSteps + 4] = new Vector2(1, 1);
                        uvs[i * vertexIndexSteps + 5] = new Vector2(0, 1);
                        uvs[i * vertexIndexSteps + 6] = new Vector2(0, 0);
                        uvs[i * vertexIndexSteps + 7] = new Vector2(1, 0);
                    }

                    //First triangle.
                    triangles[i * triangleIndexSteps]     = i * vertexIndexSteps;
                    triangles[i * triangleIndexSteps + 1] = i * vertexIndexSteps + 2;
                    triangles[i * triangleIndexSteps + 2] = i * vertexIndexSteps + 1;
                    //Second triangle.
                    triangles[i * triangleIndexSteps + 3] = i * vertexIndexSteps + 2;
                    triangles[i * triangleIndexSteps + 4] = i * vertexIndexSteps;
                    triangles[i * triangleIndexSteps + 5] = i * vertexIndexSteps + 3;

                    if (shouldBeDoubleSided)
                    {
                        //Third triangle.
                        triangles[i * triangleIndexSteps + 6] = i * vertexIndexSteps + 5;
                        triangles[i * triangleIndexSteps + 7] = i * vertexIndexSteps + 6;
                        triangles[i * triangleIndexSteps + 8] = i * vertexIndexSteps + 4;
                        //Forth triangle.
                        triangles[i * triangleIndexSteps + 9]  = i * vertexIndexSteps + 7;
                        triangles[i * triangleIndexSteps + 10] = i * vertexIndexSteps + 4;
                        triangles[i * triangleIndexSteps + 11] = i * vertexIndexSteps + 6;
                    }
                }
            }

            // TODO: Bubble sort with limited run time.
            finalMesh.vertices  = vertices;
            finalMesh.uv        = uvs;
            finalMesh.uv2       = uv2s;
            finalMesh.normals   = normals;
            finalMesh.tangents  = tangents;
            finalMesh.colors    = colors;
            finalMesh.triangles = triangles;
        }
Beispiel #5
0
        // GET SYSTEM PROPERTY //
        //
        public static Vector4 GetSystemProperty(AmpsBlueprint theBlueprint, int particleIndex, eCurveInputs property)
        {
            float   f;                  // Helper variable.
            Vector4 returnValue = Vector4.zero;

            switch (property)
            {
            case AmpsHelpers.eCurveInputs.EmitterTime:
                returnValue = ConvertFloatVector4(theBlueprint.ownerEmitter.emitterTime);
                break;

            case AmpsHelpers.eCurveInputs.LoopTime:
                returnValue = ConvertFloatVector4(theBlueprint.ownerEmitter.emitterLoopTime);
                break;

            case AmpsHelpers.eCurveInputs.ParticleTime:
                if (particleIndex >= 0)
                {
                    returnValue = ConvertFloatVector4(theBlueprint.ownerEmitter.particleTimes[particleIndex]);
                }
                break;

            case AmpsHelpers.eCurveInputs.DeathCondition:
                if (particleIndex >= 0)
                {
                    returnValue = ConvertFloatVector4(theBlueprint.deathConditionStack.values[particleIndex]);
                }
                break;

            case AmpsHelpers.eCurveInputs.DyingDuration:
                if (particleIndex >= 0)
                {
                    returnValue = ConvertFloatVector4(theBlueprint.deathDurationStack.values[particleIndex]);
                }
                break;

            case AmpsHelpers.eCurveInputs.DyingTime:
                if (particleIndex >= 0)
                {
                    if (theBlueprint.deathDurationStack.values[particleIndex] > 0 && theBlueprint.ownerEmitter.particleDyingTimes[particleIndex] > 0)
                    {
                        f           = theBlueprint.ownerEmitter.particleDyingTimes[particleIndex] - theBlueprint.ownerEmitter.particleTimes[particleIndex];
                        f           = 1 - (f / theBlueprint.deathDurationStack.values[particleIndex]);
                        returnValue = ConvertFloatVector4(f);
                    }
                    else
                    {
                        returnValue = Vector4.zero;
                    }
                }
                break;

            case AmpsHelpers.eCurveInputs.CollisionTime:
                if (particleIndex >= 0)
                {
                    returnValue = ConvertFloatVector4(theBlueprint.ownerEmitter.collisionTimes[particleIndex]);
                }
                break;

            case AmpsHelpers.eCurveInputs.SpawnRate:
                returnValue = ConvertFloatVector4(theBlueprint.spawnRateStack.value);
                break;

            case AmpsHelpers.eCurveInputs.CustomScalar:
                if (particleIndex >= 0)
                {
                    returnValue = ConvertFloatVector4(theBlueprint.customScalarStack.values[particleIndex]);
                }
                break;

            case AmpsHelpers.eCurveInputs.FrameRate:
                f           = 1 / Mathf.Clamp(theBlueprint.ownerEmitter.smoothDeltaTime, 0.016666f, 0.06666f); // Limiting range to 15..60 fps.
                returnValue = ConvertFloatVector4((f - 15f) / 45);                                             // Normalizing.
                break;

            case AmpsHelpers.eCurveInputs.EmitterPosition:
                returnValue = theBlueprint.ownerEmitter.emitterPosition;
                break;

            case AmpsHelpers.eCurveInputs.EmitterRotation:
                returnValue = theBlueprint.ownerEmitter.emitterRotation;
                break;

            case AmpsHelpers.eCurveInputs.EmitterForward:
                returnValue = theBlueprint.ownerEmitter.emitterDirection;
                break;

            case AmpsHelpers.eCurveInputs.EmitterScale:
                returnValue = theBlueprint.ownerEmitter.emitterScale;
                break;

            case AmpsHelpers.eCurveInputs.EmitterAcceleration:
                returnValue = theBlueprint.ownerEmitter.emitterAcceleration;
                break;

            case AmpsHelpers.eCurveInputs.EmitterVelocity:
                returnValue = theBlueprint.ownerEmitter.emitterVelocity;
                break;

            case AmpsHelpers.eCurveInputs.CustomVector:
                if (particleIndex >= 0)
                {
                    returnValue = theBlueprint.customVectorStack.values[particleIndex];
                }
                break;

            case AmpsHelpers.eCurveInputs.Acceleration:
                if (particleIndex >= 0)
                {
                    returnValue = theBlueprint.accelerationStack.values[particleIndex];
                }
                break;

            case AmpsHelpers.eCurveInputs.Velocity:
                if (particleIndex >= 0)
                {
                    returnValue = theBlueprint.velocityStack.values[particleIndex];
                }
                break;

            case AmpsHelpers.eCurveInputs.Position:
                if (particleIndex >= 0)
                {
                    returnValue = theBlueprint.positionStack.values[particleIndex];
                }
                break;

            case AmpsHelpers.eCurveInputs.RotationRate:
                if (particleIndex >= 0)
                {
                    returnValue = theBlueprint.rotationRateStack.values[particleIndex];
                }
                break;

            case AmpsHelpers.eCurveInputs.Rotation:
                if (particleIndex >= 0)
                {
                    returnValue = theBlueprint.rotationStack.values[particleIndex];
                }
                break;

            case AmpsHelpers.eCurveInputs.Forward:
                if (particleIndex >= 0)
                {
                    returnValue = Quaternion.Euler(AmpsHelpers.ConvertVector4Vector3(theBlueprint.rotationStack.values[particleIndex])) * Vector3.forward;
                }
                break;

            case AmpsHelpers.eCurveInputs.Scale:
                if (particleIndex >= 0)
                {
                    returnValue = theBlueprint.scaleStack.values[particleIndex];
                }
                break;

            case AmpsHelpers.eCurveInputs.Color:
                if (particleIndex >= 0)
                {
                    returnValue = theBlueprint.colorStack.values[particleIndex];
                }
                break;

            case AmpsHelpers.eCurveInputs.ParticleCount:
                if (theBlueprint.ownerEmitter.particleMarkers != null)
                {
                    returnValue = ConvertFloatVector4(theBlueprint.ownerEmitter.particleMarkers.ActiveCount);
                }
                break;

            case AmpsHelpers.eCurveInputs.EmitterPositionLocal:
                returnValue = theBlueprint.ownerEmitter.transform.localPosition;
                break;

            case AmpsHelpers.eCurveInputs.EmitterRotationLocal:
                returnValue = theBlueprint.ownerEmitter.transform.localRotation.eulerAngles;
                break;

            case AmpsHelpers.eCurveInputs.NonZeroParticleCountTime:
                returnValue = ConvertFloatVector4(theBlueprint.ownerEmitter.nonZeroParticleCountTime);
                break;
            }

            return(returnValue);
        }
        // EVALUATE //
        //
        override public void Evaluate()
        {
            bool       shouldRecreateMesh;
            Vector3    position;
            Vector3    pivotOffset;
            Vector3    rotation;
            Quaternion quaternionRotation;
            Vector3    scale;
            Color      color;

            System.Random theRandom = new System.Random();

            InitializeNewParticles();

            if (ownerBlueprint.ownerEmitter.particleMarkers == null)
            {
                return;                                                                                 // To fix null ref log spam after script rebuild.
            }
            ownerBlueprint.ownerEmitter.activeParticleIndices = ownerBlueprint.ownerEmitter.particleMarkers.GetActiveIndices();
            particleCount      = ownerBlueprint.ownerEmitter.activeParticleIndices.Length;
            shouldRecreateMesh = particleCount != lastParticleCount;

            if (shouldRecreateMesh)
            {
                ownerBlueprint.ownerEmitter.emitterMesh.Clear();
                lastParticleCount = particleCount;
            }

            CombineInstance[] combine = new CombineInstance[particleCount];
            int particleIndex;

            for (int i = 0; i < ownerBlueprint.ownerEmitter.activeParticleIndices.Length; i++)
            {
                particleIndex = ownerBlueprint.ownerEmitter.activeParticleIndices[i];
                position      = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.ownerEmitter.blueprint.positionStack.values[particleIndex]); // Raw position stack result.
                position      = AmpsHelpers.RotateAroundPoint(position, ownerBlueprint.ownerEmitter.transform.position, Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation));
                position     -= ownerBlueprint.ownerEmitter.emitterPosition;                                                                  // Compensating for emitter position, turning position world relative.

                pivotOffset = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.pivotOffsetStack.values[particleIndex]);

                rotation           = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.rotationStack.values[particleIndex]);       // Raw particle stack result.
                quaternionRotation = Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation) * Quaternion.Euler(rotation);

                scale = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.scaleStack.values[particleIndex]);
                color = ownerBlueprint.colorStack.values[particleIndex];

                if (meshIndices[particleIndex] < 0)
                {
                    meshIndices[particleIndex] = theRandom.Next(0, inputMeshes.Length);
                }
                Mesh pickedMesh = inputMeshes[meshIndices[particleIndex]].GetValue();

                meshCache[particleIndex].Clear();
                combine[i].mesh = meshCache[particleIndex];
                if (pickedMesh != null)
                {
                    combine[i].mesh.vertices  = pickedMesh.vertices;
                    combine[i].mesh.normals   = pickedMesh.normals;
                    combine[i].mesh.uv        = pickedMesh.uv;
                    combine[i].mesh.triangles = pickedMesh.triangles;
                    combine[i].mesh.tangents  = pickedMesh.tangents;

                    Color[] vertexColors = new Color[pickedMesh.vertices.Length];
                    for (int j = 0; j < pickedMesh.vertices.Length; j++)
                    {
                        vertexColors[j] = color;
                    }
                    combine[i].mesh.colors = vertexColors;

                    combine[i].transform = Matrix4x4.TRS(position + pivotOffset, quaternionRotation, scale);
                }
                else
                {
                    combine[i].transform = new Matrix4x4();
                }

                if (shouldRecreateMesh)                 // Things go in here which don't change unless particle count changes.
                {
                }
            }

            finalMesh.CombineMeshes(combine, true, true);
        }