Particle generator script

From The SchomEmunity Wiki
Jump to: navigation, search

ok a rush job here folks but some info to get it onto Schome! I am musing fireworks but there's a million other things particles can be used for in SL.

Particle System info: https://wiki.secondlife.com/wiki/LSL_llParticleSystem

Tutorial: http://slnatalia.blogspot.com/2007/03/day-158-creating-attachments-with.html

Warning

Just a side note to say you should take great care with particle scripts. The client can only render a finite number of particules at one time. The particle code itself can very easily (attempt to) generate more than is viewable. As such you need to think carefully about how you deploy the particle script, as you cannot guarantee what someone else will see, and you can easily contribute to other SLers having a poor inworld experience. Woop Kamachi 15:03, 20 March 2007 (GMT)

Woop - would one particle = one prim? (therefore a spray with say 50 particles seen = 50 prims?) Mark Cabaret
No no. Particles do NOT equal prims. The particle script is stored and run server-side, but the actual particle effect is rendered on the individual client (thus potentially different on every client, much like a function such as llTargetOmega which is used to creat a smooth client-side rotation). Therefore the limitations are nothing to do with prims and prim limits per sim. They are an entirely separate kind of limitation. As a brief example however. If I wrote 3 particle scripts each generating around 1000 particles per second and set them next to each other, I would have no guarantee at all of what each end user would see, because the SL client is not designed to support such great numbers of particles concurrently. Woop.

The script

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//// eltee Statosky's Particle Creation Engine 1.0
//// 01/09/2004
//// *PUBLIC DOMAIN*
//// Free to use
//// Free to copy
//// Free to poke at
//// Free to hide in stuff you sell
//// Just please leave this header intact
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

integer effectFlags=0;
integer running=TRUE;


///////////////////////////////////////////////////////
// Color Secelection Variables
///////////////////////////////////////////////////////
// Interpolate between startColor and endColor
integer colorInterpolation  = TRUE;
// Starting color for each particle 
vector  startColor          = <1.0, 0.5, 0.75>;
// Ending color for each particle
vector  endColor            = <0.75, 0.5, 1.0>;
// Starting Transparency for each particle (1.0 is solid)
float   startAlpha          = 1.0;
// Ending Transparency for each particle (0.0 is invisible)
float   endAlpha            = 0.0;
// Enables Absolute color (true) ambient lighting (false)
integer glowEffect          = TRUE;


///////////////////////////////////////////////////////
// Size & Shape Selection Variables
///////////////////////////////////////////////////////
// Interpolate between startSize and endSize
integer sizeInterpolation   = TRUE;
// Starting size of each particle
vector  startSize           = <0.5, 0.5, 0.0>;
// Ending size of each particle
vector  endSize             = <0.5, 0.5, 0.0>;
// Turns particles to face their movement direction
integer followVelocity      = TRUE;
// Texture the particles will use ("" for default)
string  texture             = "";


///////////////////////////////////////////////////////
// Timing & Creation Variables Variables
///////////////////////////////////////////////////////
// Lifetime of one particle (seconds)
float   particleLife        = 3.0;
// Lifetime of the system 0.0 for no time out (seconds)
float   SystemLife          = 0.0;
// Number of seconds between particle emissions
float   emissionRate        = 0.02;
// Number of particles to releast on each emission
integer partPerEmission     = 1;


///////////////////////////////////////////////////////
// Angular Variables
///////////////////////////////////////////////////////
// The radius used to spawn angular particle patterns
float   radius              = 3.0;
// Inside angle for angular particle patterns
float   innerAngle          = 1;
// Outside angle for angular particle patterns
float   outerAngle          = 0;
// Rotational potential of the inner/outer angle
vector  omega               = <0.0, 0.0, 0.2>;


///////////////////////////////////////////////////////
// Movement & Speed Variables
///////////////////////////////////////////////////////
// The minimum speed a particle will be moving on creation
float   minSpeed            = 0.0;
// The maximum speed a particle will be moving on creation
float   maxSpeed            = 0.1;
// Global acceleration applied to all particles
vector  acceleration        = <0.0, 0.0, -0.5>;
// If true, particles will be blown by the current wind
integer windEffect          = FALSE;
// if true, particles 'bounce' off of the object's Z height
integer bounceEffect        = FALSE;
// If true, particles spawn at the container object center
integer followSource        = FALSE;
// If true, particles will move to expire at the target
//integer followTarget        = TRUE;
// Desired target for the particles (any valid object/av key)
// target Needs to be set at runtime
key     target              = "";


///////////////////////////////////////////////////////
//As yet unimplemented particle system flags
///////////////////////////////////////////////////////
integer randomAcceleration  = FALSE;
integer randomVelocity      = FALSE;
integer particleTrails      = FALSE;

///////////////////////////////////////////////////////
// Pattern Selection
///////////////////////////////////////////////////////
//   Uncomment the pattern call you would like to use
//   Drop parcles at the container objects' center
//integer pattern = PSYS_SRC_PATTERN_DROP;
//   Burst pattern originating at objects' center
//integer pattern = PSYS_SRC_PATTERN_EXPLODE;
//   Uses 2D angle between innerAngle and outerAngle
integer pattern = PSYS_SRC_PATTERN_ANGLE;
//   Uses 3D cone spread between innerAngle and outerAngle
//integer pattern = PSYS_SRC_PATTERN_ANGLE_CONE;
// 
//integer pattern = PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY;



setParticles()
{
// Here is where to set the current target
// llGetKey() targets this script's container object
// llGetOwner() targets the owner of this script
// Feel free to insert any other valid key
    target="";
// The following block of if statements is used to construct the mask 
    if (colorInterpolation) effectFlags = effectFlags|PSYS_PART_INTERP_COLOR_MASK;
    if (sizeInterpolation)  effectFlags = effectFlags|PSYS_PART_INTERP_SCALE_MASK;
    if (windEffect)         effectFlags = effectFlags|PSYS_PART_WIND_MASK;
    if (bounceEffect)       effectFlags = effectFlags|PSYS_PART_BOUNCE_MASK;
    if (followSource)       effectFlags = effectFlags|PSYS_PART_FOLLOW_SRC_MASK;
    if (followVelocity)     effectFlags = effectFlags|PSYS_PART_FOLLOW_VELOCITY_MASK;
    if (target!="")       effectFlags = effectFlags|PSYS_PART_TARGET_POS_MASK;
    if (glowEffect)         effectFlags = effectFlags|PSYS_PART_EMISSIVE_MASK;
//Uncomment the following selections once they've been implemented
//    if (randomAcceleration) effectFlags = effectFlags|PSYS_PART_RANDOM_ACCEL_MASK;
//    if (randomVelocity)     effectFlags = effectFlags|PSYS_PART_RANDOM_VEL_MASK;
//    if (particleTrails)     effectFlags = effectFlags|PSYS_PART_TRAIL_MASK;
    llParticleSystem([
        PSYS_PART_FLAGS,            effectFlags,
        PSYS_SRC_PATTERN,           pattern,
        PSYS_PART_START_COLOR,      startColor,
        PSYS_PART_END_COLOR,        endColor,
        PSYS_PART_START_ALPHA,      startAlpha,
        PSYS_PART_END_ALPHA,        endAlpha,
        PSYS_PART_START_SCALE,      startSize,
        PSYS_PART_END_SCALE,        endSize,    
        PSYS_PART_MAX_AGE,          particleLife,
        PSYS_SRC_ACCEL,             acceleration,
        PSYS_SRC_TEXTURE,           texture,
        PSYS_SRC_BURST_RATE,        emissionRate,
        PSYS_SRC_INNERANGLE,        innerAngle,
        PSYS_SRC_OUTERANGLE,        outerAngle,
        PSYS_SRC_BURST_PART_COUNT,  partPerEmission,      
        PSYS_SRC_BURST_RADIUS,      radius,
        PSYS_SRC_BURST_SPEED_MIN,   minSpeed,
        PSYS_SRC_BURST_SPEED_MAX,   maxSpeed, 
        PSYS_SRC_MAX_AGE,           SystemLife,
        PSYS_SRC_TARGET_KEY,        target,
        PSYS_SRC_OMEGA,             omega   ]);
}

default
{
    state_entry()
    {
        running=TRUE;
        llSetText("Running", <0.0, 1.0, 0.0>, 0.5);
        setParticles();
    }
    
    touch_start(integer num_detected)
    {
        if (running==TRUE)
        {
            running=FALSE;
            llSetText("Stopped", <1.0, 0.0, 0.0>, 0.5);
            llParticleSystem([]);
        }
        else
        {
            running=TRUE;
            llSetText("Running", <0.0, 1.0, 0.0>, 0.5);
            setParticles();
        }
    }
}


also see: http://www.sluniverse.com/forums/shwmessage.aspx?ForumID=26&MessageID=748

This tutorial was created by Oz Spade [Smile]  Editing and images coming soon [Smile]

 Tutorial: Creating a candle with particle effects

First we want to make our base objects, we're just going to be using some simple things for this since the main objective will be the particle effect. You can add textures or whatever if you want later.

Lets start with the main candle part by making a white cylinder:

- Right click and click Create

- Select the Cylinder object and then point and click where you want to rez it

- We then want to shrink the Cylinder down to about:
X - 0.044
Y - 0.044
Z - 0.272


If you want to do that exactly you can click the More >> button in the edit window and then click Object and enter in those values under Size (meters)

- Then we want to make it white, so while still in the Edit screen click Texture, click the

Texture window (the one with the wood texture and Texture under it), and click the Blank button in the new window and then click Ok. Your cylinder should now be white.

Next, we want to create the wick:

- The easiest way to do this is to right click the main cylinder we just created and select

Edit, then click Position, hold down the Shift key on your keyboard and click the Blue Arrow and drag it up. This will create a duplication of the object where it just was and drag the original up. We will use this as our wick.

- We now want to shrink it to these sizes:
X - 0.010
Y - 0.010
Z - 0.033

Use the same method as before if you want exact results, you may also have to reposition it so its on top and in the middle of the main cylinder.

You should now have a candle with a wick. Simple enough hopefully.

Now we are going to take a simple cube and shrink it down very small, this will be used to emit the particles from, I made mine as 0.016,0.016,0.016 (x,y,z) but you can make it any size you want. If you have an invisible texture (just a texture with a clear alpha) you can also apply that to the cube. Position this cube with the wick.

Then, make another cube doing the same thing and position it above the wick, this is going to be used by the particles also.

We want to place the particle script inside the first box (the one thats actually on the wick as opposed to the one above the wick).

For particle effects I always use Ama Omega's particle script and edit it, it just makes things alot simpler, the current version is 0.4 I believe, but I use 0.3 for this because it works good enough and the extra stuff added to 0.4 is not needed for this script.

I will provide the particle script, and then go over it quickly explaining why I've done what I've done.

==============Start Code===============

// Particle Script 0.3
// Created by Ama Omega
// 10-10-2003

// Mask Flags - set to TRUE to enable
integer glow = TRUE;            // Make the particles glow
integer bounce = FALSE;          // Make particles bounce on Z plan of object
integer interpColor = TRUE;     // Go from start to end color
integer interpSize = TRUE;      // Go from start to end size
integer wind = FALSE;           // Particles effected by wind
integer followSource = FALSE;    // Particles follow the source
integer followVel = TRUE;       // Particles turn to velocity direction

// Choose a pattern from the following:
// PSYS_SRC_PATTERN_EXPLODE
// PSYS_SRC_PATTERN_DROP
// PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY
// PSYS_SRC_PATTERN_ANGLE_CONE
// PSYS_SRC_PATTERN_ANGLE
integer pattern = PSYS_SRC_PATTERN_ANGLE_CONE;

// Select a target for particles to go towards
// "" for no target, "owner" will follow object owner
//    and "self" will target this object
//    or put the key of an object for particles to go to
key target;

// Particle paramaters
float age = 0.4;                  // Life of each particle
float maxSpeed = 0.1;            // Max speed each particle is spit out at
float minSpeed = 0.1;            // Min speed each particle is spit out at
string texture;                 // Texture used for particles, default used if blank
float startAlpha = 1;           // Start alpha (transparency) value
float endAlpha = 0.0;           // End alpha (transparency) value
vector startColor = <1,0.5,0>;    // Start color of particles <R,G,B>
vector endColor = <1,1,0>;      // End color of particles <R,G,B> (if interpColor == TRUE)
vector startSize = <0.06,0.08,0.06>;     // Start size of particles
vector endSize = <0.04,0.08,0.04>;       // End size of particles (if interpSize == TRUE)
vector push = <0,0,0.7>;          // Force pushed on particles

// System paramaters
float rate = 0.01;            // How fast (rate) to emit particles
float radius = 0.001;          // Radius to emit particles for BURST pattern
integer count = 100;        // How many particles to emit per BURST
float outerAngle = 0.08;    // Outer angle for all ANGLE patterns
float innerAngle = 0.9;    // Inner angle for all ANGLE patterns
vector omega = <0,0,0>;    // Rotation of ANGLE patterns around the source
float life = 0;             // Life in seconds for the system to make particles

// Script variables
integer flags;

updateParticles()
{
    flags = 0;
    if (target == "owner") target = llGetOwner();
    if (target == "self") target = llGetKey();
    if (glow) flags = flags | PSYS_PART_EMISSIVE_MASK;
    if (bounce) flags = flags | PSYS_PART_BOUNCE_MASK;
    if (interpColor) flags = flags | PSYS_PART_INTERP_COLOR_MASK;
    if (interpSize) flags = flags | PSYS_PART_INTERP_SCALE_MASK;
    if (wind) flags = flags | PSYS_PART_WIND_MASK;
    if (followSource) flags = flags | PSYS_PART_FOLLOW_SRC_MASK;
    if (followVel) flags = flags | PSYS_PART_FOLLOW_VELOCITY_MASK;
    if (target != "") flags = flags | PSYS_PART_TARGET_POS_MASK;

    llParticleSystem([  PSYS_PART_MAX_AGE,age,
                        PSYS_PART_FLAGS,flags,
                        PSYS_PART_START_COLOR, startColor,
                        PSYS_PART_END_COLOR, endColor,
                        PSYS_PART_START_SCALE,startSize,
                        PSYS_PART_END_SCALE,endSize,
                        PSYS_SRC_PATTERN, pattern,
                        PSYS_SRC_BURST_RATE,rate,
                        PSYS_SRC_ACCEL, push,
                        PSYS_SRC_BURST_PART_COUNT,count,
                        PSYS_SRC_BURST_RADIUS,radius,
                        PSYS_SRC_BURST_SPEED_MIN,minSpeed,
                        PSYS_SRC_BURST_SPEED_MAX,maxSpeed,
                        PSYS_SRC_TARGET_KEY,target,
                        PSYS_SRC_INNERANGLE,innerAngle,
                        PSYS_SRC_OUTERANGLE,outerAngle,
                        PSYS_SRC_OMEGA, omega,
                        PSYS_SRC_MAX_AGE, life,
                        PSYS_SRC_TEXTURE, texture,
                        PSYS_PART_START_ALPHA, startAlpha,
                        PSYS_PART_END_ALPHA, endAlpha
                            ]);
}

default
{
    state_entry()
    {
        updateParticles();
    }
   
    link_message(integer snum, integer num, string str, key id)
    {
        if(str=="d")
        {
            target=id;
            updateParticles();
        }
    }
}

===========End Code================

The mask flags... Glow we of course want on, bounce we of course want off, you might think we want wind, but actually we don't because it wont help with the general effect we want to pull off, also I leave followSource FALSE in alot of scripts when I want more control, this allows me to have control over the radius so I can tell how big it goes etc.

Our pattern we want as an ANGLE_CONE, this helps us acheive our goal of our effect better.

You will notice that all of the parameters are very small floats, this is of course because we want them to be very small for our small candle. I have found that there is a limit to how small some of the parameters can go, so most of these are already close to the smallest size.

Something that is not part of the particle system is the link_message call... this is because we need our particles to target the box above the wick to complete the effect. This simply tells our script that when a message from another object in our linked set (we will be linking all the objects together later) comes to the script, to get the key of the object that said it, and update our target to that key, and then to update the particles.

Now... in order for this to work we must add a script to our box above the wick, here is the script...
========Start Code=====

default
{
    state_entry()
    {
        llMessageLinked(LINK_SET, 0, "d", llGetKey());
    }
   
    on_rez(integer spa)
    {
        llMessageLinked(LINK_SET, 0, "d", llGetKey());
    }
}

====End Code====

This is a pretty basic script, whenever the script is first started or when your candle is "rezed" (take out into world), it will send a message out to all the objects it is linked to. I just used the simple letter "d", and then put the objects key in place so it sends its own key along with the message.

You can then link all the objects together, it doesn't matter the order they are linked, but I just linked the main cylinder last to use it as the adult in the link set.

Then take it into your inventory, and bring it back out into world and it should look as we want.

To go over whats going on with our whole candle scripts...

- Our particle script starts up
- Our other script, upon rez or on reset of the script, sends a message to all objects linked with it
- Our particle script then picks this up and sets the target as the key of the object that sent the message and then updates the particles

And thats our candle!