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

Inconsistent behaviour between CPUParticles2D and GPUParticles2D when changing node parameters in _process #65516

Closed
Novark opened this issue Sep 8, 2022 · 7 comments

Comments

@Novark
Copy link

Novark commented Sep 8, 2022

Godot version

4.0 Alpha 16

System information

Windows 10 (x64), Vulkan, nVidia GTX 980 Ti

Issue description

Background to my issue / what I'm trying to achieve:

I'm emitting particles at the mouse cursor position. When moving the mouse around the screen, this results in "gaps" between the emitted particles (due to the delta time between render frames). What I'd like to do, is emit them along a "Line" emission_shape, however, since this doesn't exist, I've resorted to selecting a "Box" / "Rectangle" emission_shape, and then rotating the Node based on the angle between consecutive _process frames.

This "hack" works well for CPUParticles2D, but does not work for GPUParticles2D. I'm not sure if this inconsistent behaviour is intended, so I'm relying on others who are more familiar with the specific implementations to inform me if this is correct.

particles

Steps to reproduce

Repro project attached

Create two nodes, 1x CPUParticles2D and 1x GPUParticles2D. Configure them to each emit 10,000 particles with 0 gravity. Change their respective emission_shape properties to either "Rectangle" (CPUParticles2D) or "Box" (GPUParticles2D).

Test each node separately by toggling the other node's visibility.

CPUParticles2D script:

extends CPUParticles2D

var mouse_pos = Vector2.ZERO
var prev_pos = Vector2.ZERO


func _process(delta):
	mouse_pos = get_global_mouse_position()
	self.position = lerp(prev_pos, mouse_pos, 0.5)
	self.rotation = prev_pos.angle_to_point(mouse_pos)
	self.emission_rect_extents.x = prev_pos.distance_to(mouse_pos) / 2
	prev_pos = mouse_pos

GPUParticles2D script:

extends GPUParticles2D

var mouse_pos = Vector2.ZERO
var prev_pos = Vector2.ZERO


func _process(delta):
	mouse_pos = get_global_mouse_position()
	self.position = lerp(prev_pos, mouse_pos, 0.5)
	self.rotation = prev_pos.angle_to_point(mouse_pos)
	self.process_material.emission_box_extents.x = prev_pos.distance_to(mouse_pos) / 2
	prev_pos = mouse_pos

Minimal reproduction project

Particles_Repro.zip

@Calinou
Copy link
Member

Calinou commented Sep 8, 2022

Can you reproduce this if you disable Interpolate in GPUParticles? Also try changing Fixed FPS to 60, 0 or 1000.

When moving the mouse around the screen, this results in "gaps" between the emitted particles (due to the delta time between render frames).

See also #47973.

@Novark
Copy link
Author

Novark commented Sep 8, 2022

Can you reproduce this if you disable Interpolate in GPUParticles? Also try changing Fixed FPS to 60, 0 or 1000.

When moving the mouse around the screen, this results in "gaps" between the emitted particles (due to the delta time between render frames).

See also #47973.

Disabling "Interpolate" had no effect. Changing the "Fixed FPS" to either 0 or 1000, however, appeared to fix the issue. I'm not entirely sure how this property works though - will this solution still work on lower-spec systems if the render FPS is low?

I also just noticed that CPUParticles2D has this Fixed FPS set to 0 by default, which (unbeknownst to me at the time of submitting this issue) is what gave it the smooth behaviour. If I change the CPUParticles2D "Fixed FPS" to 30 (to match the default value on GPUParticles2D), then it has the same choppy behaviour.

Finally, regarding #47973: I think other engines (GameMaker comes to mind) provide a "Line" emission shape, so you can essentially interpolate the emission of particles by distributing them along a line. This is what I was trying to achieve with my workaround "hack". There's even an optional parameter in other engines for how you want the particles to be distributed (either a normal distribution, or gaussian). This would be my preferred solution to this issue. Per #47973, this could also take the form of an "Interpolate Position" checkbox which would essentially have the same functional implementation (at least, for the "Point" emission_shape - interpolation for other emission_shapes might be more complicated).

@Calinou
Copy link
Member

Calinou commented Sep 9, 2022

I'm not entirely sure how this property works though - will this solution still work on lower-spec systems if the render FPS is low?

It should keep working – you most likely weren't rendering at 1000 FPS, yet setting Fixed FPS to 1000 did the trick 🙂

If I change the CPUParticles2D "Fixed FPS" to 30 (to match the default value on GPUParticles2D), then it has the same choppy behaviour.

CPUParticles doesn't have interpolation, unlike GPUParticles.

@Novark
Copy link
Author

Novark commented Sep 9, 2022

I'm not entirely sure how this property works though - will this solution still work on lower-spec systems if the render FPS is low?

It should keep working – you most likely weren't rendering at 1000 FPS, yet setting Fixed FPS to 1000 did the trick 🙂

If I change the CPUParticles2D "Fixed FPS" to 30 (to match the default value on GPUParticles2D), then it has the same choppy behaviour.

CPUParticles doesn't have interpolation, unlike GPUParticles.

Is there any reason why "Fixed FPS" shouldn't just always be set to the highest possible value? What are the tradeoffs of choosing, say 30fps versus 1000fps?

@Calinou
Copy link
Member

Calinou commented Sep 9, 2022

Is there any reason why "Fixed FPS" shouldn't just always be set to the highest possible value? What are the tradeoffs of choosing, say 30fps versus 1000fps?

Lower FPS values save processing power, as values don't need to be recalculated on the GPU as often. This is especially important when attractors and collision are used.

@Novark
Copy link
Author

Novark commented Sep 9, 2022

Is there any reason why "Fixed FPS" shouldn't just always be set to the highest possible value? What are the tradeoffs of choosing, say 30fps versus 1000fps?

Lower FPS values save processing power, as values don't need to be recalculated on the GPU as often. This is especially important when attractors and collision are used.

Gotcha, that makes sense. As long as that behaviour is preserved at low game FPS, then that would be an acceptable workaround for my purpose.

I'd still love to see an interpolate option, or Line emission_shape added as a longer term solution, but this will work for now.

This issue can probably be closed, as it doesn't appear to be a bug, and my requested proposal duplicates #47973.

@Calinou
Copy link
Member

Calinou commented Sep 9, 2022

Closing in favor of #47973 and #51318 (not all GPUParticles properties are interpolated yet, even when interpolation is enabled).

@Calinou Calinou closed this as not planned Won't fix, can't repro, duplicate, stale Sep 9, 2022
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

2 participants