Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Particle system: Add emission by distance travelled between emits (instead of time) #780

Open
ghsoares opened this issue May 2, 2020 · 5 comments
Milestone

Comments

@ghsoares
Copy link

ghsoares commented May 2, 2020

Describe the project you are working on:
A simple top-down shooter where I have high-speed rocket launcher adn the rocket leaves smoke behind.

Describe the problem or limitation you are having in your project:
The particles system (2D and 3D) are leaving a "gap" between particles when local coords speed is high or the system is set to global coords and the parent speed is high. In the Unity engine, we have a option to emit particles by distance that creates new particles in between gaps

Describe the feature / enhancement and how it helps to overcome the problem or limitation:
To overcome the problem, it would be great if there was an option to emit by distance, like in Unity engine.

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
In my mind, it can have two new properties: "rate by distance" and "minimal distance delta",
then if the distance from previous global position and current global position is higher than minimal distance delta, then creates new particles between this gap.

In a custom particles shader, I can't just create new particles because there's pre-defined amount of particles that restarts to "create new ones".

So in pseudocode we could have (thinking in a particles shader):

uniform float min_distance_delta;
uniform int interpolation_emission_step;
uniform int rate_by_distance;

void vertex() {
    vec3 previous_position; //some kind of previous particle system global position read
    vec3 current_position; //some kind of current particle system global position read
    float distance = distance(current_position, previous_position);
    if (distance > min_distance_delta) {
        //calculates every position using interpolation_emission_step
        //and creates new particles in each position
    }
}

I don't know if with current particles system shader API, it's possible to create options to read previous and current position and create new particles besides the already alocated ones.

If this enhancement will not be used often, can it be worked around with a few lines of script?:
I think that it can't be made with gdscript or C# for performance reasons, as the only way is to instantiate new particles systems

Is there a reason why this should be core and not an add-on in the asset library?:
Because there are many projects that have high-speed gameplay and uses particles with global coords (a racing game where has tires smokes in drifting, for example), so it would be nice to be a main feature

@Calinou Calinou changed the title Particles system emission by distance Particles system emission by distance travelled between emits (instead of time) Jun 3, 2020
@Calinou Calinou changed the title Particles system emission by distance travelled between emits (instead of time) Particle system: Add emission by distance travelled between emits (instead of time) Jun 3, 2020
@reduz
Copy link
Member

reduz commented Sep 5, 2020

Manual particle emission in 4.0 should allow you to solve this. You can just set the maximum amount of particles processed, then do your own emitter logic.

@Calinou
Copy link
Member

Calinou commented Jun 16, 2022

In 4.0.alpha, it looks like you can implement GPUParticles manual emission in a script, rather than in a shader. Shaders can only emit subparticles, but scripts can emit standard particles. However, CPUParticles still lacks a way to perform manual particle emission.

Here's an example with emission by distance (try moving the GPUParticles3D node in the editor): test_particle_manual_emission.zip

Edit: Updated example for Godot 4.2+ (tested on 4.3.beta1): test_particle_emission_over_distance.zip

However, custom transform origins seem to be ignored, so I can't actually create a "line" between the old position and new position when the particle moves too fast in a given frame (to create particles on this "line").
Edit: Fixed thanks to #780 (comment) 🙂

Note that calling emit_particle() will set emitting to false, as you're expected to handle all the emission yourself.

@aaronfranke aaronfranke modified the milestones: 4.0, 4.x Feb 24, 2023
@Wiggan
Copy link

Wiggan commented May 10, 2023

@Calinou Hi, I tested your zip-file. I found a way to make it work when changing the last parameter, the int flags to1. That makes it respect the transform sent in. Now i get a line! Cool stuff, thank you for the example!

@Xorblax
Copy link

Xorblax commented Jun 15, 2024

Any plans on this still being implemented? While it can be done through script, you lose a lot of the functionality of the particle shader whic forces you to script that yourself. It's also a very common thing youd want a particle system to do I think, and would be more performant if it were part of the particle system, since otherwise youre doing a lot of interpolation loops in gdscript for what may be a large number of particle systems.

@Calinou
Copy link
Member

Calinou commented Jun 16, 2024

Any plans on this still being implemented?

It should be possible to implement this in core by porting what the project linked in #780 (comment) does in C++. Note that it has a few caveats, such as requiring the Emitting property to be false (otherwise, the manually emitted particles will be overwritten by the automatically emitted ones).

Also, since particle emission occurs manually in C++ in this case, it won't be able to use particle emission shapes from ParticleProcessMaterial or ShaderMaterial. Instead, new properties will be needed to define the random spread for particle emission by distance (e.g. an enum to choose between point, box, sphere and sphere surface, and a Vector3 to choose the spread on each axis).

Edit: Here's a WIP C++ implementation: https://github.com/Calinou/godot/tree/particles-add-emit-over-distance

particles_over_distance.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants