1
0
mirror of https://github.com/godotengine/godot synced 2024-07-05 17:03:36 +00:00

Particle internal refactor and additions for more artistic control

Co-authored-by: Hugo Locurcio <hugo.locurcio@hugo.pro>
Co-authored-by: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com>
Co-authored-by: Raul Santos <raulsntos@gmail.com>
Co-authored-by: Mew Pur Pur <85438892+MewPurPur@users.noreply.github.com>
Co-authored-by: Clay John <claynjohn@gmail.com>
This commit is contained in:
QbieShay 2023-08-13 13:08:52 +02:00
parent 6916349697
commit c228fe1a0d
24 changed files with 1232 additions and 518 deletions

View File

@ -50,6 +50,10 @@
<member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
Number of particles emitted in one emission cycle.
</member>
<member name="amount_ratio" type="float" setter="set_amount_ratio" getter="get_amount_ratio" default="1.0">
The ratio of particles that should actually be emitted. If set to a value lower than [code]1.0[/code], this will set the amount of emitted particles throughout the lifetime to [code]amount * amount_ratio[/code]. Unlike changing [member amount], changing [member amount_ratio] while emitting does not affect already-emitted particles and doesn't cause the particle system to restart. [member amount_ratio] can be used to create effects that make the number of emitted particles vary over time.
[b]Note:[/b] Reducing the [member amount_ratio] has no performance benefit, since resources need to be allocated and processed for the total [member amount] of particles regardless of the [member amount_ratio].
</member>
<member name="collision_base_size" type="float" setter="set_collision_base_size" getter="get_collision_base_size" default="1.0">
Multiplier for particle's collision radius. [code]1.0[/code] corresponds to the size of the sprite.
</member>
@ -68,6 +72,10 @@
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
</member>
<member name="interp_to_end" type="float" setter="set_interp_to_end" getter="get_interp_to_end" default="0.0">
Causes all the particles in this node to interpolate towards the end of their lifetime.
[b]Note[/b]: This only works when used with a [ParticleProcessMaterial]. It needs to be manually implemented for custom process shaders.
</member>
<member name="interpolate" type="bool" setter="set_interpolate" getter="get_interpolate" default="true">
Enables particle interpolation, which makes the particle movement smoother when their [member fixed_fps] is lower than the screen refresh rate.
</member>

View File

@ -63,6 +63,10 @@
<member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
Number of particles to emit.
</member>
<member name="amount_ratio" type="float" setter="set_amount_ratio" getter="get_amount_ratio" default="1.0">
The ratio of particles that should actually be emitted. If set to a value lower than [code]1.0[/code], this will set the amount of emitted particles throughout the lifetime to [code]amount * amount_ratio[/code]. Unlike changing [member amount], changing [member amount_ratio] while emitting does not affect already-emitted particles and doesn't cause the particle system to restart. [member amount_ratio] can be used to create effects that make the number of emitted particles vary over time.
[b]Note:[/b] Reducing the [member amount_ratio] has no performance benefit, since resources need to be allocated and processed for the total [member amount] of particles regardless of the [member amount_ratio].
</member>
<member name="collision_base_size" type="float" setter="set_collision_base_size" getter="get_collision_base_size" default="0.01">
</member>
<member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="GPUParticles3D.DrawOrder" default="0">
@ -98,6 +102,10 @@
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
</member>
<member name="interp_to_end" type="float" setter="set_interp_to_end" getter="get_interp_to_end" default="0.0">
Causes all the particles in this node to interpolate towards the end of their lifetime.
[b]Note[/b]: This only works when used with a [ParticleProcessMaterial]. It needs to be manually implemented for custom process shaders.
</member>
<member name="interpolate" type="bool" setter="set_interpolate" getter="get_interpolate" default="true">
Enables particle interpolation, which makes the particle movement smoother when their [member fixed_fps] is lower than the screen refresh rate.
</member>

View File

@ -71,6 +71,9 @@
</method>
</methods>
<members>
<member name="alpha_curve" type="Texture2D" setter="set_alpha_curve" getter="get_alpha_curve">
The alpha value of each particle's color will be multiplied by this [CurveTexture] over its lifetime.
</member>
<member name="angle_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
Each particle's rotation will be animated along this [CurveTexture].
</member>
@ -151,6 +154,18 @@
<member name="direction" type="Vector3" setter="set_direction" getter="get_direction" default="Vector3(1, 0, 0)">
Unit vector specifying the particles' emission direction.
</member>
<member name="directional_velocity_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
A curve that specifies the velocity along each of the axes of the particle system along its lifetime.
[b]Note:[/b] Animated velocities will not be affected by damping, use [member velocity_limit_curve] instead.
</member>
<member name="directional_velocity_max" type="float" setter="set_param_max" getter="get_param_max">
Maximum directional velocity value, which is multiplied by [member directional_velocity_curve].
[b]Note:[/b] Animated velocities will not be affected by damping, use [member velocity_limit_curve] instead.
</member>
<member name="directional_velocity_min" type="float" setter="set_param_min" getter="get_param_min">
Minimum directional velocity value, which is multiplied by [member directional_velocity_curve].
[b]Note:[/b] Animated velocities will not be affected by damping, use [member velocity_limit_curve] instead.
</member>
<member name="emission_box_extents" type="Vector3" setter="set_emission_box_extents" getter="get_emission_box_extents">
The box's extents if [member emission_shape] is set to [constant EMISSION_SHAPE_BOX].
</member>
@ -158,6 +173,10 @@
Particle color will be modulated by color determined by sampling this texture at the same point as the [member emission_point_texture].
[b]Note:[/b] [member emission_color_texture] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member emission_color_texture] will have no visible effect.
</member>
<member name="emission_curve" type="Texture2D" setter="set_emission_curve" getter="get_emission_curve">
Each particle's color will be multiplied by this [CurveTexture] over its lifetime.
[b]Note:[/b] This property won't have a visible effect unless the render material is marked as unshaded.
</member>
<member name="emission_normal_texture" type="Texture2D" setter="set_emission_normal_texture" getter="get_emission_normal_texture">
Particle velocity and rotation will be set by sampling this texture at the same point as the [member emission_point_texture]. Used only in [constant EMISSION_SHAPE_DIRECTED_POINTS]. Can be created automatically from mesh or node by selecting "Create Emission Points from Mesh/Node" under the "Particles" tool in the toolbar.
</member>
@ -182,6 +201,12 @@
<member name="emission_shape" type="int" setter="set_emission_shape" getter="get_emission_shape" enum="ParticleProcessMaterial.EmissionShape" default="0">
Particles will be emitted inside this region. Use [enum EmissionShape] constants for values.
</member>
<member name="emission_shape_offset" type="Vector3" setter="set_emission_shape_offset" getter="get_emission_shape_offset" default="Vector3(0, 0, 0)">
The offset for the [member emission_shape], in local space.
</member>
<member name="emission_shape_scale" type="Vector3" setter="set_emission_shape_scale" getter="get_emission_shape_scale" default="Vector3(1, 1, 1)">
The scale of the [member emission_shape], in local space.
</member>
<member name="emission_sphere_radius" type="float" setter="set_emission_sphere_radius" getter="get_emission_sphere_radius">
The sphere's radius if [member emission_shape] is set to [constant EMISSION_SHAPE_SPHERE].
</member>
@ -200,6 +225,9 @@
<member name="hue_variation_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
Minimum equivalent of [member hue_variation_max].
</member>
<member name="inherit_velocity_ratio" type="float" setter="set_inherit_velocity_ratio" getter="get_inherit_velocity_ratio" default="0.0">
Percentage of the velocity of the respective [GPUParticles2D] or [GPUParticles3D] inherited by each particle when spawning.
</member>
<member name="initial_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
Maximum initial velocity magnitude for each particle. Direction comes from [member direction] and [member spread].
</member>
@ -220,17 +248,23 @@
</member>
<member name="orbit_velocity_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
Each particle's orbital velocity will vary along this [CurveTexture].
[b]Note:[/b] For 3D orbital velocity, use a [CurveXYZTexture].
[b]Note:[/b] Animated velocities will not be affected by damping, use [member velocity_limit_curve] instead.
</member>
<member name="orbit_velocity_max" type="float" setter="set_param_max" getter="get_param_max">
<member name="orbit_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
Maximum orbital velocity applied to each particle. Makes the particles circle around origin. Specified in number of full rotations around origin per second.
Only available when [member particle_flag_disable_z] is [code]true[/code].
[b]Note:[/b] Animated velocities will not be affected by damping, use [member velocity_limit_curve] instead.
</member>
<member name="orbit_velocity_min" type="float" setter="set_param_min" getter="get_param_min">
<member name="orbit_velocity_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
Minimum equivalent of [member orbit_velocity_max].
[b]Note:[/b] Animated velocities will not be affected by damping, use [member velocity_limit_curve] instead.
</member>
<member name="particle_flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false">
Align Y axis of particle with the direction of its velocity.
</member>
<member name="particle_flag_damping_as_friction" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false">
Changes the behavior of the damping properties from a linear deceleration to a deceleration based on speed percentage.
</member>
<member name="particle_flag_disable_z" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false">
If [code]true[/code], particles will not move on the z axis.
</member>
@ -246,6 +280,18 @@
<member name="radial_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
Minimum equivalent of [member radial_accel_max].
</member>
<member name="radial_velocity_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
A [CurveTexture] that defines the velocity over the particle's lifetime away (or toward) the [member velocity_pivot].
[b]Note:[/b] Animated velocities will not be affected by damping, use [member velocity_limit_curve] instead.
</member>
<member name="radial_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
Maximum radial velocity applied to each particle. Makes particles move away from the [member velocity_pivot], or toward it if negative.
[b]Note:[/b] Animated velocities will not be affected by damping, use [member velocity_limit_curve] instead.
</member>
<member name="radial_velocity_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
Minimum radial velocity applied to each particle. Makes particles move away from the [member velocity_pivot], or toward it if negative.
[b]Note:[/b] Animated velocities will not be affected by damping, use [member velocity_limit_curve] instead.
</member>
<member name="scale_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
Each particle's scale will vary along this [CurveTexture]. If a [CurveXYZTexture] is supplied instead, the scale will be separated per-axis.
</member>
@ -255,6 +301,17 @@
<member name="scale_min" type="float" setter="set_param_min" getter="get_param_min" default="1.0">
Minimum equivalent of [member scale_max].
</member>
<member name="scale_over_velocity_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
Either a [CurveTexture] or a [CurveXYZTexture] that scales each particle based on its velocity.
</member>
<member name="scale_over_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
Maximum velocity value reference for [member scale_over_velocity_curve].
[member scale_over_velocity_curve] will be interpolated between [member scale_over_velocity_min] and [member scale_over_velocity_max].
</member>
<member name="scale_over_velocity_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
Minimum velocity value reference for [member scale_over_velocity_curve].
[member scale_over_velocity_curve] will be interpolated between [member scale_over_velocity_min] and [member scale_over_velocity_max].
</member>
<member name="spread" type="float" setter="set_spread" getter="get_spread" default="45.0">
Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees.
</member>
@ -317,6 +374,11 @@
<member name="turbulence_noise_strength" type="float" setter="set_turbulence_noise_strength" getter="get_turbulence_noise_strength" default="1.0">
The turbulence noise strength. Increasing this will result in a stronger, more contrasting, flow pattern.
</member>
<member name="velocity_limit_curve" type="Texture2D" setter="set_velocity_limit_curve" getter="get_velocity_limit_curve">
A [CurveTexture] that defines the maximum velocity of a particle during its lifetime.
</member>
<member name="velocity_pivot" type="Vector3" setter="set_velocity_pivot" getter="get_velocity_pivot" default="Vector3(0, 0, 0)">
</member>
</members>
<constants>
<constant name="PARAM_INITIAL_LINEAR_VELOCITY" value="0" enum="Parameter">
@ -355,7 +417,16 @@
<constant name="PARAM_ANIM_OFFSET" value="11" enum="Parameter">
Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set animation offset properties.
</constant>
<constant name="PARAM_MAX" value="15" enum="Parameter">
<constant name="PARAM_RADIAL_VELOCITY" value="15" enum="Parameter">
Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set radial velocity properties.
</constant>
<constant name="PARAM_DIRECTIONAL_VELOCITY" value="16" enum="Parameter">
Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set directional velocity properties.
</constant>
<constant name="PARAM_SCALE_OVER_VELOCITY" value="17" enum="Parameter">
Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set scale over velocity properties.
</constant>
<constant name="PARAM_MAX" value="18" enum="Parameter">
Represents the size of the [enum Parameter] enum.
</constant>
<constant name="PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="ParticleFlags">
@ -367,7 +438,9 @@
<constant name="PARTICLE_FLAG_DISABLE_Z" value="2" enum="ParticleFlags">
Use with [method set_particle_flag] to set [member particle_flag_disable_z].
</constant>
<constant name="PARTICLE_FLAG_MAX" value="3" enum="ParticleFlags">
<constant name="PARTICLE_FLAG_DAMPING_AS_FRICTION" value="3" enum="ParticleFlags">
</constant>
<constant name="PARTICLE_FLAG_MAX" value="4" enum="ParticleFlags">
Represents the size of the [enum ParticleFlags] enum.
</constant>
<constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape">

View File

@ -2627,6 +2627,14 @@
Sets the number of particles to be drawn and allocates the memory for them. Equivalent to [member GPUParticles3D.amount].
</description>
</method>
<method name="particles_set_amount_ratio">
<return type="void" />
<param index="0" name="particles" type="RID" />
<param index="1" name="ratio" type="float" />
<description>
Sets the amount ratio for particles to be emitted. Equivalent to [member GPUParticles3D.amount_ratio].
</description>
</method>
<method name="particles_set_collision_base_size">
<return type="void" />
<param index="0" name="particles" type="RID" />
@ -2675,6 +2683,14 @@
Sets the [Transform3D] that will be used by the particles when they first emit.
</description>
</method>
<method name="particles_set_emitter_velocity">
<return type="void" />
<param index="0" name="particles" type="RID" />
<param index="1" name="velocity" type="Vector3" />
<description>
Sets the velocity of a particle node, that will be used by [member ParticleProcessMaterial.inherit_velocity_ratio].
</description>
</method>
<method name="particles_set_emitting">
<return type="void" />
<param index="0" name="particles" type="RID" />
@ -2707,6 +2723,14 @@
If [code]true[/code], uses fractional delta which smooths the movement of the particles. Equivalent to [member GPUParticles3D.fract_delta].
</description>
</method>
<method name="particles_set_interp_to_end">
<return type="void" />
<param index="0" name="particles" type="RID" />
<param index="1" name="factor" type="float" />
<description>
Sets the value that informs a [ParticleProcessMaterial] to rush all particles towards the end of their lifetime.
</description>
</method>
<method name="particles_set_interpolate">
<return type="void" />
<param index="0" name="particles" type="RID" />

View File

@ -78,7 +78,7 @@ layout(std140) uniform FrameData { //ubo:0
float delta;
float particle_size;
float pad0;
float amount_ratio;
float pad1;
float pad2;
@ -89,6 +89,9 @@ layout(std140) uniform FrameData { //ubo:0
mat4 emission_transform;
vec3 emitter_velocity;
float interp_to_end;
Attractor attractors[MAX_ATTRACTORS];
Collider colliders[MAX_COLLIDERS];
};

View File

@ -1395,6 +1395,7 @@ MaterialStorage::MaterialStorage() {
actions.renames["DELTA"] = "local_delta";
actions.renames["NUMBER"] = "particle_number";
actions.renames["INDEX"] = "index";
actions.renames["AMOUNT_RATIO"] = "amount_ratio";
//actions.renames["GRAVITY"] = "current_gravity";
actions.renames["EMISSION_TRANSFORM"] = "emission_transform";
actions.renames["RANDOM_SEED"] = "random_seed";
@ -1407,6 +1408,8 @@ MaterialStorage::MaterialStorage() {
actions.renames["COLLISION_NORMAL"] = "collision_normal";
actions.renames["COLLISION_DEPTH"] = "collision_depth";
actions.renames["ATTRACTOR_FORCE"] = "attractor_force";
actions.renames["EMITTER_VELOCITY"] = "emitter_velocity";
actions.renames["INTERPOLATE_TO_END"] = "interp_to_end";
// These are unsupported, but may be used by users. To avoid compile time overhead, we add the stub only when used.
actions.renames["FLAG_EMIT_POSITION"] = "uint(1)";

View File

@ -190,6 +190,13 @@ void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) {
particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
}
void ParticlesStorage::particles_set_amount_ratio(RID p_particles, float p_amount_ratio) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL(particles);
particles->amount_ratio = p_amount_ratio;
}
void ParticlesStorage::particles_set_lifetime(RID p_particles, double p_lifetime) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL(particles);
@ -431,6 +438,20 @@ void ParticlesStorage::particles_set_emission_transform(RID p_particles, const T
particles->emission_transform = p_transform;
}
void ParticlesStorage::particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL(particles);
particles->emitter_velocity = p_velocity;
}
void ParticlesStorage::particles_set_interp_to_end(RID p_particles, float p_interp) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL(particles);
particles->interp_to_end = p_interp;
}
int ParticlesStorage::particles_get_draw_passes(RID p_particles) const {
const Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL_V(particles, 0);
@ -507,9 +528,13 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
frame_params.cycle = p_particles->cycle_number;
frame_params.frame = p_particles->frame_counter++;
frame_params.pad0 = 0;
frame_params.amount_ratio = p_particles->amount_ratio;
frame_params.pad1 = 0;
frame_params.pad2 = 0;
frame_params.interp_to_end = p_particles->interp_to_end;
frame_params.emitter_velocity[0] = p_particles->emitter_velocity.x;
frame_params.emitter_velocity[1] = p_particles->emitter_velocity.y;
frame_params.emitter_velocity[2] = p_particles->emitter_velocity.z;
{ //collision and attractors

View File

@ -128,7 +128,7 @@ private:
float delta;
float particle_size;
float pad0;
float amount_ratio;
float pad1;
float pad2;
@ -138,6 +138,8 @@ private:
uint32_t frame;
float emission_transform[16];
float emitter_velocity[3];
float interp_to_end;
Attractor attractors[MAX_ATTRACTORS];
Collider colliders[MAX_COLLIDERS];
@ -149,6 +151,7 @@ private:
double inactive_time = 0.0;
bool emitting = false;
bool one_shot = false;
float amount_ratio = 1.0;
int amount = 0;
double lifetime = 1.0;
double pre_process_time = 0.0;
@ -229,6 +232,8 @@ private:
bool clear = true;
Transform3D emission_transform;
Vector3 emitter_velocity;
float interp_to_end;
HashSet<RID> collisions;
@ -313,6 +318,7 @@ public:
virtual void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override;
virtual void particles_set_emitting(RID p_particles, bool p_emitting) override;
virtual void particles_set_amount(RID p_particles, int p_amount) override;
virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) override;
virtual void particles_set_lifetime(RID p_particles, double p_lifetime) override;
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) override;
virtual void particles_set_pre_process_time(RID p_particles, double p_time) override;
@ -347,6 +353,8 @@ public:
virtual AABB particles_get_aabb(RID p_particles) const override;
virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override;
virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) override;
virtual void particles_set_interp_to_end(RID p_particles, float p_interp) override;
virtual bool particles_get_emitting(RID p_particles) override;
virtual int particles_get_draw_passes(RID p_particles) const override;

View File

@ -287,3 +287,9 @@ Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/shader_ge
Validate extension JSON: Error: Field 'classes/SurfaceTool/methods/commit/arguments/1': meta changed value in new API, from "uint32" to "uint64".
Surface format was increased to 64 bits from 32 bits. Compatibility methods registered.
GH-79527
--------
Validate extension JSON: Error: Field 'classes/ParticleProcessMaterial/properties/orbit_velocity_curve': type changed value in new API, from "CurveTexture" to "CurveTexture,CurveXYZTexture".
Added accepted curve type from only CurveTexture to CurveXYZTexture.

View File

@ -192,6 +192,11 @@ void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) {
queue_redraw();
}
void GPUParticles2D::set_interp_to_end(float p_interp) {
interp_to_end_factor = CLAMP(p_interp, 0.0, 1.0);
RS::get_singleton()->particles_set_interp_to_end(particles, interp_to_end_factor);
}
#ifdef TOOLS_ENABLED
void GPUParticles2D::set_show_visibility_rect(bool p_show_visibility_rect) {
show_visibility_rect = p_show_visibility_rect;
@ -318,6 +323,10 @@ bool GPUParticles2D::get_interpolate() const {
return interpolate;
}
float GPUParticles2D::get_interp_to_end() const {
return interp_to_end_factor;
}
PackedStringArray GPUParticles2D::get_configuration_warnings() const {
PackedStringArray warnings = Node2D::get_configuration_warnings();
@ -423,6 +432,15 @@ NodePath GPUParticles2D::get_sub_emitter() const {
return sub_emitter;
}
void GPUParticles2D::set_amount_ratio(float p_ratio) {
amount_ratio = p_ratio;
RenderingServer::get_singleton()->particles_set_amount_ratio(particles, p_ratio);
}
float GPUParticles2D::get_amount_ratio() const {
return amount_ratio;
}
void GPUParticles2D::restart() {
RS::get_singleton()->particles_restart(particles);
RS::get_singleton()->particles_set_emitting(particles, true);
@ -670,6 +688,8 @@ void GPUParticles2D::_notification(int p_what) {
} else {
RS::get_singleton()->particles_set_speed_scale(particles, 0);
}
set_process_internal(true);
previous_position = get_global_position();
} break;
case NOTIFICATION_EXIT_TREE: {
@ -692,6 +712,12 @@ void GPUParticles2D::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
RS::get_singleton()->particles_set_emitter_velocity(particles,
Vector3((get_global_position() - previous_position).x,
(get_global_position() - previous_position).y,
0.0) /
get_process_delta_time());
previous_position = get_global_position();
if (one_shot) {
time += get_process_delta_time();
if (time > emission_time) {
@ -730,6 +756,7 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles2D::set_process_material);
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles2D::set_speed_scale);
ClassDB::bind_method(D_METHOD("set_collision_base_size", "size"), &GPUParticles2D::set_collision_base_size);
ClassDB::bind_method(D_METHOD("set_interp_to_end", "interp"), &GPUParticles2D::set_interp_to_end);
ClassDB::bind_method(D_METHOD("is_emitting"), &GPUParticles2D::is_emitting);
ClassDB::bind_method(D_METHOD("get_amount"), &GPUParticles2D::get_amount);
@ -746,6 +773,7 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles2D::get_process_material);
ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles2D::get_speed_scale);
ClassDB::bind_method(D_METHOD("get_collision_base_size"), &GPUParticles2D::get_collision_base_size);
ClassDB::bind_method(D_METHOD("get_interp_to_end"), &GPUParticles2D::get_interp_to_end);
ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &GPUParticles2D::set_draw_order);
ClassDB::bind_method(D_METHOD("get_draw_order"), &GPUParticles2D::get_draw_order);
@ -776,11 +804,15 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &GPUParticles2D::convert_from_particles);
ClassDB::bind_method(D_METHOD("set_amount_ratio", "ratio"), &GPUParticles2D::set_amount_ratio);
ClassDB::bind_method(D_METHOD("get_amount_ratio"), &GPUParticles2D::get_amount_ratio);
ADD_SIGNAL(MethodInfo("finished"));
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false.
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amount_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001"), "set_amount_ratio", "get_amount_ratio");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles2D"), "set_sub_emitter", "get_sub_emitter");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticleProcessMaterial"), "set_process_material", "get_process_material");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
@ -794,6 +826,7 @@ void GPUParticles2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1,suffix:FPS"), "set_fixed_fps", "get_fixed_fps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interpolate"), "set_interpolate", "get_interpolate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "interp_to_end", PROPERTY_HINT_RANGE, "0.00,1.0,0.001"), "set_interp_to_end", "get_interp_to_end");
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_collision_base_size", "get_collision_base_size");
ADD_GROUP("Drawing", "");
@ -829,6 +862,7 @@ GPUParticles2D::GPUParticles2D() {
set_emitting(true);
set_one_shot(false);
set_amount(8);
set_amount_ratio(1.0);
set_lifetime(1);
set_fixed_fps(0);
set_fractional_delta(true);

View File

@ -52,6 +52,7 @@ private:
bool signal_canceled = false;
bool one_shot = false;
int amount = 0;
float amount_ratio = 1.0;
double lifetime = 0.0;
double pre_process_time = 0.0;
real_t explosiveness_ratio = 0.0;
@ -62,6 +63,8 @@ private:
int fixed_fps = 0;
bool fractional_delta = false;
bool interpolate = true;
float interp_to_end_factor = 0;
Vector2 previous_position;
#ifdef TOOLS_ENABLED
bool show_visibility_rect = false;
#endif
@ -114,6 +117,7 @@ public:
void set_trail_lifetime(double p_seconds);
void set_trail_sections(int p_sections);
void set_trail_section_subdivisions(int p_subdivisions);
void set_interp_to_end(float p_interp);
#ifdef TOOLS_ENABLED
void set_show_visibility_rect(bool p_show_visibility_rect);
@ -136,6 +140,7 @@ public:
double get_trail_lifetime() const;
int get_trail_sections() const;
int get_trail_section_subdivisions() const;
float get_interp_to_end() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
@ -152,6 +157,9 @@ public:
void set_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture() const;
void set_amount_ratio(float p_ratio);
float get_amount_ratio() const;
PackedStringArray get_configuration_warnings() const override;
void set_sub_emitter(const NodePath &p_path);

View File

@ -61,6 +61,8 @@ void GPUParticles3D::set_emitting(bool p_emitting) {
} else {
set_process_internal(false);
}
} else {
set_process_internal(true);
}
emitting = p_emitting;
@ -79,20 +81,20 @@ void GPUParticles3D::set_lifetime(double p_lifetime) {
RS::get_singleton()->particles_set_lifetime(particles, lifetime);
}
void GPUParticles3D::set_interp_to_end(float p_interp) {
interp_to_end_factor = CLAMP(p_interp, 0.0, 1.0);
RS::get_singleton()->particles_set_interp_to_end(particles, interp_to_end_factor);
}
void GPUParticles3D::set_one_shot(bool p_one_shot) {
one_shot = p_one_shot;
RS::get_singleton()->particles_set_one_shot(particles, one_shot);
if (is_emitting()) {
set_process_internal(true);
if (!one_shot) {
RenderingServer::get_singleton()->particles_restart(particles);
}
}
if (!one_shot) {
set_process_internal(false);
}
}
void GPUParticles3D::set_pre_process_time(double p_time) {
@ -154,6 +156,10 @@ double GPUParticles3D::get_lifetime() const {
return lifetime;
}
float GPUParticles3D::get_interp_to_end() const {
return interp_to_end_factor;
}
bool GPUParticles3D::get_one_shot() const {
return one_shot;
}
@ -401,9 +407,7 @@ void GPUParticles3D::restart() {
time = 0;
emission_time = lifetime * (1 - explosiveness_ratio);
active_time = lifetime * (2 - explosiveness_ratio);
if (one_shot) {
set_process_internal(true);
}
set_process_internal(true);
}
AABB GPUParticles3D::capture_aabb() const {
@ -456,6 +460,9 @@ void GPUParticles3D::_notification(int p_what) {
// Use internal process when emitting and one_shot is on so that when
// the shot ends the editor can properly update.
case NOTIFICATION_INTERNAL_PROCESS: {
RS::get_singleton()->particles_set_emitter_velocity(particles, (get_global_position() - previous_position) / get_process_delta_time());
previous_position = get_global_position();
if (one_shot) {
time += get_process_delta_time();
if (time > emission_time) {
@ -477,6 +484,7 @@ void GPUParticles3D::_notification(int p_what) {
} break;
case NOTIFICATION_ENTER_TREE: {
set_process_internal(false);
if (sub_emitter != NodePath()) {
_attach_sub_emitter();
}
@ -485,6 +493,8 @@ void GPUParticles3D::_notification(int p_what) {
} else {
RS::get_singleton()->particles_set_speed_scale(particles, 0);
}
previous_position = get_global_transform().origin;
set_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
@ -641,6 +651,15 @@ void GPUParticles3D::convert_from_particles(Node *p_particles) {
#undef CONVERT_PARAM
}
void GPUParticles3D::set_amount_ratio(float p_ratio) {
amount_ratio = p_ratio;
RS::get_singleton()->particles_set_amount_ratio(particles, p_ratio);
}
float GPUParticles3D::get_amount_ratio() const {
return amount_ratio;
}
void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &GPUParticles3D::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &GPUParticles3D::set_amount);
@ -657,6 +676,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles3D::set_process_material);
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles3D::set_speed_scale);
ClassDB::bind_method(D_METHOD("set_collision_base_size", "size"), &GPUParticles3D::set_collision_base_size);
ClassDB::bind_method(D_METHOD("set_interp_to_end", "interp"), &GPUParticles3D::set_interp_to_end);
ClassDB::bind_method(D_METHOD("is_emitting"), &GPUParticles3D::is_emitting);
ClassDB::bind_method(D_METHOD("get_amount"), &GPUParticles3D::get_amount);
@ -673,6 +693,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles3D::get_process_material);
ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles3D::get_speed_scale);
ClassDB::bind_method(D_METHOD("get_collision_base_size"), &GPUParticles3D::get_collision_base_size);
ClassDB::bind_method(D_METHOD("get_interp_to_end"), &GPUParticles3D::get_interp_to_end);
ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &GPUParticles3D::set_draw_order);
@ -706,14 +727,19 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &GPUParticles3D::convert_from_particles);
ClassDB::bind_method(D_METHOD("set_amount_ratio", "ratio"), &GPUParticles3D::set_amount_ratio);
ClassDB::bind_method(D_METHOD("get_amount_ratio"), &GPUParticles3D::get_amount_ratio);
ADD_SIGNAL(MethodInfo("finished"));
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false.
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amount_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001"), "set_amount_ratio", "get_amount_ratio");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles3D"), "set_sub_emitter", "get_sub_emitter");
ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp,suffix:s"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "interp_to_end", PROPERTY_HINT_RANGE, "0.00,1.0,0.01"), "set_interp_to_end", "get_interp_to_end");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01,exp,suffix:s"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
@ -767,6 +793,7 @@ GPUParticles3D::GPUParticles3D() {
one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
set_emitting(true);
set_one_shot(false);
set_amount_ratio(1.0);
set_amount(8);
set_lifetime(1);
set_fixed_fps(30);

View File

@ -65,6 +65,7 @@ private:
bool signal_canceled = false;
bool one_shot = false;
int amount = 0;
float amount_ratio = 1.0;
double lifetime = 0.0;
double pre_process_time = 0.0;
real_t explosiveness_ratio = 0.0;
@ -93,6 +94,8 @@ private:
double time = 0.0;
double emission_time = 0.0;
double active_time = 0.0;
float interp_to_end_factor = 0;
Vector3 previous_position;
void _attach_sub_emitter();
@ -120,9 +123,11 @@ public:
void set_collision_base_size(real_t p_ratio);
void set_trail_enabled(bool p_enabled);
void set_trail_lifetime(double p_seconds);
void set_interp_to_end(float p_interp);
bool is_emitting() const;
int get_amount() const;
double get_lifetime() const;
bool get_one_shot() const;
double get_pre_process_time() const;
@ -135,6 +140,10 @@ public:
real_t get_collision_base_size() const;
bool is_trail_enabled() const;
double get_trail_lifetime() const;
float get_interp_to_end() const;
void set_amount_ratio(float p_ratio);
float get_amount_ratio() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@
#define PARTICLE_PROCESS_MATERIAL_H
#include "core/templates/rid.h"
#include "core/templates/self_list.h"
#include "scene/resources/material.h"
/*
@ -61,6 +62,9 @@ public:
PARAM_TURB_INFLUENCE_OVER_LIFE,
PARAM_TURB_VEL_INFLUENCE,
PARAM_TURB_INIT_DISPLACEMENT,
PARAM_RADIAL_VELOCITY,
PARAM_DIRECTIONAL_VELOCITY,
PARAM_SCALE_OVER_VELOCITY,
PARAM_MAX
};
@ -69,6 +73,7 @@ public:
PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY,
PARTICLE_FLAG_ROTATE_Y,
PARTICLE_FLAG_DISABLE_Z,
PARTICLE_FLAG_DAMPING_AS_FRICTION,
PARTICLE_FLAG_MAX
};
@ -102,35 +107,37 @@ public:
};
private:
union MaterialKey {
// The bit size of the struct must be kept below or equal to 32 bits.
struct MaterialKey {
// The bit size of the struct must be kept below or equal to 64 bits.
// Consider this when extending ParticleFlags, EmissionShape, or SubEmitterMode.
struct {
uint32_t texture_mask : 16;
uint32_t texture_color : 1;
uint32_t particle_flags : 4;
uint32_t emission_shape : 3;
uint32_t invalid_key : 1;
uint32_t has_emission_color : 1;
uint32_t sub_emitter : 2;
uint32_t attractor_enabled : 1;
uint32_t collision_mode : 2;
uint32_t collision_scale : 1;
uint32_t turbulence_enabled : 1;
};
uint64_t texture_mask : PARAM_MAX;
uint64_t texture_color : 1;
uint64_t particle_flags : PARTICLE_FLAG_MAX - 1;
uint64_t emission_shape : 3;
uint64_t invalid_key : 1;
uint64_t has_emission_color : 1;
uint64_t sub_emitter : 2;
uint64_t attractor_enabled : 1;
uint64_t collision_mode : 2;
uint64_t collision_scale : 1;
uint64_t turbulence_enabled : 1;
uint64_t limiter_curve : 1;
uint64_t alpha_curve : 1;
uint64_t emission_curve : 1;
uint64_t has_initial_ramp : 1;
uint64_t key = 0;
MaterialKey() {
memset(this, 0, sizeof(MaterialKey));
}
static uint32_t hash(const MaterialKey &p_key) {
return hash_murmur3_one_32(p_key.key);
return hash_djb2_buffer((const uint8_t *)&p_key, sizeof(MaterialKey));
}
bool operator==(const MaterialKey &p_key) const {
return key == p_key.key;
return memcmp(this, &p_key, sizeof(MaterialKey)) == 0;
}
bool operator<(const MaterialKey &p_key) const {
return key < p_key.key;
return memcmp(this, &p_key, sizeof(MaterialKey)) < 0;
}
};
@ -145,17 +152,6 @@ private:
_FORCE_INLINE_ MaterialKey _compute_key() const {
MaterialKey mk;
mk.key = 0;
for (int i = 0; i < PARAM_MAX; i++) {
if (tex_parameters[i].is_valid()) {
mk.texture_mask |= (1 << i);
}
}
for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
if (particle_flags[i]) {
mk.particle_flags |= (1 << i);
}
}
mk.texture_color = color_ramp.is_valid() ? 1 : 0;
mk.emission_shape = emission_shape;
@ -165,6 +161,21 @@ private:
mk.attractor_enabled = attractor_interaction_enabled;
mk.collision_scale = collision_scale;
mk.turbulence_enabled = turbulence_enabled;
mk.limiter_curve = velocity_limit_curve.is_valid() ? 1 : 0;
mk.alpha_curve = alpha_curve.is_valid() ? 1 : 0;
mk.emission_curve = emission_curve.is_valid() ? 1 : 0;
mk.has_initial_ramp = color_initial_ramp.is_valid() ? 1 : 0;
for (int i = 0; i < PARAM_MAX; i++) {
if (tex_parameters[i].is_valid()) {
mk.texture_mask |= ((uint64_t)1 << i);
}
}
for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
if (particle_flags[i]) {
mk.particle_flags |= ((uint64_t)1 << i);
}
}
return mk;
}
@ -180,44 +191,59 @@ private:
StringName initial_angle_min;
StringName angular_velocity_min;
StringName orbit_velocity_min;
StringName radial_velocity_min;
StringName linear_accel_min;
StringName radial_accel_min;
StringName tangent_accel_min;
StringName damping_min;
StringName scale_min;
StringName scale_over_velocity_min;
StringName hue_variation_min;
StringName anim_speed_min;
StringName anim_offset_min;
StringName directional_velocity_min;
StringName initial_linear_velocity_max;
StringName initial_angle_max;
StringName angular_velocity_max;
StringName orbit_velocity_max;
StringName radial_velocity_max;
StringName linear_accel_max;
StringName radial_accel_max;
StringName tangent_accel_max;
StringName damping_max;
StringName scale_max;
StringName scale_over_velocity_max;
StringName hue_variation_max;
StringName anim_speed_max;
StringName anim_offset_max;
StringName directional_velocity_max;
StringName angle_texture;
StringName angular_velocity_texture;
StringName orbit_velocity_texture;
StringName radial_velocity_texture;
StringName linear_accel_texture;
StringName radial_accel_texture;
StringName tangent_accel_texture;
StringName damping_texture;
StringName scale_texture;
StringName scale_over_velocity_texture;
StringName hue_variation_texture;
StringName anim_speed_texture;
StringName anim_offset_texture;
StringName velocity_limiter_texture;
StringName directional_velocity_texture;
StringName color;
StringName color_ramp;
StringName alpha_ramp;
StringName emission_ramp;
StringName color_initial_ramp;
StringName velocity_limit_curve;
StringName velocity_pivot;
StringName emission_sphere_radius;
StringName emission_box_extents;
StringName emission_texture_point_count;
@ -228,6 +254,8 @@ private:
StringName emission_ring_height;
StringName emission_ring_radius;
StringName emission_ring_inner_radius;
StringName emission_shape_offset;
StringName emission_shape_scale;
StringName turbulence_enabled;
StringName turbulence_noise_strength;
@ -241,6 +269,7 @@ private:
StringName turbulence_initial_displacement_max;
StringName gravity;
StringName inherit_emitter_velocity_ratio;
StringName lifetime_randomness;
@ -272,7 +301,13 @@ private:
Ref<Texture2D> tex_parameters[PARAM_MAX];
Color color;
Ref<Texture2D> color_ramp;
Ref<Texture2D> alpha_curve;
Ref<Texture2D> emission_curve;
Ref<Texture2D> color_initial_ramp;
Ref<Texture2D> velocity_limit_curve;
bool directional_velocity_global = false;
Vector3 velocity_pivot;
bool particle_flags[PARTICLE_FLAG_MAX];
@ -287,6 +322,8 @@ private:
real_t emission_ring_radius = 0.0f;
real_t emission_ring_inner_radius = 0.0f;
int emission_point_count = 1;
Vector3 emission_shape_offset;
Vector3 emission_shape_scale;
bool anim_loop = false;
@ -300,6 +337,7 @@ private:
Vector3 gravity;
double lifetime_randomness = 0.0;
double inherit_emitter_velocity_ratio = 0.0;
SubEmitterMode sub_emitter_mode;
double sub_emitter_frequency = 0.0;
@ -328,6 +366,9 @@ public:
void set_flatness(float p_flatness);
float get_flatness() const;
void set_velocity_pivot(const Vector3 &p_pivot);
Vector3 get_velocity_pivot();
void set_param_min(Parameter p_param, float p_value);
float get_param_min(Parameter p_param) const;
@ -337,6 +378,11 @@ public:
void set_param_texture(Parameter p_param, const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_param_texture(Parameter p_param) const;
void set_velocity_limit_curve(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_velocity_limit_curve() const;
void set_alpha_curve(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_alpha_curve() const;
void set_color(const Color &p_color);
Color get_color() const;
@ -346,6 +392,9 @@ public:
void set_color_initial_ramp(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_color_initial_ramp() const;
void set_emission_curve(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_emission_curve() const;
void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable);
bool get_particle_flag(ParticleFlags p_particle_flag) const;
@ -391,6 +440,9 @@ public:
void set_lifetime_randomness(double p_lifetime);
double get_lifetime_randomness() const;
void set_inherit_velocity_ratio(double p_ratio);
double get_inherit_velocity_ratio();
void set_attractor_interaction_enabled(bool p_enable);
bool is_attractor_interaction_enabled() const;
@ -425,6 +477,12 @@ public:
void set_sub_emitter_keep_velocity(bool p_enable);
bool get_sub_emitter_keep_velocity() const;
void set_emission_shape_offset(const Vector3 &p_emission_shape_offset);
Vector3 get_emission_shape_offset() const;
void set_emission_shape_scale(const Vector3 &p_emission_shape_scale);
Vector3 get_emission_shape_scale() const;
virtual RID get_shader_rid() const override;
virtual Shader::Mode get_shader_mode() const override;

View File

@ -47,6 +47,7 @@ public:
virtual void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override {}
virtual void particles_set_emitting(RID p_particles, bool p_emitting) override {}
virtual void particles_set_amount(RID p_particles, int p_amount) override {}
virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) override {}
virtual void particles_set_lifetime(RID p_particles, double p_lifetime) override {}
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) override {}
virtual void particles_set_pre_process_time(RID p_particles, double p_time) override {}
@ -81,6 +82,8 @@ public:
virtual AABB particles_get_aabb(RID p_particles) const override { return AABB(); }
virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override {}
virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) override {}
virtual void particles_set_interp_to_end(RID p_particles, float p_interp) override {}
virtual bool particles_get_emitting(RID p_particles) override { return false; }
virtual int particles_get_draw_passes(RID p_particles) const override { return 0; }

View File

@ -67,7 +67,7 @@ struct FrameParams {
float delta;
uint frame;
uint pad0;
float amount_ratio;
uint pad1;
uint pad2;
@ -77,6 +77,8 @@ struct FrameParams {
float particle_size;
mat4 emission_transform;
vec3 emitter_velocity;
float interp_to_end;
Attractor attractors[MAX_ATTRACTORS];
Collider colliders[MAX_COLLIDERS];

View File

@ -72,6 +72,7 @@ ParticlesStorage::ParticlesStorage() {
actions.renames["ACTIVE"] = "particle_active";
actions.renames["RESTART"] = "restart";
actions.renames["CUSTOM"] = "PARTICLE.custom";
actions.renames["AMOUNT_RATIO"] = "FRAME.amount_ratio";
for (int i = 0; i < ParticlesShader::MAX_USERDATAS; i++) {
String udname = "USERDATA" + itos(i + 1);
actions.renames[udname] = "PARTICLE.userdata" + itos(i + 1);
@ -88,6 +89,8 @@ ParticlesStorage::ParticlesStorage() {
actions.renames["INDEX"] = "index";
//actions.renames["GRAVITY"] = "current_gravity";
actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform";
actions.renames["EMITTER_VELOCITY"] = "FRAME.emitter_velocity";
actions.renames["INTERPOLATE_TO_END"] = "FRAME.interp_to_end";
actions.renames["RANDOM_SEED"] = "FRAME.random_seed";
actions.renames["FLAG_EMIT_POSITION"] = "EMISSION_FLAG_HAS_POSITION";
actions.renames["FLAG_EMIT_ROT_SCALE"] = "EMISSION_FLAG_HAS_ROTATION_SCALE";
@ -329,6 +332,13 @@ void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) {
particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
}
void ParticlesStorage::particles_set_amount_ratio(RID p_particles, float p_amount_ratio) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL(particles);
particles->amount_ratio = p_amount_ratio;
}
void ParticlesStorage::particles_set_lifetime(RID p_particles, double p_lifetime) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL(particles);
@ -651,6 +661,20 @@ void ParticlesStorage::particles_set_emission_transform(RID p_particles, const T
particles->emission_transform = p_transform;
}
void ParticlesStorage::particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL(particles);
particles->emitter_velocity = p_velocity;
}
void ParticlesStorage::particles_set_interp_to_end(RID p_particles, float p_interp) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL(particles);
particles->interp_to_end = p_interp;
}
int ParticlesStorage::particles_get_draw_passes(RID p_particles) const {
const Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL_V(particles, 0);
@ -791,9 +815,13 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
frame_params.cycle = p_particles->cycle_number;
frame_params.frame = p_particles->frame_counter++;
frame_params.pad0 = 0;
frame_params.amount_ratio = p_particles->amount_ratio;
frame_params.pad1 = 0;
frame_params.pad2 = 0;
frame_params.emitter_velocity[0] = p_particles->emitter_velocity.x;
frame_params.emitter_velocity[1] = p_particles->emitter_velocity.y;
frame_params.emitter_velocity[2] = p_particles->emitter_velocity.z;
frame_params.interp_to_end = p_particles->interp_to_end;
{ //collision and attractors

View File

@ -123,7 +123,7 @@ private:
float delta;
uint32_t frame;
uint32_t pad0;
float amount_ratio;
uint32_t pad1;
uint32_t pad2;
@ -134,6 +134,9 @@ private:
float emission_transform[16];
float emitter_velocity[3];
float interp_to_end;
Attractor attractors[MAX_ATTRACTORS];
Collider colliders[MAX_COLLIDERS];
};
@ -235,6 +238,9 @@ private:
bool force_sub_emit = false;
Transform3D emission_transform;
Vector3 emitter_velocity;
float interp_to_end = 0.0;
float amount_ratio = 1.0;
Vector<uint8_t> emission_buffer_data;
@ -425,6 +431,7 @@ public:
virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override;
virtual void particles_set_emitting(RID p_particles, bool p_emitting) override;
virtual void particles_set_amount(RID p_particles, int p_amount) override;
virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) override;
virtual void particles_set_lifetime(RID p_particles, double p_lifetime) override;
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) override;
virtual void particles_set_pre_process_time(RID p_particles, double p_time) override;
@ -460,6 +467,8 @@ public:
virtual AABB particles_get_aabb(RID p_particles) const override;
virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override;
virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) override;
virtual void particles_set_interp_to_end(RID p_particles, float p_interp_to_end) override;
virtual bool particles_get_emitting(RID p_particles) override;
virtual int particles_get_draw_passes(RID p_particles) const override;

View File

@ -490,6 +490,7 @@ public:
FUNC2(particles_set_emitting, RID, bool)
FUNC1R(bool, particles_get_emitting, RID)
FUNC2(particles_set_amount, RID, int)
FUNC2(particles_set_amount_ratio, RID, float)
FUNC2(particles_set_lifetime, RID, double)
FUNC2(particles_set_one_shot, RID, bool)
FUNC2(particles_set_pre_process_time, RID, double)
@ -521,6 +522,8 @@ public:
FUNC1R(AABB, particles_get_current_aabb, RID)
FUNC2(particles_set_emission_transform, RID, const Transform3D &)
FUNC2(particles_set_emitter_velocity, RID, const Vector3 &)
FUNC2(particles_set_interp_to_end, RID, float)
/* PARTICLES COLLISION */

View File

@ -348,6 +348,8 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMITTER_VELOCITY"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INTERPOLATE_TO_END"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
@ -359,6 +361,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_COLOR"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_CUSTOM"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["AMOUNT_RATIO"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_PARTICLES].functions["start"].main_function = true;
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
@ -379,6 +382,8 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["EMITTER_VELOCITY"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INTERPOLATE_TO_END"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
@ -389,6 +394,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_DEPTH"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["ATTRACTOR_FORCE"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["AMOUNT_RATIO"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_PARTICLES].functions["process"].main_function = true;
{

View File

@ -49,6 +49,7 @@ public:
virtual bool particles_get_emitting(RID p_particles) = 0;
virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) = 0;
virtual void particles_set_lifetime(RID p_particles, double p_lifetime) = 0;
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
virtual void particles_set_pre_process_time(RID p_particles, double p_time) = 0;
@ -85,6 +86,8 @@ public:
virtual AABB particles_get_aabb(RID p_particles) const = 0;
virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) = 0;
virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) = 0;
virtual void particles_set_interp_to_end(RID p_particles, float p_interp_to_end) = 0;
virtual int particles_get_draw_passes(RID p_particles) const = 0;
virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0;

View File

@ -2497,11 +2497,14 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &RenderingServer::particles_set_emitting);
ClassDB::bind_method(D_METHOD("particles_get_emitting", "particles"), &RenderingServer::particles_get_emitting);
ClassDB::bind_method(D_METHOD("particles_set_amount", "particles", "amount"), &RenderingServer::particles_set_amount);
ClassDB::bind_method(D_METHOD("particles_set_amount_ratio", "particles", "ratio"), &RenderingServer::particles_set_amount_ratio);
ClassDB::bind_method(D_METHOD("particles_set_lifetime", "particles", "lifetime"), &RenderingServer::particles_set_lifetime);
ClassDB::bind_method(D_METHOD("particles_set_one_shot", "particles", "one_shot"), &RenderingServer::particles_set_one_shot);
ClassDB::bind_method(D_METHOD("particles_set_pre_process_time", "particles", "time"), &RenderingServer::particles_set_pre_process_time);
ClassDB::bind_method(D_METHOD("particles_set_explosiveness_ratio", "particles", "ratio"), &RenderingServer::particles_set_explosiveness_ratio);
ClassDB::bind_method(D_METHOD("particles_set_randomness_ratio", "particles", "ratio"), &RenderingServer::particles_set_randomness_ratio);
ClassDB::bind_method(D_METHOD("particles_set_interp_to_end", "particles", "factor"), &RenderingServer::particles_set_interp_to_end);
ClassDB::bind_method(D_METHOD("particles_set_emitter_velocity", "particles", "velocity"), &RenderingServer::particles_set_emitter_velocity);
ClassDB::bind_method(D_METHOD("particles_set_custom_aabb", "particles", "aabb"), &RenderingServer::particles_set_custom_aabb);
ClassDB::bind_method(D_METHOD("particles_set_speed_scale", "particles", "scale"), &RenderingServer::particles_set_speed_scale);
ClassDB::bind_method(D_METHOD("particles_set_use_local_coordinates", "particles", "enable"), &RenderingServer::particles_set_use_local_coordinates);

View File

@ -660,6 +660,7 @@ public:
virtual void particles_set_emitting(RID p_particles, bool p_enable) = 0;
virtual bool particles_get_emitting(RID p_particles) = 0;
virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) = 0;
virtual void particles_set_lifetime(RID p_particles, double p_lifetime) = 0;
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
virtual void particles_set_pre_process_time(RID p_particles, double p_time) = 0;
@ -717,6 +718,8 @@ public:
virtual AABB particles_get_current_aabb(RID p_particles) = 0;
virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) = 0; // This is only used for 2D, in 3D it's automatic.
virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) = 0;
virtual void particles_set_interp_to_end(RID p_particles, float p_interp) = 0;
/* PARTICLES COLLISION API */