Asset - Graphics sPart 3D particle system - ON SALE for $5.99

Discussion in 'Marketplace' started by TheSnidr, Aug 26, 2018.

  1. TheSnidr

    TheSnidr Heavy metal viking dentist GMC Elder

    Joined:
    Jun 21, 2016
    Posts:
    391
    [​IMG]
    Thank you for showing interest in the sPart system!

    What is it?
    The sPart system is a 3D particle system for Gamemaker Studio 2 that provides you with a fast and easy way to create beautiful particle effects in 3D. It aims to be similar in use to the built-in 2D particle system in Gamemaker, and the documentation will assume the user has a basic familiarity with the built-in system.

    Where do I find it?
    The sPart system is available on the Marketplace:
    Get it on the Marketplace

    Download executable demo
    Download documentation

    How does it do it? Some technical info!
    The particles are simulated entirely on the GPU via a vertex shader using the equations of motion. This is much, much faster than moving and drawing particles individually as sprites, and allows for drawing tens of thousands, or even hundreds of thousands of particles at a time.
    To be able to draw particles, we need to send a vertex buffer to the shader. The vertex buffer used by the sPart system is a bare-bones buffer that contains the following data per vertex:
    1. The index of the particle, stored in three bytes. This allows for a maximum of 255x255x255 unique particles to be drawn per batch. This index is used to generate a unique seed for the noise function in the shader, giving each particle a unique trajectory.
    2. The corner ID of the vertex, stored in the last byte. This can be 0, 1, 2, or 3. This is used to construct the local vertex position and texture coordinate.
    The vertex buffer uses four bytes per vertex, and six vertices per particle. Multiple vertex buffers with differing numbers of particles can be created, so that the most fitting one can be used. This will be described later, in the function called spart_system_create. If the number of particles exceeds the maximum number of the vertex buffer, they will have to be split up into smaller batches.
    We need to send some info about where to spawn particles to the shader. This is where the emitters come in handy. You can create an emitter and tell it how, where and how many particles it should emit per unit of time, and the sPart system sends this info to the vertex shader. Emitters are the most efficient when static, but they can be dynamically moved as well. Each batch can draw up to 32 separate static emitters, or 32 steps of a moving emitter at a time, after which the particle system has to be split up into multiple batches.
    Particles can spawn other particles. This only works for one generation, particles spawned from other particles cannot spawn particles of their own. Particles can spawn other particles either each step or upon death. This uses a slightly different shader than the regular particles.
    Particles are by default billboarded images, but meshes can also be used to achieve fully 3D particles. The format for 3D mesh particles contains the following data per vertex:
    1. Vertex position, stored in three bytes (one byte per dimension)
    2. Particle index, stored in one byte (and so is capped to 255)
    3. Texture coords stored in two bytes (one byte per dimension)
    4. Vertex normals stored in two bytes (polar coordinate angles)
    The mesh vertex buffer contains eight bytes per vertex. The number of vertices is uncapped, but for the sake of speed and memory usage, it is recommended to keep the vertex count low.

    Particle system functions overview
    Following is an overview of the various functions included in the sPart system, as well as a description of each.
    spart_init()
    Returns: N/A
    Initializes the sPart system. Shuld be run once at the start of the game. It creates a vertex format, and initializes various global variables, macros and enums used by the sPart system.

    spart_system_create(batchSizeArray)
    Returns: Index of new particle system
    Creates a new particle system, which is a container for the emitters created within the system. You must define the particle batch sizes in an array of ascending values, and the sPart system will at any time pick the batch size that fits best for your particles.
    For a dynamic particle system it’s often useful to define multiple vertex batch sizes. Say there are only fifty particles on screen; if the minimum vertex batch is ten thousand, that is a lot of wasted vertices. On the opposite extreme, say there are ten thousand particles, but the maximum batch size is fifty – this would require a whole lot of draw calls to draw all particles, and would slow down your game!
    Usage example:
    spart_system_create([50, 150, 500, 1500, 5000]); //<- this would let you draw a wide range of particles with as few draw calls as possible

    spart_system_update(partSystem, timeIncrement)
    Returns: N/A
    Updates the particle system, keeping track of time and emitter deaths. Needs to be called every step! This script lets you define the time increment per step. Set the timeIncrement to for example 1 to increment time by one unit per step, or to for example delta_time / 10000000 to increment it by one unit per second irrespective of the framerate.
    Usage example:
    spart_system_update(partSystem, delta_time / 10000000);

    spart_system_draw(partSystem)
    Returns: N/A
    Draws your particle system. Must be called in draw event. You can set the world matrix with matrix_set(matrix_world, etc) to alter the position, orientation and scale of the entire particle system as a whole.

    spart_system_destroy(partSystem)
    Returns: N/A
    Destroys the particle system and all emitters, particle types and vertex buffers it contains.



    Particle type functions overview
    Following is a list of all particle type functions, as well as a description of each.

    spart_type_create(partSystem)
    Returns: Index of new particle type
    Creates a new blank particle type. You can define the rules for this particle type with the following functions.

    spart_type_destroy(partTypeInd)
    Returns: N/A
    Destroys a particle type. If this function isn’t called, the particle type will live on for the entire duration of the game.

    spart_type_life(partType, life_min, life_max)
    Returns: N/A
    Define the possible life span of each particle. A life span is randomly selected between the minimum and maximum. A special note here: The seed for the random function only depends on the particle index. This means that the life span will be the same each time the particle is spawned. This is a necessary evil for the step/death spawning to work. This is the only variable that is affected this way.

    spart_type_sprite(partType, sprite, image_speed, random)
    Returns: N/A
    Defines the sprite of a particle. The sprite can be animated, and you can set the animation speed. Set image_speed to -1 to stretch the animation to the particle’s life span.
    This function will duplicate the sprite and transform it into a format the particle shader can use. Sprites whose dimensions are not powers of two will be resized to the nearest power of two. Animated sprites will be arranged one after another horizontally on the new sprite sheet. This new sprite is deleted when the particle type is destroyed.
    If the particle is a mesh particle, the sprite will be used as a texture. The texture may be animated.

    spart_type_mesh(partType, model, numPerBatch)
    Returns: N/A
    Makes the particle draw a 3D mesh instead of a billboard. The meshes will be simulated in the same way as the billboarded particles, but will be drawn in full 3D and not in view-space.
    «Model» can be an index of a vertex buffer, a path to an .obj model or a path to a saved buffer.
    If a vertex buffer is supplied, it must be formatted in the following way:
    1. 3D position 3x4 bytes
    2. Normal 3x4 bytes
    3. Texture coordinates 2x4 bytes
    4. Colour 4x1 bytes
    NumPerBatch cannot exceed 255

    spart_type_mesh_rotation(partType, rotAxis[3], axisDeviation)
    Returns: N/A
    A 3D mesh can rotate about an axis, and this axis is defined in this function. Give the axis to rotate around, as well as how far (in degrees) from this axis the rotation axis of the individual particles may deviate. Setting axisDeviation to 360 gives totally random rotation axes. The final rotation axis is also affected by the «radial» setting in spart_type_direction, which makes each particle face in its moving direction.

    spart_type_mesh_lighting(partType, ambientCol, lightCol, lightDir[3])
    Returns: N/A
    Enables a directional light onto mesh particles. Only one directional light may be used with the built-in shaders, for more advanced lighting you will have to manually edit the shaders.

    spart_type_direction(partType, dir[3], dir_vary, radial)
    Returns: N/A
    Set the starting direction of the particle. Also lets you define the angle (in degrees) from the given direction the particle may randomly deviate. Setting relative to true modifies the starting direction to be relative to its spawning pos within the emitter. Particles that have been spawned by other particles will ignore their own direction, and instead keep moving in the direction of its creator, plus the direction variation.

    spart_type_scale(partType, scale_min, scale_max, scale_incr)
    Returns: N/A
    Sets the scale of the particle. A starting scale will be randomly selected between scale_min and scale_max, and the scale will be incremented by scale_incr for each unit of time.

    spart_type_orientation(partType, ang_min, ang_max, ang_incr, ang_relative)
    Returns: N/A
    Defines the angle and angular momentum (in degrees per unit of time) of the particle in screen-space. A starting angle will be randomly selected between ang_min and ang_max, and the angle will be incremented by ang_incr for each unit of time. Setting ang_relative to true will make the particle face in its screen-space moving direction, plus the given angle.

    spart_type_speed(partType, speed_min, speed_max, speed_acc, speed_jerk)
    Returns: N/A
    Sets the speed of the particle. A starting speed will be randomly selected between speed_min and speed_max, and the speed will be incremented by speed_acc for each unit of time. The speed will also be incremented by speed_jerk for each unit of time squared, enabling more advanced movement patterns.

    spart_type_gravity(partType, grav_amount, grav_direction[3])
    Returns: N/A
    Define the gravity vector and amount.

    spart_type_colour_mix(partType, colour1, alpha1, colour2, alpha2)
    Returns: N/A
    Sets the colour of the particle to a random mix between the two given colours

    spart_type_colour1/2/3/4(partType, colour1, alpha1, colour2, alpha2…etc)
    Returns: N/A
    Sets the colour of the particle to a linear blend of the given colours, stretched over the course of the particle’s life.

    spart_type_blend(partType, additive)
    Returns: N/A
    Lets you toggle additive blend mode. Turning additive blend mode on will also disable zwriting. This is useful for, for example, fire effects.

    spart_type_blend_ext(partType, src, dest, zwrite)
    Returns: N/A
    Lets you define source and destination blend modes, as well as give you control over the zwriting, for the particle.

    spart_type_step(partType, num, childType)
    Returns: N/A
    Make the particle emit a given number of particles for each unit of time. Note that particles emitted this way cannot emit particles of their own.

    spart_type_death(partType, num, childType)
    Returns: N/A
    Make the particle emit a given number of particles upon death. Note that particles emitted this way cannot emit particles of their own.



    Particle emitter function overview
    Following is a list of all particle emitter functions, as well as a description of each.

    spart_emitter_create(partSystem)
    Returns: Index of new emitter
    Create a new inactive emitter. To active the emitter, use spart_emitter_stream.

    spart_emitter_stream(emitterInd, parttype, particleNumPerTime, lifeTime, dynamic)
    Returns: N/A
    Make the emitter emit the given number of particles per unit of time. You can define the emitters life time, or set it to -1 to use the default life span.
    Setting dynamic to true will let you change the emitter’s orientation without altering the particles that have already been created. This effectively keeps a «log» of all previous emitter positions/orientations, so that existing particles are not retroactively altered.

    spart_emitter_region(ind, centerPos[3], scale[3], eulerAngles[3], shape, distribution, dynamic)
    Returns: N/A
    Move the emitter. The new position, scale and euler angles should all be supplied as three-part vectors. The angles are defined in degrees.
    Shape can be one of the following constants:
    0. spart_shape_cube
    1. spart_shape_circle
    2. spart_shape_cylinder
    3. spart_shape_sphere
    Distribution can be one of the following constants:
    0. spart_distr_linear (or ps_distr_linear) //Generate with equal propbability anywhere in space
    1. spart_distr_gaussian (or ps_distr_gaussian) //Generate more at the center of the shape
    2. spart_distr_invgaussian (or ps_distr_invgaussian) //Generate more at the edges of the shape
    Setting dynamic to true will let you change the emitter’s orientation without altering the particles that have already been created. This effectively keeps a «log» of all previous emitter positions/orientations, so that existing particles are not retroactively altered.
    Usage example:
    spart_emitter_region(emitterInd, [x, y, z], [32, 32, 32], [0, 0, direction], spart_shape_cube, spart_distr_gaussian, true);

    spart_emitter_mature(emitterInd)
    Returns: N/A
    This function will mature an emitter. This means that it will look like it has been emitting for quite a while, even though it just started. This function must be called after you’re done defining the emitter, as all it really does is subtract the maximum life span of its particle types from the emitter’s creation time.

    spart_emitter_retire(ind)
    Returns: N/A
    Deletes the selected emitter from the active emitters list, and makes a new, special emitter that will only finish the old emitter’s spawned particles without spawning new ones for its own. The new emitter will indicate the given emitter as its parent.

    spart_emitter_destroy(ind)
    Returns: N/A
    Destroys the emitter, as well as any child emitters. This function will be unnecessary if you also delete the particle system with spart_system_destroy, as that function also deletes all emitters.



    Helper function overview
    Here’s an overview of the helper scripts that are not meant for used by themselves, but are used in the other functions.

    spart__type_set_uniforms(shader, partType);
    Returns: N/A
    Sets the shader uniforms for the given particle type.

    spart__type_set_parent_uniforms(shader, partType, effectType);
    Returns: N/A
    Sets the shader uniforms for the given parent particle type. This is used for particles that are spawned each step or upon death of other particles.

    spart__get_vbuff_settings(partSystem, partNum)
    Returns: Array containing [vertex buffer, number of batches, number of particles per batch]
    Looks up the batch sizes in this particle system, and finds a fitting one for the desired number of particles.

    spart__update_vbuffers(partSystem)
    Returns: N/A
    Makes sure the necessary vertex buffers exist. When a particle system is destroyed, its vertex buffers are deleted. However, other particle systems may still use the same vertex buffers, and they will have to be created again. This is basically a cheap workaround.

    spart__load_obj(fname)
    Returns: Buffer index
    Loads a .obj file into a buffer that is formatted in a way the sPart system can use. This is used for loading meshes in the spart_type_mesh function.

    Gallery
    [​IMG]

    [​IMG]
    [​IMG]
    [​IMG]
    [​IMG]
    [​IMG]
    [​IMG]
     
    Last edited: Sep 22, 2018
    zbox, Xor, icuurd12b42 and 11 others like this.
  2. Dragonite

    Dragonite Member

    Joined:
    Jun 20, 2016
    Posts:
    5
    I approve of your uses of ducks.

    (As I've told you before, I like it! Getting this to work in my current project might be a bit of work owing to how far along it is but I'll play around with it all the same!)
     
    Samuel Venable and TheSnidr like this.
  3. TheSnidr

    TheSnidr Heavy metal viking dentist GMC Elder

    Joined:
    Jun 21, 2016
    Posts:
    391
    New version is up with a couple'a fixes:
    - Added the possibility to set a custom cull mode for your particle type. This particularly applies to mesh particles. The script is called spart_type_mesh_cullmode
    - Fixed a problem with dynamically moving emitters, billboarded particles would flicker once emitters passed their life span. This was due to a problem when generating the vertex buffers. If you have incorporated the particle system into your project, I recommend to at the very least update the helper script called spart__update_vbuffers.

    Feedback is greatly appreciated!
    Cheers!
     
    Rukola and Samuel Venable like this.
  4. Rukola

    Rukola Member

    Joined:
    Jun 20, 2016
    Posts:
    72
    It seems like a good system @TheSnidr. Some suggestions :D
    • Post a link in your open source(ish?) project. Like an add-on to the project :)
    • Use more populair effects. Like the zelda explosion
    • Use a higher texture grass. Pixels might work.
    • Instead of low quality gifs, upload it to youtube using recorder: https://obsproject.com/
    Anyway, it seems great. Good job!
     
    TheSnidr likes this.
  5. TheSnidr

    TheSnidr Heavy metal viking dentist GMC Elder

    Joined:
    Jun 21, 2016
    Posts:
    391
    Thank you, I will definitely have to market it more! While working on an explosion effect, however, I found a bug that I haven't managed to fix yet:
    * When particles emit particles per step, retiring the emitter makes the emitter think it has to draw the maximum possible number of particles that could have existed at the same time if its life span was longer. For short burst effects like explosions, it could end up drawing hundreds of thousands of particles when it only needs a couple of thousand. This will be fixed as soon as I have the time.
     
  6. TheSnidr

    TheSnidr Heavy metal viking dentist GMC Elder

    Joined:
    Jun 21, 2016
    Posts:
    391
    I'm in the process of fixing up my new apartment, sorry for being slow with updates!
    I fixed the bug with the burst emitters! Secondary particles should now work correctly even for burst effects and dynamically moving emitters. There are also a couple of other changes, so here's a full change log:
    • Fixed an error with the step particle effect, which made the system think it had to render all possible particles even for short burst effects. The bug resulted in possibly rendering ten thousand times more particles than necessary when dynamically moving emitters with step effects.
    • Added a new demo: Simple explosion. Press 9 in the demo project to view this effect.
    • Added acceleration to the scale and angle settings. This allows you to change the rate at which the scale and angle increases. This could be used to for example create a particle that first increases in size, and then gradually slows down, and in the end decreases in size again.
    • Generally cleaner code, particularly in the shaders
    [​IMG]

    Download at the Marketplace, link in first post!
    If there is a demand for it, I'll make a 1.4 version as well. Gimme a holler.
     
    Last edited: Sep 16, 2018
    Rukola likes this.
  7. Misty

    Misty Member

    Joined:
    Jun 22, 2016
    Posts:
    826
    i demand two things:

    1.4 support
    a demo so i can speed test on my machine
     
    TheSnidr likes this.
  8. Posh Indie

    Posh Indie Member

    Joined:
    Dec 5, 2016
    Posts:
    155
    You are welcome.
     
  9. Misty

    Misty Member

    Joined:
    Jun 22, 2016
    Posts:
    826
    You forget the first rule of business: Supply and demand.
     
  10. sylvain_l

    sylvain_l Member

    Joined:
    Sep 18, 2016
    Posts:
    661
    you should supply a request in that case :D

    hi @TheSnidr just to be sure; we can constrain the trajectories at will?

    for example, instead of plastic ducks, have basic car looking things, and have them go straight line on a road , or even more complex road shape (as long as we can feed the system with telling him what the trajectory)
     
  11. TheSnidr

    TheSnidr Heavy metal viking dentist GMC Elder

    Joined:
    Jun 21, 2016
    Posts:
    391
    Not with the standard sPart shader, no. You specify the starting direction, starting speed, gravity and the like, and the system generates particles randomly within given parameters.

    It is, however, possible to modify the shader in many ways! I plan to make a dynamic clutter engine, that places grass and flowers and stuff randomly near the camera. Your idea seems like an interesting one that I'd like to explore.
     
    sylvain_l likes this.
  12. Misty

    Misty Member

    Joined:
    Jun 22, 2016
    Posts:
    826
    Sniders EXACT words were:

    "If there is a demand for it, I'll make a 1.4 version as well. Gimme a holler."

    He said two keywords "demand". "Holler". Not soft, not sensitive.

    So I say what my demands are, and then society comes at me, society is getting so sensitive and soft, I have to go through my neurons and always pick the softess, most gentle, sensitive words at all times or else I KNOW some guy will come here giving my flak about it.
     
    IndianaBones likes this.
  13. TheSnidr

    TheSnidr Heavy metal viking dentist GMC Elder

    Joined:
    Jun 21, 2016
    Posts:
    391
    I've been swamped with IRL stuff lately, but I will make a 1.4 version as soon as possible.
    Just popping in to say I've put the asset on sale for $2.99 for a short while to hopefully get more reviews on the Marketplace page! So if you buy, a review would be greatly appreciated! Even a super short one ^.^
     
    Misty likes this.
  14. Mert

    Mert Member

    Joined:
    Jul 20, 2016
    Posts:
    96
    Just purchased it. Thanks for the discount :)
     
    TheSnidr likes this.
  15. The-any-Key

    The-any-Key Member

    Joined:
    Feb 2, 2017
    Posts:
    1,366
    +1 sale

    But it is possible to run SMF and the particle system together?
     
  16. TheSnidr

    TheSnidr Heavy metal viking dentist GMC Elder

    Joined:
    Jun 21, 2016
    Posts:
    391
    Oh absolutely, neither affects the other, so that should be no problem! I plan to incorporate a particle editor into the SMF model tool as well, specifically for the sPart system. You'll still need the sPart system as well though ;)
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice