Custom Particle System, Best Practice - Speed?

I’m creating a custom particle system and want to know what’s best practice and what’s fastest.

Each instantitated prefab needs properties such as its colour, velocity, spin, scale, lifetimeleft etc.

Previously I’ve used a manager with multiple arrays- as prefabs are instantiated, they’re added to an prefabArray and at the same time properties are added to various property arrays, velocityArray etc…

The prefab and its properties can then be accessed from a index value.

prefabArray i , returns the prefab
spinArray i , returns that prefabs spin

The manager would then for loop through the arrays and make the objects spin, change colour etc…

I’m wondering if this way of doing things is faster than having a script on each prefab which stores that prefab’s properties, as storing the properties on a script on the prefab seems more intuitive and easier to understand, the way outlined feels a bit clunky and gets hard to read.

Ive got the following code which houses properties on each prefab but i think I’m missing a trick could using a class be useful?

Thanks

// Adds the particles when space is pressed

var cube : Transform;

var currentRotation : Vector3;
var currentScale    : float;
var currentVelocity : Vector3;
var currentColour     : Color;
var currentSpin        : Vector3;
var currentTime        : float;

function Start () {

}

function Update () {

    currentRotation = Vector3(Random.Range(0,360.0), Random.Range(0,360.0), Random.Range(0,360.0));
    currentScale    = Random.value * 5;
    currentColour    = Color(Random.value, Random.value, Random.value);
    currentVelocity = Vector3(Random.Range(-0.3, 0.3),Random.Range(-0.3, 0.3),Random.Range(-0.3, 0.3));
    currentSpin        = Vector3(Random.Range(-10.0,10.0), Random.Range(-10.0,10.0), Random.Range(-10.0,10.0));
    currentTime        = Random.Range(1,10);

    if (Input.GetKey("space")){
        var prefab = Instantiate(cube, this.transform.localPosition, Quaternion.identity);
        var script : ScriptCube = prefab.GetComponent(ScriptCube);
               
        script.Initialise(currentRotation, currentScale, currentColour, currentVelocity, currentSpin, currentTime);
    }
}

and

#pragma strict
// updates the prefabs properties

var startTime             : float;
var timeLeft            : float;
var velocity             : Vector3;
var colour                : Color;
var scale                : float;
var rotation            : Vector3;
var distanceFromOrigin    : float;
var spin                : Vector3;

var managerObject : GameObject;
var managerScript : ScriptManager;


function Start ()
{
    managerObject = GameObject.Find("Manager");
    managerScript = managerObject.GetComponent(ScriptManager);
}

function Update ()
{
    this.transform.localPosition += velocity;
    this.transform.Rotate(spin);
   
    timeLeft -= Time.deltaTime;
   
    if (timeLeft <= 0)
        Disable();
}

function Reverse()
{
    velocity *= -1;
}

function Initialise( rot : Vector3, sca : float, col : Color, vel : Vector3, spi : Vector3, tim : float)
{   
    rotation = rot;
    scale = sca;
    colour = col;
    velocity = vel;
    timeLeft = tim;
    spin = spi;
    startTime = Time.time;
    distanceFromOrigin = 0;

    this.transform.localRotation = Quaternion.Euler(rotation);
    this.transform.localScale = Vector3(scale, scale, scale);
    this.renderer.material.color = colour;    // costly, replace with a material bank...
    
}

function Disable()
{
    this.gameObject.SetActive(false);
}

For a particle system, making each individual particle an object like that is super heavy weight. Objects have overheads, and when you’re dealing with hundreds or thousands of things at once and care about performance you want to avoid those overheads.

A fairly typical approach for particles is to have a native, fixed-size array for each piece of data you need in your particles, and iterate over those in a small number of tight loops to apply updates or modify rendering.

In terms of Unity you’d want to write custom rendering code of some kind, because both making a GameObject per particle and/or using the built in rendering components directly goes right back to making (a bunch of!) objects per particle. I’m not a graphics expert, so I can’t suggest the best way to do this, but I’d recommend looking at procedural mesh generation and/or vertex shaders for a start (make a base mesh with your particles un-transformed, then do all transformations in the vert shader for animation/movement etc.). Newer stuff like geometry and/or tessellation could come in super handy here, too, and I believe that there are even ways that you can get the shader to do even more of the work as well.

My mistake, I shouldn’t have used the word particle! It just seemed to fit what I’m after quite nicely!

My aim to have around 2-4000 prefabs from a bank of up to 8 different objects each object having animations along with the properties I’ve highlighted above.

I’ve coded this in maxmsp but it’s not too speedy when working with lots of objects, unity seems better at lots of objects.

From what you’ve said iterating over arrays sounds faster, but would it be noticeably faster on only 4000 objects than storing data in scripts on the individual prefabs?

Thanks

In case anyone finds this useful in the future…

Moving 4096 prefabs in an array and a for loop runs at 36fps on my machine.

doing the same but with a script running on each prefab takes it down to 26fps.

However with 2048 prefabs both run at around 80fps.