From 723bf851452a5a387a3fa6dbc24cbbc789610892 Mon Sep 17 00:00:00 2001 From: Micky Date: Thu, 18 Aug 2022 11:09:22 +0200 Subject: Rename ParticlesMaterial to ParticleProcessMaterial Also affects their file names, related classes and documentation. --- doc/classes/BaseMaterial3D.xml | 2 +- doc/classes/CPUParticles2D.xml | 2 +- doc/classes/CPUParticles3D.xml | 2 +- doc/classes/CanvasItemMaterial.xml | 2 +- doc/classes/GPUParticles2D.xml | 4 +- doc/classes/GPUParticles3D.xml | 4 +- doc/classes/GPUParticlesAttractor3D.xml | 2 +- doc/classes/GPUParticlesCollision3D.xml | 6 +- doc/classes/GPUParticlesCollisionBox3D.xml | 2 +- doc/classes/GPUParticlesCollisionHeightField3D.xml | 2 +- doc/classes/GPUParticlesCollisionSDF3D.xml | 2 +- doc/classes/GPUParticlesCollisionSphere3D.xml | 2 +- doc/classes/ParticleProcessMaterial.xml | 421 +++++ doc/classes/ParticlesMaterial.xml | 421 ----- editor/editor_node.cpp | 2 +- editor/icons/ParticleProcessMaterial.svg | 1 + editor/icons/ParticlesMaterial.svg | 1 - editor/plugins/cpu_particles_2d_editor_plugin.cpp | 2 +- editor/plugins/gpu_particles_2d_editor_plugin.cpp | 10 +- editor/plugins/gpu_particles_3d_editor_plugin.cpp | 12 +- editor/plugins/material_editor_plugin.cpp | 12 +- editor/plugins/material_editor_plugin.h | 4 +- editor/project_converter_3_to_4.cpp | 5 +- scene/2d/cpu_particles_2d.cpp | 26 +- scene/2d/gpu_particles_2d.cpp | 16 +- scene/3d/cpu_particles_3d.cpp | 30 +- scene/3d/gpu_particles_3d.cpp | 10 +- scene/register_scene_types.cpp | 11 +- scene/resources/particle_process_material.cpp | 1895 ++++++++++++++++++++ scene/resources/particle_process_material.h | 438 +++++ scene/resources/particles_material.cpp | 1895 -------------------- scene/resources/particles_material.h | 438 ----- .../renderer_rd/storage_rd/particles_storage.cpp | 12 +- .../renderer_rd/storage_rd/particles_storage.h | 4 +- 34 files changed, 2850 insertions(+), 2848 deletions(-) create mode 100644 doc/classes/ParticleProcessMaterial.xml delete mode 100644 doc/classes/ParticlesMaterial.xml create mode 100644 editor/icons/ParticleProcessMaterial.svg delete mode 100644 editor/icons/ParticlesMaterial.svg create mode 100644 scene/resources/particle_process_material.cpp create mode 100644 scene/resources/particle_process_material.h delete mode 100644 scene/resources/particles_material.cpp delete mode 100644 scene/resources/particles_material.h diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index fcdf59e36e..33a129a48e 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -718,7 +718,7 @@ Used for particle systems when assigned to [GPUParticles3D] and [CPUParticles3D] nodes. Enables [code]particles_anim_*[/code] properties. - The [member ParticlesMaterial.anim_speed_min] or [member CPUParticles3D.anim_speed_min] should also be set to a value bigger than zero for the animation to play. + The [member ParticleProcessMaterial.anim_speed_min] or [member CPUParticles3D.anim_speed_min] should also be set to a value bigger than zero for the animation to play. Used to read from the red channel of a texture. diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml index 64e9310181..906789d09f 100644 --- a/doc/classes/CPUParticles2D.xml +++ b/doc/classes/CPUParticles2D.xml @@ -15,7 +15,7 @@ - Sets this node's properties to match a given [GPUParticles2D] node with an assigned [ParticlesMaterial]. + Sets this node's properties to match a given [GPUParticles2D] node with an assigned [ParticleProcessMaterial]. diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml index bb1dcd322f..99fd0501fc 100644 --- a/doc/classes/CPUParticles3D.xml +++ b/doc/classes/CPUParticles3D.xml @@ -14,7 +14,7 @@ - Sets this node's properties to match a given [GPUParticles3D] node with an assigned [ParticlesMaterial]. + Sets this node's properties to match a given [GPUParticles3D] node with an assigned [ParticleProcessMaterial]. diff --git a/doc/classes/CanvasItemMaterial.xml b/doc/classes/CanvasItemMaterial.xml index 22daf79074..59226840bc 100644 --- a/doc/classes/CanvasItemMaterial.xml +++ b/doc/classes/CanvasItemMaterial.xml @@ -28,7 +28,7 @@ [b]Note:[/b] This property is only used and visible in the editor if [member particles_animation] is [code]true[/code]. - If [code]true[/code], enable spritesheet-based animation features when assigned to [GPUParticles2D] and [CPUParticles2D] nodes. The [member ParticlesMaterial.anim_speed_max] or [member CPUParticles2D.anim_speed_max] should also be set to a positive value for the animation to play. + If [code]true[/code], enable spritesheet-based animation features when assigned to [GPUParticles2D] and [CPUParticles2D] nodes. The [member ParticleProcessMaterial.anim_speed_max] or [member CPUParticles2D.anim_speed_max] should also be set to a positive value for the animation to play. This property (and other [code]particles_anim_*[/code] properties that depend on it) has no effect on other types of nodes. diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml index 606d2456c5..f41e34c43a 100644 --- a/doc/classes/GPUParticles2D.xml +++ b/doc/classes/GPUParticles2D.xml @@ -5,7 +5,7 @@ 2D particle node used to create a variety of particle systems and effects. [GPUParticles2D] features an emitter that generates some number of particles at a given rate. - Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles. + Use the [code]process_material[/code] property to add a [ParticleProcessMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles. $DOCS_URL/tutorials/2d/particle_systems_2d.html @@ -73,7 +73,7 @@ Particle system starts as if it had already run for this many seconds. - [Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial]. + [Material] for processing particles. Can be a [ParticleProcessMaterial] or a [ShaderMaterial]. Emission lifetime randomness ratio. diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml index fc7b12e64f..e7b436010e 100644 --- a/doc/classes/GPUParticles3D.xml +++ b/doc/classes/GPUParticles3D.xml @@ -5,7 +5,7 @@ 3D particle node used to create a variety of particle systems and effects. [GPUParticles3D] features an emitter that generates some number of particles at a given rate. - Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles. + Use the [code]process_material[/code] property to add a [ParticleProcessMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles. $DOCS_URL/tutorials/performance/vertex_animation/controlling_thousands_of_fish.html @@ -105,7 +105,7 @@ Amount of time to preprocess the particles before animation starts. Lets you start the animation some time after particles have started emitting. - [Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial]. + [Material] for processing particles. Can be a [ParticleProcessMaterial] or a [ShaderMaterial]. Emission randomness ratio. diff --git a/doc/classes/GPUParticlesAttractor3D.xml b/doc/classes/GPUParticlesAttractor3D.xml index e69255cc31..a1c49afcca 100644 --- a/doc/classes/GPUParticlesAttractor3D.xml +++ b/doc/classes/GPUParticlesAttractor3D.xml @@ -18,7 +18,7 @@ The particle rendering layers ([member VisualInstance3D.layers]) that will be affected by the attractor. By default, all particles are affected by an attractor. 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 ParticleProcessMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node. Adjusts how directional the attractor is. At [code]0.0[/code], the attractor is not directional at all: it will attract particles towards its center. At [code]1.0[/code], the attractor is fully directional: particles will always be pushed towards local -Z (or +Z if [member strength] is negative). diff --git a/doc/classes/GPUParticlesCollision3D.xml b/doc/classes/GPUParticlesCollision3D.xml index 27e3590e75..1b744f7ed6 100644 --- a/doc/classes/GPUParticlesCollision3D.xml +++ b/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 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. - [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] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.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] 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. @@ -15,9 +15,9 @@ - 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. + The particle rendering layers ([member VisualInstance3D.layers]) that will be affected by the collision shape. By default, all particles that have [member ParticleProcessMaterial.collision_mode] set to [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.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. - 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 ParticleProcessMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node. diff --git a/doc/classes/GPUParticlesCollisionBox3D.xml b/doc/classes/GPUParticlesCollisionBox3D.xml index 65b69c0098..103be18bfd 100644 --- a/doc/classes/GPUParticlesCollisionBox3D.xml +++ b/doc/classes/GPUParticlesCollisionBox3D.xml @@ -5,7 +5,7 @@ Box-shaped 3D particle collision shape affecting [GPUParticles3D] nodes. - [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] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work. [b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D]. diff --git a/doc/classes/GPUParticlesCollisionHeightField3D.xml b/doc/classes/GPUParticlesCollisionHeightField3D.xml index 72d273112e..6e996d5fbd 100644 --- a/doc/classes/GPUParticlesCollisionHeightField3D.xml +++ b/doc/classes/GPUParticlesCollisionHeightField3D.xml @@ -7,7 +7,7 @@ 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. [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_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] [member ParticleProcessMaterial.collision_mode] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work. [b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D]. diff --git a/doc/classes/GPUParticlesCollisionSDF3D.xml b/doc/classes/GPUParticlesCollisionSDF3D.xml index 0e7640ba89..8467cfdda1 100644 --- a/doc/classes/GPUParticlesCollisionSDF3D.xml +++ b/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. [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] [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] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work. [b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D]. diff --git a/doc/classes/GPUParticlesCollisionSphere3D.xml b/doc/classes/GPUParticlesCollisionSphere3D.xml index bfebe05005..ee582108dd 100644 --- a/doc/classes/GPUParticlesCollisionSphere3D.xml +++ b/doc/classes/GPUParticlesCollisionSphere3D.xml @@ -5,7 +5,7 @@ Sphere-shaped 3D particle collision shape affecting [GPUParticles3D] nodes. - [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] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work. [b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D]. diff --git a/doc/classes/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml new file mode 100644 index 0000000000..b2dca5a2df --- /dev/null +++ b/doc/classes/ParticleProcessMaterial.xml @@ -0,0 +1,421 @@ + + + + Particle properties for [GPUParticles3D] and [GPUParticles2D] nodes. + + + ParticleProcessMaterial defines particle properties and behavior. It is used in the [code]process_material[/code] of [GPUParticles3D] and [GPUParticles2D] emitter nodes. + Some of this material's properties are applied to each particle when emitted, while others can have a [CurveTexture] applied to vary values over the lifetime of the particle. + Particle animation is available only in [GPUParticles2D]. To use it, attach a [CanvasItemMaterial], with [member CanvasItemMaterial.particles_animation] enabled, to the particles node. + + + + + + + + + Returns the maximum value range for the given parameter. + + + + + + + Returns the minimum value range for the given parameter. + + + + + + + Returns the [Texture2D] used by the specified parameter. + + + + + + + Returns [code]true[/code] if the specified particle flag is enabled. See [enum ParticleFlags] for options. + + + + + + + + Sets the maximum value range for the given parameter. + + + + + + + + Sets the minimum value range for the given parameter. + + + + + + + + Sets the [Texture2D] for the specified [enum Parameter]. + + + + + + + + If [code]true[/code], enables the specified particle flag. See [enum ParticleFlags] for options. + + + + + + Each particle's rotation will be animated along this [CurveTexture]. + + + Maximum initial rotation applied to each particle, in degrees. + Only applied when [member particle_flag_disable_z] or [member particle_flag_rotate_y] are [code]true[/code] or the [BaseMaterial3D] being used to draw the particle is using [constant BaseMaterial3D.BILLBOARD_PARTICLES]. + + + Minimum equivalent of [member angle_max]. + + + Each particle's angular velocity (rotation speed) will vary along this [CurveTexture] over its lifetime. + + + Maximum initial angular velocity (rotation speed) applied to each particle in [i]degrees[/i] per second. + Only applied when [member particle_flag_disable_z] or [member particle_flag_rotate_y] are [code]true[/code] or the [BaseMaterial3D] being used to draw the particle is using [constant BaseMaterial3D.BILLBOARD_PARTICLES]. + + + Minimum equivalent of [member angular_velocity_max]. + + + Each particle's animation offset will vary along this [CurveTexture]. + + + Maximum animation offset that corresponds to frame index in the texture. [code]0[/code] is the first frame, [code]1[/code] is the last one. See [member CanvasItemMaterial.particles_animation]. + + + Minimum equivalent of [member anim_offset_max]. + + + Each particle's animation speed will vary along this [CurveTexture]. + + + Maximum particle animation speed. Animation speed of [code]1[/code] means that the particles will make full [code]0[/code] to [code]1[/code] offset cycle during lifetime, [code]2[/code] means [code]2[/code] cycles etc. + With animation speed greater than [code]1[/code], remember to enable [member CanvasItemMaterial.particles_anim_loop] property if you want the animation to repeat. + + + Minimum equivalent of [member anim_speed_max]. + + + True if the interaction with particle attractors is enabled. + + + 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]. + + + 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]. + + + 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. + + + Should collision take scale into account. + + + Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/code] is defined, it will be multiplied by this color. To have particle display color in a [BaseMaterial3D] make sure to set [member BaseMaterial3D.vertex_color_use_as_albedo] to [code]true[/code]. + + + Each particle's initial color will vary along this [GradientTexture1D] (multiplied with [member color]). + + + Each particle's color will vary along this [GradientTexture1D] over its lifetime (multiplied with [member color]). + + + Damping will vary along this [CurveTexture]. + + + The maximum rate at which particles lose velocity. For example value of [code]100[/code] means that the particle will go from [code]100[/code] velocity to [code]0[/code] in [code]1[/code] second. + + + Minimum equivalent of [member damping_max]. + + + Unit vector specifying the particles' emission direction. + + + The box's extents if [code]emission_shape[/code] is set to [constant EMISSION_SHAPE_BOX]. + + + Particle color will be modulated by color determined by sampling this texture at the same point as the [member emission_point_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. + + + The number of emission points if [code]emission_shape[/code] is set to [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS]. + + + 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. + + + The axis of the ring when using the emitter [constant EMISSION_SHAPE_RING]. + + + The height of the ring when using the emitter [constant EMISSION_SHAPE_RING]. + + + The inner radius of the ring when using the emitter [constant EMISSION_SHAPE_RING]. + + + The radius of the ring when using the emitter [constant EMISSION_SHAPE_RING]. + + + Particles will be emitted inside this region. Use [enum EmissionShape] constants for values. + + + The sphere's radius if [code]emission_shape[/code] is set to [constant EMISSION_SHAPE_SPHERE]. + + + Amount of [member spread] along the Y axis. + + + Gravity applied to every particle. + + + Each particle's hue will vary along this [CurveTexture]. + + + Maximum initial hue variation applied to each particle. It will shift the particle color's hue. + + + Minimum equivalent of [member hue_variation_max]. + + + Maximum initial velocity magnitude for each particle. Direction comes from [member direction] and [member spread]. + + + Minimum equivalent of [member initial_velocity_max]. + + + Particle lifetime randomness ratio. The lifetime will be multiplied by a value interpolated between [code]1.0[/code] and a random number less than one. For example a random ratio of [code]0.4[/code] would scale the original lifetime between [code]0.4-1.0[/code] of its original value. + + + Each particle's linear acceleration will vary along this [CurveTexture]. + + + Maximum linear acceleration applied to each particle in the direction of motion. + + + Minimum equivalent of [member linear_accel_min]. + + + Each particle's orbital velocity will vary along this [CurveTexture]. + + + 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]. + + + Minimum equivalent of [member orbit_velocity_max]. + + + Align Y axis of particle with the direction of its velocity. + + + If [code]true[/code], particles will not move on the z axis. + + + If [code]true[/code], particles rotate around Y axis by [member angle_min]. + + + Each particle's radial acceleration will vary along this [CurveTexture]. + + + Maximum radial acceleration applied to each particle. Makes particle accelerate away from the origin or towards it if negative. + + + Minimum equivalent of [member radial_accel_max]. + + + Each particle's scale will vary along this [CurveTexture]. If a [CurveXYZTexture] is supplied instead, the scale will be separated per-axis. + + + Maximum initial scale applied to each particle. + + + Minimum equivalent of [member scale_max]. + + + Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees. + + + + + + + + + + + Each particle's tangential acceleration will vary along this [CurveTexture]. + + + Maximum tangential acceleration applied to each particle. Tangential acceleration is perpendicular to the particle's velocity giving the particles a swirling motion. + + + Minimum equivalent of [member tangential_accel_max]. + + + Enables and disables Turbulence for the particle system. + + + Minimum turbulence influence on each particle. + The actual amount of turbulence influence on each particle is calculated as a random value between [member turbulence_influence_min] and [member turbulence_influence_max] and multiplied by the amount of turbulence influence from [member turbulence_influence_over_life]. + + + Maximum turbulence influence on each particle. + The actual amount of turbulence influence on each particle is calculated as a random value between [member turbulence_influence_min] and [member turbulence_influence_max] and multiplied by the amount of turbulence influence from [member turbulence_influence_over_life]. + + + Each particle's amount of turbulence will be influenced along this [CurveTexture] over its life time. + + + Maximum displacement of each particles spawn position by the turbulence. + The actual amount of displacement will be a factor of the underlying turbulence multiplied by a random value between [member turbulence_initial_displacement_min] and [member turbulence_initial_displacement_max]. + + + Minimum displacement of each particles spawn position by the turbulence. + The actual amount of displacement will be a factor of the underlying turbulence multiplied by a random value between [member turbulence_initial_displacement_min] and [member turbulence_initial_displacement_max]. + + + This value controls the overall scale/frequency of the turbulence noise pattern. + A small scale will result in smaller features with more detail while a high scale will result in smoother noise with larger features. + + + The movement speed of the turbulence pattern. This changes how quickly the noise changes over time. + A value of [code]Vector3(0.0, 0.0, 0.0)[/code] will freeze the turbulence pattern in place. + + + Use to influence the noise speed in a random pattern. This helps to break up visible movement patterns. + + + The turbulence noise strength. Increasing this will result in a stronger, more contrasting, noise pattern. + + + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set initial velocity properties. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set angular velocity properties. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set orbital velocity properties. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set linear acceleration properties. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set radial acceleration properties. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set tangential acceleration properties. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set damping properties. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set angle properties. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set scale properties. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set hue variation properties. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set animation speed properties. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set animation offset properties. + + + Represents the size of the [enum Parameter] enum. + + + Use with [method set_particle_flag] to set [member particle_flag_align_y]. + + + Use with [method set_particle_flag] to set [member particle_flag_rotate_y]. + + + Use with [method set_particle_flag] to set [member particle_flag_disable_z]. + + + Represents the size of the [enum ParticleFlags] enum. + + + All particles will be emitted from a single point. + + + Particles will be emitted in the volume of a sphere. + + + Particles will be emitted on the surface of a sphere. + + + Particles will be emitted in the volume of a box. + + + Particles will be emitted at a position determined by sampling a random point on the [member emission_point_texture]. Particle color will be modulated by [member emission_color_texture]. + + + 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]. + + + Particles will be emitted in a ring or cylinder. + + + Represents the size of the [enum EmissionShape] enum. + + + Use with [method set_param_min] and [method set_param_max] to set the turbulence minimum und maximum influence on each particles velocity. + + + Use with [method set_param_min] and [method set_param_max] to set the turbulence minimum and maximum displacement of the particles spawn position. + + + Use with [method set_param_texture] to set the turbulence influence over the particles life time. + + + + + + + + + + + Represents the size of the [enum SubEmitterMode] enum. + + + No collision for particles. Particles will go through [GPUParticlesCollision3D] nodes. + + + [RigidDynamicBody3D]-style collision for particles using [GPUParticlesCollision3D] nodes. + + + 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. + + + Represents the size of the [enum CollisionMode] enum. + + + diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml deleted file mode 100644 index 55f4c4dcdd..0000000000 --- a/doc/classes/ParticlesMaterial.xml +++ /dev/null @@ -1,421 +0,0 @@ - - - - Particle properties for [GPUParticles3D] and [GPUParticles2D] nodes. - - - ParticlesMaterial defines particle properties and behavior. It is used in the [code]process_material[/code] of [GPUParticles3D] and [GPUParticles2D] emitter nodes. - Some of this material's properties are applied to each particle when emitted, while others can have a [CurveTexture] applied to vary values over the lifetime of the particle. - Particle animation is available only in [GPUParticles2D]. To use it, attach a [CanvasItemMaterial], with [member CanvasItemMaterial.particles_animation] enabled, to the particles node. - - - - - - - - - Returns the maximum value range for the given parameter. - - - - - - - Returns the minimum value range for the given parameter. - - - - - - - Returns the [Texture2D] used by the specified parameter. - - - - - - - Returns [code]true[/code] if the specified particle flag is enabled. See [enum ParticleFlags] for options. - - - - - - - - Sets the maximum value range for the given parameter. - - - - - - - - Sets the minimum value range for the given parameter. - - - - - - - - Sets the [Texture2D] for the specified [enum Parameter]. - - - - - - - - If [code]true[/code], enables the specified particle flag. See [enum ParticleFlags] for options. - - - - - - Each particle's rotation will be animated along this [CurveTexture]. - - - Maximum initial rotation applied to each particle, in degrees. - Only applied when [member particle_flag_disable_z] or [member particle_flag_rotate_y] are [code]true[/code] or the [BaseMaterial3D] being used to draw the particle is using [constant BaseMaterial3D.BILLBOARD_PARTICLES]. - - - Minimum equivalent of [member angle_max]. - - - Each particle's angular velocity (rotation speed) will vary along this [CurveTexture] over its lifetime. - - - Maximum initial angular velocity (rotation speed) applied to each particle in [i]degrees[/i] per second. - Only applied when [member particle_flag_disable_z] or [member particle_flag_rotate_y] are [code]true[/code] or the [BaseMaterial3D] being used to draw the particle is using [constant BaseMaterial3D.BILLBOARD_PARTICLES]. - - - Minimum equivalent of [member angular_velocity_max]. - - - Each particle's animation offset will vary along this [CurveTexture]. - - - Maximum animation offset that corresponds to frame index in the texture. [code]0[/code] is the first frame, [code]1[/code] is the last one. See [member CanvasItemMaterial.particles_animation]. - - - Minimum equivalent of [member anim_offset_max]. - - - Each particle's animation speed will vary along this [CurveTexture]. - - - Maximum particle animation speed. Animation speed of [code]1[/code] means that the particles will make full [code]0[/code] to [code]1[/code] offset cycle during lifetime, [code]2[/code] means [code]2[/code] cycles etc. - With animation speed greater than [code]1[/code], remember to enable [member CanvasItemMaterial.particles_anim_loop] property if you want the animation to repeat. - - - Minimum equivalent of [member anim_speed_max]. - - - True if the interaction with particle attractors is enabled. - - - 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]. - - - 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]. - - - 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. - - - Should collision take scale into account. - - - Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/code] is defined, it will be multiplied by this color. To have particle display color in a [BaseMaterial3D] make sure to set [member BaseMaterial3D.vertex_color_use_as_albedo] to [code]true[/code]. - - - Each particle's initial color will vary along this [GradientTexture1D] (multiplied with [member color]). - - - Each particle's color will vary along this [GradientTexture1D] over its lifetime (multiplied with [member color]). - - - Damping will vary along this [CurveTexture]. - - - The maximum rate at which particles lose velocity. For example value of [code]100[/code] means that the particle will go from [code]100[/code] velocity to [code]0[/code] in [code]1[/code] second. - - - Minimum equivalent of [member damping_max]. - - - Unit vector specifying the particles' emission direction. - - - The box's extents if [code]emission_shape[/code] is set to [constant EMISSION_SHAPE_BOX]. - - - Particle color will be modulated by color determined by sampling this texture at the same point as the [member emission_point_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. - - - The number of emission points if [code]emission_shape[/code] is set to [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS]. - - - 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. - - - The axis of the ring when using the emitter [constant EMISSION_SHAPE_RING]. - - - The height of the ring when using the emitter [constant EMISSION_SHAPE_RING]. - - - The inner radius of the ring when using the emitter [constant EMISSION_SHAPE_RING]. - - - The radius of the ring when using the emitter [constant EMISSION_SHAPE_RING]. - - - Particles will be emitted inside this region. Use [enum EmissionShape] constants for values. - - - The sphere's radius if [code]emission_shape[/code] is set to [constant EMISSION_SHAPE_SPHERE]. - - - Amount of [member spread] along the Y axis. - - - Gravity applied to every particle. - - - Each particle's hue will vary along this [CurveTexture]. - - - Maximum initial hue variation applied to each particle. It will shift the particle color's hue. - - - Minimum equivalent of [member hue_variation_max]. - - - Maximum initial velocity magnitude for each particle. Direction comes from [member direction] and [member spread]. - - - Minimum equivalent of [member initial_velocity_max]. - - - Particle lifetime randomness ratio. The lifetime will be multiplied by a value interpolated between [code]1.0[/code] and a random number less than one. For example a random ratio of [code]0.4[/code] would scale the original lifetime between [code]0.4-1.0[/code] of its original value. - - - Each particle's linear acceleration will vary along this [CurveTexture]. - - - Maximum linear acceleration applied to each particle in the direction of motion. - - - Minimum equivalent of [member linear_accel_min]. - - - Each particle's orbital velocity will vary along this [CurveTexture]. - - - 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]. - - - Minimum equivalent of [member orbit_velocity_max]. - - - Align Y axis of particle with the direction of its velocity. - - - If [code]true[/code], particles will not move on the z axis. - - - If [code]true[/code], particles rotate around Y axis by [member angle_min]. - - - Each particle's radial acceleration will vary along this [CurveTexture]. - - - Maximum radial acceleration applied to each particle. Makes particle accelerate away from the origin or towards it if negative. - - - Minimum equivalent of [member radial_accel_max]. - - - Each particle's scale will vary along this [CurveTexture]. If a [CurveXYZTexture] is supplied instead, the scale will be separated per-axis. - - - Maximum initial scale applied to each particle. - - - Minimum equivalent of [member scale_max]. - - - Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees. - - - - - - - - - - - Each particle's tangential acceleration will vary along this [CurveTexture]. - - - Maximum tangential acceleration applied to each particle. Tangential acceleration is perpendicular to the particle's velocity giving the particles a swirling motion. - - - Minimum equivalent of [member tangential_accel_max]. - - - Enables and disables Turbulence for the particle system. - - - Minimum turbulence influence on each particle. - The actual amount of turbulence influence on each particle is calculated as a random value between [member turbulence_influence_min] and [member turbulence_influence_max] and multiplied by the amount of turbulence influence from [member turbulence_influence_over_life]. - - - Maximum turbulence influence on each particle. - The actual amount of turbulence influence on each particle is calculated as a random value between [member turbulence_influence_min] and [member turbulence_influence_max] and multiplied by the amount of turbulence influence from [member turbulence_influence_over_life]. - - - Each particle's amount of turbulence will be influenced along this [CurveTexture] over its life time. - - - Maximum displacement of each particles spawn position by the turbulence. - The actual amount of displacement will be a factor of the underlying turbulence multiplied by a random value between [member turbulence_initial_displacement_min] and [member turbulence_initial_displacement_max]. - - - Minimum displacement of each particles spawn position by the turbulence. - The actual amount of displacement will be a factor of the underlying turbulence multiplied by a random value between [member turbulence_initial_displacement_min] and [member turbulence_initial_displacement_max]. - - - This value controls the overall scale/frequency of the turbulence noise pattern. - A small scale will result in smaller features with more detail while a high scale will result in smoother noise with larger features. - - - The movement speed of the turbulence pattern. This changes how quickly the noise changes over time. - A value of [code]Vector3(0.0, 0.0, 0.0)[/code] will freeze the turbulence pattern in place. - - - Use to influence the noise speed in a random pattern. This helps to break up visible movement patterns. - - - The turbulence noise strength. Increasing this will result in a stronger, more contrasting, noise pattern. - - - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set initial velocity properties. - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set angular velocity properties. - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set orbital velocity properties. - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set linear acceleration properties. - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set radial acceleration properties. - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set tangential acceleration properties. - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set damping properties. - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set angle properties. - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set scale properties. - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set hue variation properties. - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set animation speed properties. - - - Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set animation offset properties. - - - Represents the size of the [enum Parameter] enum. - - - Use with [method set_particle_flag] to set [member particle_flag_align_y]. - - - Use with [method set_particle_flag] to set [member particle_flag_rotate_y]. - - - Use with [method set_particle_flag] to set [member particle_flag_disable_z]. - - - Represents the size of the [enum ParticleFlags] enum. - - - All particles will be emitted from a single point. - - - Particles will be emitted in the volume of a sphere. - - - Particles will be emitted on the surface of a sphere. - - - Particles will be emitted in the volume of a box. - - - Particles will be emitted at a position determined by sampling a random point on the [member emission_point_texture]. Particle color will be modulated by [member emission_color_texture]. - - - 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]. - - - Particles will be emitted in a ring or cylinder. - - - Represents the size of the [enum EmissionShape] enum. - - - Use with [method set_param_min] and [method set_param_max] to set the turbulence minimum und maximum influence on each particles velocity. - - - Use with [method set_param_min] and [method set_param_max] to set the turbulence minimum and maximum displacement of the particles spawn position. - - - Use with [method set_param_texture] to set the turbulence influence over the particles life time. - - - - - - - - - - - Represents the size of the [enum SubEmitterMode] enum. - - - No collision for particles. Particles will go through [GPUParticlesCollision3D] nodes. - - - [RigidDynamicBody3D]-style collision for particles using [GPUParticlesCollision3D] nodes. - - - 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. - - - Represents the size of the [enum CollisionMode] enum. - - - diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 4aedd98bd3..0194c8f729 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -7294,7 +7294,7 @@ EditorNode::EditorNode() { canvas_item_mat_convert.instantiate(); resource_conversion_plugins.push_back(canvas_item_mat_convert); - Ref particles_mat_convert; + Ref particles_mat_convert; particles_mat_convert.instantiate(); resource_conversion_plugins.push_back(particles_mat_convert); diff --git a/editor/icons/ParticleProcessMaterial.svg b/editor/icons/ParticleProcessMaterial.svg new file mode 100644 index 0000000000..33598980a5 --- /dev/null +++ b/editor/icons/ParticleProcessMaterial.svg @@ -0,0 +1 @@ + diff --git a/editor/icons/ParticlesMaterial.svg b/editor/icons/ParticlesMaterial.svg deleted file mode 100644 index 33598980a5..0000000000 --- a/editor/icons/ParticlesMaterial.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index e20d298195..e56fd5dfe3 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -37,7 +37,7 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/2d/cpu_particles_2d.h" #include "scene/gui/separator.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" void CPUParticles2DEditorPlugin::edit(Object *p_object) { particles = Object::cast_to(p_object); diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index 1487f8b7bc..e2d19c34e6 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -38,7 +38,7 @@ #include "editor/scene_tree_dock.h" #include "scene/2d/cpu_particles_2d.h" #include "scene/gui/separator.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" void GPUParticles2DEditorPlugin::edit(Object *p_object) { particles = Object::cast_to(p_object); @@ -167,9 +167,9 @@ void GPUParticles2DEditorPlugin::_generate_visibility_rect() { } void GPUParticles2DEditorPlugin::_generate_emission_mask() { - Ref pm = particles->get_process_material(); + Ref pm = particles->get_process_material(); if (!pm.is_valid()) { - EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticlesMaterial process material")); + EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticleProcessMaterial process material")); return; } @@ -320,7 +320,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { } if (valid_normals.size()) { - pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS); + pm->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_DIRECTED_POINTS); Vector normdata; normdata.resize(w * h * 2 * sizeof(float)); //use RG texture @@ -339,7 +339,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { pm->set_emission_normal_texture(ImageTexture::create_from_image(img)); } else { - pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS); + pm->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_POINTS); } } diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index 335efd6949..ebc92bf531 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -36,7 +36,7 @@ #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/scene_tree_dock.h" #include "scene/3d/cpu_particles_3d.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" bool GPUParticles3DEditorBase::_generate(Vector &points, Vector &normals) { bool use_normals = emission_fill->get_selected() == 1; @@ -255,9 +255,9 @@ void GPUParticles3DEditor::_menu_option(int p_option) { } } break; case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: { - Ref material = node->get_process_material(); + Ref material = node->get_process_material(); if (material.is_null()) { - EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required.")); + EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticleProcessMaterial' is required.")); return; } @@ -366,11 +366,11 @@ void GPUParticles3DEditor::_generate_emission_points() { Ref image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img)); Ref tex = ImageTexture::create_from_image(image); - Ref material = node->get_process_material(); + Ref material = node->get_process_material(); ERR_FAIL_COND(material.is_null()); if (normals.size() > 0) { - material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS); + material->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_DIRECTED_POINTS); material->set_emission_point_count(point_count); material->set_emission_point_texture(tex); @@ -392,7 +392,7 @@ void GPUParticles3DEditor::_generate_emission_points() { Ref image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2)); material->set_emission_normal_texture(ImageTexture::create_from_image(image2)); } else { - material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS); + material->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_POINTS); material->set_emission_point_count(point_count); material->set_emission_point_texture(tex); } diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index 5d59f62f05..9fcb6619c0 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -36,7 +36,7 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/gui/subviewport_container.h" #include "scene/resources/fog_material.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" #include "scene/resources/sky_material.h" void MaterialEditor::_notification(int p_what) { @@ -405,17 +405,17 @@ Ref ORMMaterial3DConversionPlugin::convert(const Ref &p_reso return smat; } -String ParticlesMaterialConversionPlugin::converts_to() const { +String ParticleProcessMaterialConversionPlugin::converts_to() const { return "ShaderMaterial"; } -bool ParticlesMaterialConversionPlugin::handles(const Ref &p_resource) const { - Ref mat = p_resource; +bool ParticleProcessMaterialConversionPlugin::handles(const Ref &p_resource) const { + Ref mat = p_resource; return mat.is_valid(); } -Ref ParticlesMaterialConversionPlugin::convert(const Ref &p_resource) const { - Ref mat = p_resource; +Ref ParticleProcessMaterialConversionPlugin::convert(const Ref &p_resource) const { + Ref mat = p_resource; ERR_FAIL_COND_V(!mat.is_valid(), Ref()); Ref smat; diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index fc3da5fd9f..06ae43e6d7 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -122,8 +122,8 @@ public: virtual Ref convert(const Ref &p_resource) const override; }; -class ParticlesMaterialConversionPlugin : public EditorResourceConversionPlugin { - GDCLASS(ParticlesMaterialConversionPlugin, EditorResourceConversionPlugin); +class ParticleProcessMaterialConversionPlugin : public EditorResourceConversionPlugin { + GDCLASS(ParticleProcessMaterialConversionPlugin, EditorResourceConversionPlugin); public: virtual String converts_to() const override; diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index 9e3062d3bc..b78c583c16 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -201,7 +201,7 @@ static const char *gdscript_function_renames[][2] = { // { "set_color", "surface_set_color"}, // ImmediateMesh broke Light2D, Theme, SurfaceTool // { "set_event", "set_shortcut" }, // BaseButton - Cyclic Rename // { "set_extents", "set_size"}, // BoxShape, RectangleShape broke ReflectionProbe - // { "set_flag", "set_particle_flag"}, // ParticlesMaterial broke Window, HingeJoint3D + // { "set_flag", "set_particle_flag"}, // ParticleProcessMaterial broke Window, HingeJoint3D // { "set_h_offset", "set_drag_horizontal_offset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D // { "set_margin", "set_offset" }, // Control broke Shape3D, AtlasTexture // { "set_mode", "set_mode_file_mode" }, // FileDialog broke Panel, Shader, CSGPolygon, Tilemap @@ -610,7 +610,7 @@ static const char *csharp_function_renames[][2] = { // { "SetColor", "SurfaceSetColor"}, // ImmediateMesh broke Light2D, Theme, SurfaceTool // { "SetEvent", "SetShortcut" }, // BaseButton - Cyclic Rename // { "SetExtents", "SetSize"}, // BoxShape, RectangleShape broke ReflectionProbe - // { "SetFlag", "SetParticleFlag"}, // ParticlesMaterial broke Window, HingeJoint3D + // { "SetFlag", "SetParticleFlag"}, // ParticleProcessMaterial broke Window, HingeJoint3D // { "SetHOffset", "SetDragHorizontalOffset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D // { "SetMargin", "SetOffset" }, // Control broke Shape3D, AtlasTexture // { "SetMode", "SetModeFileMode" }, // FileDialog broke Panel, Shader, CSGPolygon, Tilemap @@ -1357,6 +1357,7 @@ static const char *class_renames[][2] = { { "PanoramaSky", "Sky" }, { "Particles", "GPUParticles3D" }, // Be careful, this will be used everywhere { "Particles2D", "GPUParticles2D" }, + { "ParticlesMaterial", "ParticleProcessMaterial" }, { "Path", "Path3D" }, // Be careful, this will be used everywhere { "PathFollow", "PathFollow3D" }, { "PhysicalBone", "PhysicalBone3D" }, diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 40f74d3f50..15d2cdf2a8 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -32,7 +32,7 @@ #include "core/core_string_names.h" #include "scene/2d/gpu_particles_2d.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" void CPUParticles2D::set_emitting(bool p_emitting) { if (emitting == p_emitting) { @@ -890,7 +890,7 @@ void CPUParticles2D::_particles_process(double p_delta) { real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed)); if (orbit_amount != 0.0) { real_t ang = orbit_amount * local_delta * Math_TAU; - // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix, + // Not sure why the ParticleProcessMaterial code uses a clockwise rotation matrix, // but we use -ang here to reproduce its behavior. Transform2D rot = Transform2D(-ang, Vector2()); p.transform[2] -= diff; @@ -1184,7 +1184,7 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) { set_material(mat); } - Ref material = particles->get_process_material(); + Ref material = particles->get_process_material(); if (material.is_null()) { return; } @@ -1205,14 +1205,14 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) { set_color_initial_ramp(gti->get_gradient()); } - set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); + set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); set_emission_shape(EmissionShape(material->get_emission_shape())); set_emission_sphere_radius(material->get_emission_sphere_radius()); Vector2 rect_extents = Vector2(material->get_emission_box_extents().x, material->get_emission_box_extents().y); set_emission_rect_extents(rect_extents); - Ref scale3D = material->get_param_texture(ParticlesMaterial::PARAM_SCALE); + Ref scale3D = material->get_param_texture(ParticleProcessMaterial::PARAM_SCALE); if (scale3D.is_valid()) { split_scale = true; scale_curve_x = scale3D->get_curve_x(); @@ -1222,14 +1222,14 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) { set_gravity(gravity); set_lifetime_randomness(material->get_lifetime_randomness()); -#define CONVERT_PARAM(m_param) \ - set_param_min(m_param, material->get_param_min(ParticlesMaterial::m_param)); \ - { \ - Ref ctex = material->get_param_texture(ParticlesMaterial::m_param); \ - if (ctex.is_valid()) \ - set_param_curve(m_param, ctex->get_curve()); \ - } \ - set_param_max(m_param, material->get_param_max(ParticlesMaterial::m_param)); +#define CONVERT_PARAM(m_param) \ + set_param_min(m_param, material->get_param_min(ParticleProcessMaterial::m_param)); \ + { \ + Ref ctex = material->get_param_texture(ParticleProcessMaterial::m_param); \ + if (ctex.is_valid()) \ + set_param_curve(m_param, ctex->get_curve()); \ + } \ + set_param_max(m_param, material->get_param_max(ParticleProcessMaterial::m_param)); CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY); CONVERT_PARAM(PARAM_ANGULAR_VELOCITY); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index e4354a69e2..65ead7afbc 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -30,7 +30,7 @@ #include "gpu_particles_2d.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" #ifdef TOOLS_ENABLED #include "core/config/engine.h" @@ -123,10 +123,10 @@ void GPUParticles2D::_update_particle_emission_transform() { void GPUParticles2D::set_process_material(const Ref &p_material) { process_material = p_material; - Ref pm = p_material; - if (pm.is_valid() && !pm->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) { + Ref pm = p_material; + if (pm.is_valid() && !pm->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) { // Likely a new (3D) material, modify it to match 2D space - pm->set_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z, true); + pm->set_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z, true); pm->set_gravity(Vector3(0, 98, 0)); } RID material_rid; @@ -308,10 +308,10 @@ TypedArray GPUParticles2D::get_configuration_warnings() const { CanvasItemMaterial *mat = Object::cast_to(get_material().ptr()); if (get_material().is_null() || (mat && !mat->get_particles_animation())) { - const ParticlesMaterial *process = Object::cast_to(process_material.ptr()); + const ParticleProcessMaterial *process = Object::cast_to(process_material.ptr()); if (process && - (process->get_param_max(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 || - process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) { + (process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_OFFSET) != 0.0 || + process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_OFFSET).is_valid())) { warnings.push_back(RTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.")); } } @@ -625,7 +625,7 @@ void GPUParticles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_trail_sections", "get_trail_sections"); ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_section_subdivisions", PROPERTY_HINT_RANGE, "1,1024,1"), "set_trail_section_subdivisions", "get_trail_section_subdivisions"); ADD_GROUP("Process Material", "process_"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticleProcessMaterial"), "set_process_material", "get_process_material"); ADD_GROUP("Textures", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index a79fd15b1a..719dc42f3a 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -33,7 +33,7 @@ #include "scene/3d/camera_3d.h" #include "scene/3d/gpu_particles_3d.h" #include "scene/main/viewport.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" AABB CPUParticles3D::get_aabb() const { return AABB(); @@ -983,7 +983,7 @@ void CPUParticles3D::_particles_process(double p_delta) { real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed)); if (orbit_amount != 0.0) { real_t ang = orbit_amount * local_delta * Math_TAU; - // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix, + // Not sure why the ParticleProcessMaterial code uses a clockwise rotation matrix, // but we use -ang here to reproduce its behavior. Transform2D rot = Transform2D(-ang, Vector2()); Vector2 rotv = rot.basis_xform(Vector2(diff.x, diff.y)); @@ -1343,7 +1343,7 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) { set_draw_order(DrawOrder(particles->get_draw_order())); set_mesh(particles->get_draw_pass_mesh(0)); - Ref material = particles->get_process_material(); + Ref material = particles->get_process_material(); if (material.is_null()) { return; } @@ -1364,14 +1364,14 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) { set_color_initial_ramp(gti->get_gradient()); } - set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); - set_particle_flag(PARTICLE_FLAG_ROTATE_Y, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ROTATE_Y)); - set_particle_flag(PARTICLE_FLAG_DISABLE_Z, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z)); + set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); + set_particle_flag(PARTICLE_FLAG_ROTATE_Y, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ROTATE_Y)); + set_particle_flag(PARTICLE_FLAG_DISABLE_Z, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z)); 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()); - Ref scale3D = material->get_param_texture(ParticlesMaterial::PARAM_SCALE); + Ref scale3D = material->get_param_texture(ParticleProcessMaterial::PARAM_SCALE); if (scale3D.is_valid()) { split_scale = true; scale_curve_x = scale3D->get_curve_x(); @@ -1382,14 +1382,14 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) { set_gravity(material->get_gravity()); set_lifetime_randomness(material->get_lifetime_randomness()); -#define CONVERT_PARAM(m_param) \ - set_param_min(m_param, material->get_param_min(ParticlesMaterial::m_param)); \ - { \ - Ref ctex = material->get_param_texture(ParticlesMaterial::m_param); \ - if (ctex.is_valid()) \ - set_param_curve(m_param, ctex->get_curve()); \ - } \ - set_param_max(m_param, material->get_param_max(ParticlesMaterial::m_param)); +#define CONVERT_PARAM(m_param) \ + set_param_min(m_param, material->get_param_min(ParticleProcessMaterial::m_param)); \ + { \ + Ref ctex = material->get_param_texture(ParticleProcessMaterial::m_param); \ + if (ctex.is_valid()) \ + set_param_curve(m_param, ctex->get_curve()); \ + } \ + set_param_max(m_param, material->get_param_max(ParticleProcessMaterial::m_param)); CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY); CONVERT_PARAM(PARAM_ANGULAR_VELOCITY); diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index b46e6a8b71..bd63939d74 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -30,7 +30,7 @@ #include "gpu_particles_3d.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" AABB GPUParticles3D::get_aabb() const { return AABB(); @@ -306,10 +306,10 @@ TypedArray GPUParticles3D::get_configuration_warnings() const { if (process_material.is_null()) { warnings.push_back(RTR("A material to process the particles is not assigned, so no behavior is imprinted.")); } else { - const ParticlesMaterial *process = Object::cast_to(process_material.ptr()); + const ParticleProcessMaterial *process = Object::cast_to(process_material.ptr()); if (!anim_material_found && process && - (process->get_param_max(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 || - process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) { + (process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_OFFSET) != 0.0 || + process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_OFFSET).is_valid())) { warnings.push_back(RTR("Particles animation requires the usage of a BaseMaterial3D whose Billboard Mode is set to \"Particle Billboard\".")); } } @@ -585,7 +585,7 @@ void GPUParticles3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), "set_trail_length", "get_trail_length"); ADD_GROUP("Process Material", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticleProcessMaterial"), "set_process_material", "get_process_material"); ADD_GROUP("Draw Passes", "draw_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_passes", PROPERTY_HINT_RANGE, "0," + itos(MAX_DRAW_PASSES) + ",1"), "set_draw_passes", "get_draw_passes"); for (int i = 0; i < MAX_DRAW_PASSES; i++) { diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 62573ed3e8..a66b354576 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -162,7 +162,7 @@ #include "scene/resources/multimesh.h" #include "scene/resources/navigation_mesh.h" #include "scene/resources/packed_scene.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" #include "scene/resources/physics_material.h" #include "scene/resources/polygon_path_finder.h" #include "scene/resources/primitive_meshes.h" @@ -761,9 +761,9 @@ void register_scene_types() { /* REGISTER RESOURCES */ GDREGISTER_ABSTRACT_CLASS(Shader); - GDREGISTER_CLASS(ParticlesMaterial); - SceneTree::add_idle_callback(ParticlesMaterial::flush_changes); - ParticlesMaterial::init_shaders(); + GDREGISTER_CLASS(ParticleProcessMaterial); + SceneTree::add_idle_callback(ParticleProcessMaterial::flush_changes); + ParticleProcessMaterial::init_shaders(); GDREGISTER_VIRTUAL_CLASS(Mesh); GDREGISTER_CLASS(ArrayMesh); @@ -1019,6 +1019,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("PanoramaSky", "Sky"); ClassDB::add_compatibility_class("Particles", "GPUParticles3D"); ClassDB::add_compatibility_class("Particles2D", "GPUParticles2D"); + ClassDB::add_compatibility_class("ParticlesMaterial", "ParticleProcessMaterial"); ClassDB::add_compatibility_class("Path", "Path3D"); ClassDB::add_compatibility_class("PathFollow", "PathFollow3D"); ClassDB::add_compatibility_class("PhysicalBone", "PhysicalBone3D"); @@ -1209,7 +1210,7 @@ void unregister_scene_types() { ProceduralSkyMaterial::cleanup_shader(); #endif // _3D_DISABLED - ParticlesMaterial::finish_shaders(); + ParticleProcessMaterial::finish_shaders(); CanvasItemMaterial::finish_shaders(); ColorPicker::finish_shaders(); SceneStringNames::free(); diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp new file mode 100644 index 0000000000..ed19101de4 --- /dev/null +++ b/scene/resources/particle_process_material.cpp @@ -0,0 +1,1895 @@ +/*************************************************************************/ +/* particle_process_material.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "particle_process_material.h" + +#include "core/version.h" + +Mutex ParticleProcessMaterial::material_mutex; +SelfList::List *ParticleProcessMaterial::dirty_materials = nullptr; +HashMap ParticleProcessMaterial::shader_map; +ParticleProcessMaterial::ShaderNames *ParticleProcessMaterial::shader_names = nullptr; + +void ParticleProcessMaterial::init_shaders() { + dirty_materials = memnew(SelfList::List); + + shader_names = memnew(ShaderNames); + + shader_names->direction = "direction"; + shader_names->spread = "spread"; + shader_names->flatness = "flatness"; + shader_names->initial_linear_velocity_min = "initial_linear_velocity_min"; + shader_names->initial_angle_min = "initial_angle_min"; + shader_names->angular_velocity_min = "angular_velocity_min"; + shader_names->orbit_velocity_min = "orbit_velocity_min"; + shader_names->linear_accel_min = "linear_accel_min"; + shader_names->radial_accel_min = "radial_accel_min"; + shader_names->tangent_accel_min = "tangent_accel_min"; + shader_names->damping_min = "damping_min"; + shader_names->scale_min = "scale_min"; + shader_names->hue_variation_min = "hue_variation_min"; + shader_names->anim_speed_min = "anim_speed_min"; + shader_names->anim_offset_min = "anim_offset_min"; + + shader_names->initial_linear_velocity_max = "initial_linear_velocity_max"; + shader_names->initial_angle_max = "initial_angle_max"; + shader_names->angular_velocity_max = "angular_velocity_max"; + shader_names->orbit_velocity_max = "orbit_velocity_max"; + shader_names->linear_accel_max = "linear_accel_max"; + shader_names->radial_accel_max = "radial_accel_max"; + shader_names->tangent_accel_max = "tangent_accel_max"; + shader_names->damping_max = "damping_max"; + shader_names->scale_max = "scale_max"; + shader_names->hue_variation_max = "hue_variation_max"; + shader_names->anim_speed_max = "anim_speed_max"; + shader_names->anim_offset_max = "anim_offset_max"; + + shader_names->angle_texture = "angle_texture"; + shader_names->angular_velocity_texture = "angular_velocity_texture"; + shader_names->orbit_velocity_texture = "orbit_velocity_texture"; + shader_names->linear_accel_texture = "linear_accel_texture"; + shader_names->radial_accel_texture = "radial_accel_texture"; + shader_names->tangent_accel_texture = "tangent_accel_texture"; + shader_names->damping_texture = "damping_texture"; + shader_names->scale_texture = "scale_texture"; + shader_names->hue_variation_texture = "hue_variation_texture"; + shader_names->anim_speed_texture = "anim_speed_texture"; + shader_names->anim_offset_texture = "anim_offset_texture"; + + shader_names->color = "color_value"; + shader_names->color_ramp = "color_ramp"; + shader_names->color_initial_ramp = "color_initial_ramp"; + + shader_names->emission_sphere_radius = "emission_sphere_radius"; + shader_names->emission_box_extents = "emission_box_extents"; + shader_names->emission_texture_point_count = "emission_texture_point_count"; + shader_names->emission_texture_points = "emission_texture_points"; + shader_names->emission_texture_normal = "emission_texture_normal"; + shader_names->emission_texture_color = "emission_texture_color"; + shader_names->emission_ring_axis = "emission_ring_axis"; + shader_names->emission_ring_height = "emission_ring_height"; + shader_names->emission_ring_radius = "emission_ring_radius"; + shader_names->emission_ring_inner_radius = "emission_ring_inner_radius"; + + shader_names->turbulence_enabled = "turbulence_enabled"; + shader_names->turbulence_noise_strength = "turbulence_noise_strength"; + shader_names->turbulence_noise_scale = "turbulence_noise_scale"; + shader_names->turbulence_noise_speed = "turbulence_noise_speed"; + shader_names->turbulence_noise_speed_random = "turbulence_noise_speed_random"; + shader_names->turbulence_influence_over_life = "turbulence_influence_over_life"; + shader_names->turbulence_influence_min = "turbulence_influence_min"; + shader_names->turbulence_influence_max = "turbulence_influence_max"; + shader_names->turbulence_initial_displacement_min = "turbulence_initial_displacement_min"; + shader_names->turbulence_initial_displacement_max = "turbulence_initial_displacement_max"; + + shader_names->gravity = "gravity"; + + shader_names->lifetime_randomness = "lifetime_randomness"; + + shader_names->sub_emitter_frequency = "sub_emitter_frequency"; + shader_names->sub_emitter_amount_at_end = "sub_emitter_amount_at_end"; + shader_names->sub_emitter_keep_velocity = "sub_emitter_keep_velocity"; + + shader_names->collision_friction = "collision_friction"; + shader_names->collision_bounce = "collision_bounce"; +} + +void ParticleProcessMaterial::finish_shaders() { + memdelete(dirty_materials); + dirty_materials = nullptr; + + memdelete(shader_names); +} + +void ParticleProcessMaterial::_update_shader() { + dirty_materials->remove(&element); + + MaterialKey mk = _compute_key(); + if (mk.key == current_key.key) { + return; //no update required in the end + } + + if (shader_map.has(current_key)) { + shader_map[current_key].users--; + if (shader_map[current_key].users == 0) { + //deallocate shader, as it's no longer in use + RS::get_singleton()->free(shader_map[current_key].shader); + shader_map.erase(current_key); + } + } + + current_key = mk; + + if (shader_map.has(mk)) { + RS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader); + shader_map[mk].users++; + return; + } + //must create a shader! + + // Add a comment to describe the shader origin (useful when converting to ShaderMaterial). + String code = "// NOTE: Shader automatically converted from " VERSION_NAME " " VERSION_FULL_CONFIG "'s ParticleProcessMaterial.\n\n"; + + code += "shader_type particles;\n"; + + if (collision_scale) { + code += "render_mode collision_use_scale;\n"; + } + + code += "uniform vec3 direction;\n"; + code += "uniform float spread;\n"; + code += "uniform float flatness;\n"; + code += "uniform float initial_linear_velocity_min;\n"; + code += "uniform float initial_angle_min;\n"; + code += "uniform float angular_velocity_min;\n"; + code += "uniform float orbit_velocity_min;\n"; + code += "uniform float linear_accel_min;\n"; + code += "uniform float radial_accel_min;\n"; + code += "uniform float tangent_accel_min;\n"; + code += "uniform float damping_min;\n"; + code += "uniform float scale_min;\n"; + code += "uniform float hue_variation_min;\n"; + code += "uniform float anim_speed_min;\n"; + code += "uniform float anim_offset_min;\n"; + + code += "uniform float initial_linear_velocity_max;\n"; + code += "uniform float initial_angle_max;\n"; + code += "uniform float angular_velocity_max;\n"; + code += "uniform float orbit_velocity_max;\n"; + code += "uniform float linear_accel_max;\n"; + code += "uniform float radial_accel_max;\n"; + code += "uniform float tangent_accel_max;\n"; + code += "uniform float damping_max;\n"; + code += "uniform float scale_max;\n"; + code += "uniform float hue_variation_max;\n"; + code += "uniform float anim_speed_max;\n"; + code += "uniform float anim_offset_max;\n"; + code += "uniform float lifetime_randomness;\n"; + + switch (emission_shape) { + case EMISSION_SHAPE_POINT: { + //do none + } break; + case EMISSION_SHAPE_SPHERE: { + code += "uniform float emission_sphere_radius;\n"; + } break; + case EMISSION_SHAPE_SPHERE_SURFACE: { + code += "uniform float emission_sphere_radius;\n"; + } break; + case EMISSION_SHAPE_BOX: { + code += "uniform vec3 emission_box_extents;\n"; + } break; + case EMISSION_SHAPE_DIRECTED_POINTS: { + code += "uniform sampler2D emission_texture_normal : hint_default_black;\n"; + [[fallthrough]]; + } + case EMISSION_SHAPE_POINTS: { + code += "uniform sampler2D emission_texture_points : hint_default_black;\n"; + code += "uniform int emission_texture_point_count;\n"; + if (emission_color_texture.is_valid()) { + code += "uniform sampler2D emission_texture_color : hint_default_white;\n"; + } + } break; + case EMISSION_SHAPE_RING: { + code += "uniform vec3 " + shader_names->emission_ring_axis + ";\n"; + code += "uniform float " + shader_names->emission_ring_height + ";\n"; + code += "uniform float " + shader_names->emission_ring_radius + ";\n"; + code += "uniform float " + shader_names->emission_ring_inner_radius + ";\n"; + } break; + case EMISSION_SHAPE_MAX: { // Max value for validity check. + break; + } + } + + if (sub_emitter_mode != SUB_EMITTER_DISABLED) { + if (sub_emitter_mode == SUB_EMITTER_CONSTANT) { + code += "uniform float sub_emitter_frequency;\n"; + } + if (sub_emitter_mode == SUB_EMITTER_AT_END) { + code += "uniform int sub_emitter_amount_at_end;\n"; + } + code += "uniform bool sub_emitter_keep_velocity;\n"; + } + + code += "uniform vec4 color_value : source_color;\n"; + + code += "uniform vec3 gravity;\n"; + + if (color_ramp.is_valid()) { + code += "uniform sampler2D color_ramp : repeat_disable;\n"; + } + + if (color_initial_ramp.is_valid()) { + code += "uniform sampler2D color_initial_ramp : repeat_disable;\n"; + } + + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { + code += "uniform sampler2D linear_velocity_texture : repeat_disable;\n"; + } + if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { + code += "uniform sampler2D orbit_velocity_texture : repeat_disable;\n"; + } + if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { + code += "uniform sampler2D angular_velocity_texture : repeat_disable;\n"; + } + if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) { + code += "uniform sampler2D linear_accel_texture : repeat_disable;\n"; + } + if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) { + code += "uniform sampler2D radial_accel_texture : repeat_disable;\n"; + } + if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { + code += "uniform sampler2D tangent_accel_texture : repeat_disable;\n"; + } + if (tex_parameters[PARAM_DAMPING].is_valid()) { + code += "uniform sampler2D damping_texture : repeat_disable;\n"; + } + if (tex_parameters[PARAM_ANGLE].is_valid()) { + code += "uniform sampler2D angle_texture : repeat_disable;\n"; + } + if (tex_parameters[PARAM_SCALE].is_valid()) { + code += "uniform sampler2D scale_texture : repeat_disable;\n"; + } + if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) { + code += "uniform sampler2D hue_variation_texture : repeat_disable;\n"; + } + if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) { + code += "uniform sampler2D anim_speed_texture : repeat_disable;\n"; + } + if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) { + code += "uniform sampler2D anim_offset_texture : repeat_disable;\n"; + } + + if (collision_mode == COLLISION_RIGID) { + code += "uniform float collision_friction;\n"; + code += "uniform float collision_bounce;\n"; + } + + if (turbulence_enabled) { + code += "uniform float turbulence_noise_strength;\n"; + code += "uniform float turbulence_noise_scale;\n"; + code += "uniform float turbulence_influence_min;\n"; + code += "uniform float turbulence_influence_max;\n"; + code += "uniform float turbulence_initial_displacement_min;\n"; + code += "uniform float turbulence_initial_displacement_max;\n"; + code += "uniform float turbulence_noise_speed_random;\n"; + code += "uniform vec3 turbulence_noise_speed = vec3(1.0, 1.0, 1.0);\n"; + if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) { + code += "uniform sampler2D turbulence_influence_over_life;\n"; + } + if (turbulence_color_ramp.is_valid()) { + code += "uniform sampler2D turbulence_color_ramp;\n"; + } + code += "\n"; + + //functions for 3D noise / turbulence + code += "\n\n"; + code += "// 3D Noise with friendly permission by Inigo Quilez\n"; + code += "vec3 hash_noise( vec3 p ) {\n"; + code += " p *= mat3(vec3(127.1, 311.7, -53.7), vec3(269.5, 183.3, 77.1), vec3(-301.7, 27.3, 215.3));\n"; + code += " return 2.0 * fract(fract(p)*4375.55) -1.;\n"; + code += "}\n"; + code += "\n"; + code += "float noise( vec3 p) {\n"; + code += " vec3 i = floor(p);;\n"; + code += " vec3 f = fract(p);\n "; + code += " vec3 u = f * f * (3.0 - 2.0 * f);\n"; + code += "\n"; + code += " return 2.0*mix( mix( mix( dot( hash_noise( i + vec3(0.0,0.0,0.0) ), f - vec3(0.0,0.0,0.0) ), dot( hash_noise( i + vec3(1.0,0.0,0.0) ), f - vec3(1.0,0.0,0.0) ), u.x),\n"; + code += " mix( dot( hash_noise( i + vec3(0.0,1.0,0.0) ), f - vec3(0.0,1.0,0.0) ), dot( hash_noise( i + vec3(1.0,1.0,0.0) ), f - vec3(1.0,1.0,0.0) ), u.x), u.y),\n"; + code += " mix( mix( dot( hash_noise( i + vec3(0.0,0.0,1.0) ), f - vec3(0.0,0.0,1.0) ), dot( hash_noise( i + vec3(1.0,0.0,1.0) ), f - vec3(1.0,0.0,1.0) ), u.x),\n"; + code += " mix( dot( hash_noise( i + vec3(0.0,1.0,1.0) ), f - vec3(0.0,1.0,1.0) ), dot( hash_noise( i + vec3(1.0,1.0,1.0) ), f - vec3(1.0,1.0,1.0) ), u.x), u.y), u.z);\n"; + code += "}\n\n"; + code += "// Curl 3D and noise_3d function with friendly permission by Isaac Cohen\n"; + code += "vec3 noise_3d(vec3 p) {\n"; + code += " float s = noise(p);\n"; + code += " float s1 = noise(vec3(p.y - 19.1, p.z + 33.4, p.x + 47.2));\n"; + code += " float s2 = noise(vec3(p.z + 74.2, p.x - 124.5, p.y + 99.4));\n"; + code += " vec3 c = vec3(s, s1, s2);\n"; + code += " return c;\n"; + code += "}\n\n"; + code += "vec3 curl_3d(vec3 p, float c) {\n"; + code += " float epsilon = 0.001 + c;\n"; + code += " vec3 dx = vec3(epsilon, 0.0, 0.0);\n"; + code += " vec3 dy = vec3(0.0, epsilon, 0.0);\n"; + code += " vec3 dz = vec3(0.0, 0.0, epsilon);\n"; + code += " vec3 x0 = noise_3d(p - dx).xyz;\n"; + code += " vec3 x1 = noise_3d(p + dx).xyz;\n"; + code += " vec3 y0 = noise_3d(p - dy).xyz;\n"; + code += " vec3 y1 = noise_3d(p + dy).xyz;\n"; + code += " vec3 z0 = noise_3d(p - dz).xyz;\n"; + code += " vec3 z1 = noise_3d(p + dz).xyz;\n"; + code += " float x = y1.z - y0.z - z1.y + z0.y;\n"; + code += " float y = z1.x - z0.x - x1.z + x0.z;\n"; + code += " float z = x1.y - x0.y - y1.x + y0.x;\n"; + code += " float divisor = 1.0 / (2.0 * epsilon);\n"; + code += " return vec3(normalize(vec3(x, y, z) * divisor));\n"; + code += "}\n"; + code += "vec3 get_noise_direction(vec3 pos, vec3 emission_pos, vec3 time_noise) {\n"; + code += " float adj_contrast = max((turbulence_noise_strength - 1.0), 0.0) * 70.0;\n"; + code += " vec3 noise_time = (vec3(TIME) * turbulence_noise_speed) + time_noise;\n"; + code += " vec3 noise_pos = (pos * turbulence_noise_scale) - emission_pos;\n"; + code += " vec3 diff = pos - emission_pos;\n"; + code += " vec3 noise_direction = curl_3d(noise_pos + noise_time - diff, adj_contrast);\n"; + code += " noise_direction = mix(0.9 * noise_direction, noise_direction, turbulence_noise_strength - 9.0);\n"; + code += " return noise_direction;\n"; + code += "}\n"; + } + + //need a random function + code += "\n\n"; + code += "float rand_from_seed(inout uint seed) {\n"; + code += " int k;\n"; + code += " int s = int(seed);\n"; + code += " if (s == 0)\n"; + code += " s = 305420679;\n"; + code += " k = s / 127773;\n"; + code += " s = 16807 * (s - k * 127773) - 2836 * k;\n"; + code += " if (s < 0)\n"; + code += " s += 2147483647;\n"; + code += " seed = uint(s);\n"; + code += " return float(seed % uint(65536)) / 65535.0;\n"; + code += "}\n"; + code += "\n"; + + code += "float rand_from_seed_m1_p1(inout uint seed) {\n"; + code += " return rand_from_seed(seed) * 2.0 - 1.0;\n"; + code += "}\n"; + code += "\n"; + + //improve seed quality + code += "uint hash(uint x) {\n"; + code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; + code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; + code += " x = (x >> uint(16)) ^ x;\n"; + code += " return x;\n"; + code += "}\n"; + code += "\n"; + + code += "void start() {\n"; + code += " uint base_number = NUMBER;\n"; + code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n"; + code += " float angle_rand = rand_from_seed(alt_seed);\n"; + code += " float scale_rand = rand_from_seed(alt_seed);\n"; + code += " float hue_rot_rand = rand_from_seed(alt_seed);\n"; + code += " float anim_offset_rand = rand_from_seed(alt_seed);\n"; + if (color_initial_ramp.is_valid()) { + code += " float color_initial_rand = rand_from_seed(alt_seed);\n"; + } + code += " float pi = 3.14159;\n"; + code += " float degree_to_rad = pi / 180.0;\n"; + code += "\n"; + + if (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { + code += " int point = min(emission_texture_point_count - 1, int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n"; + code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n"; + code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n"; + } + if (tex_parameters[PARAM_ANGLE].is_valid()) { + code += " float tex_angle = textureLod(angle_texture, vec2(0.0, 0.0), 0.0).r;\n"; + } else { + code += " float tex_angle = 0.0;\n"; + } + + if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) { + code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(0.0, 0.0), 0.0).r;\n"; + } else { + code += " float tex_anim_offset = 1.0;\n"; + } + + code += " float spread_rad = spread * degree_to_rad;\n"; + + code += " if (RESTART_VELOCITY) {\n"; + + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { + code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n"; + } else { + code += " float tex_linear_velocity = 1.0;\n"; + } + + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + code += " {\n"; + code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; + code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n"; + code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n"; + code += " VELOCITY = rot * mix(initial_linear_velocity_min,initial_linear_velocity_max, rand_from_seed(alt_seed));\n"; + code += " }\n"; + + } else { + //initiate velocity spread in 3D + code += " {\n"; + code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; + code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n"; + code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n"; + code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n"; + code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n"; + code += " vec3 spread_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; + code += " vec3 direction_nrm = length(direction) > 0.0 ? normalize(direction) : vec3(0.0, 0.0, 1.0);\n"; + code += " // rotate spread to direction\n"; + code += " vec3 binormal = cross(vec3(0.0, 1.0, 0.0), direction_nrm);\n"; + code += " if (length(binormal) < 0.0001) {\n"; + code += " // direction is parallel to Y. Choose Z as the binormal.\n"; + code += " binormal = vec3(0.0, 0.0, 1.0);\n"; + code += " }\n"; + code += " binormal = normalize(binormal);\n"; + code += " vec3 normal = cross(binormal, direction_nrm);\n"; + code += " spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;\n"; + code += " VELOCITY = spread_direction * mix(initial_linear_velocity_min, initial_linear_velocity_max,rand_from_seed(alt_seed));\n"; + code += " }\n"; + } + code += " }\n"; + + code += " float base_angle = (tex_angle) * mix(initial_angle_min, initial_angle_max, angle_rand);\n"; + code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle + code += " CUSTOM.y = 0.0;\n"; // phase + code += " CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n"; + code += " CUSTOM.z = (tex_anim_offset) * mix(anim_offset_min, anim_offset_max, anim_offset_rand);\n"; // animation offset (0-1) + + code += " if (RESTART_POSITION) {\n"; + + switch (emission_shape) { + case EMISSION_SHAPE_POINT: { + //do none, identity (will later be multiplied by emission transform) + code += " TRANSFORM = mat4(vec4(1,0,0,0),vec4(0,1,0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n"; + } break; + case EMISSION_SHAPE_SPHERE: { + code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n"; + code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n"; + code += " float p = rand_from_seed(alt_seed);\n"; + code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n"; + code += " TRANSFORM[3].xyz = mix(vec3(0.0, 0.0, 0.0), vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s), p);\n"; + } break; + case EMISSION_SHAPE_SPHERE_SURFACE: { + code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n"; + code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n"; + code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n"; + code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n"; + } break; + case EMISSION_SHAPE_BOX: { + code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n"; + } break; + case EMISSION_SHAPE_POINTS: + case EMISSION_SHAPE_DIRECTED_POINTS: { + code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n"; + + if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + code += " {\n"; + code += " mat2 rotm;"; + code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n"; + code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n"; + code += " if (RESTART_VELOCITY) VELOCITY.xy = rotm * VELOCITY.xy;\n"; + code += " }\n"; + } else { + code += " {\n"; + code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n"; + code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n"; + code += " vec3 tangent = normalize(cross(v0, normal));\n"; + code += " vec3 bitangent = normalize(cross(tangent, normal));\n"; + code += " if (RESTART_VELOCITY) VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n"; + code += " }\n"; + } + } + } break; + case EMISSION_SHAPE_RING: { + code += " float ring_spawn_angle = rand_from_seed(alt_seed) * 2.0 * pi;\n"; + code += " float ring_random_radius = rand_from_seed(alt_seed) * (emission_ring_radius - emission_ring_inner_radius) + emission_ring_inner_radius;\n"; + code += " vec3 axis = normalize(emission_ring_axis);\n"; + code += " vec3 ortho_axis = vec3(0.0);\n"; + code += " if (axis == vec3(1.0, 0.0, 0.0)) {\n"; + code += " ortho_axis = cross(axis, vec3(0.0, 1.0, 0.0));\n"; + code += " } else {\n"; + code += " ortho_axis = cross(axis, vec3(1.0, 0.0, 0.0));\n"; + code += " }\n"; + code += " ortho_axis = normalize(ortho_axis);\n"; + code += " float s = sin(ring_spawn_angle);\n"; + code += " float c = cos(ring_spawn_angle);\n"; + code += " float oc = 1.0 - c;\n"; + code += " ortho_axis = mat3(\n"; + code += " vec3(c + axis.x * axis.x * oc, axis.x * axis.y * oc - axis.z * s, axis.x * axis.z *oc + axis.y * s),\n"; + code += " vec3(axis.x * axis.y * oc + s * axis.z, c + axis.y * axis.y * oc, axis.y * axis.z * oc - axis.x * s),\n"; + code += " vec3(axis.z * axis.x * oc - axis.y * s, axis.z * axis.y * oc + axis.x * s, c + axis.z * axis.z * oc)\n"; + code += " ) * ortho_axis;\n"; + code += " ortho_axis = normalize(ortho_axis);\n"; + code += " TRANSFORM[3].xyz = ortho_axis * ring_random_radius + (rand_from_seed(alt_seed) * emission_ring_height - emission_ring_height / 2.0) * axis;\n"; + } break; + case EMISSION_SHAPE_MAX: { // Max value for validity check. + break; + } + } + code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; + // Apply noise/turbulence: initial displacement. + if (turbulence_enabled) { + if (get_turbulence_noise_speed_random() >= 0.0) { + code += " vec3 time_noise = noise_3d( vec3(TIME) * turbulence_noise_speed_random ) * -turbulence_noise_speed;\n"; + } else { + code += " const vec3 time_noise = vec3(0.0);\n"; + } + code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz, EMISSION_TRANSFORM[3].xyz, time_noise);\n"; + code += " float turb_init_displacement = mix(turbulence_initial_displacement_min, turbulence_initial_displacement_max, rand_from_seed(alt_seed));"; + code += " TRANSFORM[3].xyz += noise_direction * turb_init_displacement;\n"; + } + code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + code += " VELOCITY.z = 0.0;\n"; + code += " TRANSFORM[3].z = 0.0;\n"; + } + code += " }\n"; + code += "}\n\n"; + + code += "void process() {\n"; + code += " uint base_number = NUMBER;\n"; + code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n"; + code += " float angle_rand = rand_from_seed(alt_seed);\n"; + code += " float scale_rand = rand_from_seed(alt_seed);\n"; + code += " float hue_rot_rand = rand_from_seed(alt_seed);\n"; + code += " float anim_offset_rand = rand_from_seed(alt_seed);\n"; + if (color_initial_ramp.is_valid()) { + code += " float color_initial_rand = rand_from_seed(alt_seed);\n"; + } + code += " float pi = 3.14159;\n"; + code += " float degree_to_rad = pi / 180.0;\n"; + code += "\n"; + + if (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { + code += " int point = min(emission_texture_point_count - 1, int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n"; + code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n"; + code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n"; + } + + code += " CUSTOM.y += DELTA / LIFETIME;\n"; + code += " float tv = CUSTOM.y / CUSTOM.w;\n"; + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { + code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " float tex_linear_velocity = 1.0;\n"; + } + + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { + code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " float tex_orbit_velocity = 1.0;\n"; + } + } + + if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { + code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " float tex_angular_velocity = 1.0;\n"; + } + + if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) { + code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " float tex_linear_accel = 1.0;\n"; + } + + if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) { + code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " float tex_radial_accel = 1.0;\n"; + } + + if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { + code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " float tex_tangent_accel = 1.0;\n"; + } + + if (tex_parameters[PARAM_DAMPING].is_valid()) { + code += " float tex_damping = textureLod(damping_texture, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " float tex_damping = 1.0;\n"; + } + + if (tex_parameters[PARAM_ANGLE].is_valid()) { + code += " float tex_angle = textureLod(angle_texture, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " float tex_angle = 1.0;\n"; + } + + if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) { + code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " float tex_anim_speed = 1.0;\n"; + } + + if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) { + code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " float tex_anim_offset = 1.0;\n"; + } + + code += " vec3 force = gravity;\n"; + code += " vec3 pos = TRANSFORM[3].xyz;\n"; + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + code += " pos.z = 0.0;\n"; + } + code += " // apply linear acceleration\n"; + code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * tex_linear_accel * mix(linear_accel_min, linear_accel_max, rand_from_seed(alt_seed)) : vec3(0.0);\n"; + code += " // apply radial acceleration\n"; + code += " vec3 org = EMISSION_TRANSFORM[3].xyz;\n"; + code += " vec3 diff = pos - org;\n"; + code += " force += length(diff) > 0.0 ? normalize(diff) * tex_radial_accel * mix(radial_accel_min, radial_accel_max, rand_from_seed(alt_seed)) : vec3(0.0);\n"; + code += " // apply tangential acceleration;\n"; + code += " float tangent_accel_val = tex_tangent_accel * mix(tangent_accel_min, tangent_accel_max, rand_from_seed(alt_seed));\n"; + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * tangent_accel_val : vec3(0.0);\n"; + + } else { + code += " vec3 crossDiff = cross(normalize(diff), normalize(gravity));\n"; + code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * tangent_accel_val : vec3(0.0);\n"; + } + if (attractor_interaction_enabled) { + code += " force += ATTRACTOR_FORCE;\n\n"; + } + + code += " // apply attractor forces\n"; + code += " VELOCITY += force * DELTA;\n"; + + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { + code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n"; + } + + // Apply noise/turbulence. + if (turbulence_enabled) { + code += " // apply turbulence\n"; + if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) { + code += " float turbulence_influence = textureLod(turbulence_influence_over_life, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " const float turbulence_influence = 1.0;\n"; + } + code += " \n"; + if (get_turbulence_noise_speed_random() >= 0.0) { + code += " vec3 time_noise = noise_3d( vec3(TIME) * turbulence_noise_speed_random ) * -turbulence_noise_speed;\n"; + } else { + code += " const vec3 time_noise = vec3(0.0);\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. + // We don't need this check when the collision mode is "hide on contact", + // as the particle will be hidden anyway. + String extra_tab = ""; + if (collision_mode != COLLISION_RIGID) { + code += " if (!COLLIDED) {\n"; + extra_tab = " "; + } + code += extra_tab + " \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 + " VELOCITY = mix(VELOCITY, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n"; + if (collision_mode != COLLISION_RIGID) { + code += " }"; + } + } + code += " \n"; + code += " // orbit velocity\n"; + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + code += " float orbit_amount = tex_orbit_velocity * mix(orbit_velocity_min, orbit_velocity_max, rand_from_seed(alt_seed));\n"; + code += " if (orbit_amount != 0.0) {\n"; + code += " float ang = orbit_amount * DELTA * pi * 2.0;\n"; + code += " mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang)));\n"; + code += " TRANSFORM[3].xy -= diff.xy;\n"; + code += " TRANSFORM[3].xy += rot * diff.xy;\n"; + code += " }\n"; + } + + code += " float dmp = mix(damping_min, damping_max, rand_from_seed(alt_seed));\n"; + code += " if (dmp * tex_damping > 0.0) {\n"; + code += " float v = length(VELOCITY);\n"; + code += " float damp = tex_damping * dmp;\n"; + code += " v -= damp * DELTA;\n"; + code += " if (v < 0.0) {\n"; + code += " VELOCITY = vec3(0.0);\n"; + code += " } else {\n"; + code += " VELOCITY = normalize(VELOCITY) * v;\n"; + code += " }\n"; + code += " }\n"; + code += " float base_angle = (tex_angle) * mix(initial_angle_min, initial_angle_max, rand_from_seed(alt_seed));\n"; + code += " base_angle += CUSTOM.y * LIFETIME * (tex_angular_velocity) * mix(angular_velocity_min,angular_velocity_max, rand_from_seed(alt_seed));\n"; + code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle + code += " CUSTOM.z = (tex_anim_offset) * mix(anim_offset_min, anim_offset_max, rand_from_seed(alt_seed)) + tv * tex_anim_speed * mix(anim_speed_min, anim_speed_max, rand_from_seed(alt_seed));\n"; // angle + + // apply color + // apply hue rotation + if (tex_parameters[PARAM_SCALE].is_valid()) { + code += " vec3 tex_scale = textureLod(scale_texture, vec2(tv, 0.0), 0.0).rgb;\n"; + } else { + code += " vec3 tex_scale = vec3(1.0);\n"; + } + + if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) { + code += " float tex_hue_variation = textureLod(hue_variation_texture, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " float tex_hue_variation = 1.0;\n"; + } + + code += " float hue_rot_angle = (tex_hue_variation) * pi * 2.0 * mix(hue_variation_min, hue_variation_max, rand_from_seed(alt_seed));\n"; + code += " float hue_rot_c = cos(hue_rot_angle);\n"; + code += " float hue_rot_s = sin(hue_rot_angle);\n"; + code += " mat4 hue_rot_mat = mat4(vec4(0.299, 0.587, 0.114, 0.0),\n"; + code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; + code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; + code += " vec4(0.000, 0.000, 0.000, 1.0)) +\n"; + code += " mat4(vec4(0.701, -0.587, -0.114, 0.0),\n"; + code += " vec4(-0.299, 0.413, -0.114, 0.0),\n"; + code += " vec4(-0.300, -0.588, 0.886, 0.0),\n"; + code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_c +\n"; + code += " mat4(vec4(0.168, 0.330, -0.497, 0.0),\n"; + code += " vec4(-0.328, 0.035, 0.292, 0.0),\n"; + code += " vec4(1.250, -1.050, -0.203, 0.0),\n"; + code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_s;\n"; + if (color_ramp.is_valid()) { + code += " COLOR = hue_rot_mat * textureLod(color_ramp, vec2(tv, 0.0), 0.0) * color_value;\n"; + } else { + code += " COLOR = hue_rot_mat * color_value;\n"; + } + + if (color_initial_ramp.is_valid()) { + code += " vec4 start_color = textureLod(color_initial_ramp, vec2(color_initial_rand, 0.0), 0.0);\n"; + code += " COLOR *= start_color;\n"; + } + + if (emission_color_texture.is_valid() && (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS)) { + code += " COLOR *= texelFetch(emission_texture_color, emission_tex_ofs, 0);\n"; + } + code += "\n"; + + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { + code += " if (length(VELOCITY) > 0.0) {\n"; + code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n"; + code += " } else {\n"; + code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n"; + code += " }\n"; + code += " TRANSFORM[0].xyz = normalize(cross(TRANSFORM[1].xyz, TRANSFORM[2].xyz));\n"; + code += " TRANSFORM[2] = vec4(0.0, 0.0, 1.0, 0.0);\n"; + } else { + code += " TRANSFORM[0] = vec4(cos(CUSTOM.x), -sin(CUSTOM.x), 0.0, 0.0);\n"; + code += " TRANSFORM[1] = vec4(sin(CUSTOM.x), cos(CUSTOM.x), 0.0, 0.0);\n"; + code += " TRANSFORM[2] = vec4(0.0, 0.0, 1.0, 0.0);\n"; + } + + } else { + // orient particle Y towards velocity + if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { + code += " if (length(VELOCITY) > 0.0) {\n"; + code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n"; + code += " } else {\n"; + code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n"; + code += " }\n"; + code += " if (TRANSFORM[1].xyz == normalize(TRANSFORM[0].xyz)) {\n"; + code += " TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz), normalize(TRANSFORM[2].xyz)));\n"; + code += " TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz), normalize(TRANSFORM[1].xyz)));\n"; + code += " } else {\n"; + code += " TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz), normalize(TRANSFORM[1].xyz)));\n"; + code += " TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz), normalize(TRANSFORM[2].xyz)));\n"; + code += " }\n"; + } else { + code += " TRANSFORM[0].xyz = normalize(TRANSFORM[0].xyz);\n"; + code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n"; + code += " TRANSFORM[2].xyz = normalize(TRANSFORM[2].xyz);\n"; + } + // turn particle by rotation in Y + if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) { + code += " vec4 origin = TRANSFORM[3];\n"; + code += " TRANSFORM = mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; + code += " TRANSFORM[3] = origin;\n"; + } + } + + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + code += " TRANSFORM[3].z = 0.0;\n"; + } + + if (collision_mode == COLLISION_RIGID) { + code += " if (COLLIDED) {\n"; + code += " if (length(VELOCITY) > 3.0) {\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),clamp(collision_friction, 0.0, 1.0));\n"; + code += " } else {\n"; + code += " VELOCITY = vec3(0.0);\n"; + // If turbulence is enabled, set the noise direction to up so the turbulence color is "neutral" + if (turbulence_enabled) { + code += " noise_direction = vec3(1.0, 0.0, 0.0);\n"; + } + code += " }\n"; + code += " }\n"; + } + + // scale by scale + code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n"; + code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n"; + code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 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"; + + 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) { + code += " int emit_count = 0;\n"; + switch (sub_emitter_mode) { + case SUB_EMITTER_CONSTANT: { + code += " float interval_from = CUSTOM.y * LIFETIME - DELTA;\n"; + code += " float interval_rem = sub_emitter_frequency - mod(interval_from,sub_emitter_frequency);\n"; + code += " if (DELTA >= interval_rem) emit_count = 1;\n"; + } break; + case SUB_EMITTER_AT_COLLISION: { + code += " if (COLLIDED) emit_count = 1;\n"; + } break; + case SUB_EMITTER_AT_END: { + code += " float unit_delta = DELTA/LIFETIME;\n"; + code += " float end_time = CUSTOM.w * 0.95;\n"; // if we do at the end we might miss it, as it can just get deactivated by emitter + code += " if (CUSTOM.y < end_time && (CUSTOM.y + unit_delta) >= end_time) emit_count = sub_emitter_amount_at_end;\n"; + } break; + default: { + } + } + code += " for(int i=0;ishader_create(); + shader_data.users = 1; + + RS::get_singleton()->shader_set_code(shader_data.shader, code); + + shader_map[mk] = shader_data; + + RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader); +} + +void ParticleProcessMaterial::flush_changes() { + MutexLock lock(material_mutex); + + while (dirty_materials->first()) { + dirty_materials->first()->self()->_update_shader(); + } +} + +void ParticleProcessMaterial::_queue_shader_change() { + MutexLock lock(material_mutex); + + if (is_initialized && !element.in_list()) { + dirty_materials->add(&element); + } +} + +bool ParticleProcessMaterial::_is_shader_dirty() const { + MutexLock lock(material_mutex); + + return element.in_list(); +} + +void ParticleProcessMaterial::set_direction(Vector3 p_direction) { + direction = p_direction; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->direction, direction); +} + +Vector3 ParticleProcessMaterial::get_direction() const { + return direction; +} + +void ParticleProcessMaterial::set_spread(float p_spread) { + spread = p_spread; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread); +} + +float ParticleProcessMaterial::get_spread() const { + return spread; +} + +void ParticleProcessMaterial::set_flatness(float p_flatness) { + flatness = p_flatness; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness); +} + +float ParticleProcessMaterial::get_flatness() const { + return flatness; +} + +void ParticleProcessMaterial::set_param_min(Parameter p_param, float p_value) { + ERR_FAIL_INDEX(p_param, PARAM_MAX); + + params_min[p_param] = p_value; + if (params_min[p_param] > params_max[p_param]) { + set_param_max(p_param, p_value); + } + + switch (p_param) { + case PARAM_INITIAL_LINEAR_VELOCITY: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_min, p_value); + } break; + case PARAM_ANGULAR_VELOCITY: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_min, p_value); + } break; + case PARAM_ORBIT_VELOCITY: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_min, p_value); + } break; + case PARAM_LINEAR_ACCEL: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_min, p_value); + } break; + case PARAM_RADIAL_ACCEL: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_min, p_value); + } break; + case PARAM_TANGENTIAL_ACCEL: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_min, p_value); + } break; + case PARAM_DAMPING: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_min, p_value); + } break; + case PARAM_ANGLE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_min, p_value); + } break; + case PARAM_SCALE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_min, p_value); + } break; + case PARAM_HUE_VARIATION: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_min, p_value); + } break; + case PARAM_ANIM_SPEED: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_min, p_value); + } break; + case PARAM_ANIM_OFFSET: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_min, p_value); + } break; + case PARAM_TURB_VEL_INFLUENCE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_min, p_value); + } break; + case PARAM_TURB_INIT_DISPLACEMENT: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_initial_displacement_min, p_value); + } break; + case PARAM_TURB_INFLUENCE_OVER_LIFE: { + // Can't happen, but silences warning + } break; + case PARAM_MAX: + break; // Can't happen, but silences warning + } +} + +float ParticleProcessMaterial::get_param_min(Parameter p_param) const { + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); + + return params_min[p_param]; +} + +void ParticleProcessMaterial::set_param_max(Parameter p_param, float p_value) { + ERR_FAIL_INDEX(p_param, PARAM_MAX); + + params_max[p_param] = p_value; + if (params_min[p_param] > params_max[p_param]) { + set_param_min(p_param, p_value); + } + + switch (p_param) { + case PARAM_INITIAL_LINEAR_VELOCITY: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_max, p_value); + } break; + case PARAM_ANGULAR_VELOCITY: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_max, p_value); + } break; + case PARAM_ORBIT_VELOCITY: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_max, p_value); + } break; + case PARAM_LINEAR_ACCEL: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_max, p_value); + } break; + case PARAM_RADIAL_ACCEL: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_max, p_value); + } break; + case PARAM_TANGENTIAL_ACCEL: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_max, p_value); + } break; + case PARAM_DAMPING: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_max, p_value); + } break; + case PARAM_ANGLE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_max, p_value); + } break; + case PARAM_SCALE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_max, p_value); + } break; + case PARAM_HUE_VARIATION: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_max, p_value); + } break; + case PARAM_ANIM_SPEED: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_max, p_value); + } break; + case PARAM_ANIM_OFFSET: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_max, p_value); + } break; + case PARAM_TURB_VEL_INFLUENCE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_max, p_value); + } break; + case PARAM_TURB_INIT_DISPLACEMENT: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_initial_displacement_max, p_value); + } break; + case PARAM_TURB_INFLUENCE_OVER_LIFE: { + // Can't happen, but silences warning + } break; + case PARAM_MAX: + break; // Can't happen, but silences warning + } +} + +float ParticleProcessMaterial::get_param_max(Parameter p_param) const { + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); + + return params_max[p_param]; +} + +static void _adjust_curve_range(const Ref &p_texture, float p_min, float p_max) { + Ref curve_tex = p_texture; + if (!curve_tex.is_valid()) { + return; + } + + curve_tex->ensure_default_setup(p_min, p_max); +} + +void ParticleProcessMaterial::set_param_texture(Parameter p_param, const Ref &p_texture) { + ERR_FAIL_INDEX(p_param, PARAM_MAX); + + tex_parameters[p_param] = p_texture; + + RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + + switch (p_param) { + case PARAM_INITIAL_LINEAR_VELOCITY: { + //do none for this one + } break; + case PARAM_ANGULAR_VELOCITY: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, tex_rid); + _adjust_curve_range(p_texture, -360, 360); + } break; + case PARAM_ORBIT_VELOCITY: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, tex_rid); + _adjust_curve_range(p_texture, -500, 500); + } break; + case PARAM_LINEAR_ACCEL: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, tex_rid); + _adjust_curve_range(p_texture, -200, 200); + } break; + case PARAM_RADIAL_ACCEL: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, tex_rid); + _adjust_curve_range(p_texture, -200, 200); + } break; + case PARAM_TANGENTIAL_ACCEL: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, tex_rid); + _adjust_curve_range(p_texture, -200, 200); + } break; + case PARAM_DAMPING: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, tex_rid); + _adjust_curve_range(p_texture, 0, 100); + } break; + case PARAM_ANGLE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, tex_rid); + _adjust_curve_range(p_texture, -360, 360); + } break; + case PARAM_SCALE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, tex_rid); + _adjust_curve_range(p_texture, 0, 1); + } break; + case PARAM_HUE_VARIATION: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, tex_rid); + _adjust_curve_range(p_texture, -1, 1); + } break; + case PARAM_ANIM_SPEED: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, tex_rid); + _adjust_curve_range(p_texture, 0, 200); + } break; + case PARAM_ANIM_OFFSET: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, tex_rid); + } break; + case PARAM_TURB_INFLUENCE_OVER_LIFE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_over_life, tex_rid); + _adjust_curve_range(p_texture, 0, 1); + } break; + case PARAM_TURB_VEL_INFLUENCE: { + // Can't happen, but silences warning + } break; + case PARAM_TURB_INIT_DISPLACEMENT: { + // Can't happen, but silences warning + } break; + case PARAM_MAX: + break; // Can't happen, but silences warning + } + + _queue_shader_change(); +} + +Ref ParticleProcessMaterial::get_param_texture(Parameter p_param) const { + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref()); + + return tex_parameters[p_param]; +} + +void ParticleProcessMaterial::set_color(const Color &p_color) { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color); + color = p_color; +} + +Color ParticleProcessMaterial::get_color() const { + return color; +} + +void ParticleProcessMaterial::set_color_ramp(const Ref &p_texture) { + color_ramp = p_texture; + RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, tex_rid); + _queue_shader_change(); + notify_property_list_changed(); +} + +Ref ParticleProcessMaterial::get_color_ramp() const { + return color_ramp; +} + +void ParticleProcessMaterial::set_color_initial_ramp(const Ref &p_texture) { + color_initial_ramp = p_texture; + RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_initial_ramp, tex_rid); + _queue_shader_change(); + notify_property_list_changed(); +} + +Ref ParticleProcessMaterial::get_color_initial_ramp() const { + return color_initial_ramp; +} + +void ParticleProcessMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) { + ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX); + particle_flags[p_particle_flag] = p_enable; + _queue_shader_change(); + if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) { + notify_property_list_changed(); + } +} + +bool ParticleProcessMaterial::get_particle_flag(ParticleFlags p_particle_flag) const { + ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false); + return particle_flags[p_particle_flag]; +} + +void ParticleProcessMaterial::set_emission_shape(EmissionShape p_shape) { + ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX); + emission_shape = p_shape; + notify_property_list_changed(); + _queue_shader_change(); +} + +void ParticleProcessMaterial::set_emission_sphere_radius(real_t p_radius) { + emission_sphere_radius = p_radius; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius); +} + +void ParticleProcessMaterial::set_emission_box_extents(Vector3 p_extents) { + emission_box_extents = p_extents; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents); +} + +void ParticleProcessMaterial::set_emission_point_texture(const Ref &p_points) { + emission_point_texture = p_points; + RID tex_rid = p_points.is_valid() ? p_points->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, tex_rid); +} + +void ParticleProcessMaterial::set_emission_normal_texture(const Ref &p_normals) { + emission_normal_texture = p_normals; + RID tex_rid = p_normals.is_valid() ? p_normals->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, tex_rid); +} + +void ParticleProcessMaterial::set_emission_color_texture(const Ref &p_colors) { + emission_color_texture = p_colors; + RID tex_rid = p_colors.is_valid() ? p_colors->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, tex_rid); + _queue_shader_change(); +} + +void ParticleProcessMaterial::set_emission_point_count(int p_count) { + emission_point_count = p_count; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count); +} + +void ParticleProcessMaterial::set_emission_ring_axis(Vector3 p_axis) { + emission_ring_axis = p_axis; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_axis, p_axis); +} + +void ParticleProcessMaterial::set_emission_ring_height(real_t p_height) { + emission_ring_height = p_height; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_height, p_height); +} + +void ParticleProcessMaterial::set_emission_ring_radius(real_t p_radius) { + emission_ring_radius = p_radius; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_radius, p_radius); +} + +void ParticleProcessMaterial::set_emission_ring_inner_radius(real_t p_radius) { + emission_ring_inner_radius = p_radius; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_inner_radius, p_radius); +} + +ParticleProcessMaterial::EmissionShape ParticleProcessMaterial::get_emission_shape() const { + return emission_shape; +} + +real_t ParticleProcessMaterial::get_emission_sphere_radius() const { + return emission_sphere_radius; +} + +Vector3 ParticleProcessMaterial::get_emission_box_extents() const { + return emission_box_extents; +} + +Ref ParticleProcessMaterial::get_emission_point_texture() const { + return emission_point_texture; +} + +Ref ParticleProcessMaterial::get_emission_normal_texture() const { + return emission_normal_texture; +} + +Ref ParticleProcessMaterial::get_emission_color_texture() const { + return emission_color_texture; +} + +int ParticleProcessMaterial::get_emission_point_count() const { + return emission_point_count; +} + +Vector3 ParticleProcessMaterial::get_emission_ring_axis() const { + return emission_ring_axis; +} + +real_t ParticleProcessMaterial::get_emission_ring_height() const { + return emission_ring_height; +} + +real_t ParticleProcessMaterial::get_emission_ring_radius() const { + return emission_ring_radius; +} + +real_t ParticleProcessMaterial::get_emission_ring_inner_radius() const { + return emission_ring_inner_radius; +} + +void ParticleProcessMaterial::set_turbulence_enabled(const bool p_turbulence_enabled) { + turbulence_enabled = p_turbulence_enabled; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_enabled, turbulence_enabled); + _queue_shader_change(); + notify_property_list_changed(); +} + +bool ParticleProcessMaterial::get_turbulence_enabled() const { + return turbulence_enabled; +} + +void ParticleProcessMaterial::set_turbulence_noise_strength(float p_turbulence_noise_strength) { + turbulence_noise_strength = p_turbulence_noise_strength; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_strength, p_turbulence_noise_strength); +} + +float ParticleProcessMaterial::get_turbulence_noise_strength() const { + return turbulence_noise_strength; +} + +void ParticleProcessMaterial::set_turbulence_noise_scale(float p_turbulence_noise_scale) { + turbulence_noise_scale = p_turbulence_noise_scale; + float shader_turbulence_noise_scale = (pow(p_turbulence_noise_scale, 0.25) * 5.6234 / 10.0) * 4.0 - 3.0; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_scale, shader_turbulence_noise_scale); +} + +float ParticleProcessMaterial::get_turbulence_noise_scale() const { + return turbulence_noise_scale; +} + +void ParticleProcessMaterial::set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random) { + turbulence_noise_speed_random = p_turbulence_noise_speed_random; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed_random, p_turbulence_noise_speed_random); +} + +float ParticleProcessMaterial::get_turbulence_noise_speed_random() const { + return turbulence_noise_speed_random; +} + +void ParticleProcessMaterial::set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed) { + turbulence_noise_speed = p_turbulence_noise_speed; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed, turbulence_noise_speed); +} + +Vector3 ParticleProcessMaterial::get_turbulence_noise_speed() const { + return turbulence_noise_speed; +} + +void ParticleProcessMaterial::set_gravity(const Vector3 &p_gravity) { + gravity = p_gravity; + Vector3 gset = gravity; + if (gset == Vector3()) { + gset = Vector3(0, -0.000001, 0); //as gravity is used as upvector in some calculations + } + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->gravity, gset); +} + +Vector3 ParticleProcessMaterial::get_gravity() const { + return gravity; +} + +void ParticleProcessMaterial::set_lifetime_randomness(double p_lifetime) { + lifetime_randomness = p_lifetime; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->lifetime_randomness, lifetime_randomness); +} + +double ParticleProcessMaterial::get_lifetime_randomness() const { + return lifetime_randomness; +} + +RID ParticleProcessMaterial::get_shader_rid() const { + ERR_FAIL_COND_V(!shader_map.has(current_key), RID()); + return shader_map[current_key].shader; +} + +void ParticleProcessMaterial::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (p_property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture") && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (p_property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (p_property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (p_property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (p_property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (p_property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (!turbulence_enabled) { + if (p_property.name == "turbulence_noise_strength" || + p_property.name == "turbulence_noise_scale" || + p_property.name == "turbulence_noise_speed" || + p_property.name == "turbulence_noise_speed_random" || + p_property.name == "turbulence_influence_over_life" || + p_property.name == "turbulence_influence_min" || + p_property.name == "turbulence_influence_max" || + p_property.name == "turbulence_initial_displacement_min" || + p_property.name == "turbulence_initial_displacement_max") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } + } + + if (p_property.name == "collision_friction" && collision_mode != COLLISION_RIGID) { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (p_property.name == "collision_bounce" && collision_mode != COLLISION_RIGID) { + p_property.usage = PROPERTY_USAGE_NONE; + } +} + +void ParticleProcessMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) { + sub_emitter_mode = p_sub_emitter_mode; + _queue_shader_change(); + notify_property_list_changed(); +} + +ParticleProcessMaterial::SubEmitterMode ParticleProcessMaterial::get_sub_emitter_mode() const { + return sub_emitter_mode; +} + +void ParticleProcessMaterial::set_sub_emitter_frequency(double p_frequency) { + sub_emitter_frequency = p_frequency; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pass delta instead of frequency, since its easier to compute +} + +double ParticleProcessMaterial::get_sub_emitter_frequency() const { + return sub_emitter_frequency; +} + +void ParticleProcessMaterial::set_sub_emitter_amount_at_end(int p_amount) { + sub_emitter_amount_at_end = p_amount; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_end, p_amount); +} + +int ParticleProcessMaterial::get_sub_emitter_amount_at_end() const { + return sub_emitter_amount_at_end; +} + +void ParticleProcessMaterial::set_sub_emitter_keep_velocity(bool p_enable) { + sub_emitter_keep_velocity = p_enable; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable); +} +bool ParticleProcessMaterial::get_sub_emitter_keep_velocity() const { + return sub_emitter_keep_velocity; +} + +void ParticleProcessMaterial::set_attractor_interaction_enabled(bool p_enable) { + attractor_interaction_enabled = p_enable; + _queue_shader_change(); +} + +bool ParticleProcessMaterial::is_attractor_interaction_enabled() const { + return attractor_interaction_enabled; +} + +void ParticleProcessMaterial::set_collision_mode(CollisionMode p_collision_mode) { + collision_mode = p_collision_mode; + _queue_shader_change(); + notify_property_list_changed(); +} + +ParticleProcessMaterial::CollisionMode ParticleProcessMaterial::get_collision_mode() const { + return collision_mode; +} + +void ParticleProcessMaterial::set_collision_use_scale(bool p_scale) { + collision_scale = p_scale; + _queue_shader_change(); +} + +bool ParticleProcessMaterial::is_collision_using_scale() const { + return collision_scale; +} + +void ParticleProcessMaterial::set_collision_friction(float p_friction) { + collision_friction = p_friction; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_friction, p_friction); +} + +float ParticleProcessMaterial::get_collision_friction() const { + return collision_friction; +} + +void ParticleProcessMaterial::set_collision_bounce(float p_bounce) { + collision_bounce = p_bounce; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_bounce, p_bounce); +} + +float ParticleProcessMaterial::get_collision_bounce() const { + return collision_bounce; +} + +Shader::Mode ParticleProcessMaterial::get_shader_mode() const { + return Shader::MODE_PARTICLES; +} + +void ParticleProcessMaterial::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_direction", "degrees"), &ParticleProcessMaterial::set_direction); + ClassDB::bind_method(D_METHOD("get_direction"), &ParticleProcessMaterial::get_direction); + + ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticleProcessMaterial::set_spread); + ClassDB::bind_method(D_METHOD("get_spread"), &ParticleProcessMaterial::get_spread); + + ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticleProcessMaterial::set_flatness); + ClassDB::bind_method(D_METHOD("get_flatness"), &ParticleProcessMaterial::get_flatness); + + ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &ParticleProcessMaterial::set_param_min); + ClassDB::bind_method(D_METHOD("get_param_min", "param"), &ParticleProcessMaterial::get_param_min); + + ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &ParticleProcessMaterial::set_param_max); + ClassDB::bind_method(D_METHOD("get_param_max", "param"), &ParticleProcessMaterial::get_param_max); + + ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticleProcessMaterial::set_param_texture); + ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticleProcessMaterial::get_param_texture); + + ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticleProcessMaterial::set_color); + ClassDB::bind_method(D_METHOD("get_color"), &ParticleProcessMaterial::get_color); + + ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticleProcessMaterial::set_color_ramp); + ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticleProcessMaterial::get_color_ramp); + + ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &ParticleProcessMaterial::set_color_initial_ramp); + ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &ParticleProcessMaterial::get_color_initial_ramp); + + ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &ParticleProcessMaterial::set_particle_flag); + ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &ParticleProcessMaterial::get_particle_flag); + + ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticleProcessMaterial::set_emission_shape); + ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticleProcessMaterial::get_emission_shape); + + ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticleProcessMaterial::set_emission_sphere_radius); + ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticleProcessMaterial::get_emission_sphere_radius); + + ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticleProcessMaterial::set_emission_box_extents); + ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticleProcessMaterial::get_emission_box_extents); + + ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture"), &ParticleProcessMaterial::set_emission_point_texture); + ClassDB::bind_method(D_METHOD("get_emission_point_texture"), &ParticleProcessMaterial::get_emission_point_texture); + + ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture"), &ParticleProcessMaterial::set_emission_normal_texture); + ClassDB::bind_method(D_METHOD("get_emission_normal_texture"), &ParticleProcessMaterial::get_emission_normal_texture); + + ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture"), &ParticleProcessMaterial::set_emission_color_texture); + ClassDB::bind_method(D_METHOD("get_emission_color_texture"), &ParticleProcessMaterial::get_emission_color_texture); + + ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticleProcessMaterial::set_emission_point_count); + ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticleProcessMaterial::get_emission_point_count); + + ClassDB::bind_method(D_METHOD("set_emission_ring_axis", "axis"), &ParticleProcessMaterial::set_emission_ring_axis); + ClassDB::bind_method(D_METHOD("get_emission_ring_axis"), &ParticleProcessMaterial::get_emission_ring_axis); + + ClassDB::bind_method(D_METHOD("set_emission_ring_height", "height"), &ParticleProcessMaterial::set_emission_ring_height); + ClassDB::bind_method(D_METHOD("get_emission_ring_height"), &ParticleProcessMaterial::get_emission_ring_height); + + ClassDB::bind_method(D_METHOD("set_emission_ring_radius", "radius"), &ParticleProcessMaterial::set_emission_ring_radius); + ClassDB::bind_method(D_METHOD("get_emission_ring_radius"), &ParticleProcessMaterial::get_emission_ring_radius); + + ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &ParticleProcessMaterial::set_emission_ring_inner_radius); + ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &ParticleProcessMaterial::get_emission_ring_inner_radius); + + ClassDB::bind_method(D_METHOD("get_turbulence_enabled"), &ParticleProcessMaterial::get_turbulence_enabled); + ClassDB::bind_method(D_METHOD("set_turbulence_enabled", "turbulence_enabled"), &ParticleProcessMaterial::set_turbulence_enabled); + + ClassDB::bind_method(D_METHOD("get_turbulence_noise_strength"), &ParticleProcessMaterial::get_turbulence_noise_strength); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_strength", "turbulence_noise_strength"), &ParticleProcessMaterial::set_turbulence_noise_strength); + + ClassDB::bind_method(D_METHOD("get_turbulence_noise_scale"), &ParticleProcessMaterial::get_turbulence_noise_scale); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_scale", "turbulence_noise_scale"), &ParticleProcessMaterial::set_turbulence_noise_scale); + + ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed_random"), &ParticleProcessMaterial::get_turbulence_noise_speed_random); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed_random", "turbulence_noise_speed_random"), &ParticleProcessMaterial::set_turbulence_noise_speed_random); + + ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed"), &ParticleProcessMaterial::get_turbulence_noise_speed); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed", "turbulence_noise_speed"), &ParticleProcessMaterial::set_turbulence_noise_speed); + + ClassDB::bind_method(D_METHOD("get_gravity"), &ParticleProcessMaterial::get_gravity); + ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticleProcessMaterial::set_gravity); + + ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "randomness"), &ParticleProcessMaterial::set_lifetime_randomness); + ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &ParticleProcessMaterial::get_lifetime_randomness); + + ClassDB::bind_method(D_METHOD("get_sub_emitter_mode"), &ParticleProcessMaterial::get_sub_emitter_mode); + ClassDB::bind_method(D_METHOD("set_sub_emitter_mode", "mode"), &ParticleProcessMaterial::set_sub_emitter_mode); + + ClassDB::bind_method(D_METHOD("get_sub_emitter_frequency"), &ParticleProcessMaterial::get_sub_emitter_frequency); + ClassDB::bind_method(D_METHOD("set_sub_emitter_frequency", "hz"), &ParticleProcessMaterial::set_sub_emitter_frequency); + + ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticleProcessMaterial::get_sub_emitter_amount_at_end); + ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_end); + + ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticleProcessMaterial::get_sub_emitter_keep_velocity); + ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticleProcessMaterial::set_sub_emitter_keep_velocity); + + ClassDB::bind_method(D_METHOD("set_attractor_interaction_enabled", "enabled"), &ParticleProcessMaterial::set_attractor_interaction_enabled); + ClassDB::bind_method(D_METHOD("is_attractor_interaction_enabled"), &ParticleProcessMaterial::is_attractor_interaction_enabled); + + ClassDB::bind_method(D_METHOD("set_collision_mode", "mode"), &ParticleProcessMaterial::set_collision_mode); + ClassDB::bind_method(D_METHOD("get_collision_mode"), &ParticleProcessMaterial::get_collision_mode); + + ClassDB::bind_method(D_METHOD("set_collision_use_scale", "radius"), &ParticleProcessMaterial::set_collision_use_scale); + ClassDB::bind_method(D_METHOD("is_collision_using_scale"), &ParticleProcessMaterial::is_collision_using_scale); + + ClassDB::bind_method(D_METHOD("set_collision_friction", "friction"), &ParticleProcessMaterial::set_collision_friction); + ClassDB::bind_method(D_METHOD("get_collision_friction"), &ParticleProcessMaterial::get_collision_friction); + + ClassDB::bind_method(D_METHOD("set_collision_bounce", "bounce"), &ParticleProcessMaterial::set_collision_bounce); + ClassDB::bind_method(D_METHOD("get_collision_bounce"), &ParticleProcessMaterial::get_collision_bounce); + + ADD_GROUP("Time", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness"); + + ADD_GROUP("Emission Shape", "emission_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Sphere Surface,Box,Points,Directed Points,Ring"), "set_emission_shape", "get_emission_shape"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,or_greater"), "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::OBJECT, "emission_point_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_point_texture", "get_emission_point_texture"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_normal_texture", "get_emission_normal_texture"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_color_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_color_texture", "get_emission_color_texture"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_ring_axis"), "set_emission_ring_axis", "get_emission_ring_axis"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_height"), "set_emission_ring_height", "get_emission_ring_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_radius"), "set_emission_ring_radius", "get_emission_ring_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_inner_radius"), "set_emission_ring_inner_radius", "get_emission_ring_inner_radius"); + ADD_GROUP("Particle Flags", "particle_flag_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z); + ADD_GROUP("Direction", ""); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness"); + ADD_GROUP("Gravity", ""); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity"); + ADD_GROUP("Initial Velocity", "initial_"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY); + ADD_GROUP("Angular Velocity", "angular_"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY); + ADD_GROUP("Orbit Velocity", "orbit_"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY); + ADD_GROUP("Linear Accel", "linear_"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL); + ADD_GROUP("Radial Accel", "radial_"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL); + ADD_GROUP("Tangential Accel", "tangential_"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL); + ADD_GROUP("Damping", ""); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING); + ADD_GROUP("Angle", ""); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE); + ADD_GROUP("Scale", ""); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_SCALE); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture,CurveXYZTexture"), "set_param_texture", "get_param_texture", PARAM_SCALE); + ADD_GROUP("Color", ""); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture1D"), "set_color_ramp", "get_color_ramp"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_initial_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture1D"), "set_color_initial_ramp", "get_color_initial_ramp"); + + ADD_GROUP("Hue Variation", "hue_"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION); + + ADD_GROUP("Turbulence", "turbulence_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "turbulence_enabled"), "set_turbulence_enabled", "get_turbulence_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_strength", PROPERTY_HINT_RANGE, "0,20,0.01"), "set_turbulence_noise_strength", "get_turbulence_noise_strength"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_scale", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_turbulence_noise_scale", "get_turbulence_noise_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "turbulence_noise_speed"), "set_turbulence_noise_speed", "get_turbulence_noise_speed"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_speed_random", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_turbulence_noise_speed_random", "get_turbulence_noise_speed_random"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_influence_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_TURB_VEL_INFLUENCE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_influence_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_TURB_VEL_INFLUENCE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_initial_displacement_min", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_param_min", "get_param_min", PARAM_TURB_INIT_DISPLACEMENT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_initial_displacement_max", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_param_max", "get_param_max", PARAM_TURB_INIT_DISPLACEMENT); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "turbulence_influence_over_life", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TURB_INFLUENCE_OVER_LIFE); + + ADD_GROUP("Animation", "anim_"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET); + + ADD_GROUP("Sub Emitter", "sub_emitter_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,At End,At Collision"), "set_sub_emitter_mode", "get_sub_emitter_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:Hz"), "set_sub_emitter_frequency", "get_sub_emitter_frequency"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity"); + + ADD_GROUP("Attractor Interaction", "attractor_interaction_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "attractor_interaction_enabled"), "set_attractor_interaction_enabled", "is_attractor_interaction_enabled"); + ADD_GROUP("Collision", "collision_"); + 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_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"); + + BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY); + BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY); + BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL); + BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL); + BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL); + BIND_ENUM_CONSTANT(PARAM_DAMPING); + BIND_ENUM_CONSTANT(PARAM_ANGLE); + BIND_ENUM_CONSTANT(PARAM_SCALE); + BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION); + BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED); + BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET); + BIND_ENUM_CONSTANT(PARAM_MAX); + + BIND_ENUM_CONSTANT(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX); + + BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE_SURFACE); + 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); + + BIND_ENUM_CONSTANT(PARAM_TURB_VEL_INFLUENCE); + BIND_ENUM_CONSTANT(PARAM_TURB_INIT_DISPLACEMENT); + BIND_ENUM_CONSTANT(PARAM_TURB_INFLUENCE_OVER_LIFE); + + BIND_ENUM_CONSTANT(SUB_EMITTER_DISABLED); + BIND_ENUM_CONSTANT(SUB_EMITTER_CONSTANT); + BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END); + BIND_ENUM_CONSTANT(SUB_EMITTER_AT_COLLISION); + 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); +} + +ParticleProcessMaterial::ParticleProcessMaterial() : + element(this) { + set_direction(Vector3(1, 0, 0)); + set_spread(45); + set_flatness(0); + set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0); + set_param_min(PARAM_ANGULAR_VELOCITY, 0); + set_param_min(PARAM_ORBIT_VELOCITY, 0); + set_param_min(PARAM_LINEAR_ACCEL, 0); + set_param_min(PARAM_RADIAL_ACCEL, 0); + set_param_min(PARAM_TANGENTIAL_ACCEL, 0); + set_param_min(PARAM_DAMPING, 0); + set_param_min(PARAM_ANGLE, 0); + set_param_min(PARAM_SCALE, 1); + set_param_min(PARAM_HUE_VARIATION, 0); + set_param_min(PARAM_ANIM_SPEED, 0); + set_param_min(PARAM_ANIM_OFFSET, 0); + set_param_max(PARAM_INITIAL_LINEAR_VELOCITY, 0); + set_param_max(PARAM_ANGULAR_VELOCITY, 0); + set_param_max(PARAM_ORBIT_VELOCITY, 0); + set_param_max(PARAM_LINEAR_ACCEL, 0); + set_param_max(PARAM_RADIAL_ACCEL, 0); + set_param_max(PARAM_TANGENTIAL_ACCEL, 0); + set_param_max(PARAM_DAMPING, 0); + set_param_max(PARAM_ANGLE, 0); + set_param_max(PARAM_SCALE, 1); + set_param_max(PARAM_HUE_VARIATION, 0); + set_param_max(PARAM_ANIM_SPEED, 0); + set_param_max(PARAM_ANIM_OFFSET, 0); + set_emission_shape(EMISSION_SHAPE_POINT); + set_emission_sphere_radius(1); + set_emission_box_extents(Vector3(1, 1, 1)); + set_emission_ring_axis(Vector3(0, 0, 1.0)); + set_emission_ring_height(1); + set_emission_ring_radius(1); + set_emission_ring_inner_radius(0); + + set_turbulence_enabled(false); + set_turbulence_noise_speed(Vector3(0.5, 0.5, 0.5)); + set_turbulence_noise_strength(1); + set_turbulence_noise_scale(9); + set_turbulence_noise_speed_random(0); + set_param_min(PARAM_TURB_VEL_INFLUENCE, 0.1); + set_param_max(PARAM_TURB_VEL_INFLUENCE, 0.1); + set_param_min(PARAM_TURB_INIT_DISPLACEMENT, 0.0); + set_param_max(PARAM_TURB_INIT_DISPLACEMENT, 0.0); + + set_gravity(Vector3(0, -9.8, 0)); + set_lifetime_randomness(0); + + set_sub_emitter_mode(SUB_EMITTER_DISABLED); + set_sub_emitter_frequency(4); + set_sub_emitter_amount_at_end(1); + set_sub_emitter_keep_velocity(false); + + set_attractor_interaction_enabled(true); + set_collision_mode(COLLISION_DISABLED); + set_collision_bounce(0.0); + set_collision_friction(0.0); + set_collision_use_scale(false); + + for (int i = 0; i < PARTICLE_FLAG_MAX; i++) { + particle_flags[i] = false; + } + + set_color(Color(1, 1, 1, 1)); + + current_key.invalid_key = 1; + + is_initialized = true; + _queue_shader_change(); +} + +ParticleProcessMaterial::~ParticleProcessMaterial() { + MutexLock lock(material_mutex); + + if (shader_map.has(current_key)) { + shader_map[current_key].users--; + if (shader_map[current_key].users == 0) { + //deallocate shader, as it's no longer in use + RS::get_singleton()->free(shader_map[current_key].shader); + shader_map.erase(current_key); + } + + RS::get_singleton()->material_set_shader(_get_material(), RID()); + } +} diff --git a/scene/resources/particle_process_material.h b/scene/resources/particle_process_material.h new file mode 100644 index 0000000000..fe4741d6e5 --- /dev/null +++ b/scene/resources/particle_process_material.h @@ -0,0 +1,438 @@ +/*************************************************************************/ +/* particle_process_material.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "core/templates/rid.h" +#include "scene/resources/material.h" + +#ifndef PARTICLE_PROCESS_MATERIAL_H +#define PARTICLE_PROCESS_MATERIAL_H + +/* + TODO: +-Path following +-Emitter positions deformable by bones +-Proper trails +*/ + +class ParticleProcessMaterial : public Material { + GDCLASS(ParticleProcessMaterial, Material); + +public: + enum Parameter { + PARAM_INITIAL_LINEAR_VELOCITY, + PARAM_ANGULAR_VELOCITY, + PARAM_ORBIT_VELOCITY, + PARAM_LINEAR_ACCEL, + PARAM_RADIAL_ACCEL, + PARAM_TANGENTIAL_ACCEL, + PARAM_DAMPING, + PARAM_ANGLE, + PARAM_SCALE, + PARAM_HUE_VARIATION, + PARAM_ANIM_SPEED, + PARAM_ANIM_OFFSET, + PARAM_TURB_INFLUENCE_OVER_LIFE, + PARAM_TURB_VEL_INFLUENCE, + PARAM_TURB_INIT_DISPLACEMENT, + PARAM_MAX + }; + + // When extending, make sure not to overflow the size of the MaterialKey below. + enum ParticleFlags { + PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, + PARTICLE_FLAG_ROTATE_Y, + PARTICLE_FLAG_DISABLE_Z, + PARTICLE_FLAG_MAX + }; + + // When extending, make sure not to overflow the size of the MaterialKey below. + enum EmissionShape { + EMISSION_SHAPE_POINT, + EMISSION_SHAPE_SPHERE, + EMISSION_SHAPE_SPHERE_SURFACE, + EMISSION_SHAPE_BOX, + EMISSION_SHAPE_POINTS, + EMISSION_SHAPE_DIRECTED_POINTS, + EMISSION_SHAPE_RING, + EMISSION_SHAPE_MAX + }; + + // When extending, make sure not to overflow the size of the MaterialKey below. + enum SubEmitterMode { + SUB_EMITTER_DISABLED, + SUB_EMITTER_CONSTANT, + SUB_EMITTER_AT_END, + SUB_EMITTER_AT_COLLISION, + 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: + union MaterialKey { + // The bit size of the struct must be kept below or equal to 32 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 key = 0; + + static uint32_t hash(const MaterialKey &p_key) { + return hash_murmur3_one_32(p_key.key); + } + + bool operator==(const MaterialKey &p_key) const { + return key == p_key.key; + } + + bool operator<(const MaterialKey &p_key) const { + return key < p_key.key; + } + }; + + struct ShaderData { + RID shader; + int users = 0; + }; + + static HashMap shader_map; + + MaterialKey current_key; + + _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; + mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid(); + mk.sub_emitter = sub_emitter_mode; + mk.collision_mode = collision_mode; + mk.attractor_enabled = attractor_interaction_enabled; + mk.collision_scale = collision_scale; + mk.turbulence_enabled = turbulence_enabled; + + return mk; + } + + static Mutex material_mutex; + static SelfList::List *dirty_materials; + + struct ShaderNames { + StringName direction; + StringName spread; + StringName flatness; + StringName initial_linear_velocity_min; + StringName initial_angle_min; + StringName angular_velocity_min; + StringName orbit_velocity_min; + StringName linear_accel_min; + StringName radial_accel_min; + StringName tangent_accel_min; + StringName damping_min; + StringName scale_min; + StringName hue_variation_min; + StringName anim_speed_min; + StringName anim_offset_min; + + StringName initial_linear_velocity_max; + StringName initial_angle_max; + StringName angular_velocity_max; + StringName orbit_velocity_max; + StringName linear_accel_max; + StringName radial_accel_max; + StringName tangent_accel_max; + StringName damping_max; + StringName scale_max; + StringName hue_variation_max; + StringName anim_speed_max; + StringName anim_offset_max; + + StringName angle_texture; + StringName angular_velocity_texture; + StringName orbit_velocity_texture; + StringName linear_accel_texture; + StringName radial_accel_texture; + StringName tangent_accel_texture; + StringName damping_texture; + StringName scale_texture; + StringName hue_variation_texture; + StringName anim_speed_texture; + StringName anim_offset_texture; + + StringName color; + StringName color_ramp; + StringName color_initial_ramp; + + StringName emission_sphere_radius; + StringName emission_box_extents; + StringName emission_texture_point_count; + StringName emission_texture_points; + StringName emission_texture_normal; + StringName emission_texture_color; + StringName emission_ring_axis; + StringName emission_ring_height; + StringName emission_ring_radius; + StringName emission_ring_inner_radius; + + StringName turbulence_enabled; + StringName turbulence_noise_strength; + StringName turbulence_noise_scale; + StringName turbulence_noise_speed; + StringName turbulence_noise_speed_random; + StringName turbulence_influence_over_life; + StringName turbulence_influence_min; + StringName turbulence_influence_max; + StringName turbulence_initial_displacement_min; + StringName turbulence_initial_displacement_max; + + StringName gravity; + + StringName lifetime_randomness; + + StringName sub_emitter_frequency; + StringName sub_emitter_amount_at_end; + StringName sub_emitter_keep_velocity; + + StringName collision_friction; + StringName collision_bounce; + }; + + static ShaderNames *shader_names; + + SelfList element; + + void _update_shader(); + _FORCE_INLINE_ void _queue_shader_change(); + _FORCE_INLINE_ bool _is_shader_dirty() const; + + bool is_initialized = false; + Vector3 direction; + float spread = 0.0f; + float flatness = 0.0f; + + float params_min[PARAM_MAX]; + float params_max[PARAM_MAX]; + float params[PARAM_MAX]; + + Ref tex_parameters[PARAM_MAX]; + Color color; + Ref color_ramp; + Ref color_initial_ramp; + + bool particle_flags[PARTICLE_FLAG_MAX]; + + EmissionShape emission_shape; + float emission_sphere_radius = 0.0f; + Vector3 emission_box_extents; + Ref emission_point_texture; + Ref emission_normal_texture; + Ref emission_color_texture; + Vector3 emission_ring_axis; + real_t emission_ring_height = 0.0f; + real_t emission_ring_radius = 0.0f; + real_t emission_ring_inner_radius = 0.0f; + int emission_point_count = 1; + + bool anim_loop = false; + + bool turbulence_enabled; + Vector3 turbulence_noise_speed; + Ref turbulence_color_ramp; + float turbulence_noise_strength = 0.0f; + float turbulence_noise_scale = 0.0f; + float turbulence_noise_speed_random = 0.0f; + + Vector3 gravity; + + double lifetime_randomness = 0.0; + + SubEmitterMode sub_emitter_mode; + double sub_emitter_frequency = 0.0; + int sub_emitter_amount_at_end = 0; + bool sub_emitter_keep_velocity = false; + //do not save emission points here + + bool attractor_interaction_enabled = false; + CollisionMode collision_mode; + bool collision_scale = false; + float collision_friction = 0.0f; + float collision_bounce = 0.0f; + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &p_property) const; + +public: + void set_direction(Vector3 p_direction); + Vector3 get_direction() const; + + void set_spread(float p_spread); + float get_spread() const; + + void set_flatness(float p_flatness); + float get_flatness() const; + + void set_param_min(Parameter p_param, float p_value); + float get_param_min(Parameter p_param) const; + + void set_param_max(Parameter p_param, float p_value); + float get_param_max(Parameter p_param) const; + + void set_param_texture(Parameter p_param, const Ref &p_texture); + Ref get_param_texture(Parameter p_param) const; + + void set_color(const Color &p_color); + Color get_color() const; + + void set_color_ramp(const Ref &p_texture); + Ref get_color_ramp() const; + + void set_color_initial_ramp(const Ref &p_texture); + Ref get_color_initial_ramp() const; + + void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable); + bool get_particle_flag(ParticleFlags p_particle_flag) const; + + void set_emission_shape(EmissionShape p_shape); + void set_emission_sphere_radius(real_t p_radius); + void set_emission_box_extents(Vector3 p_extents); + void set_emission_point_texture(const Ref &p_points); + void set_emission_normal_texture(const Ref &p_normals); + void set_emission_color_texture(const Ref &p_colors); + void set_emission_ring_axis(Vector3 p_axis); + void set_emission_ring_height(real_t p_height); + void set_emission_ring_radius(real_t p_radius); + void set_emission_ring_inner_radius(real_t p_radius); + void set_emission_point_count(int p_count); + + EmissionShape get_emission_shape() const; + real_t get_emission_sphere_radius() const; + Vector3 get_emission_box_extents() const; + Ref get_emission_point_texture() const; + Ref get_emission_normal_texture() const; + Ref get_emission_color_texture() const; + Vector3 get_emission_ring_axis() const; + real_t get_emission_ring_height() const; + real_t get_emission_ring_radius() const; + real_t get_emission_ring_inner_radius() const; + int get_emission_point_count() const; + + void set_turbulence_enabled(bool p_turbulence_enabled); + void set_turbulence_noise_strength(float p_turbulence_noise_strength); + void set_turbulence_noise_scale(float p_turbulence_noise_scale); + void set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random); + void set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed); + + bool get_turbulence_enabled() const; + float get_turbulence_noise_strength() const; + float get_turbulence_noise_scale() const; + float get_turbulence_noise_speed_random() const; + Vector3 get_turbulence_noise_speed() const; + + void set_gravity(const Vector3 &p_gravity); + Vector3 get_gravity() const; + + void set_lifetime_randomness(double p_lifetime); + double get_lifetime_randomness() const; + + void set_attractor_interaction_enabled(bool p_enable); + bool is_attractor_interaction_enabled() const; + + void set_collision_mode(CollisionMode p_collision_mode); + CollisionMode get_collision_mode() const; + + void set_collision_use_scale(bool p_scale); + bool is_collision_using_scale() const; + + void set_collision_friction(float p_friction); + float get_collision_friction() const; + + void set_collision_bounce(float p_bounce); + float get_collision_bounce() const; + + static void init_shaders(); + static void finish_shaders(); + static void flush_changes(); + + void set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode); + SubEmitterMode get_sub_emitter_mode() const; + + void set_sub_emitter_frequency(double p_frequency); + double get_sub_emitter_frequency() const; + + void set_sub_emitter_amount_at_end(int p_amount); + int get_sub_emitter_amount_at_end() const; + + void set_sub_emitter_keep_velocity(bool p_enable); + bool get_sub_emitter_keep_velocity() const; + + virtual RID get_shader_rid() const override; + + virtual Shader::Mode get_shader_mode() const override; + + ParticleProcessMaterial(); + ~ParticleProcessMaterial(); +}; + +VARIANT_ENUM_CAST(ParticleProcessMaterial::Parameter) +VARIANT_ENUM_CAST(ParticleProcessMaterial::ParticleFlags) +VARIANT_ENUM_CAST(ParticleProcessMaterial::EmissionShape) +VARIANT_ENUM_CAST(ParticleProcessMaterial::SubEmitterMode) +VARIANT_ENUM_CAST(ParticleProcessMaterial::CollisionMode) + +#endif // PARTICLE_PROCESS_MATERIAL_H diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp deleted file mode 100644 index 29a06622a3..0000000000 --- a/scene/resources/particles_material.cpp +++ /dev/null @@ -1,1895 +0,0 @@ -/*************************************************************************/ -/* particles_material.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "particles_material.h" - -#include "core/version.h" - -Mutex ParticlesMaterial::material_mutex; -SelfList::List *ParticlesMaterial::dirty_materials = nullptr; -HashMap ParticlesMaterial::shader_map; -ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = nullptr; - -void ParticlesMaterial::init_shaders() { - dirty_materials = memnew(SelfList::List); - - shader_names = memnew(ShaderNames); - - shader_names->direction = "direction"; - shader_names->spread = "spread"; - shader_names->flatness = "flatness"; - shader_names->initial_linear_velocity_min = "initial_linear_velocity_min"; - shader_names->initial_angle_min = "initial_angle_min"; - shader_names->angular_velocity_min = "angular_velocity_min"; - shader_names->orbit_velocity_min = "orbit_velocity_min"; - shader_names->linear_accel_min = "linear_accel_min"; - shader_names->radial_accel_min = "radial_accel_min"; - shader_names->tangent_accel_min = "tangent_accel_min"; - shader_names->damping_min = "damping_min"; - shader_names->scale_min = "scale_min"; - shader_names->hue_variation_min = "hue_variation_min"; - shader_names->anim_speed_min = "anim_speed_min"; - shader_names->anim_offset_min = "anim_offset_min"; - - shader_names->initial_linear_velocity_max = "initial_linear_velocity_max"; - shader_names->initial_angle_max = "initial_angle_max"; - shader_names->angular_velocity_max = "angular_velocity_max"; - shader_names->orbit_velocity_max = "orbit_velocity_max"; - shader_names->linear_accel_max = "linear_accel_max"; - shader_names->radial_accel_max = "radial_accel_max"; - shader_names->tangent_accel_max = "tangent_accel_max"; - shader_names->damping_max = "damping_max"; - shader_names->scale_max = "scale_max"; - shader_names->hue_variation_max = "hue_variation_max"; - shader_names->anim_speed_max = "anim_speed_max"; - shader_names->anim_offset_max = "anim_offset_max"; - - shader_names->angle_texture = "angle_texture"; - shader_names->angular_velocity_texture = "angular_velocity_texture"; - shader_names->orbit_velocity_texture = "orbit_velocity_texture"; - shader_names->linear_accel_texture = "linear_accel_texture"; - shader_names->radial_accel_texture = "radial_accel_texture"; - shader_names->tangent_accel_texture = "tangent_accel_texture"; - shader_names->damping_texture = "damping_texture"; - shader_names->scale_texture = "scale_texture"; - shader_names->hue_variation_texture = "hue_variation_texture"; - shader_names->anim_speed_texture = "anim_speed_texture"; - shader_names->anim_offset_texture = "anim_offset_texture"; - - shader_names->color = "color_value"; - shader_names->color_ramp = "color_ramp"; - shader_names->color_initial_ramp = "color_initial_ramp"; - - shader_names->emission_sphere_radius = "emission_sphere_radius"; - shader_names->emission_box_extents = "emission_box_extents"; - shader_names->emission_texture_point_count = "emission_texture_point_count"; - shader_names->emission_texture_points = "emission_texture_points"; - shader_names->emission_texture_normal = "emission_texture_normal"; - shader_names->emission_texture_color = "emission_texture_color"; - shader_names->emission_ring_axis = "emission_ring_axis"; - shader_names->emission_ring_height = "emission_ring_height"; - shader_names->emission_ring_radius = "emission_ring_radius"; - shader_names->emission_ring_inner_radius = "emission_ring_inner_radius"; - - shader_names->turbulence_enabled = "turbulence_enabled"; - shader_names->turbulence_noise_strength = "turbulence_noise_strength"; - shader_names->turbulence_noise_scale = "turbulence_noise_scale"; - shader_names->turbulence_noise_speed = "turbulence_noise_speed"; - shader_names->turbulence_noise_speed_random = "turbulence_noise_speed_random"; - shader_names->turbulence_influence_over_life = "turbulence_influence_over_life"; - shader_names->turbulence_influence_min = "turbulence_influence_min"; - shader_names->turbulence_influence_max = "turbulence_influence_max"; - shader_names->turbulence_initial_displacement_min = "turbulence_initial_displacement_min"; - shader_names->turbulence_initial_displacement_max = "turbulence_initial_displacement_max"; - - shader_names->gravity = "gravity"; - - shader_names->lifetime_randomness = "lifetime_randomness"; - - shader_names->sub_emitter_frequency = "sub_emitter_frequency"; - shader_names->sub_emitter_amount_at_end = "sub_emitter_amount_at_end"; - shader_names->sub_emitter_keep_velocity = "sub_emitter_keep_velocity"; - - shader_names->collision_friction = "collision_friction"; - shader_names->collision_bounce = "collision_bounce"; -} - -void ParticlesMaterial::finish_shaders() { - memdelete(dirty_materials); - dirty_materials = nullptr; - - memdelete(shader_names); -} - -void ParticlesMaterial::_update_shader() { - dirty_materials->remove(&element); - - MaterialKey mk = _compute_key(); - if (mk.key == current_key.key) { - return; //no update required in the end - } - - if (shader_map.has(current_key)) { - shader_map[current_key].users--; - if (shader_map[current_key].users == 0) { - //deallocate shader, as it's no longer in use - RS::get_singleton()->free(shader_map[current_key].shader); - shader_map.erase(current_key); - } - } - - current_key = mk; - - if (shader_map.has(mk)) { - RS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader); - shader_map[mk].users++; - return; - } - //must create a shader! - - // Add a comment to describe the shader origin (useful when converting to ShaderMaterial). - String code = "// NOTE: Shader automatically converted from " VERSION_NAME " " VERSION_FULL_CONFIG "'s ParticlesMaterial.\n\n"; - - code += "shader_type particles;\n"; - - if (collision_scale) { - code += "render_mode collision_use_scale;\n"; - } - - code += "uniform vec3 direction;\n"; - code += "uniform float spread;\n"; - code += "uniform float flatness;\n"; - code += "uniform float initial_linear_velocity_min;\n"; - code += "uniform float initial_angle_min;\n"; - code += "uniform float angular_velocity_min;\n"; - code += "uniform float orbit_velocity_min;\n"; - code += "uniform float linear_accel_min;\n"; - code += "uniform float radial_accel_min;\n"; - code += "uniform float tangent_accel_min;\n"; - code += "uniform float damping_min;\n"; - code += "uniform float scale_min;\n"; - code += "uniform float hue_variation_min;\n"; - code += "uniform float anim_speed_min;\n"; - code += "uniform float anim_offset_min;\n"; - - code += "uniform float initial_linear_velocity_max;\n"; - code += "uniform float initial_angle_max;\n"; - code += "uniform float angular_velocity_max;\n"; - code += "uniform float orbit_velocity_max;\n"; - code += "uniform float linear_accel_max;\n"; - code += "uniform float radial_accel_max;\n"; - code += "uniform float tangent_accel_max;\n"; - code += "uniform float damping_max;\n"; - code += "uniform float scale_max;\n"; - code += "uniform float hue_variation_max;\n"; - code += "uniform float anim_speed_max;\n"; - code += "uniform float anim_offset_max;\n"; - code += "uniform float lifetime_randomness;\n"; - - switch (emission_shape) { - case EMISSION_SHAPE_POINT: { - //do none - } break; - case EMISSION_SHAPE_SPHERE: { - code += "uniform float emission_sphere_radius;\n"; - } break; - case EMISSION_SHAPE_SPHERE_SURFACE: { - code += "uniform float emission_sphere_radius;\n"; - } break; - case EMISSION_SHAPE_BOX: { - code += "uniform vec3 emission_box_extents;\n"; - } break; - case EMISSION_SHAPE_DIRECTED_POINTS: { - code += "uniform sampler2D emission_texture_normal : hint_default_black;\n"; - [[fallthrough]]; - } - case EMISSION_SHAPE_POINTS: { - code += "uniform sampler2D emission_texture_points : hint_default_black;\n"; - code += "uniform int emission_texture_point_count;\n"; - if (emission_color_texture.is_valid()) { - code += "uniform sampler2D emission_texture_color : hint_default_white;\n"; - } - } break; - case EMISSION_SHAPE_RING: { - code += "uniform vec3 " + shader_names->emission_ring_axis + ";\n"; - code += "uniform float " + shader_names->emission_ring_height + ";\n"; - code += "uniform float " + shader_names->emission_ring_radius + ";\n"; - code += "uniform float " + shader_names->emission_ring_inner_radius + ";\n"; - } break; - case EMISSION_SHAPE_MAX: { // Max value for validity check. - break; - } - } - - if (sub_emitter_mode != SUB_EMITTER_DISABLED) { - if (sub_emitter_mode == SUB_EMITTER_CONSTANT) { - code += "uniform float sub_emitter_frequency;\n"; - } - if (sub_emitter_mode == SUB_EMITTER_AT_END) { - code += "uniform int sub_emitter_amount_at_end;\n"; - } - code += "uniform bool sub_emitter_keep_velocity;\n"; - } - - code += "uniform vec4 color_value : source_color;\n"; - - code += "uniform vec3 gravity;\n"; - - if (color_ramp.is_valid()) { - code += "uniform sampler2D color_ramp : repeat_disable;\n"; - } - - if (color_initial_ramp.is_valid()) { - code += "uniform sampler2D color_initial_ramp : repeat_disable;\n"; - } - - if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - code += "uniform sampler2D linear_velocity_texture : repeat_disable;\n"; - } - if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { - code += "uniform sampler2D orbit_velocity_texture : repeat_disable;\n"; - } - if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { - code += "uniform sampler2D angular_velocity_texture : repeat_disable;\n"; - } - if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) { - code += "uniform sampler2D linear_accel_texture : repeat_disable;\n"; - } - if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) { - code += "uniform sampler2D radial_accel_texture : repeat_disable;\n"; - } - if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { - code += "uniform sampler2D tangent_accel_texture : repeat_disable;\n"; - } - if (tex_parameters[PARAM_DAMPING].is_valid()) { - code += "uniform sampler2D damping_texture : repeat_disable;\n"; - } - if (tex_parameters[PARAM_ANGLE].is_valid()) { - code += "uniform sampler2D angle_texture : repeat_disable;\n"; - } - if (tex_parameters[PARAM_SCALE].is_valid()) { - code += "uniform sampler2D scale_texture : repeat_disable;\n"; - } - if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) { - code += "uniform sampler2D hue_variation_texture : repeat_disable;\n"; - } - if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) { - code += "uniform sampler2D anim_speed_texture : repeat_disable;\n"; - } - if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) { - code += "uniform sampler2D anim_offset_texture : repeat_disable;\n"; - } - - if (collision_mode == COLLISION_RIGID) { - code += "uniform float collision_friction;\n"; - code += "uniform float collision_bounce;\n"; - } - - if (turbulence_enabled) { - code += "uniform float turbulence_noise_strength;\n"; - code += "uniform float turbulence_noise_scale;\n"; - code += "uniform float turbulence_influence_min;\n"; - code += "uniform float turbulence_influence_max;\n"; - code += "uniform float turbulence_initial_displacement_min;\n"; - code += "uniform float turbulence_initial_displacement_max;\n"; - code += "uniform float turbulence_noise_speed_random;\n"; - code += "uniform vec3 turbulence_noise_speed = vec3(1.0, 1.0, 1.0);\n"; - if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) { - code += "uniform sampler2D turbulence_influence_over_life;\n"; - } - if (turbulence_color_ramp.is_valid()) { - code += "uniform sampler2D turbulence_color_ramp;\n"; - } - code += "\n"; - - //functions for 3D noise / turbulence - code += "\n\n"; - code += "// 3D Noise with friendly permission by Inigo Quilez\n"; - code += "vec3 hash_noise( vec3 p ) {\n"; - code += " p *= mat3(vec3(127.1, 311.7, -53.7), vec3(269.5, 183.3, 77.1), vec3(-301.7, 27.3, 215.3));\n"; - code += " return 2.0 * fract(fract(p)*4375.55) -1.;\n"; - code += "}\n"; - code += "\n"; - code += "float noise( vec3 p) {\n"; - code += " vec3 i = floor(p);;\n"; - code += " vec3 f = fract(p);\n "; - code += " vec3 u = f * f * (3.0 - 2.0 * f);\n"; - code += "\n"; - code += " return 2.0*mix( mix( mix( dot( hash_noise( i + vec3(0.0,0.0,0.0) ), f - vec3(0.0,0.0,0.0) ), dot( hash_noise( i + vec3(1.0,0.0,0.0) ), f - vec3(1.0,0.0,0.0) ), u.x),\n"; - code += " mix( dot( hash_noise( i + vec3(0.0,1.0,0.0) ), f - vec3(0.0,1.0,0.0) ), dot( hash_noise( i + vec3(1.0,1.0,0.0) ), f - vec3(1.0,1.0,0.0) ), u.x), u.y),\n"; - code += " mix( mix( dot( hash_noise( i + vec3(0.0,0.0,1.0) ), f - vec3(0.0,0.0,1.0) ), dot( hash_noise( i + vec3(1.0,0.0,1.0) ), f - vec3(1.0,0.0,1.0) ), u.x),\n"; - code += " mix( dot( hash_noise( i + vec3(0.0,1.0,1.0) ), f - vec3(0.0,1.0,1.0) ), dot( hash_noise( i + vec3(1.0,1.0,1.0) ), f - vec3(1.0,1.0,1.0) ), u.x), u.y), u.z);\n"; - code += "}\n\n"; - code += "// Curl 3D and noise_3d function with friendly permission by Isaac Cohen\n"; - code += "vec3 noise_3d(vec3 p) {\n"; - code += " float s = noise(p);\n"; - code += " float s1 = noise(vec3(p.y - 19.1, p.z + 33.4, p.x + 47.2));\n"; - code += " float s2 = noise(vec3(p.z + 74.2, p.x - 124.5, p.y + 99.4));\n"; - code += " vec3 c = vec3(s, s1, s2);\n"; - code += " return c;\n"; - code += "}\n\n"; - code += "vec3 curl_3d(vec3 p, float c) {\n"; - code += " float epsilon = 0.001 + c;\n"; - code += " vec3 dx = vec3(epsilon, 0.0, 0.0);\n"; - code += " vec3 dy = vec3(0.0, epsilon, 0.0);\n"; - code += " vec3 dz = vec3(0.0, 0.0, epsilon);\n"; - code += " vec3 x0 = noise_3d(p - dx).xyz;\n"; - code += " vec3 x1 = noise_3d(p + dx).xyz;\n"; - code += " vec3 y0 = noise_3d(p - dy).xyz;\n"; - code += " vec3 y1 = noise_3d(p + dy).xyz;\n"; - code += " vec3 z0 = noise_3d(p - dz).xyz;\n"; - code += " vec3 z1 = noise_3d(p + dz).xyz;\n"; - code += " float x = y1.z - y0.z - z1.y + z0.y;\n"; - code += " float y = z1.x - z0.x - x1.z + x0.z;\n"; - code += " float z = x1.y - x0.y - y1.x + y0.x;\n"; - code += " float divisor = 1.0 / (2.0 * epsilon);\n"; - code += " return vec3(normalize(vec3(x, y, z) * divisor));\n"; - code += "}\n"; - code += "vec3 get_noise_direction(vec3 pos, vec3 emission_pos, vec3 time_noise) {\n"; - code += " float adj_contrast = max((turbulence_noise_strength - 1.0), 0.0) * 70.0;\n"; - code += " vec3 noise_time = (vec3(TIME) * turbulence_noise_speed) + time_noise;\n"; - code += " vec3 noise_pos = (pos * turbulence_noise_scale) - emission_pos;\n"; - code += " vec3 diff = pos - emission_pos;\n"; - code += " vec3 noise_direction = curl_3d(noise_pos + noise_time - diff, adj_contrast);\n"; - code += " noise_direction = mix(0.9 * noise_direction, noise_direction, turbulence_noise_strength - 9.0);\n"; - code += " return noise_direction;\n"; - code += "}\n"; - } - - //need a random function - code += "\n\n"; - code += "float rand_from_seed(inout uint seed) {\n"; - code += " int k;\n"; - code += " int s = int(seed);\n"; - code += " if (s == 0)\n"; - code += " s = 305420679;\n"; - code += " k = s / 127773;\n"; - code += " s = 16807 * (s - k * 127773) - 2836 * k;\n"; - code += " if (s < 0)\n"; - code += " s += 2147483647;\n"; - code += " seed = uint(s);\n"; - code += " return float(seed % uint(65536)) / 65535.0;\n"; - code += "}\n"; - code += "\n"; - - code += "float rand_from_seed_m1_p1(inout uint seed) {\n"; - code += " return rand_from_seed(seed) * 2.0 - 1.0;\n"; - code += "}\n"; - code += "\n"; - - //improve seed quality - code += "uint hash(uint x) {\n"; - code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; - code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; - code += " x = (x >> uint(16)) ^ x;\n"; - code += " return x;\n"; - code += "}\n"; - code += "\n"; - - code += "void start() {\n"; - code += " uint base_number = NUMBER;\n"; - code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n"; - code += " float angle_rand = rand_from_seed(alt_seed);\n"; - code += " float scale_rand = rand_from_seed(alt_seed);\n"; - code += " float hue_rot_rand = rand_from_seed(alt_seed);\n"; - code += " float anim_offset_rand = rand_from_seed(alt_seed);\n"; - if (color_initial_ramp.is_valid()) { - code += " float color_initial_rand = rand_from_seed(alt_seed);\n"; - } - code += " float pi = 3.14159;\n"; - code += " float degree_to_rad = pi / 180.0;\n"; - code += "\n"; - - if (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { - code += " int point = min(emission_texture_point_count - 1, int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n"; - code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n"; - code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n"; - } - if (tex_parameters[PARAM_ANGLE].is_valid()) { - code += " float tex_angle = textureLod(angle_texture, vec2(0.0, 0.0), 0.0).r;\n"; - } else { - code += " float tex_angle = 0.0;\n"; - } - - if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) { - code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(0.0, 0.0), 0.0).r;\n"; - } else { - code += " float tex_anim_offset = 1.0;\n"; - } - - code += " float spread_rad = spread * degree_to_rad;\n"; - - code += " if (RESTART_VELOCITY) {\n"; - - if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n"; - } else { - code += " float tex_linear_velocity = 1.0;\n"; - } - - if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " {\n"; - code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; - code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n"; - code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n"; - code += " VELOCITY = rot * mix(initial_linear_velocity_min,initial_linear_velocity_max, rand_from_seed(alt_seed));\n"; - code += " }\n"; - - } else { - //initiate velocity spread in 3D - code += " {\n"; - code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; - code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n"; - code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n"; - code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n"; - code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n"; - code += " vec3 spread_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; - code += " vec3 direction_nrm = length(direction) > 0.0 ? normalize(direction) : vec3(0.0, 0.0, 1.0);\n"; - code += " // rotate spread to direction\n"; - code += " vec3 binormal = cross(vec3(0.0, 1.0, 0.0), direction_nrm);\n"; - code += " if (length(binormal) < 0.0001) {\n"; - code += " // direction is parallel to Y. Choose Z as the binormal.\n"; - code += " binormal = vec3(0.0, 0.0, 1.0);\n"; - code += " }\n"; - code += " binormal = normalize(binormal);\n"; - code += " vec3 normal = cross(binormal, direction_nrm);\n"; - code += " spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;\n"; - code += " VELOCITY = spread_direction * mix(initial_linear_velocity_min, initial_linear_velocity_max,rand_from_seed(alt_seed));\n"; - code += " }\n"; - } - code += " }\n"; - - code += " float base_angle = (tex_angle) * mix(initial_angle_min, initial_angle_max, angle_rand);\n"; - code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle - code += " CUSTOM.y = 0.0;\n"; // phase - code += " CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n"; - code += " CUSTOM.z = (tex_anim_offset) * mix(anim_offset_min, anim_offset_max, anim_offset_rand);\n"; // animation offset (0-1) - - code += " if (RESTART_POSITION) {\n"; - - switch (emission_shape) { - case EMISSION_SHAPE_POINT: { - //do none, identity (will later be multiplied by emission transform) - code += " TRANSFORM = mat4(vec4(1,0,0,0),vec4(0,1,0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n"; - } break; - case EMISSION_SHAPE_SPHERE: { - code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n"; - code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n"; - code += " float p = rand_from_seed(alt_seed);\n"; - code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n"; - code += " TRANSFORM[3].xyz = mix(vec3(0.0, 0.0, 0.0), vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s), p);\n"; - } break; - case EMISSION_SHAPE_SPHERE_SURFACE: { - code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n"; - code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n"; - code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n"; - code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n"; - } break; - case EMISSION_SHAPE_BOX: { - code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n"; - } break; - case EMISSION_SHAPE_POINTS: - case EMISSION_SHAPE_DIRECTED_POINTS: { - code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n"; - - if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { - if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " {\n"; - code += " mat2 rotm;"; - code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n"; - code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n"; - code += " if (RESTART_VELOCITY) VELOCITY.xy = rotm * VELOCITY.xy;\n"; - code += " }\n"; - } else { - code += " {\n"; - code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n"; - code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n"; - code += " vec3 tangent = normalize(cross(v0, normal));\n"; - code += " vec3 bitangent = normalize(cross(tangent, normal));\n"; - code += " if (RESTART_VELOCITY) VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n"; - code += " }\n"; - } - } - } break; - case EMISSION_SHAPE_RING: { - code += " float ring_spawn_angle = rand_from_seed(alt_seed) * 2.0 * pi;\n"; - code += " float ring_random_radius = rand_from_seed(alt_seed) * (emission_ring_radius - emission_ring_inner_radius) + emission_ring_inner_radius;\n"; - code += " vec3 axis = normalize(emission_ring_axis);\n"; - code += " vec3 ortho_axis = vec3(0.0);\n"; - code += " if (axis == vec3(1.0, 0.0, 0.0)) {\n"; - code += " ortho_axis = cross(axis, vec3(0.0, 1.0, 0.0));\n"; - code += " } else {\n"; - code += " ortho_axis = cross(axis, vec3(1.0, 0.0, 0.0));\n"; - code += " }\n"; - code += " ortho_axis = normalize(ortho_axis);\n"; - code += " float s = sin(ring_spawn_angle);\n"; - code += " float c = cos(ring_spawn_angle);\n"; - code += " float oc = 1.0 - c;\n"; - code += " ortho_axis = mat3(\n"; - code += " vec3(c + axis.x * axis.x * oc, axis.x * axis.y * oc - axis.z * s, axis.x * axis.z *oc + axis.y * s),\n"; - code += " vec3(axis.x * axis.y * oc + s * axis.z, c + axis.y * axis.y * oc, axis.y * axis.z * oc - axis.x * s),\n"; - code += " vec3(axis.z * axis.x * oc - axis.y * s, axis.z * axis.y * oc + axis.x * s, c + axis.z * axis.z * oc)\n"; - code += " ) * ortho_axis;\n"; - code += " ortho_axis = normalize(ortho_axis);\n"; - code += " TRANSFORM[3].xyz = ortho_axis * ring_random_radius + (rand_from_seed(alt_seed) * emission_ring_height - emission_ring_height / 2.0) * axis;\n"; - } break; - case EMISSION_SHAPE_MAX: { // Max value for validity check. - break; - } - } - code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; - // Apply noise/turbulence: initial displacement. - if (turbulence_enabled) { - if (get_turbulence_noise_speed_random() >= 0.0) { - code += " vec3 time_noise = noise_3d( vec3(TIME) * turbulence_noise_speed_random ) * -turbulence_noise_speed;\n"; - } else { - code += " const vec3 time_noise = vec3(0.0);\n"; - } - code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz, EMISSION_TRANSFORM[3].xyz, time_noise);\n"; - code += " float turb_init_displacement = mix(turbulence_initial_displacement_min, turbulence_initial_displacement_max, rand_from_seed(alt_seed));"; - code += " TRANSFORM[3].xyz += noise_direction * turb_init_displacement;\n"; - } - code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; - if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " VELOCITY.z = 0.0;\n"; - code += " TRANSFORM[3].z = 0.0;\n"; - } - code += " }\n"; - code += "}\n\n"; - - code += "void process() {\n"; - code += " uint base_number = NUMBER;\n"; - code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n"; - code += " float angle_rand = rand_from_seed(alt_seed);\n"; - code += " float scale_rand = rand_from_seed(alt_seed);\n"; - code += " float hue_rot_rand = rand_from_seed(alt_seed);\n"; - code += " float anim_offset_rand = rand_from_seed(alt_seed);\n"; - if (color_initial_ramp.is_valid()) { - code += " float color_initial_rand = rand_from_seed(alt_seed);\n"; - } - code += " float pi = 3.14159;\n"; - code += " float degree_to_rad = pi / 180.0;\n"; - code += "\n"; - - if (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { - code += " int point = min(emission_texture_point_count - 1, int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n"; - code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n"; - code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n"; - } - - code += " CUSTOM.y += DELTA / LIFETIME;\n"; - code += " float tv = CUSTOM.y / CUSTOM.w;\n"; - if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " float tex_linear_velocity = 1.0;\n"; - } - - if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { - code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " float tex_orbit_velocity = 1.0;\n"; - } - } - - if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { - code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " float tex_angular_velocity = 1.0;\n"; - } - - if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) { - code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " float tex_linear_accel = 1.0;\n"; - } - - if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) { - code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " float tex_radial_accel = 1.0;\n"; - } - - if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { - code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " float tex_tangent_accel = 1.0;\n"; - } - - if (tex_parameters[PARAM_DAMPING].is_valid()) { - code += " float tex_damping = textureLod(damping_texture, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " float tex_damping = 1.0;\n"; - } - - if (tex_parameters[PARAM_ANGLE].is_valid()) { - code += " float tex_angle = textureLod(angle_texture, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " float tex_angle = 1.0;\n"; - } - - if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) { - code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " float tex_anim_speed = 1.0;\n"; - } - - if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) { - code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " float tex_anim_offset = 1.0;\n"; - } - - code += " vec3 force = gravity;\n"; - code += " vec3 pos = TRANSFORM[3].xyz;\n"; - if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " pos.z = 0.0;\n"; - } - code += " // apply linear acceleration\n"; - code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * tex_linear_accel * mix(linear_accel_min, linear_accel_max, rand_from_seed(alt_seed)) : vec3(0.0);\n"; - code += " // apply radial acceleration\n"; - code += " vec3 org = EMISSION_TRANSFORM[3].xyz;\n"; - code += " vec3 diff = pos - org;\n"; - code += " force += length(diff) > 0.0 ? normalize(diff) * tex_radial_accel * mix(radial_accel_min, radial_accel_max, rand_from_seed(alt_seed)) : vec3(0.0);\n"; - code += " // apply tangential acceleration;\n"; - code += " float tangent_accel_val = tex_tangent_accel * mix(tangent_accel_min, tangent_accel_max, rand_from_seed(alt_seed));\n"; - if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * tangent_accel_val : vec3(0.0);\n"; - - } else { - code += " vec3 crossDiff = cross(normalize(diff), normalize(gravity));\n"; - code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * tangent_accel_val : vec3(0.0);\n"; - } - if (attractor_interaction_enabled) { - code += " force += ATTRACTOR_FORCE;\n\n"; - } - - code += " // apply attractor forces\n"; - code += " VELOCITY += force * DELTA;\n"; - - if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n"; - } - - // Apply noise/turbulence. - if (turbulence_enabled) { - code += " // apply turbulence\n"; - if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) { - code += " float turbulence_influence = textureLod(turbulence_influence_over_life, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " const float turbulence_influence = 1.0;\n"; - } - code += " \n"; - if (get_turbulence_noise_speed_random() >= 0.0) { - code += " vec3 time_noise = noise_3d( vec3(TIME) * turbulence_noise_speed_random ) * -turbulence_noise_speed;\n"; - } else { - code += " const vec3 time_noise = vec3(0.0);\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. - // We don't need this check when the collision mode is "hide on contact", - // as the particle will be hidden anyway. - String extra_tab = ""; - if (collision_mode != COLLISION_RIGID) { - code += " if (!COLLIDED) {\n"; - extra_tab = " "; - } - code += extra_tab + " \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 + " VELOCITY = mix(VELOCITY, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n"; - if (collision_mode != COLLISION_RIGID) { - code += " }"; - } - } - code += " \n"; - code += " // orbit velocity\n"; - if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " float orbit_amount = tex_orbit_velocity * mix(orbit_velocity_min, orbit_velocity_max, rand_from_seed(alt_seed));\n"; - code += " if (orbit_amount != 0.0) {\n"; - code += " float ang = orbit_amount * DELTA * pi * 2.0;\n"; - code += " mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang)));\n"; - code += " TRANSFORM[3].xy -= diff.xy;\n"; - code += " TRANSFORM[3].xy += rot * diff.xy;\n"; - code += " }\n"; - } - - code += " float dmp = mix(damping_min, damping_max, rand_from_seed(alt_seed));\n"; - code += " if (dmp * tex_damping > 0.0) {\n"; - code += " float v = length(VELOCITY);\n"; - code += " float damp = tex_damping * dmp;\n"; - code += " v -= damp * DELTA;\n"; - code += " if (v < 0.0) {\n"; - code += " VELOCITY = vec3(0.0);\n"; - code += " } else {\n"; - code += " VELOCITY = normalize(VELOCITY) * v;\n"; - code += " }\n"; - code += " }\n"; - code += " float base_angle = (tex_angle) * mix(initial_angle_min, initial_angle_max, rand_from_seed(alt_seed));\n"; - code += " base_angle += CUSTOM.y * LIFETIME * (tex_angular_velocity) * mix(angular_velocity_min,angular_velocity_max, rand_from_seed(alt_seed));\n"; - code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle - code += " CUSTOM.z = (tex_anim_offset) * mix(anim_offset_min, anim_offset_max, rand_from_seed(alt_seed)) + tv * tex_anim_speed * mix(anim_speed_min, anim_speed_max, rand_from_seed(alt_seed));\n"; // angle - - // apply color - // apply hue rotation - if (tex_parameters[PARAM_SCALE].is_valid()) { - code += " vec3 tex_scale = textureLod(scale_texture, vec2(tv, 0.0), 0.0).rgb;\n"; - } else { - code += " vec3 tex_scale = vec3(1.0);\n"; - } - - if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) { - code += " float tex_hue_variation = textureLod(hue_variation_texture, vec2(tv, 0.0), 0.0).r;\n"; - } else { - code += " float tex_hue_variation = 1.0;\n"; - } - - code += " float hue_rot_angle = (tex_hue_variation) * pi * 2.0 * mix(hue_variation_min, hue_variation_max, rand_from_seed(alt_seed));\n"; - code += " float hue_rot_c = cos(hue_rot_angle);\n"; - code += " float hue_rot_s = sin(hue_rot_angle);\n"; - code += " mat4 hue_rot_mat = mat4(vec4(0.299, 0.587, 0.114, 0.0),\n"; - code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; - code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; - code += " vec4(0.000, 0.000, 0.000, 1.0)) +\n"; - code += " mat4(vec4(0.701, -0.587, -0.114, 0.0),\n"; - code += " vec4(-0.299, 0.413, -0.114, 0.0),\n"; - code += " vec4(-0.300, -0.588, 0.886, 0.0),\n"; - code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_c +\n"; - code += " mat4(vec4(0.168, 0.330, -0.497, 0.0),\n"; - code += " vec4(-0.328, 0.035, 0.292, 0.0),\n"; - code += " vec4(1.250, -1.050, -0.203, 0.0),\n"; - code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_s;\n"; - if (color_ramp.is_valid()) { - code += " COLOR = hue_rot_mat * textureLod(color_ramp, vec2(tv, 0.0), 0.0) * color_value;\n"; - } else { - code += " COLOR = hue_rot_mat * color_value;\n"; - } - - if (color_initial_ramp.is_valid()) { - code += " vec4 start_color = textureLod(color_initial_ramp, vec2(color_initial_rand, 0.0), 0.0);\n"; - code += " COLOR *= start_color;\n"; - } - - if (emission_color_texture.is_valid() && (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS)) { - code += " COLOR *= texelFetch(emission_texture_color, emission_tex_ofs, 0);\n"; - } - code += "\n"; - - if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { - code += " if (length(VELOCITY) > 0.0) {\n"; - code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n"; - code += " } else {\n"; - code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n"; - code += " }\n"; - code += " TRANSFORM[0].xyz = normalize(cross(TRANSFORM[1].xyz, TRANSFORM[2].xyz));\n"; - code += " TRANSFORM[2] = vec4(0.0, 0.0, 1.0, 0.0);\n"; - } else { - code += " TRANSFORM[0] = vec4(cos(CUSTOM.x), -sin(CUSTOM.x), 0.0, 0.0);\n"; - code += " TRANSFORM[1] = vec4(sin(CUSTOM.x), cos(CUSTOM.x), 0.0, 0.0);\n"; - code += " TRANSFORM[2] = vec4(0.0, 0.0, 1.0, 0.0);\n"; - } - - } else { - // orient particle Y towards velocity - if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { - code += " if (length(VELOCITY) > 0.0) {\n"; - code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n"; - code += " } else {\n"; - code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n"; - code += " }\n"; - code += " if (TRANSFORM[1].xyz == normalize(TRANSFORM[0].xyz)) {\n"; - code += " TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz), normalize(TRANSFORM[2].xyz)));\n"; - code += " TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz), normalize(TRANSFORM[1].xyz)));\n"; - code += " } else {\n"; - code += " TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz), normalize(TRANSFORM[1].xyz)));\n"; - code += " TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz), normalize(TRANSFORM[2].xyz)));\n"; - code += " }\n"; - } else { - code += " TRANSFORM[0].xyz = normalize(TRANSFORM[0].xyz);\n"; - code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n"; - code += " TRANSFORM[2].xyz = normalize(TRANSFORM[2].xyz);\n"; - } - // turn particle by rotation in Y - if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) { - code += " vec4 origin = TRANSFORM[3];\n"; - code += " TRANSFORM = mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; - code += " TRANSFORM[3] = origin;\n"; - } - } - - if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " TRANSFORM[3].z = 0.0;\n"; - } - - if (collision_mode == COLLISION_RIGID) { - code += " if (COLLIDED) {\n"; - code += " if (length(VELOCITY) > 3.0) {\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),clamp(collision_friction, 0.0, 1.0));\n"; - code += " } else {\n"; - code += " VELOCITY = vec3(0.0);\n"; - // If turbulence is enabled, set the noise direction to up so the turbulence color is "neutral" - if (turbulence_enabled) { - code += " noise_direction = vec3(1.0, 0.0, 0.0);\n"; - } - code += " }\n"; - code += " }\n"; - } - - // scale by scale - code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n"; - code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n"; - code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 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"; - - 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) { - code += " int emit_count = 0;\n"; - switch (sub_emitter_mode) { - case SUB_EMITTER_CONSTANT: { - code += " float interval_from = CUSTOM.y * LIFETIME - DELTA;\n"; - code += " float interval_rem = sub_emitter_frequency - mod(interval_from,sub_emitter_frequency);\n"; - code += " if (DELTA >= interval_rem) emit_count = 1;\n"; - } break; - case SUB_EMITTER_AT_COLLISION: { - code += " if (COLLIDED) emit_count = 1;\n"; - } break; - case SUB_EMITTER_AT_END: { - code += " float unit_delta = DELTA/LIFETIME;\n"; - code += " float end_time = CUSTOM.w * 0.95;\n"; // if we do at the end we might miss it, as it can just get deactivated by emitter - code += " if (CUSTOM.y < end_time && (CUSTOM.y + unit_delta) >= end_time) emit_count = sub_emitter_amount_at_end;\n"; - } break; - default: { - } - } - code += " for(int i=0;ishader_create(); - shader_data.users = 1; - - RS::get_singleton()->shader_set_code(shader_data.shader, code); - - shader_map[mk] = shader_data; - - RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader); -} - -void ParticlesMaterial::flush_changes() { - MutexLock lock(material_mutex); - - while (dirty_materials->first()) { - dirty_materials->first()->self()->_update_shader(); - } -} - -void ParticlesMaterial::_queue_shader_change() { - MutexLock lock(material_mutex); - - if (is_initialized && !element.in_list()) { - dirty_materials->add(&element); - } -} - -bool ParticlesMaterial::_is_shader_dirty() const { - MutexLock lock(material_mutex); - - return element.in_list(); -} - -void ParticlesMaterial::set_direction(Vector3 p_direction) { - direction = p_direction; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->direction, direction); -} - -Vector3 ParticlesMaterial::get_direction() const { - return direction; -} - -void ParticlesMaterial::set_spread(float p_spread) { - spread = p_spread; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread); -} - -float ParticlesMaterial::get_spread() const { - return spread; -} - -void ParticlesMaterial::set_flatness(float p_flatness) { - flatness = p_flatness; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness); -} - -float ParticlesMaterial::get_flatness() const { - return flatness; -} - -void ParticlesMaterial::set_param_min(Parameter p_param, float p_value) { - ERR_FAIL_INDEX(p_param, PARAM_MAX); - - params_min[p_param] = p_value; - if (params_min[p_param] > params_max[p_param]) { - set_param_max(p_param, p_value); - } - - switch (p_param) { - case PARAM_INITIAL_LINEAR_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_min, p_value); - } break; - case PARAM_ANGULAR_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_min, p_value); - } break; - case PARAM_ORBIT_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_min, p_value); - } break; - case PARAM_LINEAR_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_min, p_value); - } break; - case PARAM_RADIAL_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_min, p_value); - } break; - case PARAM_TANGENTIAL_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_min, p_value); - } break; - case PARAM_DAMPING: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_min, p_value); - } break; - case PARAM_ANGLE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_min, p_value); - } break; - case PARAM_SCALE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_min, p_value); - } break; - case PARAM_HUE_VARIATION: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_min, p_value); - } break; - case PARAM_ANIM_SPEED: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_min, p_value); - } break; - case PARAM_ANIM_OFFSET: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_min, p_value); - } break; - case PARAM_TURB_VEL_INFLUENCE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_min, p_value); - } break; - case PARAM_TURB_INIT_DISPLACEMENT: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_initial_displacement_min, p_value); - } break; - case PARAM_TURB_INFLUENCE_OVER_LIFE: { - // Can't happen, but silences warning - } break; - case PARAM_MAX: - break; // Can't happen, but silences warning - } -} - -float ParticlesMaterial::get_param_min(Parameter p_param) const { - ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); - - return params_min[p_param]; -} - -void ParticlesMaterial::set_param_max(Parameter p_param, float p_value) { - ERR_FAIL_INDEX(p_param, PARAM_MAX); - - params_max[p_param] = p_value; - if (params_min[p_param] > params_max[p_param]) { - set_param_min(p_param, p_value); - } - - switch (p_param) { - case PARAM_INITIAL_LINEAR_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_max, p_value); - } break; - case PARAM_ANGULAR_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_max, p_value); - } break; - case PARAM_ORBIT_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_max, p_value); - } break; - case PARAM_LINEAR_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_max, p_value); - } break; - case PARAM_RADIAL_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_max, p_value); - } break; - case PARAM_TANGENTIAL_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_max, p_value); - } break; - case PARAM_DAMPING: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_max, p_value); - } break; - case PARAM_ANGLE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_max, p_value); - } break; - case PARAM_SCALE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_max, p_value); - } break; - case PARAM_HUE_VARIATION: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_max, p_value); - } break; - case PARAM_ANIM_SPEED: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_max, p_value); - } break; - case PARAM_ANIM_OFFSET: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_max, p_value); - } break; - case PARAM_TURB_VEL_INFLUENCE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_max, p_value); - } break; - case PARAM_TURB_INIT_DISPLACEMENT: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_initial_displacement_max, p_value); - } break; - case PARAM_TURB_INFLUENCE_OVER_LIFE: { - // Can't happen, but silences warning - } break; - case PARAM_MAX: - break; // Can't happen, but silences warning - } -} - -float ParticlesMaterial::get_param_max(Parameter p_param) const { - ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); - - return params_max[p_param]; -} - -static void _adjust_curve_range(const Ref &p_texture, float p_min, float p_max) { - Ref curve_tex = p_texture; - if (!curve_tex.is_valid()) { - return; - } - - curve_tex->ensure_default_setup(p_min, p_max); -} - -void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref &p_texture) { - ERR_FAIL_INDEX(p_param, PARAM_MAX); - - tex_parameters[p_param] = p_texture; - - RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); - - switch (p_param) { - case PARAM_INITIAL_LINEAR_VELOCITY: { - //do none for this one - } break; - case PARAM_ANGULAR_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, tex_rid); - _adjust_curve_range(p_texture, -360, 360); - } break; - case PARAM_ORBIT_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, tex_rid); - _adjust_curve_range(p_texture, -500, 500); - } break; - case PARAM_LINEAR_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, tex_rid); - _adjust_curve_range(p_texture, -200, 200); - } break; - case PARAM_RADIAL_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, tex_rid); - _adjust_curve_range(p_texture, -200, 200); - } break; - case PARAM_TANGENTIAL_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, tex_rid); - _adjust_curve_range(p_texture, -200, 200); - } break; - case PARAM_DAMPING: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, tex_rid); - _adjust_curve_range(p_texture, 0, 100); - } break; - case PARAM_ANGLE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, tex_rid); - _adjust_curve_range(p_texture, -360, 360); - } break; - case PARAM_SCALE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, tex_rid); - _adjust_curve_range(p_texture, 0, 1); - } break; - case PARAM_HUE_VARIATION: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, tex_rid); - _adjust_curve_range(p_texture, -1, 1); - } break; - case PARAM_ANIM_SPEED: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, tex_rid); - _adjust_curve_range(p_texture, 0, 200); - } break; - case PARAM_ANIM_OFFSET: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, tex_rid); - } break; - case PARAM_TURB_INFLUENCE_OVER_LIFE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_over_life, tex_rid); - _adjust_curve_range(p_texture, 0, 1); - } break; - case PARAM_TURB_VEL_INFLUENCE: { - // Can't happen, but silences warning - } break; - case PARAM_TURB_INIT_DISPLACEMENT: { - // Can't happen, but silences warning - } break; - case PARAM_MAX: - break; // Can't happen, but silences warning - } - - _queue_shader_change(); -} - -Ref ParticlesMaterial::get_param_texture(Parameter p_param) const { - ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref()); - - return tex_parameters[p_param]; -} - -void ParticlesMaterial::set_color(const Color &p_color) { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color); - color = p_color; -} - -Color ParticlesMaterial::get_color() const { - return color; -} - -void ParticlesMaterial::set_color_ramp(const Ref &p_texture) { - color_ramp = p_texture; - RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, tex_rid); - _queue_shader_change(); - notify_property_list_changed(); -} - -Ref ParticlesMaterial::get_color_ramp() const { - return color_ramp; -} - -void ParticlesMaterial::set_color_initial_ramp(const Ref &p_texture) { - color_initial_ramp = p_texture; - RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_initial_ramp, tex_rid); - _queue_shader_change(); - notify_property_list_changed(); -} - -Ref ParticlesMaterial::get_color_initial_ramp() const { - return color_initial_ramp; -} - -void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) { - ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX); - particle_flags[p_particle_flag] = p_enable; - _queue_shader_change(); - if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) { - notify_property_list_changed(); - } -} - -bool ParticlesMaterial::get_particle_flag(ParticleFlags p_particle_flag) const { - ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false); - return particle_flags[p_particle_flag]; -} - -void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) { - ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX); - emission_shape = p_shape; - notify_property_list_changed(); - _queue_shader_change(); -} - -void ParticlesMaterial::set_emission_sphere_radius(real_t p_radius) { - emission_sphere_radius = p_radius; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius); -} - -void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) { - emission_box_extents = p_extents; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents); -} - -void ParticlesMaterial::set_emission_point_texture(const Ref &p_points) { - emission_point_texture = p_points; - RID tex_rid = p_points.is_valid() ? p_points->get_rid() : RID(); - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, tex_rid); -} - -void ParticlesMaterial::set_emission_normal_texture(const Ref &p_normals) { - emission_normal_texture = p_normals; - RID tex_rid = p_normals.is_valid() ? p_normals->get_rid() : RID(); - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, tex_rid); -} - -void ParticlesMaterial::set_emission_color_texture(const Ref &p_colors) { - emission_color_texture = p_colors; - RID tex_rid = p_colors.is_valid() ? p_colors->get_rid() : RID(); - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, tex_rid); - _queue_shader_change(); -} - -void ParticlesMaterial::set_emission_point_count(int p_count) { - emission_point_count = p_count; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count); -} - -void ParticlesMaterial::set_emission_ring_axis(Vector3 p_axis) { - emission_ring_axis = p_axis; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_axis, p_axis); -} - -void ParticlesMaterial::set_emission_ring_height(real_t p_height) { - emission_ring_height = p_height; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_height, p_height); -} - -void ParticlesMaterial::set_emission_ring_radius(real_t p_radius) { - emission_ring_radius = p_radius; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_radius, p_radius); -} - -void ParticlesMaterial::set_emission_ring_inner_radius(real_t p_radius) { - emission_ring_inner_radius = p_radius; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_inner_radius, p_radius); -} - -ParticlesMaterial::EmissionShape ParticlesMaterial::get_emission_shape() const { - return emission_shape; -} - -real_t ParticlesMaterial::get_emission_sphere_radius() const { - return emission_sphere_radius; -} - -Vector3 ParticlesMaterial::get_emission_box_extents() const { - return emission_box_extents; -} - -Ref ParticlesMaterial::get_emission_point_texture() const { - return emission_point_texture; -} - -Ref ParticlesMaterial::get_emission_normal_texture() const { - return emission_normal_texture; -} - -Ref ParticlesMaterial::get_emission_color_texture() const { - return emission_color_texture; -} - -int ParticlesMaterial::get_emission_point_count() const { - return emission_point_count; -} - -Vector3 ParticlesMaterial::get_emission_ring_axis() const { - return emission_ring_axis; -} - -real_t ParticlesMaterial::get_emission_ring_height() const { - return emission_ring_height; -} - -real_t ParticlesMaterial::get_emission_ring_radius() const { - return emission_ring_radius; -} - -real_t ParticlesMaterial::get_emission_ring_inner_radius() const { - return emission_ring_inner_radius; -} - -void ParticlesMaterial::set_turbulence_enabled(const bool p_turbulence_enabled) { - turbulence_enabled = p_turbulence_enabled; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_enabled, turbulence_enabled); - _queue_shader_change(); - notify_property_list_changed(); -} - -bool ParticlesMaterial::get_turbulence_enabled() const { - return turbulence_enabled; -} - -void ParticlesMaterial::set_turbulence_noise_strength(float p_turbulence_noise_strength) { - turbulence_noise_strength = p_turbulence_noise_strength; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_strength, p_turbulence_noise_strength); -} - -float ParticlesMaterial::get_turbulence_noise_strength() const { - return turbulence_noise_strength; -} - -void ParticlesMaterial::set_turbulence_noise_scale(float p_turbulence_noise_scale) { - turbulence_noise_scale = p_turbulence_noise_scale; - float shader_turbulence_noise_scale = (pow(p_turbulence_noise_scale, 0.25) * 5.6234 / 10.0) * 4.0 - 3.0; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_scale, shader_turbulence_noise_scale); -} - -float ParticlesMaterial::get_turbulence_noise_scale() const { - return turbulence_noise_scale; -} - -void ParticlesMaterial::set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random) { - turbulence_noise_speed_random = p_turbulence_noise_speed_random; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed_random, p_turbulence_noise_speed_random); -} - -float ParticlesMaterial::get_turbulence_noise_speed_random() const { - return turbulence_noise_speed_random; -} - -void ParticlesMaterial::set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed) { - turbulence_noise_speed = p_turbulence_noise_speed; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed, turbulence_noise_speed); -} - -Vector3 ParticlesMaterial::get_turbulence_noise_speed() const { - return turbulence_noise_speed; -} - -void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) { - gravity = p_gravity; - Vector3 gset = gravity; - if (gset == Vector3()) { - gset = Vector3(0, -0.000001, 0); //as gravity is used as upvector in some calculations - } - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->gravity, gset); -} - -Vector3 ParticlesMaterial::get_gravity() const { - return gravity; -} - -void ParticlesMaterial::set_lifetime_randomness(double p_lifetime) { - lifetime_randomness = p_lifetime; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->lifetime_randomness, lifetime_randomness); -} - -double ParticlesMaterial::get_lifetime_randomness() const { - return lifetime_randomness; -} - -RID ParticlesMaterial::get_shader_rid() const { - ERR_FAIL_COND_V(!shader_map.has(current_key), RID()); - return shader_map[current_key].shader; -} - -void ParticlesMaterial::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { - p_property.usage = PROPERTY_USAGE_NONE; - } - - if (p_property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { - p_property.usage = PROPERTY_USAGE_NONE; - } - - if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture") && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { - p_property.usage = PROPERTY_USAGE_NONE; - } - - if (p_property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - p_property.usage = PROPERTY_USAGE_NONE; - } - - if (p_property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { - p_property.usage = PROPERTY_USAGE_NONE; - } - - if (p_property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) { - p_property.usage = PROPERTY_USAGE_NONE; - } - - if (p_property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) { - p_property.usage = PROPERTY_USAGE_NONE; - } - - if (p_property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) { - p_property.usage = PROPERTY_USAGE_NONE; - } - - if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - p_property.usage = PROPERTY_USAGE_NONE; - } - - if (!turbulence_enabled) { - if (p_property.name == "turbulence_noise_strength" || - p_property.name == "turbulence_noise_scale" || - p_property.name == "turbulence_noise_speed" || - p_property.name == "turbulence_noise_speed_random" || - p_property.name == "turbulence_influence_over_life" || - p_property.name == "turbulence_influence_min" || - p_property.name == "turbulence_influence_max" || - p_property.name == "turbulence_initial_displacement_min" || - p_property.name == "turbulence_initial_displacement_max") { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } - } - - if (p_property.name == "collision_friction" && collision_mode != COLLISION_RIGID) { - p_property.usage = PROPERTY_USAGE_NONE; - } - - if (p_property.name == "collision_bounce" && collision_mode != COLLISION_RIGID) { - p_property.usage = PROPERTY_USAGE_NONE; - } -} - -void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) { - sub_emitter_mode = p_sub_emitter_mode; - _queue_shader_change(); - notify_property_list_changed(); -} - -ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() const { - return sub_emitter_mode; -} - -void ParticlesMaterial::set_sub_emitter_frequency(double p_frequency) { - sub_emitter_frequency = p_frequency; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pass delta instead of frequency, since its easier to compute -} - -double ParticlesMaterial::get_sub_emitter_frequency() const { - return sub_emitter_frequency; -} - -void ParticlesMaterial::set_sub_emitter_amount_at_end(int p_amount) { - sub_emitter_amount_at_end = p_amount; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_end, p_amount); -} - -int ParticlesMaterial::get_sub_emitter_amount_at_end() const { - return sub_emitter_amount_at_end; -} - -void ParticlesMaterial::set_sub_emitter_keep_velocity(bool p_enable) { - sub_emitter_keep_velocity = p_enable; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable); -} -bool ParticlesMaterial::get_sub_emitter_keep_velocity() const { - return sub_emitter_keep_velocity; -} - -void ParticlesMaterial::set_attractor_interaction_enabled(bool p_enable) { - attractor_interaction_enabled = p_enable; - _queue_shader_change(); -} - -bool ParticlesMaterial::is_attractor_interaction_enabled() const { - return attractor_interaction_enabled; -} - -void ParticlesMaterial::set_collision_mode(CollisionMode p_collision_mode) { - collision_mode = p_collision_mode; - _queue_shader_change(); - notify_property_list_changed(); -} - -ParticlesMaterial::CollisionMode ParticlesMaterial::get_collision_mode() const { - return collision_mode; -} - -void ParticlesMaterial::set_collision_use_scale(bool p_scale) { - collision_scale = p_scale; - _queue_shader_change(); -} - -bool ParticlesMaterial::is_collision_using_scale() const { - return collision_scale; -} - -void ParticlesMaterial::set_collision_friction(float p_friction) { - collision_friction = p_friction; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_friction, p_friction); -} - -float ParticlesMaterial::get_collision_friction() const { - return collision_friction; -} - -void ParticlesMaterial::set_collision_bounce(float p_bounce) { - collision_bounce = p_bounce; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_bounce, p_bounce); -} - -float ParticlesMaterial::get_collision_bounce() const { - return collision_bounce; -} - -Shader::Mode ParticlesMaterial::get_shader_mode() const { - return Shader::MODE_PARTICLES; -} - -void ParticlesMaterial::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_direction", "degrees"), &ParticlesMaterial::set_direction); - ClassDB::bind_method(D_METHOD("get_direction"), &ParticlesMaterial::get_direction); - - ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticlesMaterial::set_spread); - ClassDB::bind_method(D_METHOD("get_spread"), &ParticlesMaterial::get_spread); - - ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticlesMaterial::set_flatness); - ClassDB::bind_method(D_METHOD("get_flatness"), &ParticlesMaterial::get_flatness); - - ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &ParticlesMaterial::set_param_min); - ClassDB::bind_method(D_METHOD("get_param_min", "param"), &ParticlesMaterial::get_param_min); - - ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &ParticlesMaterial::set_param_max); - ClassDB::bind_method(D_METHOD("get_param_max", "param"), &ParticlesMaterial::get_param_max); - - ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticlesMaterial::set_param_texture); - ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticlesMaterial::get_param_texture); - - ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticlesMaterial::set_color); - ClassDB::bind_method(D_METHOD("get_color"), &ParticlesMaterial::get_color); - - ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticlesMaterial::set_color_ramp); - ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticlesMaterial::get_color_ramp); - - ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &ParticlesMaterial::set_color_initial_ramp); - ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &ParticlesMaterial::get_color_initial_ramp); - - ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &ParticlesMaterial::set_particle_flag); - ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &ParticlesMaterial::get_particle_flag); - - ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape); - ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape); - - ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticlesMaterial::set_emission_sphere_radius); - ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticlesMaterial::get_emission_sphere_radius); - - ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticlesMaterial::set_emission_box_extents); - ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticlesMaterial::get_emission_box_extents); - - ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture"), &ParticlesMaterial::set_emission_point_texture); - ClassDB::bind_method(D_METHOD("get_emission_point_texture"), &ParticlesMaterial::get_emission_point_texture); - - ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture"), &ParticlesMaterial::set_emission_normal_texture); - ClassDB::bind_method(D_METHOD("get_emission_normal_texture"), &ParticlesMaterial::get_emission_normal_texture); - - ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture"), &ParticlesMaterial::set_emission_color_texture); - ClassDB::bind_method(D_METHOD("get_emission_color_texture"), &ParticlesMaterial::get_emission_color_texture); - - ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count); - ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count); - - ClassDB::bind_method(D_METHOD("set_emission_ring_axis", "axis"), &ParticlesMaterial::set_emission_ring_axis); - ClassDB::bind_method(D_METHOD("get_emission_ring_axis"), &ParticlesMaterial::get_emission_ring_axis); - - ClassDB::bind_method(D_METHOD("set_emission_ring_height", "height"), &ParticlesMaterial::set_emission_ring_height); - ClassDB::bind_method(D_METHOD("get_emission_ring_height"), &ParticlesMaterial::get_emission_ring_height); - - ClassDB::bind_method(D_METHOD("set_emission_ring_radius", "radius"), &ParticlesMaterial::set_emission_ring_radius); - ClassDB::bind_method(D_METHOD("get_emission_ring_radius"), &ParticlesMaterial::get_emission_ring_radius); - - ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &ParticlesMaterial::set_emission_ring_inner_radius); - ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &ParticlesMaterial::get_emission_ring_inner_radius); - - ClassDB::bind_method(D_METHOD("get_turbulence_enabled"), &ParticlesMaterial::get_turbulence_enabled); - ClassDB::bind_method(D_METHOD("set_turbulence_enabled", "turbulence_enabled"), &ParticlesMaterial::set_turbulence_enabled); - - ClassDB::bind_method(D_METHOD("get_turbulence_noise_strength"), &ParticlesMaterial::get_turbulence_noise_strength); - ClassDB::bind_method(D_METHOD("set_turbulence_noise_strength", "turbulence_noise_strength"), &ParticlesMaterial::set_turbulence_noise_strength); - - ClassDB::bind_method(D_METHOD("get_turbulence_noise_scale"), &ParticlesMaterial::get_turbulence_noise_scale); - ClassDB::bind_method(D_METHOD("set_turbulence_noise_scale", "turbulence_noise_scale"), &ParticlesMaterial::set_turbulence_noise_scale); - - ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed_random"), &ParticlesMaterial::get_turbulence_noise_speed_random); - ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed_random", "turbulence_noise_speed_random"), &ParticlesMaterial::set_turbulence_noise_speed_random); - - ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed"), &ParticlesMaterial::get_turbulence_noise_speed); - ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed", "turbulence_noise_speed"), &ParticlesMaterial::set_turbulence_noise_speed); - - ClassDB::bind_method(D_METHOD("get_gravity"), &ParticlesMaterial::get_gravity); - ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticlesMaterial::set_gravity); - - ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "randomness"), &ParticlesMaterial::set_lifetime_randomness); - ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &ParticlesMaterial::get_lifetime_randomness); - - ClassDB::bind_method(D_METHOD("get_sub_emitter_mode"), &ParticlesMaterial::get_sub_emitter_mode); - ClassDB::bind_method(D_METHOD("set_sub_emitter_mode", "mode"), &ParticlesMaterial::set_sub_emitter_mode); - - ClassDB::bind_method(D_METHOD("get_sub_emitter_frequency"), &ParticlesMaterial::get_sub_emitter_frequency); - ClassDB::bind_method(D_METHOD("set_sub_emitter_frequency", "hz"), &ParticlesMaterial::set_sub_emitter_frequency); - - ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticlesMaterial::get_sub_emitter_amount_at_end); - ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticlesMaterial::set_sub_emitter_amount_at_end); - - ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticlesMaterial::get_sub_emitter_keep_velocity); - ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticlesMaterial::set_sub_emitter_keep_velocity); - - 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("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("is_collision_using_scale"), &ParticlesMaterial::is_collision_using_scale); - - ClassDB::bind_method(D_METHOD("set_collision_friction", "friction"), &ParticlesMaterial::set_collision_friction); - ClassDB::bind_method(D_METHOD("get_collision_friction"), &ParticlesMaterial::get_collision_friction); - - ClassDB::bind_method(D_METHOD("set_collision_bounce", "bounce"), &ParticlesMaterial::set_collision_bounce); - ClassDB::bind_method(D_METHOD("get_collision_bounce"), &ParticlesMaterial::get_collision_bounce); - - ADD_GROUP("Time", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness"); - - ADD_GROUP("Emission Shape", "emission_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Sphere Surface,Box,Points,Directed Points,Ring"), "set_emission_shape", "get_emission_shape"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,or_greater"), "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::OBJECT, "emission_point_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_point_texture", "get_emission_point_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_normal_texture", "get_emission_normal_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_color_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_color_texture", "get_emission_color_texture"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_ring_axis"), "set_emission_ring_axis", "get_emission_ring_axis"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_height"), "set_emission_ring_height", "get_emission_ring_height"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_radius"), "set_emission_ring_radius", "get_emission_ring_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_inner_radius"), "set_emission_ring_inner_radius", "get_emission_ring_inner_radius"); - ADD_GROUP("Particle Flags", "particle_flag_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z); - ADD_GROUP("Direction", ""); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness"); - ADD_GROUP("Gravity", ""); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity"); - ADD_GROUP("Initial Velocity", "initial_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY); - ADD_GROUP("Angular Velocity", "angular_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY); - ADD_GROUP("Orbit Velocity", "orbit_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY); - ADD_GROUP("Linear Accel", "linear_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL); - ADD_GROUP("Radial Accel", "radial_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL); - ADD_GROUP("Tangential Accel", "tangential_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL); - ADD_GROUP("Damping", ""); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING); - ADD_GROUP("Angle", ""); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE); - ADD_GROUP("Scale", ""); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_SCALE); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture,CurveXYZTexture"), "set_param_texture", "get_param_texture", PARAM_SCALE); - ADD_GROUP("Color", ""); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture1D"), "set_color_ramp", "get_color_ramp"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_initial_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture1D"), "set_color_initial_ramp", "get_color_initial_ramp"); - - ADD_GROUP("Hue Variation", "hue_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION); - - ADD_GROUP("Turbulence", "turbulence_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "turbulence_enabled"), "set_turbulence_enabled", "get_turbulence_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_strength", PROPERTY_HINT_RANGE, "0,20,0.01"), "set_turbulence_noise_strength", "get_turbulence_noise_strength"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_scale", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_turbulence_noise_scale", "get_turbulence_noise_scale"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "turbulence_noise_speed"), "set_turbulence_noise_speed", "get_turbulence_noise_speed"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_speed_random", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_turbulence_noise_speed_random", "get_turbulence_noise_speed_random"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_influence_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_TURB_VEL_INFLUENCE); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_influence_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_TURB_VEL_INFLUENCE); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_initial_displacement_min", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_param_min", "get_param_min", PARAM_TURB_INIT_DISPLACEMENT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_initial_displacement_max", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_param_max", "get_param_max", PARAM_TURB_INIT_DISPLACEMENT); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "turbulence_influence_over_life", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TURB_INFLUENCE_OVER_LIFE); - - ADD_GROUP("Animation", "anim_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET); - - ADD_GROUP("Sub Emitter", "sub_emitter_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,At End,At Collision"), "set_sub_emitter_mode", "get_sub_emitter_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:Hz"), "set_sub_emitter_frequency", "get_sub_emitter_frequency"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity"); - - ADD_GROUP("Attractor Interaction", "attractor_interaction_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "attractor_interaction_enabled"), "set_attractor_interaction_enabled", "is_attractor_interaction_enabled"); - ADD_GROUP("Collision", "collision_"); - 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_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"); - - BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY); - BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY); - BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL); - BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL); - BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL); - BIND_ENUM_CONSTANT(PARAM_DAMPING); - BIND_ENUM_CONSTANT(PARAM_ANGLE); - BIND_ENUM_CONSTANT(PARAM_SCALE); - BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION); - BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED); - BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET); - BIND_ENUM_CONSTANT(PARAM_MAX); - - BIND_ENUM_CONSTANT(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); - BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y); - BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z); - BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX); - - BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); - BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); - BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE_SURFACE); - 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); - - BIND_ENUM_CONSTANT(PARAM_TURB_VEL_INFLUENCE); - BIND_ENUM_CONSTANT(PARAM_TURB_INIT_DISPLACEMENT); - BIND_ENUM_CONSTANT(PARAM_TURB_INFLUENCE_OVER_LIFE); - - BIND_ENUM_CONSTANT(SUB_EMITTER_DISABLED); - BIND_ENUM_CONSTANT(SUB_EMITTER_CONSTANT); - BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END); - BIND_ENUM_CONSTANT(SUB_EMITTER_AT_COLLISION); - 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() : - element(this) { - set_direction(Vector3(1, 0, 0)); - set_spread(45); - set_flatness(0); - set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0); - set_param_min(PARAM_ANGULAR_VELOCITY, 0); - set_param_min(PARAM_ORBIT_VELOCITY, 0); - set_param_min(PARAM_LINEAR_ACCEL, 0); - set_param_min(PARAM_RADIAL_ACCEL, 0); - set_param_min(PARAM_TANGENTIAL_ACCEL, 0); - set_param_min(PARAM_DAMPING, 0); - set_param_min(PARAM_ANGLE, 0); - set_param_min(PARAM_SCALE, 1); - set_param_min(PARAM_HUE_VARIATION, 0); - set_param_min(PARAM_ANIM_SPEED, 0); - set_param_min(PARAM_ANIM_OFFSET, 0); - set_param_max(PARAM_INITIAL_LINEAR_VELOCITY, 0); - set_param_max(PARAM_ANGULAR_VELOCITY, 0); - set_param_max(PARAM_ORBIT_VELOCITY, 0); - set_param_max(PARAM_LINEAR_ACCEL, 0); - set_param_max(PARAM_RADIAL_ACCEL, 0); - set_param_max(PARAM_TANGENTIAL_ACCEL, 0); - set_param_max(PARAM_DAMPING, 0); - set_param_max(PARAM_ANGLE, 0); - set_param_max(PARAM_SCALE, 1); - set_param_max(PARAM_HUE_VARIATION, 0); - set_param_max(PARAM_ANIM_SPEED, 0); - set_param_max(PARAM_ANIM_OFFSET, 0); - set_emission_shape(EMISSION_SHAPE_POINT); - set_emission_sphere_radius(1); - set_emission_box_extents(Vector3(1, 1, 1)); - set_emission_ring_axis(Vector3(0, 0, 1.0)); - set_emission_ring_height(1); - set_emission_ring_radius(1); - set_emission_ring_inner_radius(0); - - set_turbulence_enabled(false); - set_turbulence_noise_speed(Vector3(0.5, 0.5, 0.5)); - set_turbulence_noise_strength(1); - set_turbulence_noise_scale(9); - set_turbulence_noise_speed_random(0); - set_param_min(PARAM_TURB_VEL_INFLUENCE, 0.1); - set_param_max(PARAM_TURB_VEL_INFLUENCE, 0.1); - set_param_min(PARAM_TURB_INIT_DISPLACEMENT, 0.0); - set_param_max(PARAM_TURB_INIT_DISPLACEMENT, 0.0); - - set_gravity(Vector3(0, -9.8, 0)); - set_lifetime_randomness(0); - - set_sub_emitter_mode(SUB_EMITTER_DISABLED); - set_sub_emitter_frequency(4); - set_sub_emitter_amount_at_end(1); - set_sub_emitter_keep_velocity(false); - - set_attractor_interaction_enabled(true); - set_collision_mode(COLLISION_DISABLED); - set_collision_bounce(0.0); - set_collision_friction(0.0); - set_collision_use_scale(false); - - for (int i = 0; i < PARTICLE_FLAG_MAX; i++) { - particle_flags[i] = false; - } - - set_color(Color(1, 1, 1, 1)); - - current_key.invalid_key = 1; - - is_initialized = true; - _queue_shader_change(); -} - -ParticlesMaterial::~ParticlesMaterial() { - MutexLock lock(material_mutex); - - if (shader_map.has(current_key)) { - shader_map[current_key].users--; - if (shader_map[current_key].users == 0) { - //deallocate shader, as it's no longer in use - RS::get_singleton()->free(shader_map[current_key].shader); - shader_map.erase(current_key); - } - - RS::get_singleton()->material_set_shader(_get_material(), RID()); - } -} diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h deleted file mode 100644 index 2e94e7e01a..0000000000 --- a/scene/resources/particles_material.h +++ /dev/null @@ -1,438 +0,0 @@ -/*************************************************************************/ -/* particles_material.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "core/templates/rid.h" -#include "scene/resources/material.h" - -#ifndef PARTICLES_MATERIAL_H -#define PARTICLES_MATERIAL_H - -/* - TODO: --Path following --Emitter positions deformable by bones --Proper trails -*/ - -class ParticlesMaterial : public Material { - GDCLASS(ParticlesMaterial, Material); - -public: - enum Parameter { - PARAM_INITIAL_LINEAR_VELOCITY, - PARAM_ANGULAR_VELOCITY, - PARAM_ORBIT_VELOCITY, - PARAM_LINEAR_ACCEL, - PARAM_RADIAL_ACCEL, - PARAM_TANGENTIAL_ACCEL, - PARAM_DAMPING, - PARAM_ANGLE, - PARAM_SCALE, - PARAM_HUE_VARIATION, - PARAM_ANIM_SPEED, - PARAM_ANIM_OFFSET, - PARAM_TURB_INFLUENCE_OVER_LIFE, - PARAM_TURB_VEL_INFLUENCE, - PARAM_TURB_INIT_DISPLACEMENT, - PARAM_MAX - }; - - // When extending, make sure not to overflow the size of the MaterialKey below. - enum ParticleFlags { - PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, - PARTICLE_FLAG_ROTATE_Y, - PARTICLE_FLAG_DISABLE_Z, - PARTICLE_FLAG_MAX - }; - - // When extending, make sure not to overflow the size of the MaterialKey below. - enum EmissionShape { - EMISSION_SHAPE_POINT, - EMISSION_SHAPE_SPHERE, - EMISSION_SHAPE_SPHERE_SURFACE, - EMISSION_SHAPE_BOX, - EMISSION_SHAPE_POINTS, - EMISSION_SHAPE_DIRECTED_POINTS, - EMISSION_SHAPE_RING, - EMISSION_SHAPE_MAX - }; - - // When extending, make sure not to overflow the size of the MaterialKey below. - enum SubEmitterMode { - SUB_EMITTER_DISABLED, - SUB_EMITTER_CONSTANT, - SUB_EMITTER_AT_END, - SUB_EMITTER_AT_COLLISION, - 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: - union MaterialKey { - // The bit size of the struct must be kept below or equal to 32 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 key = 0; - - static uint32_t hash(const MaterialKey &p_key) { - return hash_murmur3_one_32(p_key.key); - } - - bool operator==(const MaterialKey &p_key) const { - return key == p_key.key; - } - - bool operator<(const MaterialKey &p_key) const { - return key < p_key.key; - } - }; - - struct ShaderData { - RID shader; - int users = 0; - }; - - static HashMap shader_map; - - MaterialKey current_key; - - _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; - mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid(); - mk.sub_emitter = sub_emitter_mode; - mk.collision_mode = collision_mode; - mk.attractor_enabled = attractor_interaction_enabled; - mk.collision_scale = collision_scale; - mk.turbulence_enabled = turbulence_enabled; - - return mk; - } - - static Mutex material_mutex; - static SelfList::List *dirty_materials; - - struct ShaderNames { - StringName direction; - StringName spread; - StringName flatness; - StringName initial_linear_velocity_min; - StringName initial_angle_min; - StringName angular_velocity_min; - StringName orbit_velocity_min; - StringName linear_accel_min; - StringName radial_accel_min; - StringName tangent_accel_min; - StringName damping_min; - StringName scale_min; - StringName hue_variation_min; - StringName anim_speed_min; - StringName anim_offset_min; - - StringName initial_linear_velocity_max; - StringName initial_angle_max; - StringName angular_velocity_max; - StringName orbit_velocity_max; - StringName linear_accel_max; - StringName radial_accel_max; - StringName tangent_accel_max; - StringName damping_max; - StringName scale_max; - StringName hue_variation_max; - StringName anim_speed_max; - StringName anim_offset_max; - - StringName angle_texture; - StringName angular_velocity_texture; - StringName orbit_velocity_texture; - StringName linear_accel_texture; - StringName radial_accel_texture; - StringName tangent_accel_texture; - StringName damping_texture; - StringName scale_texture; - StringName hue_variation_texture; - StringName anim_speed_texture; - StringName anim_offset_texture; - - StringName color; - StringName color_ramp; - StringName color_initial_ramp; - - StringName emission_sphere_radius; - StringName emission_box_extents; - StringName emission_texture_point_count; - StringName emission_texture_points; - StringName emission_texture_normal; - StringName emission_texture_color; - StringName emission_ring_axis; - StringName emission_ring_height; - StringName emission_ring_radius; - StringName emission_ring_inner_radius; - - StringName turbulence_enabled; - StringName turbulence_noise_strength; - StringName turbulence_noise_scale; - StringName turbulence_noise_speed; - StringName turbulence_noise_speed_random; - StringName turbulence_influence_over_life; - StringName turbulence_influence_min; - StringName turbulence_influence_max; - StringName turbulence_initial_displacement_min; - StringName turbulence_initial_displacement_max; - - StringName gravity; - - StringName lifetime_randomness; - - StringName sub_emitter_frequency; - StringName sub_emitter_amount_at_end; - StringName sub_emitter_keep_velocity; - - StringName collision_friction; - StringName collision_bounce; - }; - - static ShaderNames *shader_names; - - SelfList element; - - void _update_shader(); - _FORCE_INLINE_ void _queue_shader_change(); - _FORCE_INLINE_ bool _is_shader_dirty() const; - - bool is_initialized = false; - Vector3 direction; - float spread = 0.0f; - float flatness = 0.0f; - - float params_min[PARAM_MAX]; - float params_max[PARAM_MAX]; - float params[PARAM_MAX]; - - Ref tex_parameters[PARAM_MAX]; - Color color; - Ref color_ramp; - Ref color_initial_ramp; - - bool particle_flags[PARTICLE_FLAG_MAX]; - - EmissionShape emission_shape; - float emission_sphere_radius = 0.0f; - Vector3 emission_box_extents; - Ref emission_point_texture; - Ref emission_normal_texture; - Ref emission_color_texture; - Vector3 emission_ring_axis; - real_t emission_ring_height = 0.0f; - real_t emission_ring_radius = 0.0f; - real_t emission_ring_inner_radius = 0.0f; - int emission_point_count = 1; - - bool anim_loop = false; - - bool turbulence_enabled; - Vector3 turbulence_noise_speed; - Ref turbulence_color_ramp; - float turbulence_noise_strength = 0.0f; - float turbulence_noise_scale = 0.0f; - float turbulence_noise_speed_random = 0.0f; - - Vector3 gravity; - - double lifetime_randomness = 0.0; - - SubEmitterMode sub_emitter_mode; - double sub_emitter_frequency = 0.0; - int sub_emitter_amount_at_end = 0; - bool sub_emitter_keep_velocity = false; - //do not save emission points here - - bool attractor_interaction_enabled = false; - CollisionMode collision_mode; - bool collision_scale = false; - float collision_friction = 0.0f; - float collision_bounce = 0.0f; - -protected: - static void _bind_methods(); - void _validate_property(PropertyInfo &p_property) const; - -public: - void set_direction(Vector3 p_direction); - Vector3 get_direction() const; - - void set_spread(float p_spread); - float get_spread() const; - - void set_flatness(float p_flatness); - float get_flatness() const; - - void set_param_min(Parameter p_param, float p_value); - float get_param_min(Parameter p_param) const; - - void set_param_max(Parameter p_param, float p_value); - float get_param_max(Parameter p_param) const; - - void set_param_texture(Parameter p_param, const Ref &p_texture); - Ref get_param_texture(Parameter p_param) const; - - void set_color(const Color &p_color); - Color get_color() const; - - void set_color_ramp(const Ref &p_texture); - Ref get_color_ramp() const; - - void set_color_initial_ramp(const Ref &p_texture); - Ref get_color_initial_ramp() const; - - void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable); - bool get_particle_flag(ParticleFlags p_particle_flag) const; - - void set_emission_shape(EmissionShape p_shape); - void set_emission_sphere_radius(real_t p_radius); - void set_emission_box_extents(Vector3 p_extents); - void set_emission_point_texture(const Ref &p_points); - void set_emission_normal_texture(const Ref &p_normals); - void set_emission_color_texture(const Ref &p_colors); - void set_emission_ring_axis(Vector3 p_axis); - void set_emission_ring_height(real_t p_height); - void set_emission_ring_radius(real_t p_radius); - void set_emission_ring_inner_radius(real_t p_radius); - void set_emission_point_count(int p_count); - - EmissionShape get_emission_shape() const; - real_t get_emission_sphere_radius() const; - Vector3 get_emission_box_extents() const; - Ref get_emission_point_texture() const; - Ref get_emission_normal_texture() const; - Ref get_emission_color_texture() const; - Vector3 get_emission_ring_axis() const; - real_t get_emission_ring_height() const; - real_t get_emission_ring_radius() const; - real_t get_emission_ring_inner_radius() const; - int get_emission_point_count() const; - - void set_turbulence_enabled(bool p_turbulence_enabled); - void set_turbulence_noise_strength(float p_turbulence_noise_strength); - void set_turbulence_noise_scale(float p_turbulence_noise_scale); - void set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random); - void set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed); - - bool get_turbulence_enabled() const; - float get_turbulence_noise_strength() const; - float get_turbulence_noise_scale() const; - float get_turbulence_noise_speed_random() const; - Vector3 get_turbulence_noise_speed() const; - - void set_gravity(const Vector3 &p_gravity); - Vector3 get_gravity() const; - - void set_lifetime_randomness(double p_lifetime); - double get_lifetime_randomness() const; - - void set_attractor_interaction_enabled(bool p_enable); - bool is_attractor_interaction_enabled() const; - - void set_collision_mode(CollisionMode p_collision_mode); - CollisionMode get_collision_mode() const; - - void set_collision_use_scale(bool p_scale); - bool is_collision_using_scale() const; - - void set_collision_friction(float p_friction); - float get_collision_friction() const; - - void set_collision_bounce(float p_bounce); - float get_collision_bounce() const; - - static void init_shaders(); - static void finish_shaders(); - static void flush_changes(); - - void set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode); - SubEmitterMode get_sub_emitter_mode() const; - - void set_sub_emitter_frequency(double p_frequency); - double get_sub_emitter_frequency() const; - - void set_sub_emitter_amount_at_end(int p_amount); - int get_sub_emitter_amount_at_end() const; - - void set_sub_emitter_keep_velocity(bool p_enable); - bool get_sub_emitter_keep_velocity() const; - - virtual RID get_shader_rid() const override; - - virtual Shader::Mode get_shader_mode() const override; - - ParticlesMaterial(); - ~ParticlesMaterial(); -}; - -VARIANT_ENUM_CAST(ParticlesMaterial::Parameter) -VARIANT_ENUM_CAST(ParticlesMaterial::ParticleFlags) -VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape) -VARIANT_ENUM_CAST(ParticlesMaterial::SubEmitterMode) -VARIANT_ENUM_CAST(ParticlesMaterial::CollisionMode) - -#endif // PARTICLES_MATERIAL_H diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index ba644e7eb9..022b027644 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -134,7 +134,7 @@ void process() { material_storage->material_initialize(particles_shader.default_material); material_storage->material_set_shader(particles_shader.default_material, particles_shader.default_shader); - ParticlesMaterialData *md = static_cast(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES)); + ParticleProcessMaterialData *md = static_cast(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES)); particles_shader.default_shader_rd = particles_shader.shader.version_get_shader(md->shader_data->version, 0); Vector uniforms; @@ -1072,9 +1072,9 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams) * p_particles->trail_params.size(), p_particles->trail_params.ptr()); - ParticlesMaterialData *m = static_cast(material_storage->material_get_data(p_particles->process_material, MaterialStorage::SHADER_TYPE_PARTICLES)); + ParticleProcessMaterialData *m = static_cast(material_storage->material_get_data(p_particles->process_material, MaterialStorage::SHADER_TYPE_PARTICLES)); if (!m) { - m = static_cast(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES)); + m = static_cast(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES)); } ERR_FAIL_COND(!m); @@ -1696,16 +1696,16 @@ MaterialStorage::ShaderData *ParticlesStorage::_create_particles_shader_func() { return shader_data; } -bool ParticlesStorage::ParticlesMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { +bool ParticlesStorage::ParticleProcessMaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, ParticlesStorage::get_singleton()->particles_shader.shader.version_get_shader(shader_data->version, 0), 3); } -ParticlesStorage::ParticlesMaterialData::~ParticlesMaterialData() { +ParticlesStorage::ParticleProcessMaterialData::~ParticleProcessMaterialData() { free_parameters_uniform_set(uniform_set); } MaterialStorage::MaterialData *ParticlesStorage::_create_particles_material_func(ParticlesShaderData *p_shader) { - ParticlesMaterialData *material_data = memnew(ParticlesMaterialData); + ParticleProcessMaterialData *material_data = memnew(ParticleProcessMaterialData); material_data->shader_data = p_shader; //update will happen later anyway so do nothing. return material_data; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h index 97d100e2da..299fdc6ec8 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h @@ -354,14 +354,14 @@ private: return ParticlesStorage::get_singleton()->_create_particles_shader_func(); } - struct ParticlesMaterialData : public MaterialStorage::MaterialData { + struct ParticleProcessMaterialData : public MaterialStorage::MaterialData { ParticlesShaderData *shader_data = nullptr; RID uniform_set; virtual void set_render_priority(int p_priority) {} virtual void set_next_pass(RID p_pass) {} virtual bool update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); - virtual ~ParticlesMaterialData(); + virtual ~ParticleProcessMaterialData(); }; MaterialStorage::MaterialData *_create_particles_material_func(ParticlesShaderData *p_shader); -- cgit v1.2.3