2
0
Эх сурвалжийг харах

Merge pull request #61238 from Calinou/particlesmaterial-add-fade-on-contact-collision-mode

Add "Hide on Contact" collision mode to ParticlesMaterial
Rémi Verschelde 3 жил өмнө
parent
commit
56752e32a6

+ 2 - 2
doc/classes/GPUParticlesCollision3D.xml

@@ -7,7 +7,7 @@
 		Particle collision shapes can be used to make particles stop or bounce against them.
 		Particle collision shapes can be used to make particles stop or bounce against them.
 		Particle collision shapes in real-time and can be moved, rotated and scaled during gameplay. Unlike attractors, non-uniform scaling of collision shapes is [i]not[/i] supported.
 		Particle collision shapes in real-time and can be moved, rotated and scaled during gameplay. Unlike attractors, non-uniform scaling of collision shapes is [i]not[/i] supported.
 		Particle collision shapes can be temporarily disabled by hiding them.
 		Particle collision shapes can be temporarily disabled by hiding them.
-		[b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work.
+		[b]Note:[/b] [member ParticlesMaterial.collision_mode] must be [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work.
 		[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
 		[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
 		[b]Note:[/b] Particles pushed by a collider that is being moved will not be interpolated, which can result in visible stuttering. This can be alleviated by setting [member GPUParticles3D.fixed_fps] to [code]0[/code] or a value that matches or exceeds the target framerate.
 		[b]Note:[/b] Particles pushed by a collider that is being moved will not be interpolated, which can result in visible stuttering. This can be alleviated by setting [member GPUParticles3D.fixed_fps] to [code]0[/code] or a value that matches or exceeds the target framerate.
 	</description>
 	</description>
@@ -15,7 +15,7 @@
 	</tutorials>
 	</tutorials>
 	<members>
 	<members>
 		<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="4294967295">
 		<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="4294967295">
-			The particle rendering layers ([member VisualInstance3D.layers]) that will be affected by the collision shape. By default, all particles that have [member ParticlesMaterial.collision_enabled] set to [code]true[/code] will be affected by a collision shape.
+			The particle rendering layers ([member VisualInstance3D.layers]) that will be affected by the collision shape. By default, all particles that have [member ParticlesMaterial.collision_mode] set to [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] will be affected by a collision shape.
 			After configuring particle nodes accordingly, specific layers can be unchecked to prevent certain particles from being affected by attractors. For example, this can be used if you're using an attractor as part of a spell effect but don't want the attractor to affect unrelated weather particles at the same position.
 			After configuring particle nodes accordingly, specific layers can be unchecked to prevent certain particles from being affected by attractors. For example, this can be used if you're using an attractor as part of a spell effect but don't want the attractor to affect unrelated weather particles at the same position.
 			Particle attraction can also be disabled on a per-process material basis by setting [member ParticlesMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node.
 			Particle attraction can also be disabled on a per-process material basis by setting [member ParticlesMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node.
 		</member>
 		</member>

+ 1 - 1
doc/classes/GPUParticlesCollisionBox3D.xml

@@ -5,7 +5,7 @@
 	</brief_description>
 	</brief_description>
 	<description>
 	<description>
 		Box-shaped 3D particle collision shape affecting [GPUParticles3D] nodes.
 		Box-shaped 3D particle collision shape affecting [GPUParticles3D] nodes.
-		[b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work.
+		[b]Note:[/b] [member ParticlesMaterial.collision_mode] must be [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work.
 		[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
 		[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
 	</description>
 	</description>
 	<tutorials>
 	<tutorials>

+ 1 - 1
doc/classes/GPUParticlesCollisionHeightField3D.xml

@@ -7,7 +7,7 @@
 		Real-time heightmap-shaped 3D particle attractor affecting [GPUParticles3D] nodes.
 		Real-time heightmap-shaped 3D particle attractor affecting [GPUParticles3D] nodes.
 		Heightmap shapes allow for efficiently representing collisions for convex and concave objects with a single "floor" (such as terrain). This is less flexible than [GPUParticlesCollisionSDF3D], but it doesn't require a baking step.
 		Heightmap shapes allow for efficiently representing collisions for convex and concave objects with a single "floor" (such as terrain). This is less flexible than [GPUParticlesCollisionSDF3D], but it doesn't require a baking step.
 		[GPUParticlesCollisionHeightField3D] can also be regenerated in real-time when it is moved, when the camera moves, or even continuously. This makes [GPUParticlesCollisionHeightField3D] a good choice for weather effects such as rain and snow and games with highly dynamic geometry. However, since heightmaps cannot represent overhangs, [GPUParticlesCollisionHeightField3D] is not suited for indoor particle collision.
 		[GPUParticlesCollisionHeightField3D] can also be regenerated in real-time when it is moved, when the camera moves, or even continuously. This makes [GPUParticlesCollisionHeightField3D] a good choice for weather effects such as rain and snow and games with highly dynamic geometry. However, since heightmaps cannot represent overhangs, [GPUParticlesCollisionHeightField3D] is not suited for indoor particle collision.
-		[b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work.
+		[b]Note:[/b] [member ParticlesMaterial.collision_mode] must be [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work.
 		[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
 		[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
 	</description>
 	</description>
 	<tutorials>
 	<tutorials>

+ 1 - 1
doc/classes/GPUParticlesCollisionSDF3D.xml

@@ -8,7 +8,7 @@
 		Signed distance fields (SDF) allow for efficiently representing approximate collision shapes for convex and concave objects of any shape. This is more flexible than [GPUParticlesCollisionHeightField3D], but it requires a baking step.
 		Signed distance fields (SDF) allow for efficiently representing approximate collision shapes for convex and concave objects of any shape. This is more flexible than [GPUParticlesCollisionHeightField3D], but it requires a baking step.
 		[b]Baking:[/b] The signed distance field texture can be baked by selecting the [GPUParticlesCollisionSDF3D] node in the editor, then clicking [b]Bake SDF[/b] at the top of the 3D viewport. Any [i]visible[/i] [MeshInstance3D]s touching the [member extents] will be taken into account for baking, regardless of their [member GeometryInstance3D.gi_mode].
 		[b]Baking:[/b] The signed distance field texture can be baked by selecting the [GPUParticlesCollisionSDF3D] node in the editor, then clicking [b]Bake SDF[/b] at the top of the 3D viewport. Any [i]visible[/i] [MeshInstance3D]s touching the [member extents] will be taken into account for baking, regardless of their [member GeometryInstance3D.gi_mode].
 		[b]Note:[/b] Baking a [GPUParticlesCollisionSDF3D]'s [member texture] is only possible within the editor, as there is no bake method exposed for use in exported projects. However, it's still possible to load pre-baked [Texture3D]s into its [member texture] property in an exported project.
 		[b]Note:[/b] Baking a [GPUParticlesCollisionSDF3D]'s [member texture] is only possible within the editor, as there is no bake method exposed for use in exported projects. However, it's still possible to load pre-baked [Texture3D]s into its [member texture] property in an exported project.
-		[b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work.
+		[b]Note:[/b] [member ParticlesMaterial.collision_mode] must be [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work.
 		[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
 		[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
 	</description>
 	</description>
 	<tutorials>
 	<tutorials>

+ 1 - 1
doc/classes/GPUParticlesCollisionSphere3D.xml

@@ -5,7 +5,7 @@
 	</brief_description>
 	</brief_description>
 	<description>
 	<description>
 		Sphere-shaped 3D particle collision shape affecting [GPUParticles3D] nodes.
 		Sphere-shaped 3D particle collision shape affecting [GPUParticles3D] nodes.
-		[b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work.
+		[b]Note:[/b] [member ParticlesMaterial.collision_mode] must be [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work.
 		[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
 		[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
 	</description>
 	</description>
 	<tutorials>
 	<tutorials>

+ 19 - 6
doc/classes/ParticlesMaterial.xml

@@ -115,14 +115,15 @@
 		<member name="attractor_interaction_enabled" type="bool" setter="set_attractor_interaction_enabled" getter="is_attractor_interaction_enabled" default="true">
 		<member name="attractor_interaction_enabled" type="bool" setter="set_attractor_interaction_enabled" getter="is_attractor_interaction_enabled" default="true">
 			True if the interaction with particle attractors is enabled.
 			True if the interaction with particle attractors is enabled.
 		</member>
 		</member>
-		<member name="collision_bounce" type="float" setter="set_collision_bounce" getter="get_collision_bounce" default="0.0">
-			Collision bounciness.
+		<member name="collision_bounce" type="float" setter="set_collision_bounce" getter="get_collision_bounce">
+			The particles' bounciness. Values range from [code]0[/code] (no bounce) to [code]1[/code] (full bounciness). Only effective if [member collision_mode] is [constant COLLISION_RIGID].
 		</member>
 		</member>
-		<member name="collision_enabled" type="bool" setter="set_collision_enabled" getter="is_collision_enabled" default="false">
-			True if collisions are enabled for this particle system.
+		<member name="collision_friction" type="float" setter="set_collision_friction" getter="get_collision_friction">
+			The particles' friction. Values range from [code]0[/code] (frictionless) to [code]1[/code] (maximum friction). Only effective if [member collision_mode] is [constant COLLISION_RIGID].
 		</member>
 		</member>
-		<member name="collision_friction" type="float" setter="set_collision_friction" getter="get_collision_friction" default="0.0">
-			Collision friction.
+		<member name="collision_mode" type="int" setter="set_collision_mode" getter="get_collision_mode" enum="ParticlesMaterial.CollisionMode" default="0">
+			The particles' collision mode.
+			[b]Note:[/b] Particles can only collide with [GPUParticlesCollision3D] nodes, not [PhysicsBody3D] nodes. To make particles collide with various objects, you can add [GPUParticlesCollision3D] nodes as children of [PhysicsBody3D] nodes.
 		</member>
 		</member>
 		<member name="collision_use_scale" type="bool" setter="set_collision_use_scale" getter="is_collision_using_scale" default="false">
 		<member name="collision_use_scale" type="bool" setter="set_collision_use_scale" getter="is_collision_using_scale" default="false">
 			Should collision take scale into account.
 			Should collision take scale into account.
@@ -404,5 +405,17 @@
 		<constant name="SUB_EMITTER_MAX" value="4" enum="SubEmitterMode">
 		<constant name="SUB_EMITTER_MAX" value="4" enum="SubEmitterMode">
 			Represents the size of the [enum SubEmitterMode] enum.
 			Represents the size of the [enum SubEmitterMode] enum.
 		</constant>
 		</constant>
+		<constant name="COLLISION_DISABLED" value="0" enum="CollisionMode">
+			No collision for particles. Particles will go through [GPUParticlesCollision3D] nodes.
+		</constant>
+		<constant name="COLLISION_RIGID" value="1" enum="CollisionMode">
+			[RigidDynamicBody3D]-style collision for particles using [GPUParticlesCollision3D] nodes.
+		</constant>
+		<constant name="COLLISION_HIDE_ON_CONTACT" value="2" enum="CollisionMode">
+			Hide particles instantly when colliding with a [GPUParticlesCollision3D] node. This can be combined with a subemitter that uses the [constant COLLISION_RIGID] collision mode to "replace" the parent particle with the subemitter on impact.
+		</constant>
+		<constant name="COLLISION_MAX" value="3" enum="CollisionMode">
+			Represents the size of the [enum CollisionMode] enum.
+		</constant>
 	</constants>
 	</constants>
 </class>
 </class>

+ 40 - 12
scene/resources/particles_material.cpp

@@ -287,7 +287,7 @@ void ParticlesMaterial::_update_shader() {
 		code += "uniform sampler2D anim_offset_texture : repeat_disable;\n";
 		code += "uniform sampler2D anim_offset_texture : repeat_disable;\n";
 	}
 	}
 
 
-	if (collision_enabled) {
+	if (collision_mode == COLLISION_RIGID) {
 		code += "uniform float collision_friction;\n";
 		code += "uniform float collision_friction;\n";
 		code += "uniform float collision_bounce;\n";
 		code += "uniform float collision_bounce;\n";
 	}
 	}
@@ -695,8 +695,10 @@ void ParticlesMaterial::_update_shader() {
 		}
 		}
 		code += "	vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz, EMISSION_TRANSFORM[3].xyz, time_noise);\n";
 		code += "	vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz, EMISSION_TRANSFORM[3].xyz, time_noise);\n";
 		// If collision happened, turbulence is no longer applied.
 		// If collision happened, turbulence is no longer applied.
+		// We don't need this check when the collision mode is "hide on contact",
+		// as the particle will be hidden anyway.
 		String extra_tab = "";
 		String extra_tab = "";
-		if (collision_enabled) {
+		if (collision_mode != COLLISION_RIGID) {
 			code += "	if (!COLLIDED) {\n";
 			code += "	if (!COLLIDED) {\n";
 			extra_tab = "	";
 			extra_tab = "	";
 		}
 		}
@@ -704,7 +706,7 @@ void ParticlesMaterial::_update_shader() {
 		code += extra_tab + "	float vel_mag = length(VELOCITY);\n";
 		code += extra_tab + "	float vel_mag = length(VELOCITY);\n";
 		code += extra_tab + "	float vel_infl = clamp(mix(turbulence_influence_min, turbulence_influence_max, rand_from_seed(alt_seed)) * turbulence_influence, 0.0, 1.0);\n";
 		code += extra_tab + "	float vel_infl = clamp(mix(turbulence_influence_min, turbulence_influence_max, rand_from_seed(alt_seed)) * turbulence_influence, 0.0, 1.0);\n";
 		code += extra_tab + "	VELOCITY = mix(VELOCITY, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n";
 		code += extra_tab + "	VELOCITY = mix(VELOCITY, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n";
-		if (collision_enabled) {
+		if (collision_mode != COLLISION_RIGID) {
 			code += "	}";
 			code += "	}";
 		}
 		}
 	}
 	}
@@ -828,7 +830,7 @@ void ParticlesMaterial::_update_shader() {
 		code += "	TRANSFORM[3].z = 0.0;\n";
 		code += "	TRANSFORM[3].z = 0.0;\n";
 	}
 	}
 
 
-	if (collision_enabled) {
+	if (collision_mode == COLLISION_RIGID) {
 		code += "	if (COLLIDED) {\n";
 		code += "	if (COLLIDED) {\n";
 		code += "		if (length(VELOCITY) > 3.0) {\n";
 		code += "		if (length(VELOCITY) > 3.0) {\n";
 		code += "			TRANSFORM[3].xyz += COLLISION_NORMAL * COLLISION_DEPTH;\n";
 		code += "			TRANSFORM[3].xyz += COLLISION_NORMAL * COLLISION_DEPTH;\n";
@@ -851,6 +853,18 @@ void ParticlesMaterial::_update_shader() {
 	code += "	TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n";
 	code += "	TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n";
 	code += "	TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n";
 	code += "	TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n";
 
 
+	if (collision_mode == COLLISION_RIGID) {
+		code += "	if (COLLIDED) {\n";
+		code += "		TRANSFORM[3].xyz+=COLLISION_NORMAL * COLLISION_DEPTH;\n";
+		code += "		VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n";
+		code += "		VELOCITY = mix(VELOCITY,vec3(0.0),collision_friction * DELTA * 100.0);\n";
+		code += "	}\n";
+	} else if (collision_mode == COLLISION_HIDE_ON_CONTACT) {
+		code += "	if (COLLIDED) {\n";
+		code += "		ACTIVE = false;\n";
+		code += "	}\n";
+	}
+
 	if (sub_emitter_mode != SUB_EMITTER_DISABLED) {
 	if (sub_emitter_mode != SUB_EMITTER_DISABLED) {
 		code += "	int emit_count = 0;\n";
 		code += "	int emit_count = 0;\n";
 		switch (sub_emitter_mode) {
 		switch (sub_emitter_mode) {
@@ -1436,6 +1450,14 @@ void ParticlesMaterial::_validate_property(PropertyInfo &p_property) const {
 			p_property.usage = PROPERTY_USAGE_NO_EDITOR;
 			p_property.usage = PROPERTY_USAGE_NO_EDITOR;
 		}
 		}
 	}
 	}
+
+	if (property.name == "collision_friction" && collision_mode != COLLISION_RIGID) {
+		property.usage = PROPERTY_USAGE_NONE;
+	}
+
+	if (property.name == "collision_bounce" && collision_mode != COLLISION_RIGID) {
+		property.usage = PROPERTY_USAGE_NONE;
+	}
 }
 }
 
 
 void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) {
 void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) {
@@ -1483,13 +1505,14 @@ bool ParticlesMaterial::is_attractor_interaction_enabled() const {
 	return attractor_interaction_enabled;
 	return attractor_interaction_enabled;
 }
 }
 
 
-void ParticlesMaterial::set_collision_enabled(bool p_enabled) {
-	collision_enabled = p_enabled;
+void ParticlesMaterial::set_collision_mode(CollisionMode p_collision_mode) {
+	collision_mode = p_collision_mode;
 	_queue_shader_change();
 	_queue_shader_change();
+	notify_property_list_changed();
 }
 }
 
 
-bool ParticlesMaterial::is_collision_enabled() const {
-	return collision_enabled;
+ParticlesMaterial::CollisionMode ParticlesMaterial::get_collision_mode() const {
+	return collision_mode;
 }
 }
 
 
 void ParticlesMaterial::set_collision_use_scale(bool p_scale) {
 void ParticlesMaterial::set_collision_use_scale(bool p_scale) {
@@ -1623,8 +1646,8 @@ void ParticlesMaterial::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_attractor_interaction_enabled", "enabled"), &ParticlesMaterial::set_attractor_interaction_enabled);
 	ClassDB::bind_method(D_METHOD("set_attractor_interaction_enabled", "enabled"), &ParticlesMaterial::set_attractor_interaction_enabled);
 	ClassDB::bind_method(D_METHOD("is_attractor_interaction_enabled"), &ParticlesMaterial::is_attractor_interaction_enabled);
 	ClassDB::bind_method(D_METHOD("is_attractor_interaction_enabled"), &ParticlesMaterial::is_attractor_interaction_enabled);
 
 
-	ClassDB::bind_method(D_METHOD("set_collision_enabled", "enabled"), &ParticlesMaterial::set_collision_enabled);
-	ClassDB::bind_method(D_METHOD("is_collision_enabled"), &ParticlesMaterial::is_collision_enabled);
+	ClassDB::bind_method(D_METHOD("set_collision_mode", "mode"), &ParticlesMaterial::set_collision_mode);
+	ClassDB::bind_method(D_METHOD("get_collision_mode"), &ParticlesMaterial::get_collision_mode);
 
 
 	ClassDB::bind_method(D_METHOD("set_collision_use_scale", "radius"), &ParticlesMaterial::set_collision_use_scale);
 	ClassDB::bind_method(D_METHOD("set_collision_use_scale", "radius"), &ParticlesMaterial::set_collision_use_scale);
 	ClassDB::bind_method(D_METHOD("is_collision_using_scale"), &ParticlesMaterial::is_collision_using_scale);
 	ClassDB::bind_method(D_METHOD("is_collision_using_scale"), &ParticlesMaterial::is_collision_using_scale);
@@ -1734,7 +1757,7 @@ void ParticlesMaterial::_bind_methods() {
 	ADD_GROUP("Attractor Interaction", "attractor_interaction_");
 	ADD_GROUP("Attractor Interaction", "attractor_interaction_");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "attractor_interaction_enabled"), "set_attractor_interaction_enabled", "is_attractor_interaction_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "attractor_interaction_enabled"), "set_attractor_interaction_enabled", "is_attractor_interaction_enabled");
 	ADD_GROUP("Collision", "collision_");
 	ADD_GROUP("Collision", "collision_");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_enabled"), "set_collision_enabled", "is_collision_enabled");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mode", PROPERTY_HINT_ENUM, "Disabled,Rigid,Hide On Contact"), "set_collision_mode", "get_collision_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_friction", "get_collision_friction");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_friction", "get_collision_friction");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_scale"), "set_collision_use_scale", "is_collision_using_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_scale"), "set_collision_use_scale", "is_collision_using_scale");
@@ -1776,6 +1799,11 @@ void ParticlesMaterial::_bind_methods() {
 	BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END);
 	BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END);
 	BIND_ENUM_CONSTANT(SUB_EMITTER_AT_COLLISION);
 	BIND_ENUM_CONSTANT(SUB_EMITTER_AT_COLLISION);
 	BIND_ENUM_CONSTANT(SUB_EMITTER_MAX);
 	BIND_ENUM_CONSTANT(SUB_EMITTER_MAX);
+
+	BIND_ENUM_CONSTANT(COLLISION_DISABLED);
+	BIND_ENUM_CONSTANT(COLLISION_RIGID);
+	BIND_ENUM_CONSTANT(COLLISION_HIDE_ON_CONTACT);
+	BIND_ENUM_CONSTANT(COLLISION_MAX);
 }
 }
 
 
 ParticlesMaterial::ParticlesMaterial() :
 ParticlesMaterial::ParticlesMaterial() :
@@ -1834,7 +1862,7 @@ ParticlesMaterial::ParticlesMaterial() :
 	set_sub_emitter_keep_velocity(false);
 	set_sub_emitter_keep_velocity(false);
 
 
 	set_attractor_interaction_enabled(true);
 	set_attractor_interaction_enabled(true);
-	set_collision_enabled(false);
+	set_collision_mode(COLLISION_DISABLED);
 	set_collision_bounce(0.0);
 	set_collision_bounce(0.0);
 	set_collision_friction(0.0);
 	set_collision_friction(0.0);
 	set_collision_use_scale(false);
 	set_collision_use_scale(false);

+ 14 - 5
scene/resources/particles_material.h

@@ -93,6 +93,14 @@ public:
 		SUB_EMITTER_MAX
 		SUB_EMITTER_MAX
 	};
 	};
 
 
+	// When extending, make sure not to overflow the size of the MaterialKey below.
+	enum CollisionMode {
+		COLLISION_DISABLED,
+		COLLISION_RIGID,
+		COLLISION_HIDE_ON_CONTACT,
+		COLLISION_MAX
+	};
+
 private:
 private:
 	union MaterialKey {
 	union MaterialKey {
 		// The bit size of the struct must be kept below or equal to 32 bits.
 		// The bit size of the struct must be kept below or equal to 32 bits.
@@ -106,7 +114,7 @@ private:
 			uint32_t has_emission_color : 1;
 			uint32_t has_emission_color : 1;
 			uint32_t sub_emitter : 2;
 			uint32_t sub_emitter : 2;
 			uint32_t attractor_enabled : 1;
 			uint32_t attractor_enabled : 1;
-			uint32_t collision_enabled : 1;
+			uint32_t collision_mode : 2;
 			uint32_t collision_scale : 1;
 			uint32_t collision_scale : 1;
 			uint32_t turbulence_enabled : 1;
 			uint32_t turbulence_enabled : 1;
 		};
 		};
@@ -153,7 +161,7 @@ private:
 		mk.emission_shape = emission_shape;
 		mk.emission_shape = emission_shape;
 		mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid();
 		mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid();
 		mk.sub_emitter = sub_emitter_mode;
 		mk.sub_emitter = sub_emitter_mode;
-		mk.collision_enabled = collision_enabled;
+		mk.collision_mode = collision_mode;
 		mk.attractor_enabled = attractor_interaction_enabled;
 		mk.attractor_enabled = attractor_interaction_enabled;
 		mk.collision_scale = collision_scale;
 		mk.collision_scale = collision_scale;
 		mk.turbulence_enabled = turbulence_enabled;
 		mk.turbulence_enabled = turbulence_enabled;
@@ -300,7 +308,7 @@ private:
 	//do not save emission points here
 	//do not save emission points here
 
 
 	bool attractor_interaction_enabled = false;
 	bool attractor_interaction_enabled = false;
-	bool collision_enabled = false;
+	CollisionMode collision_mode;
 	bool collision_scale = false;
 	bool collision_scale = false;
 	float collision_friction = 0.0f;
 	float collision_friction = 0.0f;
 	float collision_bounce = 0.0f;
 	float collision_bounce = 0.0f;
@@ -385,8 +393,8 @@ public:
 	void set_attractor_interaction_enabled(bool p_enable);
 	void set_attractor_interaction_enabled(bool p_enable);
 	bool is_attractor_interaction_enabled() const;
 	bool is_attractor_interaction_enabled() const;
 
 
-	void set_collision_enabled(bool p_enabled);
-	bool is_collision_enabled() const;
+	void set_collision_mode(CollisionMode p_collision_mode);
+	CollisionMode get_collision_mode() const;
 
 
 	void set_collision_use_scale(bool p_scale);
 	void set_collision_use_scale(bool p_scale);
 	bool is_collision_using_scale() const;
 	bool is_collision_using_scale() const;
@@ -425,5 +433,6 @@ VARIANT_ENUM_CAST(ParticlesMaterial::Parameter)
 VARIANT_ENUM_CAST(ParticlesMaterial::ParticleFlags)
 VARIANT_ENUM_CAST(ParticlesMaterial::ParticleFlags)
 VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape)
 VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape)
 VARIANT_ENUM_CAST(ParticlesMaterial::SubEmitterMode)
 VARIANT_ENUM_CAST(ParticlesMaterial::SubEmitterMode)
+VARIANT_ENUM_CAST(ParticlesMaterial::CollisionMode)
 
 
 #endif // PARTICLES_MATERIAL_H
 #endif // PARTICLES_MATERIAL_H