Skip to content

Commit

Permalink
Added ring emitter for 3D particles
Browse files Browse the repository at this point in the history
This commits adds a new emitter type for particles material
and 3D CPU particles. The new emitter is called "ring"
and it can emit either in a ring or cylinder fashion.
This adds the following properties for the emitter:
1. ring_emitter_axis: the axis along which the ring/cylinder
    will be constructed
2. ring_emitter_radius: outer radius of the ring/cylinder
3. ring_emitter_inner_radius: inner radius of the cylinder.
    when set to zero, particles will emit in the full volume.
4. ring_emitter_height: height of the ring/cylinder emitter.

Co-authored-by: Rémi Verschelde <rverschelde@gmail.com>
  • Loading branch information
QbieShay and akien-mga committed May 9, 2021
1 parent 84061ab commit 3af20b9
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 8 deletions.
21 changes: 18 additions & 3 deletions doc/classes/CPUParticles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -173,15 +173,27 @@
<member name="emission_box_extents" type="Vector3" setter="set_emission_box_extents" getter="get_emission_box_extents">
The rectangle's extents if [member emission_shape] is set to [constant EMISSION_SHAPE_BOX].
</member>
<member name="emission_colors" type="PoolColorArray" setter="set_emission_colors" getter="get_emission_colors" default="PoolColorArray( )">
<member name="emission_colors" type="PoolColorArray" setter="set_emission_colors" getter="get_emission_colors">
Sets the [Color]s to modulate particles by when using [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS].
</member>
<member name="emission_normals" type="PoolVector3Array" setter="set_emission_normals" getter="get_emission_normals">
Sets the direction the particles will be emitted in when using [constant EMISSION_SHAPE_DIRECTED_POINTS].
</member>
<member name="emission_points" type="PoolVector3Array" setter="set_emission_points" getter="get_emission_points" default="PoolVector3Array( )">
<member name="emission_points" type="PoolVector3Array" setter="set_emission_points" getter="get_emission_points">
Sets the initial positions to spawn particles when using [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS].
</member>
<member name="emission_ring_axis" type="Vector3" setter="set_emission_ring_axis" getter="get_emission_ring_axis">
The axis for the ring shaped emitter when using [constant EMISSION_SHAPE_RING].
</member>
<member name="emission_ring_height" type="float" setter="set_emission_ring_height" getter="get_emission_ring_height">
The height for the ring shaped emitter when using [constant EMISSION_SHAPE_RING].
</member>
<member name="emission_ring_inner_radius" type="float" setter="set_emission_ring_inner_radius" getter="get_emission_ring_inner_radius">
The inner radius for the ring shaped emitter when using [constant EMISSION_SHAPE_RING].
</member>
<member name="emission_ring_radius" type="float" setter="set_emission_ring_radius" getter="get_emission_ring_radius">
The radius for the ring shaped emitter when using [constant EMISSION_SHAPE_RING].
</member>
<member name="emission_shape" type="int" setter="set_emission_shape" getter="get_emission_shape" enum="CPUParticles.EmissionShape" default="0">
Particles will be emitted inside this region. See [enum EmissionShape] for possible values.
</member>
Expand Down Expand Up @@ -380,7 +392,10 @@
<constant name="EMISSION_SHAPE_DIRECTED_POINTS" value="4" enum="EmissionShape">
Particles will be emitted at a position chosen randomly among [member emission_points]. Particle velocity and rotation will be set based on [member emission_normals]. Particle color will be modulated by [member emission_colors].
</constant>
<constant name="EMISSION_SHAPE_MAX" value="5" enum="EmissionShape">
<constant name="EMISSION_SHAPE_RING" value="5" enum="EmissionShape">
Particles will be emitted in a ring or cylinder.
</constant>
<constant name="EMISSION_SHAPE_MAX" value="6" enum="EmissionShape">
Represents the size of the [enum EmissionShape] enum.
</constant>
</constants>
Expand Down
17 changes: 16 additions & 1 deletion doc/classes/ParticlesMaterial.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@
<member name="emission_point_texture" type="Texture" setter="set_emission_point_texture" getter="get_emission_point_texture">
Particles will be emitted at positions determined by sampling this texture at a random position. Used with [constant EMISSION_SHAPE_POINTS] and [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>
<member name="emission_ring_axis" type="Vector3" setter="set_emission_ring_axis" getter="get_emission_ring_axis" default="Vector3( 0, 0, 1 )">
The axis of the ring when using the emitter [constant EMISSION_SHAPE_RING].
</member>
<member name="emission_ring_height" type="float" setter="set_emission_ring_height" getter="get_emission_ring_height">
The height of the ring when using the emitter [constant EMISSION_SHAPE_RING].
</member>
<member name="emission_ring_inner_radius" type="float" setter="set_emission_ring_inner_radius" getter="get_emission_ring_inner_radius">
The inner radius of the ring when using the emitter [constant EMISSION_SHAPE_RING].
</member>
<member name="emission_ring_radius" type="float" setter="set_emission_ring_radius" getter="get_emission_ring_radius">
The radius of the ring when using the emitter [constant EMISSION_SHAPE_RING].
</member>
<member name="emission_shape" type="int" setter="set_emission_shape" getter="get_emission_shape" enum="ParticlesMaterial.EmissionShape" default="0">
Particles will be emitted inside this region. Use [enum EmissionShape] constants for values.
</member>
Expand Down Expand Up @@ -329,7 +341,10 @@
<constant name="EMISSION_SHAPE_DIRECTED_POINTS" value="4" enum="EmissionShape">
Particles will be emitted at a position determined by sampling a random point on the [member emission_point_texture]. Particle velocity and rotation will be set based on [member emission_normal_texture]. Particle color will be modulated by [member emission_color_texture].
</constant>
<constant name="EMISSION_SHAPE_MAX" value="5" enum="EmissionShape">
<constant name="EMISSION_SHAPE_RING" value="5" enum="EmissionShape">
Particles will be emitted in a ring or cylinder.
</constant>
<constant name="EMISSION_SHAPE_MAX" value="6" enum="EmissionShape">
Represents the size of the [enum EmissionShape] enum.
</constant>
</constants>
Expand Down
80 changes: 78 additions & 2 deletions scene/3d/cpu_particles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,21 @@ void CPUParticles::set_emission_normals(const PoolVector<Vector3> &p_normals) {
void CPUParticles::set_emission_colors(const PoolVector<Color> &p_colors) {
emission_colors = p_colors;
}
void CPUParticles::set_emission_ring_height(float p_height) {
emission_ring_height = p_height;
}

void CPUParticles::set_emission_ring_radius(float p_radius) {
emission_ring_radius = p_radius;
}

void CPUParticles::set_emission_ring_inner_radius(float p_offset) {
emission_ring_inner_radius = p_offset;
}

void CPUParticles::set_emission_ring_axis(Vector3 p_axis) {
emission_ring_axis = p_axis;
}

float CPUParticles::get_emission_sphere_radius() const {
return emission_sphere_radius;
Expand All @@ -407,6 +422,22 @@ PoolVector<Color> CPUParticles::get_emission_colors() const {
return emission_colors;
}

float CPUParticles::get_emission_ring_height() const {
return emission_ring_height;
}

float CPUParticles::get_emission_ring_inner_radius() const {
return emission_ring_inner_radius;
}

float CPUParticles::get_emission_ring_radius() const {
return emission_ring_radius;
}

Vector3 CPUParticles::get_emission_ring_axis() const {
return emission_ring_axis;
}

CPUParticles::EmissionShape CPUParticles::get_emission_shape() const {
return emission_shape;
}
Expand All @@ -431,14 +462,18 @@ void CPUParticles::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}

if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
if ((property.name == "emission_points" || property.name == "emission_colors") && (emission_shape != EMISSION_SHAPE_POINTS) && (emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
property.usage = 0;
}

if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
property.usage = 0;
}

if (property.name.begins_with("emission_ring") && emission_shape != EMISSION_SHAPE_RING) {
property.usage = 0;
}

if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
property.usage = 0;
}
Expand Down Expand Up @@ -734,6 +769,21 @@ void CPUParticles::_particles_process(float p_delta) {
p.base_color = emission_colors.get(random_idx);
}
} break;
case EMISSION_SHAPE_RING: {
float ring_random_angle = Math::randf() * 2.0 * Math_PI;
float ring_random_radius = Math::randf() * (emission_ring_radius - emission_ring_inner_radius) + emission_ring_inner_radius;
Vector3 axis = emission_ring_axis.normalized();
Vector3 ortho_axis = Vector3();
if (axis == Vector3(1.0, 0.0, 0.0)) {
ortho_axis = Vector3(0.0, 1.0, 0.0).cross(axis);
} else {
ortho_axis = Vector3(1.0, 0.0, 0.0).cross(axis);
}
ortho_axis = ortho_axis.normalized();
ortho_axis.rotate(axis, ring_random_angle);
ortho_axis = ortho_axis.normalized();
p.transform.origin = ortho_axis * ring_random_radius + (Math::randf() * emission_ring_height - emission_ring_height / 2.0) * axis;
}
case EMISSION_SHAPE_MAX: { // Max value for validity check.
break;
}
Expand Down Expand Up @@ -1194,6 +1244,10 @@ void CPUParticles::convert_from_particles(Node *p_particles) {
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
set_emission_box_extents(material->get_emission_box_extents());
set_emission_ring_height(material->get_emission_ring_height());
set_emission_ring_inner_radius(material->get_emission_ring_inner_radius());
set_emission_ring_radius(material->get_emission_ring_radius());
set_emission_ring_axis(material->get_emission_ring_axis());

set_gravity(material->get_gravity());
set_lifetime_randomness(material->get_lifetime_randomness());
Expand Down Expand Up @@ -1327,6 +1381,18 @@ void CPUParticles::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emission_colors", "array"), &CPUParticles::set_emission_colors);
ClassDB::bind_method(D_METHOD("get_emission_colors"), &CPUParticles::get_emission_colors);

ClassDB::bind_method(D_METHOD("set_emission_ring_radius", "radius"), &CPUParticles::set_emission_ring_radius);
ClassDB::bind_method(D_METHOD("get_emission_ring_radius"), &CPUParticles::get_emission_ring_radius);

ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "offset"), &CPUParticles::set_emission_ring_inner_radius);
ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &CPUParticles::get_emission_ring_inner_radius);

ClassDB::bind_method(D_METHOD("set_emission_ring_height", "height"), &CPUParticles::set_emission_ring_height);
ClassDB::bind_method(D_METHOD("get_emission_ring_height"), &CPUParticles::get_emission_ring_height);

ClassDB::bind_method(D_METHOD("set_emission_ring_axis", "axis"), &CPUParticles::set_emission_ring_axis);
ClassDB::bind_method(D_METHOD("get_emission_ring_axis"), &CPUParticles::get_emission_ring_axis);

ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles::get_gravity);
ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles::set_gravity);

Expand All @@ -1335,12 +1401,17 @@ void CPUParticles::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_render_thread"), &CPUParticles::_update_render_thread);

ADD_GROUP("Emission Shape", "emission_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape");
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points, Ring", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals");
ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_ring_radius", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater"), "set_emission_ring_radius", "get_emission_ring_radius");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_ring_inner_radius", PROPERTY_HINT_RANGE, "0.0,1000,0.01,or_greater"), "set_emission_ring_inner_radius", "get_emission_ring_inner_radius");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_ring_height", PROPERTY_HINT_RANGE, "0.0,100,0.01,or_greater"), "set_emission_ring_height", "get_emission_ring_height");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_ring_axis"), "set_emission_ring_axis", "get_emission_ring_axis");

ADD_GROUP("Flags", "flag_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_particle_flag", "get_particle_flag", FLAG_ROTATE_Y);
Expand Down Expand Up @@ -1426,6 +1497,7 @@ void CPUParticles::_bind_methods() {
BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_RING);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX);
}

Expand Down Expand Up @@ -1476,6 +1548,10 @@ CPUParticles::CPUParticles() {
set_emission_shape(EMISSION_SHAPE_POINT);
set_emission_sphere_radius(1);
set_emission_box_extents(Vector3(1, 1, 1));
set_emission_ring_height(1.0);
set_emission_ring_radius(1.0);
set_emission_ring_inner_radius(0.0);
set_emission_ring_axis(Vector3(0.0, 0.0, 1.0));

set_gravity(Vector3(0, -9.8, 0));

Expand Down
13 changes: 13 additions & 0 deletions scene/3d/cpu_particles.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class CPUParticles : public GeometryInstance {
EMISSION_SHAPE_BOX,
EMISSION_SHAPE_POINTS,
EMISSION_SHAPE_DIRECTED_POINTS,
EMISSION_SHAPE_RING,
EMISSION_SHAPE_MAX
};

Expand Down Expand Up @@ -172,6 +173,10 @@ class CPUParticles : public GeometryInstance {
PoolVector<Vector3> emission_normals;
PoolVector<Color> emission_colors;
int emission_point_count;
float emission_ring_height;
float emission_ring_inner_radius;
float emission_ring_radius;
Vector3 emission_ring_axis;

Vector3 gravity;

Expand Down Expand Up @@ -269,6 +274,10 @@ class CPUParticles : public GeometryInstance {
void set_emission_normals(const PoolVector<Vector3> &p_normals);
void set_emission_colors(const PoolVector<Color> &p_colors);
void set_emission_point_count(int p_count);
void set_emission_ring_height(float p_height);
void set_emission_ring_inner_radius(float p_inner_radius);
void set_emission_ring_radius(float p_radius);
void set_emission_ring_axis(Vector3 p_axis);

EmissionShape get_emission_shape() const;
float get_emission_sphere_radius() const;
Expand All @@ -277,6 +286,10 @@ class CPUParticles : public GeometryInstance {
PoolVector<Vector3> get_emission_normals() const;
PoolVector<Color> get_emission_colors() const;
int get_emission_point_count() const;
float get_emission_ring_height() const;
float get_emission_ring_inner_radius() const;
float get_emission_ring_radius() const;
Vector3 get_emission_ring_axis() const;

void set_gravity(const Vector3 &p_gravity);
Vector3 get_gravity() const;
Expand Down
Loading

0 comments on commit 3af20b9

Please sign in to comment.