Support for 2D particles to collide against SDF
-Added SDF collision support for 2D particles -Changed the SDF generation to be fully signed
This commit is contained in:
parent
809948f977
commit
789713b008
|
@ -31,7 +31,9 @@
|
|||
<member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
|
||||
Number of particles emitted in one emission cycle.
|
||||
</member>
|
||||
<member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="GPUParticles2D.DrawOrder" default="0">
|
||||
<member name="collision_base_size" type="float" setter="set_collision_base_size" getter="get_collision_base_size" default="1.0">
|
||||
</member>
|
||||
<member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="GPUParticles2D.DrawOrder" default="1">
|
||||
Particle draw order. Uses [enum DrawOrder] values.
|
||||
</member>
|
||||
<member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
|
||||
|
@ -40,7 +42,7 @@
|
|||
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
|
||||
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
|
||||
</member>
|
||||
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
|
||||
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="30">
|
||||
The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
|
||||
</member>
|
||||
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
|
||||
|
@ -70,6 +72,14 @@
|
|||
<member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
|
||||
Particle texture. If [code]null[/code], particles will be squares.
|
||||
</member>
|
||||
<member name="trail_enabled" type="bool" setter="set_trail_enabled" getter="is_trail_enabled" default="false">
|
||||
</member>
|
||||
<member name="trail_length_secs" type="float" setter="set_trail_length" getter="get_trail_length" default="0.3">
|
||||
</member>
|
||||
<member name="trail_section_subdivisions" type="int" setter="set_trail_section_subdivisions" getter="get_trail_section_subdivisions" default="4">
|
||||
</member>
|
||||
<member name="trail_sections" type="int" setter="set_trail_sections" getter="get_trail_sections" default="8">
|
||||
</member>
|
||||
<member name="visibility_rect" type="Rect2" setter="set_visibility_rect" getter="get_visibility_rect" default="Rect2( -100, -100, 200, 200 )">
|
||||
The [Rect2] that determines the node's region which needs to be visible on screen for the particle system to be active.
|
||||
Grow the rect if particles suddenly appear/disappear when the node enters/exits the screen. The [Rect2] can be grown via code or with the [b]Particles → Generate Visibility Rect[/b] editor tool.
|
||||
|
@ -82,5 +92,7 @@
|
|||
<constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
|
||||
Particles are drawn in order of remaining lifetime.
|
||||
</constant>
|
||||
<constant name="DRAW_ORDER_REVERSE_LIFETIME" value="2" enum="DrawOrder">
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
</member>
|
||||
<member name="sub_emitter" type="NodePath" setter="set_sub_emitter" getter="get_sub_emitter" default="NodePath("")">
|
||||
</member>
|
||||
<member name="trail_enabled" type="bool" setter="set_enable_trail" getter="is_trail_enabled" default="false">
|
||||
<member name="trail_enabled" type="bool" setter="set_trail_enabled" getter="is_trail_enabled" default="false">
|
||||
</member>
|
||||
<member name="trail_length_secs" type="float" setter="set_trail_length" getter="get_trail_length" default="0.3">
|
||||
</member>
|
||||
|
@ -144,7 +144,9 @@
|
|||
<constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
|
||||
Particles are drawn in order of remaining lifetime.
|
||||
</constant>
|
||||
<constant name="DRAW_ORDER_VIEW_DEPTH" value="2" enum="DrawOrder">
|
||||
<constant name="DRAW_ORDER_REVERSE_LIFETIME" value="2" enum="DrawOrder">
|
||||
</constant>
|
||||
<constant name="DRAW_ORDER_VIEW_DEPTH" value="3" enum="DrawOrder">
|
||||
Particles are drawn in order of depth.
|
||||
</constant>
|
||||
<constant name="EMIT_FLAG_POSITION" value="1" enum="EmitFlags">
|
||||
|
|
|
@ -135,7 +135,7 @@
|
|||
</member>
|
||||
<member name="collision_bounce" type="float" setter="set_collision_bounce" getter="get_collision_bounce" default="0.0">
|
||||
</member>
|
||||
<member name="collision_enabled" type="bool" setter="set_collision_enabled" getter="is_collision_enabled" default="true">
|
||||
<member name="collision_enabled" type="bool" setter="set_collision_enabled" getter="is_collision_enabled" default="false">
|
||||
</member>
|
||||
<member name="collision_friction" type="float" setter="set_collision_friction" getter="get_collision_friction" default="0.0">
|
||||
</member>
|
||||
|
|
|
@ -3388,7 +3388,7 @@
|
|||
<constant name="PARTICLES_DRAW_ORDER_LIFETIME" value="1" enum="ParticlesDrawOrder">
|
||||
Sort particles based on their lifetime.
|
||||
</constant>
|
||||
<constant name="PARTICLES_DRAW_ORDER_VIEW_DEPTH" value="2" enum="ParticlesDrawOrder">
|
||||
<constant name="PARTICLES_DRAW_ORDER_VIEW_DEPTH" value="3" enum="ParticlesDrawOrder">
|
||||
Sort particles based on their distance to the camera.
|
||||
</constant>
|
||||
<constant name="VIEWPORT_UPDATE_DISABLED" value="0" enum="ViewportUpdateMode">
|
||||
|
|
|
@ -140,6 +140,62 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
|
|||
update_configuration_warnings();
|
||||
}
|
||||
|
||||
void GPUParticles2D::set_trail_enabled(bool p_enabled) {
|
||||
trail_enabled = p_enabled;
|
||||
RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
|
||||
update_configuration_warnings();
|
||||
update();
|
||||
|
||||
RS::get_singleton()->particles_set_transform_align(particles, p_enabled ? RS::PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY : RS::PARTICLES_TRANSFORM_ALIGN_DISABLED);
|
||||
}
|
||||
void GPUParticles2D::set_trail_length(float p_seconds) {
|
||||
ERR_FAIL_COND(p_seconds < 0.001);
|
||||
trail_length = p_seconds;
|
||||
RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
|
||||
update();
|
||||
}
|
||||
|
||||
void GPUParticles2D::set_trail_sections(int p_sections) {
|
||||
ERR_FAIL_COND(p_sections < 2);
|
||||
ERR_FAIL_COND(p_sections > 128);
|
||||
|
||||
trail_sections = p_sections;
|
||||
update();
|
||||
}
|
||||
void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) {
|
||||
ERR_FAIL_COND(trail_section_subdivisions < 1);
|
||||
ERR_FAIL_COND(trail_section_subdivisions > 1024);
|
||||
|
||||
trail_section_subdivisions = p_subdivisions;
|
||||
update();
|
||||
}
|
||||
|
||||
bool GPUParticles2D::is_trail_enabled() const {
|
||||
return trail_enabled;
|
||||
}
|
||||
float GPUParticles2D::get_trail_length() const {
|
||||
return trail_length;
|
||||
}
|
||||
|
||||
void GPUParticles2D::_update_collision_size() {
|
||||
float csize = collision_base_size;
|
||||
|
||||
if (texture.is_valid()) {
|
||||
csize *= (texture->get_width() + texture->get_height()) / 4.0; //half size since its a radius
|
||||
}
|
||||
|
||||
RS::get_singleton()->particles_set_collision_base_size(particles, csize);
|
||||
}
|
||||
|
||||
void GPUParticles2D::set_collision_base_size(float p_size) {
|
||||
collision_base_size = p_size;
|
||||
_update_collision_size();
|
||||
}
|
||||
|
||||
float GPUParticles2D::get_collision_base_size() const {
|
||||
return collision_base_size;
|
||||
}
|
||||
|
||||
void GPUParticles2D::set_speed_scale(float p_scale) {
|
||||
speed_scale = p_scale;
|
||||
RS::get_singleton()->particles_set_speed_scale(particles, p_scale);
|
||||
|
@ -157,6 +213,13 @@ float GPUParticles2D::get_lifetime() const {
|
|||
return lifetime;
|
||||
}
|
||||
|
||||
int GPUParticles2D::get_trail_sections() const {
|
||||
return trail_sections;
|
||||
}
|
||||
int GPUParticles2D::get_trail_section_subdivisions() const {
|
||||
return trail_section_subdivisions;
|
||||
}
|
||||
|
||||
bool GPUParticles2D::get_one_shot() const {
|
||||
return one_shot;
|
||||
}
|
||||
|
@ -253,6 +316,7 @@ Rect2 GPUParticles2D::capture_rect() const {
|
|||
|
||||
void GPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) {
|
||||
texture = p_texture;
|
||||
_update_collision_size();
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -271,10 +335,119 @@ void GPUParticles2D::restart() {
|
|||
void GPUParticles2D::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_DRAW) {
|
||||
RID texture_rid;
|
||||
Size2 size;
|
||||
if (texture.is_valid()) {
|
||||
texture_rid = texture->get_rid();
|
||||
size = texture->get_size();
|
||||
} else {
|
||||
size = Size2(1, 1);
|
||||
}
|
||||
|
||||
if (trail_enabled) {
|
||||
RS::get_singleton()->mesh_clear(mesh);
|
||||
PackedVector2Array points;
|
||||
PackedVector2Array uvs;
|
||||
PackedInt32Array bone_indices;
|
||||
PackedFloat32Array bone_weights;
|
||||
PackedInt32Array indices;
|
||||
|
||||
int total_segments = trail_sections * trail_section_subdivisions;
|
||||
float depth = size.height * trail_sections;
|
||||
|
||||
for (int j = 0; j <= total_segments; j++) {
|
||||
float v = j;
|
||||
v /= total_segments;
|
||||
|
||||
float y = depth * v;
|
||||
y = (depth * 0.5) - y;
|
||||
|
||||
int bone = j / trail_section_subdivisions;
|
||||
float blend = 1.0 - float(j % trail_section_subdivisions) / float(trail_section_subdivisions);
|
||||
|
||||
float s = size.width;
|
||||
|
||||
points.push_back(Vector2(-s * 0.5, 0));
|
||||
points.push_back(Vector2(+s * 0.5, 0));
|
||||
|
||||
uvs.push_back(Vector2(0, v));
|
||||
uvs.push_back(Vector2(1, v));
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
bone_indices.push_back(bone);
|
||||
bone_indices.push_back(MIN(trail_sections, bone + 1));
|
||||
bone_indices.push_back(0);
|
||||
bone_indices.push_back(0);
|
||||
|
||||
bone_weights.push_back(blend);
|
||||
bone_weights.push_back(1.0 - blend);
|
||||
bone_weights.push_back(0);
|
||||
bone_weights.push_back(0);
|
||||
}
|
||||
|
||||
if (j > 0) {
|
||||
int base = j * 2 - 2;
|
||||
indices.push_back(base + 0);
|
||||
indices.push_back(base + 1);
|
||||
indices.push_back(base + 2);
|
||||
|
||||
indices.push_back(base + 1);
|
||||
indices.push_back(base + 3);
|
||||
indices.push_back(base + 2);
|
||||
}
|
||||
}
|
||||
|
||||
Array arr;
|
||||
arr.resize(RS::ARRAY_MAX);
|
||||
arr[RS::ARRAY_VERTEX] = points;
|
||||
arr[RS::ARRAY_TEX_UV] = uvs;
|
||||
arr[RS::ARRAY_BONES] = bone_indices;
|
||||
arr[RS::ARRAY_WEIGHTS] = bone_weights;
|
||||
arr[RS::ARRAY_INDEX] = indices;
|
||||
|
||||
RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
|
||||
|
||||
Vector<Transform> xforms;
|
||||
for (int i = 0; i <= trail_sections; i++) {
|
||||
Transform xform;
|
||||
/*
|
||||
xform.origin.y = depth / 2.0 - size.height * float(i);
|
||||
xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y */
|
||||
xforms.push_back(xform);
|
||||
}
|
||||
|
||||
RS::get_singleton()->particles_set_trail_bind_poses(particles, xforms);
|
||||
|
||||
} else {
|
||||
RS::get_singleton()->mesh_clear(mesh);
|
||||
Vector<Vector2> points;
|
||||
points.resize(4);
|
||||
points.write[0] = Vector2(-size.x / 2.0, -size.y / 2.0);
|
||||
points.write[1] = Vector2(size.x / 2.0, -size.y / 2.0);
|
||||
points.write[2] = Vector2(size.x / 2.0, size.y / 2.0);
|
||||
points.write[3] = Vector2(-size.x / 2.0, size.y / 2.0);
|
||||
Vector<Vector2> uvs;
|
||||
uvs.resize(4);
|
||||
uvs.write[0] = Vector2(0, 0);
|
||||
uvs.write[1] = Vector2(1, 0);
|
||||
uvs.write[2] = Vector2(1, 1);
|
||||
uvs.write[3] = Vector2(0, 1);
|
||||
Vector<int> indices;
|
||||
indices.resize(6);
|
||||
indices.write[0] = 0;
|
||||
indices.write[1] = 1;
|
||||
indices.write[2] = 2;
|
||||
indices.write[3] = 0;
|
||||
indices.write[4] = 2;
|
||||
indices.write[5] = 3;
|
||||
Array arr;
|
||||
arr.resize(RS::ARRAY_MAX);
|
||||
arr[RS::ARRAY_VERTEX] = points;
|
||||
arr[RS::ARRAY_TEX_UV] = uvs;
|
||||
arr[RS::ARRAY_INDEX] = indices;
|
||||
|
||||
RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
|
||||
RS::get_singleton()->particles_set_trail_bind_poses(particles, Vector<Transform>());
|
||||
}
|
||||
RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
@ -318,6 +491,7 @@ void GPUParticles2D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &GPUParticles2D::set_fractional_delta);
|
||||
ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles2D::set_process_material);
|
||||
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles2D::set_speed_scale);
|
||||
ClassDB::bind_method(D_METHOD("set_collision_base_size", "size"), &GPUParticles2D::set_collision_base_size);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_emitting"), &GPUParticles2D::is_emitting);
|
||||
ClassDB::bind_method(D_METHOD("get_amount"), &GPUParticles2D::get_amount);
|
||||
|
@ -332,6 +506,7 @@ void GPUParticles2D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &GPUParticles2D::get_fractional_delta);
|
||||
ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles2D::get_process_material);
|
||||
ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles2D::get_speed_scale);
|
||||
ClassDB::bind_method(D_METHOD("get_collision_base_size"), &GPUParticles2D::get_collision_base_size);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &GPUParticles2D::set_draw_order);
|
||||
ClassDB::bind_method(D_METHOD("get_draw_order"), &GPUParticles2D::get_draw_order);
|
||||
|
@ -343,6 +518,18 @@ void GPUParticles2D::_bind_methods() {
|
|||
|
||||
ClassDB::bind_method(D_METHOD("restart"), &GPUParticles2D::restart);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles2D::set_trail_enabled);
|
||||
ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles2D::set_trail_length);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles2D::is_trail_enabled);
|
||||
ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles2D::get_trail_length);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_trail_sections", "sections"), &GPUParticles2D::set_trail_sections);
|
||||
ClassDB::bind_method(D_METHOD("get_trail_sections"), &GPUParticles2D::get_trail_sections);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_trail_section_subdivisions", "subdivisions"), &GPUParticles2D::set_trail_section_subdivisions);
|
||||
ClassDB::bind_method(D_METHOD("get_trail_section_subdivisions"), &GPUParticles2D::get_trail_section_subdivisions);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
|
||||
ADD_GROUP("Time", "");
|
||||
|
@ -354,10 +541,17 @@ void GPUParticles2D::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
|
||||
ADD_GROUP("Collision", "collision_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_collision_base_size", "get_collision_base_size");
|
||||
ADD_GROUP("Drawing", "");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,Reverse Lifetime"), "set_draw_order", "get_draw_order");
|
||||
ADD_GROUP("Trails", "trail_");
|
||||
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"), "set_trail_length", "get_trail_length");
|
||||
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_GROUP("Textures", "");
|
||||
|
@ -365,12 +559,17 @@ void GPUParticles2D::_bind_methods() {
|
|||
|
||||
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
|
||||
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
|
||||
BIND_ENUM_CONSTANT(DRAW_ORDER_REVERSE_LIFETIME);
|
||||
}
|
||||
|
||||
GPUParticles2D::GPUParticles2D() {
|
||||
particles = RS::get_singleton()->particles_create();
|
||||
RS::get_singleton()->particles_set_mode(particles, RS::PARTICLES_MODE_2D);
|
||||
|
||||
mesh = RS::get_singleton()->mesh_create();
|
||||
RS::get_singleton()->particles_set_draw_passes(particles, 1);
|
||||
RS::get_singleton()->particles_set_draw_pass_mesh(particles, 0, mesh);
|
||||
|
||||
one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
|
||||
set_emitting(true);
|
||||
set_one_shot(false);
|
||||
|
@ -383,10 +582,13 @@ GPUParticles2D::GPUParticles2D() {
|
|||
set_randomness_ratio(0);
|
||||
set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200)));
|
||||
set_use_local_coordinates(true);
|
||||
set_draw_order(DRAW_ORDER_INDEX);
|
||||
set_draw_order(DRAW_ORDER_LIFETIME);
|
||||
set_speed_scale(1);
|
||||
set_fixed_fps(30);
|
||||
set_collision_base_size(collision_base_size);
|
||||
}
|
||||
|
||||
GPUParticles2D::~GPUParticles2D() {
|
||||
RS::get_singleton()->free(particles);
|
||||
RS::get_singleton()->free(mesh);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
enum DrawOrder {
|
||||
DRAW_ORDER_INDEX,
|
||||
DRAW_ORDER_LIFETIME,
|
||||
DRAW_ORDER_REVERSE_LIFETIME,
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -68,11 +69,23 @@ private:
|
|||
|
||||
void _update_particle_emission_transform();
|
||||
|
||||
NodePath sub_emitter;
|
||||
float collision_base_size = 1.0;
|
||||
|
||||
bool trail_enabled = false;
|
||||
float trail_length = 0.3;
|
||||
int trail_sections = 8;
|
||||
int trail_section_subdivisions = 4;
|
||||
|
||||
RID mesh;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
virtual void _validate_property(PropertyInfo &property) const override;
|
||||
void _notification(int p_what);
|
||||
|
||||
void _update_collision_size();
|
||||
|
||||
public:
|
||||
void set_emitting(bool p_emitting);
|
||||
void set_amount(int p_amount);
|
||||
|
@ -85,6 +98,11 @@ public:
|
|||
void set_use_local_coordinates(bool p_enable);
|
||||
void set_process_material(const Ref<Material> &p_material);
|
||||
void set_speed_scale(float p_scale);
|
||||
void set_collision_base_size(float p_ratio);
|
||||
void set_trail_enabled(bool p_enabled);
|
||||
void set_trail_length(float p_seconds);
|
||||
void set_trail_sections(int p_sections);
|
||||
void set_trail_section_subdivisions(int p_subdivisions);
|
||||
|
||||
bool is_emitting() const;
|
||||
int get_amount() const;
|
||||
|
@ -98,6 +116,12 @@ public:
|
|||
Ref<Material> get_process_material() const;
|
||||
float get_speed_scale() const;
|
||||
|
||||
float get_collision_base_size() const;
|
||||
bool is_trail_enabled() const;
|
||||
float get_trail_length() const;
|
||||
int get_trail_sections() const;
|
||||
int get_trail_section_subdivisions() const;
|
||||
|
||||
void set_fixed_fps(int p_count);
|
||||
int get_fixed_fps() const;
|
||||
|
||||
|
|
|
@ -181,7 +181,7 @@ void GPUParticles3D::set_draw_order(DrawOrder p_order) {
|
|||
RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order));
|
||||
}
|
||||
|
||||
void GPUParticles3D::set_enable_trail(bool p_enabled) {
|
||||
void GPUParticles3D::set_trail_enabled(bool p_enabled) {
|
||||
trail_enabled = p_enabled;
|
||||
RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
|
||||
update_configuration_warnings();
|
||||
|
@ -552,7 +552,7 @@ void GPUParticles3D::_bind_methods() {
|
|||
|
||||
ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles3D::emit_particle);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_enable_trail", "enabled"), &GPUParticles3D::set_enable_trail);
|
||||
ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles3D::set_trail_enabled);
|
||||
ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles3D::set_trail_length);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles3D::is_trail_enabled);
|
||||
|
@ -579,11 +579,11 @@ void GPUParticles3D::_bind_methods() {
|
|||
ADD_GROUP("Drawing", "");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,Reverse Lifetime,View Depth"), "set_draw_order", "get_draw_order");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,ZBillboard,YToVelocity,ZBillboardYToVelocity"), "set_transform_align", "get_transform_align");
|
||||
ADD_GROUP("Trails", "trail_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_enable_trail", "is_trail_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,4,0.01"), "set_trail_length", "get_trail_length");
|
||||
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"), "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_GROUP("Draw Passes", "draw_");
|
||||
|
@ -595,6 +595,7 @@ void GPUParticles3D::_bind_methods() {
|
|||
|
||||
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
|
||||
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
|
||||
BIND_ENUM_CONSTANT(DRAW_ORDER_REVERSE_LIFETIME);
|
||||
BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
|
||||
|
||||
BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION);
|
||||
|
@ -632,7 +633,7 @@ GPUParticles3D::GPUParticles3D() {
|
|||
set_draw_passes(1);
|
||||
set_draw_order(DRAW_ORDER_INDEX);
|
||||
set_speed_scale(1);
|
||||
set_collision_base_size(0.01);
|
||||
set_collision_base_size(collision_base_size);
|
||||
set_transform_align(TRANSFORM_ALIGN_DISABLED);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ public:
|
|||
enum DrawOrder {
|
||||
DRAW_ORDER_INDEX,
|
||||
DRAW_ORDER_LIFETIME,
|
||||
DRAW_ORDER_REVERSE_LIFETIME,
|
||||
DRAW_ORDER_VIEW_DEPTH,
|
||||
};
|
||||
|
||||
|
@ -74,7 +75,7 @@ private:
|
|||
bool fractional_delta;
|
||||
bool interpolate = true;
|
||||
NodePath sub_emitter;
|
||||
float collision_base_size;
|
||||
float collision_base_size = 0.01;
|
||||
|
||||
bool trail_enabled = false;
|
||||
float trail_length = 0.3;
|
||||
|
@ -113,7 +114,7 @@ public:
|
|||
void set_process_material(const Ref<Material> &p_material);
|
||||
void set_speed_scale(float p_scale);
|
||||
void set_collision_base_size(float p_ratio);
|
||||
void set_enable_trail(bool p_enabled);
|
||||
void set_trail_enabled(bool p_enabled);
|
||||
void set_trail_length(float p_seconds);
|
||||
|
||||
bool is_emitting() const;
|
||||
|
|
|
@ -1391,7 +1391,7 @@ ParticlesMaterial::ParticlesMaterial() :
|
|||
set_sub_emitter_keep_velocity(false);
|
||||
|
||||
set_attractor_interaction_enabled(true);
|
||||
set_collision_enabled(true);
|
||||
set_collision_enabled(false);
|
||||
set_collision_bounce(0.0);
|
||||
set_collision_friction(0.0);
|
||||
set_collision_use_scale(false);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "core/math/geometry_2d.h"
|
||||
#include "core/math/math_funcs.h"
|
||||
#include "renderer_compositor_rd.h"
|
||||
#include "servers/rendering/rendering_server_default.h"
|
||||
|
||||
void RendererCanvasRenderRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
|
||||
p_mat4[0] = p_transform.elements[0][0];
|
||||
|
@ -390,7 +391,7 @@ void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RI
|
|||
r_last_texture = p_texture;
|
||||
}
|
||||
|
||||
void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {
|
||||
void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {
|
||||
//create an empty push constant
|
||||
|
||||
RS::CanvasItemTextureFilter current_filter = default_filter;
|
||||
|
@ -747,9 +748,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
|
|||
} else if (c->type == Item::Command::TYPE_PARTICLES) {
|
||||
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
|
||||
ERR_BREAK(storage->particles_get_mode(pt->particles) != RS::PARTICLES_MODE_2D);
|
||||
storage->particles_request_process(pt->particles);
|
||||
|
||||
if (storage->particles_is_inactive(pt->particles)) {
|
||||
break;
|
||||
}
|
||||
|
||||
RenderingServerDefault::redraw_request(); // active particles means redraw request
|
||||
|
||||
bool local_coords = true;
|
||||
int dpc = storage->particles_get_draw_passes(pt->particles);
|
||||
if (dpc == 0) {
|
||||
break; //nothing to draw
|
||||
|
@ -768,6 +775,30 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
|
|||
|
||||
mesh = storage->particles_get_draw_pass_mesh(pt->particles, 0); //higher ones are ignored
|
||||
texture = pt->texture;
|
||||
|
||||
if (storage->particles_has_collision(pt->particles) && storage->render_target_is_sdf_enabled(p_render_target)) {
|
||||
//pass collision information
|
||||
Transform2D xform;
|
||||
if (local_coords) {
|
||||
xform = p_item->final_transform;
|
||||
} else {
|
||||
xform = p_canvas_transform_inverse;
|
||||
}
|
||||
|
||||
RID sdf_texture = storage->render_target_get_sdf_texture(p_render_target);
|
||||
|
||||
Rect2 to_screen;
|
||||
{
|
||||
Rect2 sdf_rect = storage->render_target_get_sdf_rect(p_render_target);
|
||||
|
||||
to_screen.size = Vector2(1.0 / sdf_rect.size.width, 1.0 / sdf_rect.size.height);
|
||||
to_screen.position = -sdf_rect.position * to_screen.size;
|
||||
}
|
||||
|
||||
storage->particles_set_canvas_sdf_collision(pt->particles, true, xform, to_screen, sdf_texture);
|
||||
} else {
|
||||
storage->particles_set_canvas_sdf_collision(pt->particles, false, Transform2D(), Rect2(), RID());
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh.is_null()) {
|
||||
|
@ -1052,7 +1083,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
|
|||
}
|
||||
}
|
||||
|
||||
_render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants);
|
||||
_render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants);
|
||||
|
||||
prev_material = material;
|
||||
}
|
||||
|
@ -1280,6 +1311,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
|
|||
Item *canvas_group_owner = nullptr;
|
||||
|
||||
bool update_skeletons = false;
|
||||
bool time_used = false;
|
||||
|
||||
while (ci) {
|
||||
if (ci->copy_back_buffer && canvas_group_owner == nullptr) {
|
||||
|
@ -1305,6 +1337,9 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
|
|||
if (md->shader_data->uses_sdf) {
|
||||
r_sdf_used = true;
|
||||
}
|
||||
if (md->shader_data->uses_time) {
|
||||
time_used = true;
|
||||
}
|
||||
if (md->last_frame != RendererCompositorRD::singleton->get_frame_number()) {
|
||||
md->last_frame = RendererCompositorRD::singleton->get_frame_number();
|
||||
if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) {
|
||||
|
@ -1401,6 +1436,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
|
|||
|
||||
ci = ci->next;
|
||||
}
|
||||
|
||||
if (time_used) {
|
||||
RenderingServerDefault::redraw_request();
|
||||
}
|
||||
}
|
||||
|
||||
RID RendererCanvasRenderRD::light_create() {
|
||||
|
@ -1877,6 +1916,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
|
|||
uniforms.clear();
|
||||
uses_screen_texture = false;
|
||||
uses_sdf = false;
|
||||
uses_time = false;
|
||||
|
||||
if (code == String()) {
|
||||
return; //just invalid, but no error
|
||||
|
@ -1901,6 +1941,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
|
|||
|
||||
actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
|
||||
actions.usage_flag_pointers["texture_sdf"] = &uses_sdf;
|
||||
actions.usage_flag_pointers["TIME"] = &uses_time;
|
||||
|
||||
actions.uniforms = &uniforms;
|
||||
|
||||
|
|
|
@ -176,6 +176,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
|||
|
||||
bool uses_screen_texture = false;
|
||||
bool uses_sdf = false;
|
||||
bool uses_time = false;
|
||||
|
||||
virtual void set_code(const String &p_Code);
|
||||
virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
|
||||
|
@ -425,7 +426,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
|
|||
RID _create_base_uniform_set(RID p_to_render_target, bool p_backbuffer);
|
||||
|
||||
inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size); //recursive, so regular inline used instead.
|
||||
void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants);
|
||||
void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants);
|
||||
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false);
|
||||
|
||||
_FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
|
||||
|
|
|
@ -4305,6 +4305,15 @@ void RendererStorageRD::particles_remove_collision(RID p_particles, RID p_partic
|
|||
particles->collisions.erase(p_particles_collision_instance);
|
||||
}
|
||||
|
||||
void RendererStorageRD::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) {
|
||||
Particles *particles = particles_owner.getornull(p_particles);
|
||||
ERR_FAIL_COND(!particles);
|
||||
particles->has_sdf_collision = p_enable;
|
||||
particles->sdf_collision_transform = p_xform;
|
||||
particles->sdf_collision_to_screen = p_to_screen;
|
||||
particles->sdf_collision_texture = p_texture;
|
||||
}
|
||||
|
||||
void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta) {
|
||||
if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) {
|
||||
Vector<RD::Uniform> uniforms;
|
||||
|
@ -4410,6 +4419,50 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
|
|||
if (p_particles->use_local_coords) {
|
||||
to_particles = p_particles->emission_transform.affine_inverse();
|
||||
}
|
||||
|
||||
if (p_particles->has_sdf_collision && RD::get_singleton()->texture_is_valid(p_particles->sdf_collision_texture)) {
|
||||
//2D collision
|
||||
|
||||
Transform2D xform = p_particles->sdf_collision_transform; //will use dotproduct manually so invert beforehand
|
||||
Transform2D revert = xform.affine_inverse();
|
||||
frame_params.collider_count = 1;
|
||||
frame_params.colliders[0].transform[0] = xform.elements[0][0];
|
||||
frame_params.colliders[0].transform[1] = xform.elements[0][1];
|
||||
frame_params.colliders[0].transform[2] = 0;
|
||||
frame_params.colliders[0].transform[3] = xform.elements[2][0];
|
||||
|
||||
frame_params.colliders[0].transform[4] = xform.elements[1][0];
|
||||
frame_params.colliders[0].transform[5] = xform.elements[1][1];
|
||||
frame_params.colliders[0].transform[6] = 0;
|
||||
frame_params.colliders[0].transform[7] = xform.elements[2][1];
|
||||
|
||||
frame_params.colliders[0].transform[8] = revert.elements[0][0];
|
||||
frame_params.colliders[0].transform[9] = revert.elements[0][1];
|
||||
frame_params.colliders[0].transform[10] = 0;
|
||||
frame_params.colliders[0].transform[11] = revert.elements[2][0];
|
||||
|
||||
frame_params.colliders[0].transform[12] = revert.elements[1][0];
|
||||
frame_params.colliders[0].transform[13] = revert.elements[1][1];
|
||||
frame_params.colliders[0].transform[14] = 0;
|
||||
frame_params.colliders[0].transform[15] = revert.elements[2][1];
|
||||
|
||||
frame_params.colliders[0].extents[0] = p_particles->sdf_collision_to_screen.size.x;
|
||||
frame_params.colliders[0].extents[1] = p_particles->sdf_collision_to_screen.size.y;
|
||||
frame_params.colliders[0].extents[2] = p_particles->sdf_collision_to_screen.position.x;
|
||||
frame_params.colliders[0].scale = p_particles->sdf_collision_to_screen.position.y;
|
||||
frame_params.colliders[0].texture_index = 0;
|
||||
frame_params.colliders[0].type = ParticlesFrameParams::COLLISION_TYPE_2D_SDF;
|
||||
|
||||
collision_heightmap_texture = p_particles->sdf_collision_texture;
|
||||
|
||||
//replace in all other history frames where used because parameters are no longer valid if screen moves
|
||||
for (uint32_t i = 1; i < p_particles->frame_history.size(); i++) {
|
||||
if (p_particles->frame_history[i].collider_count > 0 && p_particles->frame_history[i].colliders[0].type == ParticlesFrameParams::COLLISION_TYPE_2D_SDF) {
|
||||
p_particles->frame_history[i].colliders[0] = frame_params.colliders[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t collision_3d_textures_used = 0;
|
||||
for (const Set<RID>::Element *E = p_particles->collisions.front(); E; E = E->next()) {
|
||||
ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(E->get());
|
||||
|
@ -4657,6 +4710,8 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
|
|||
|
||||
ERR_FAIL_COND(!m);
|
||||
|
||||
p_particles->has_collision_cache = m->shader_data->uses_collision;
|
||||
|
||||
//todo should maybe compute all particle systems together?
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, m->shader_data->pipeline);
|
||||
|
@ -4740,6 +4795,11 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &
|
|||
copy_push_constant.trail_total = 1;
|
||||
copy_push_constant.frame_delta = 0.0;
|
||||
}
|
||||
|
||||
copy_push_constant.order_by_lifetime = (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME);
|
||||
copy_push_constant.lifetime_split = MIN(particles->amount * particles->phase, particles->amount - 1);
|
||||
copy_push_constant.lifetime_reverse = particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME;
|
||||
|
||||
copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0;
|
||||
copy_push_constant.total_particles = particles->amount;
|
||||
|
||||
|
@ -5019,6 +5079,10 @@ void RendererStorageRD::update_particles() {
|
|||
copy_push_constant.frame_delta = 0.0;
|
||||
}
|
||||
|
||||
copy_push_constant.order_by_lifetime = (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME);
|
||||
copy_push_constant.lifetime_split = MIN(particles->amount * particles->phase, particles->amount - 1);
|
||||
copy_push_constant.lifetime_reverse = particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME;
|
||||
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[particles->mode == RS::PARTICLES_MODE_2D ? ParticlesShader::COPY_MODE_FILL_INSTANCES_2D : ParticlesShader::COPY_MODE_FILL_INSTANCES]);
|
||||
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
|
||||
|
@ -5049,6 +5113,7 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
|
|||
valid = false;
|
||||
ubo_size = 0;
|
||||
uniforms.clear();
|
||||
uses_collision = false;
|
||||
|
||||
if (code == String()) {
|
||||
return; //just invalid, but no error
|
||||
|
@ -5068,6 +5133,8 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
|
|||
actions.usage_flag_pointers["TIME"] = &uses_time;
|
||||
*/
|
||||
|
||||
actions.usage_flag_pointers["COLLIDED"] = &uses_collision;
|
||||
|
||||
actions.uniforms = &uniforms;
|
||||
|
||||
Error err = base_singleton->particles_shader.compiler.compile(RS::SHADER_PARTICLES, code, &actions, path, gen_code);
|
||||
|
@ -7133,6 +7200,20 @@ Rect2i RendererStorageRD::render_target_get_sdf_rect(RID p_render_target) const
|
|||
return _render_target_get_sdf_rect(rt);
|
||||
}
|
||||
|
||||
void RendererStorageRD::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) {
|
||||
RenderTarget *rt = render_target_owner.getornull(p_render_target);
|
||||
ERR_FAIL_COND(!rt);
|
||||
|
||||
rt->sdf_enabled = p_enabled;
|
||||
}
|
||||
|
||||
bool RendererStorageRD::render_target_is_sdf_enabled(RID p_render_target) const {
|
||||
const RenderTarget *rt = render_target_owner.getornull(p_render_target);
|
||||
ERR_FAIL_COND_V(!rt, false);
|
||||
|
||||
return rt->sdf_enabled;
|
||||
}
|
||||
|
||||
RID RendererStorageRD::render_target_get_sdf_texture(RID p_render_target) {
|
||||
RenderTarget *rt = render_target_owner.getornull(p_render_target);
|
||||
ERR_FAIL_COND_V(!rt, RID());
|
||||
|
@ -7200,7 +7281,7 @@ void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) {
|
|||
rt->process_size.x = MAX(rt->process_size.x, 1);
|
||||
rt->process_size.y = MAX(rt->process_size.y, 1);
|
||||
|
||||
tformat.format = RD::DATA_FORMAT_R16G16_UINT;
|
||||
tformat.format = RD::DATA_FORMAT_R16G16_SINT;
|
||||
tformat.width = rt->process_size.width;
|
||||
tformat.height = rt->process_size.height;
|
||||
tformat.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
|
||||
|
@ -7208,7 +7289,7 @@ void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) {
|
|||
rt->sdf_buffer_process[0] = RD::get_singleton()->texture_create(tformat, RD::TextureView());
|
||||
rt->sdf_buffer_process[1] = RD::get_singleton()->texture_create(tformat, RD::TextureView());
|
||||
|
||||
tformat.format = RD::DATA_FORMAT_R16_UNORM;
|
||||
tformat.format = RD::DATA_FORMAT_R16_SNORM;
|
||||
tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
|
||||
|
||||
rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView());
|
||||
|
|
|
@ -638,7 +638,9 @@ private:
|
|||
COLLISION_TYPE_SPHERE,
|
||||
COLLISION_TYPE_BOX,
|
||||
COLLISION_TYPE_SDF,
|
||||
COLLISION_TYPE_HEIGHT_FIELD
|
||||
COLLISION_TYPE_HEIGHT_FIELD,
|
||||
COLLISION_TYPE_2D_SDF,
|
||||
|
||||
};
|
||||
|
||||
struct Collider {
|
||||
|
@ -710,6 +712,13 @@ private:
|
|||
bool restart_request = false;
|
||||
AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8));
|
||||
bool use_local_coords = true;
|
||||
bool has_collision_cache = false;
|
||||
|
||||
bool has_sdf_collision = false;
|
||||
Transform2D sdf_collision_transform;
|
||||
Rect2 sdf_collision_to_screen;
|
||||
RID sdf_collision_texture;
|
||||
|
||||
RID process_material;
|
||||
uint32_t frame_counter = 0;
|
||||
RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED;
|
||||
|
@ -820,6 +829,11 @@ private:
|
|||
|
||||
float align_up[3];
|
||||
uint32_t align_mode;
|
||||
|
||||
uint32_t order_by_lifetime;
|
||||
uint32_t lifetime_split;
|
||||
uint32_t lifetime_reverse;
|
||||
uint32_t pad;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -843,6 +857,7 @@ private:
|
|||
struct ParticlesShaderData : public ShaderData {
|
||||
bool valid;
|
||||
RID version;
|
||||
bool uses_collision = false;
|
||||
|
||||
//PipelineCacheRD pipelines[SKY_VERSION_MAX];
|
||||
Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
|
||||
|
@ -1120,6 +1135,8 @@ private:
|
|||
|
||||
bool flags[RENDER_TARGET_FLAG_MAX];
|
||||
|
||||
bool sdf_enabled = false;
|
||||
|
||||
RID backbuffer; //used for effects
|
||||
RID backbuffer_fb;
|
||||
RID backbuffer_mipmap0;
|
||||
|
@ -2175,6 +2192,13 @@ public:
|
|||
return particles->amount * r_trail_divisor;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool particles_has_collision(RID p_particles) {
|
||||
Particles *particles = particles_owner.getornull(p_particles);
|
||||
ERR_FAIL_COND_V(!particles, 0);
|
||||
|
||||
return particles->has_collision_cache;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) {
|
||||
Particles *particles = particles_owner.getornull(p_particles);
|
||||
ERR_FAIL_COND_V(!particles, false);
|
||||
|
@ -2206,6 +2230,7 @@ public:
|
|||
|
||||
virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance);
|
||||
virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance);
|
||||
virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture);
|
||||
|
||||
/* PARTICLES COLLISION */
|
||||
|
||||
|
@ -2280,6 +2305,8 @@ public:
|
|||
RID render_target_get_sdf_framebuffer(RID p_render_target);
|
||||
void render_target_sdf_process(RID p_render_target);
|
||||
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const;
|
||||
void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled);
|
||||
bool render_target_is_sdf_enabled(RID p_render_target) const;
|
||||
|
||||
Size2 render_target_get_size(RID p_render_target);
|
||||
RID render_target_get_rd_framebuffer(RID p_render_target);
|
||||
|
|
|
@ -101,36 +101,34 @@ void main() {
|
|||
|
||||
uint offset = trail_size * stride * gl_InstanceIndex;
|
||||
|
||||
mat4 matrix;
|
||||
vec4 pcolor;
|
||||
vec2 new_vertex;
|
||||
{
|
||||
uint boffset = offset + bone_attrib.x * stride;
|
||||
matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x;
|
||||
pcolor = transforms.data[boffset + 3] * weight_attrib.x;
|
||||
new_vertex = (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.x;
|
||||
pcolor = transforms.data[boffset + 2] * weight_attrib.x;
|
||||
}
|
||||
if (weight_attrib.y > 0.001) {
|
||||
uint boffset = offset + bone_attrib.y * stride;
|
||||
matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y;
|
||||
pcolor += transforms.data[boffset + 3] * weight_attrib.y;
|
||||
new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.y;
|
||||
pcolor += transforms.data[boffset + 2] * weight_attrib.y;
|
||||
}
|
||||
if (weight_attrib.z > 0.001) {
|
||||
uint boffset = offset + bone_attrib.z * stride;
|
||||
matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z;
|
||||
pcolor += transforms.data[boffset + 3] * weight_attrib.z;
|
||||
new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.z;
|
||||
pcolor += transforms.data[boffset + 2] * weight_attrib.z;
|
||||
}
|
||||
if (weight_attrib.w > 0.001) {
|
||||
uint boffset = offset + bone_attrib.w * stride;
|
||||
matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w;
|
||||
pcolor += transforms.data[boffset + 3] * weight_attrib.w;
|
||||
new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.w;
|
||||
pcolor += transforms.data[boffset + 2] * weight_attrib.w;
|
||||
}
|
||||
|
||||
instance_custom = transforms.data[offset + 4];
|
||||
instance_custom = transforms.data[offset + 3];
|
||||
|
||||
vertex = new_vertex;
|
||||
color *= pcolor;
|
||||
|
||||
matrix = transpose(matrix);
|
||||
world_matrix = world_matrix * matrix;
|
||||
|
||||
} else
|
||||
#endif // USE_ATTRIBUTES
|
||||
|
||||
|
@ -283,7 +281,7 @@ vec2 screen_uv_to_sdf(vec2 p_uv) {
|
|||
float texture_sdf(vec2 p_sdf) {
|
||||
vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
|
||||
float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r;
|
||||
d = d * SDF_MAX_LENGTH - 1.0;
|
||||
d *= SDF_MAX_LENGTH;
|
||||
return d * canvas_data.tex_to_sdf;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
|
||||
layout(r8, set = 0, binding = 1) uniform restrict readonly image2D src_pixels;
|
||||
layout(r16, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf;
|
||||
layout(r16_snorm, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf;
|
||||
|
||||
layout(rg16i, set = 0, binding = 3) uniform restrict readonly iimage2D src_process;
|
||||
layout(rg16i, set = 0, binding = 4) uniform restrict writeonly iimage2D dst_process;
|
||||
|
@ -32,7 +32,7 @@ void main() {
|
|||
#ifdef MODE_LOAD
|
||||
|
||||
bool solid = imageLoad(src_pixels, pos).r > 0.5;
|
||||
imageStore(dst_process, pos, solid ? ivec4(pos, 0, 0) : ivec4(ivec2(32767), 0, 0));
|
||||
imageStore(dst_process, pos, solid ? ivec4(ivec2(-32767), 0, 0) : ivec4(ivec2(32767), 0, 0));
|
||||
#endif
|
||||
|
||||
#ifdef MODE_LOAD_SHRINK
|
||||
|
@ -43,6 +43,8 @@ void main() {
|
|||
|
||||
ivec2 rel = ivec2(32767);
|
||||
float d = 1e20;
|
||||
int found = 0;
|
||||
int solid_found = 0;
|
||||
for (int i = 0; i < s; i++) {
|
||||
for (int j = 0; j < s; j++) {
|
||||
ivec2 src_pos = base + ivec2(i, j);
|
||||
|
@ -56,10 +58,17 @@ void main() {
|
|||
d = dist;
|
||||
rel = src_pos;
|
||||
}
|
||||
solid_found++;
|
||||
}
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
||||
if (solid_found == found) {
|
||||
//mark solid only if all are solid
|
||||
rel = ivec2(-32767);
|
||||
}
|
||||
|
||||
imageStore(dst_process, pos, ivec4(rel, 0, 0));
|
||||
#endif
|
||||
|
||||
|
@ -70,6 +79,12 @@ void main() {
|
|||
|
||||
ivec2 rel = imageLoad(src_process, pos).xy;
|
||||
|
||||
bool solid = rel.x < 0;
|
||||
|
||||
if (solid) {
|
||||
rel = -rel - ivec2(1);
|
||||
}
|
||||
|
||||
if (center != rel) {
|
||||
//only process if it does not point to itself
|
||||
const int ofs_table_size = 8;
|
||||
|
@ -92,6 +107,15 @@ void main() {
|
|||
continue;
|
||||
}
|
||||
ivec2 src_rel = imageLoad(src_process, src_pos).xy;
|
||||
bool src_solid = src_rel.x < 0;
|
||||
if (src_solid) {
|
||||
src_rel = -src_rel - ivec2(1);
|
||||
}
|
||||
|
||||
if (src_solid != solid) {
|
||||
src_rel = ivec2(src_pos << params.shift); //point to itself if of different type
|
||||
}
|
||||
|
||||
float src_dist = length(vec2(src_rel - center));
|
||||
if (src_dist < dist) {
|
||||
dist = src_dist;
|
||||
|
@ -100,18 +124,31 @@ void main() {
|
|||
}
|
||||
}
|
||||
|
||||
if (solid) {
|
||||
rel = -rel - ivec2(1);
|
||||
}
|
||||
|
||||
imageStore(dst_process, pos, ivec4(rel, 0, 0));
|
||||
#endif
|
||||
|
||||
#ifdef MODE_STORE
|
||||
|
||||
ivec2 rel = imageLoad(src_process, pos).xy;
|
||||
float d = length(vec2(rel - pos));
|
||||
if (d > 0.01) {
|
||||
d += 1.0; //make it signed
|
||||
|
||||
bool solid = rel.x < 0;
|
||||
|
||||
if (solid) {
|
||||
rel = -rel - ivec2(1);
|
||||
}
|
||||
|
||||
float d = length(vec2(rel - pos));
|
||||
|
||||
if (solid) {
|
||||
d = -d;
|
||||
}
|
||||
|
||||
d /= SDF_MAX_LENGTH;
|
||||
d = clamp(d, 0.0, 1.0);
|
||||
d = clamp(d, -1.0, 1.0);
|
||||
imageStore(dst_sdf, pos, vec4(d));
|
||||
|
||||
#endif
|
||||
|
@ -122,13 +159,20 @@ void main() {
|
|||
ivec2 center = base + ivec2(params.shift);
|
||||
|
||||
ivec2 rel = imageLoad(src_process, pos).xy;
|
||||
|
||||
bool solid = rel.x < 0;
|
||||
|
||||
if (solid) {
|
||||
rel = -rel - ivec2(1);
|
||||
}
|
||||
|
||||
float d = length(vec2(rel - center));
|
||||
|
||||
if (d > 0.01) {
|
||||
d += 1.0; //make it signed
|
||||
if (solid) {
|
||||
d = -d;
|
||||
}
|
||||
d /= SDF_MAX_LENGTH;
|
||||
d = clamp(d, 0.0, 1.0);
|
||||
d = clamp(d, -1.0, 1.0);
|
||||
imageStore(dst_sdf, pos, vec4(d));
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,6 +19,8 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
|||
#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
|
||||
#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
|
||||
|
||||
#define SDF_MAX_LENGTH 16384.0
|
||||
|
||||
/* SET 0: GLOBAL DATA */
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler material_samplers[12];
|
||||
|
@ -54,6 +56,7 @@ struct Attractor {
|
|||
#define COLLIDER_TYPE_BOX 1
|
||||
#define COLLIDER_TYPE_SDF 2
|
||||
#define COLLIDER_TYPE_HEIGHT_FIELD 3
|
||||
#define COLLIDER_TYPE_2D_SDF 4
|
||||
|
||||
struct Collider {
|
||||
mat4 transform;
|
||||
|
@ -452,128 +455,167 @@ void main() {
|
|||
|
||||
#endif
|
||||
|
||||
for (uint i = 0; i < FRAME.collider_count; i++) {
|
||||
vec3 normal;
|
||||
float depth;
|
||||
bool col = false;
|
||||
if (FRAME.collider_count == 1 && FRAME.colliders[0].type == COLLIDER_TYPE_2D_SDF) {
|
||||
//2D collision
|
||||
|
||||
vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz;
|
||||
vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform);
|
||||
vec2 pos = PARTICLE.xform[3].xy;
|
||||
vec4 to_sdf_x = FRAME.colliders[0].transform[0];
|
||||
vec4 to_sdf_y = FRAME.colliders[0].transform[1];
|
||||
vec2 sdf_pos = vec2(dot(vec4(pos, 0, 1), to_sdf_x), dot(vec4(pos, 0, 1), to_sdf_y));
|
||||
|
||||
switch (FRAME.colliders[i].type) {
|
||||
case COLLIDER_TYPE_SPHERE: {
|
||||
float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x);
|
||||
vec4 sdf_to_screen = vec4(FRAME.colliders[0].extents, FRAME.colliders[0].scale);
|
||||
|
||||
if (d < 0.0) {
|
||||
col = true;
|
||||
depth = -d;
|
||||
normal = normalize(rel_vec);
|
||||
}
|
||||
vec2 uv_pos = sdf_pos * sdf_to_screen.xy + sdf_to_screen.zw;
|
||||
|
||||
} break;
|
||||
case COLLIDER_TYPE_BOX: {
|
||||
vec3 abs_pos = abs(local_pos);
|
||||
vec3 sgn_pos = sign(local_pos);
|
||||
if (all(greaterThan(uv_pos, vec2(0.0))) && all(lessThan(uv_pos, vec2(1.0)))) {
|
||||
vec2 pos2 = pos + vec2(0, particle_size);
|
||||
vec2 sdf_pos2 = vec2(dot(vec4(pos2, 0, 1), to_sdf_x), dot(vec4(pos2, 0, 1), to_sdf_y));
|
||||
float sdf_particle_size = distance(sdf_pos, sdf_pos2);
|
||||
|
||||
if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) {
|
||||
//point outside box
|
||||
float d = texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos).r * SDF_MAX_LENGTH;
|
||||
|
||||
vec3 closest = min(abs_pos, FRAME.colliders[i].extents);
|
||||
vec3 rel = abs_pos - closest;
|
||||
depth = length(rel) - particle_size;
|
||||
if (depth < 0.0) {
|
||||
col = true;
|
||||
normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos);
|
||||
depth = -depth;
|
||||
}
|
||||
} else {
|
||||
//point inside box
|
||||
vec3 axis_len = FRAME.colliders[i].extents - abs_pos;
|
||||
// there has to be a faster way to do this?
|
||||
if (all(lessThan(axis_len.xx, axis_len.yz))) {
|
||||
normal = vec3(1, 0, 0);
|
||||
} else if (all(lessThan(axis_len.yy, axis_len.xz))) {
|
||||
normal = vec3(0, 1, 0);
|
||||
} else {
|
||||
normal = vec3(0, 0, 1);
|
||||
}
|
||||
d -= sdf_particle_size;
|
||||
|
||||
col = true;
|
||||
depth = dot(normal * axis_len, vec3(1)) + particle_size;
|
||||
normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos);
|
||||
}
|
||||
if (d < 0.0) {
|
||||
const float EPSILON = 0.001;
|
||||
vec2 n = normalize(vec2(
|
||||
texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(EPSILON, 0.0)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(EPSILON, 0.0)).r,
|
||||
texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(0.0, EPSILON)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(0.0, EPSILON)).r));
|
||||
|
||||
} break;
|
||||
case COLLIDER_TYPE_SDF: {
|
||||
vec3 apos = abs(local_pos);
|
||||
float extra_dist = 0.0;
|
||||
if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside
|
||||
vec3 mpos = min(apos, FRAME.colliders[i].extents);
|
||||
extra_dist = distance(mpos, apos);
|
||||
}
|
||||
collided = true;
|
||||
sdf_pos2 = sdf_pos + n * d;
|
||||
pos2 = vec2(dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[2]), dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[3]));
|
||||
|
||||
if (extra_dist > particle_size) {
|
||||
continue;
|
||||
}
|
||||
n = pos - pos2;
|
||||
|
||||
vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5;
|
||||
float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r;
|
||||
s *= FRAME.colliders[i].scale;
|
||||
s += extra_dist;
|
||||
if (s < particle_size) {
|
||||
col = true;
|
||||
depth = particle_size - s;
|
||||
const float EPSILON = 0.001;
|
||||
normal = mat3(FRAME.colliders[i].transform) *
|
||||
normalize(
|
||||
vec3(
|
||||
texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r,
|
||||
texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r,
|
||||
texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r));
|
||||
}
|
||||
|
||||
} break;
|
||||
case COLLIDER_TYPE_HEIGHT_FIELD: {
|
||||
vec3 local_pos_bottom = local_pos;
|
||||
local_pos_bottom.y -= particle_size;
|
||||
|
||||
if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float DELTA = 1.0 / 8192.0;
|
||||
|
||||
vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
|
||||
|
||||
float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r;
|
||||
|
||||
if (y > uvw_pos.y) {
|
||||
//inside heightfield
|
||||
|
||||
vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
|
||||
vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
|
||||
vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents;
|
||||
|
||||
normal = normalize(cross(pos1 - pos2, pos1 - pos3));
|
||||
float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
|
||||
|
||||
col = true;
|
||||
depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
|
||||
}
|
||||
|
||||
} break;
|
||||
collision_normal = normalize(vec3(n, 0.0));
|
||||
collision_depth = length(n);
|
||||
}
|
||||
}
|
||||
|
||||
if (col) {
|
||||
if (!collided) {
|
||||
collided = true;
|
||||
collision_normal = normal;
|
||||
collision_depth = depth;
|
||||
} else {
|
||||
vec3 c = collision_normal * collision_depth;
|
||||
c += normal * max(0.0, depth - dot(normal, c));
|
||||
collision_normal = normalize(c);
|
||||
collision_depth = length(c);
|
||||
} else {
|
||||
for (uint i = 0; i < FRAME.collider_count; i++) {
|
||||
vec3 normal;
|
||||
float depth;
|
||||
bool col = false;
|
||||
|
||||
vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz;
|
||||
vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform);
|
||||
|
||||
switch (FRAME.colliders[i].type) {
|
||||
case COLLIDER_TYPE_SPHERE: {
|
||||
float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x);
|
||||
|
||||
if (d < 0.0) {
|
||||
col = true;
|
||||
depth = -d;
|
||||
normal = normalize(rel_vec);
|
||||
}
|
||||
|
||||
} break;
|
||||
case COLLIDER_TYPE_BOX: {
|
||||
vec3 abs_pos = abs(local_pos);
|
||||
vec3 sgn_pos = sign(local_pos);
|
||||
|
||||
if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) {
|
||||
//point outside box
|
||||
|
||||
vec3 closest = min(abs_pos, FRAME.colliders[i].extents);
|
||||
vec3 rel = abs_pos - closest;
|
||||
depth = length(rel) - particle_size;
|
||||
if (depth < 0.0) {
|
||||
col = true;
|
||||
normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos);
|
||||
depth = -depth;
|
||||
}
|
||||
} else {
|
||||
//point inside box
|
||||
vec3 axis_len = FRAME.colliders[i].extents - abs_pos;
|
||||
// there has to be a faster way to do this?
|
||||
if (all(lessThan(axis_len.xx, axis_len.yz))) {
|
||||
normal = vec3(1, 0, 0);
|
||||
} else if (all(lessThan(axis_len.yy, axis_len.xz))) {
|
||||
normal = vec3(0, 1, 0);
|
||||
} else {
|
||||
normal = vec3(0, 0, 1);
|
||||
}
|
||||
|
||||
col = true;
|
||||
depth = dot(normal * axis_len, vec3(1)) + particle_size;
|
||||
normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos);
|
||||
}
|
||||
|
||||
} break;
|
||||
case COLLIDER_TYPE_SDF: {
|
||||
vec3 apos = abs(local_pos);
|
||||
float extra_dist = 0.0;
|
||||
if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside
|
||||
vec3 mpos = min(apos, FRAME.colliders[i].extents);
|
||||
extra_dist = distance(mpos, apos);
|
||||
}
|
||||
|
||||
if (extra_dist > particle_size) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5;
|
||||
float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r;
|
||||
s *= FRAME.colliders[i].scale;
|
||||
s += extra_dist;
|
||||
if (s < particle_size) {
|
||||
col = true;
|
||||
depth = particle_size - s;
|
||||
const float EPSILON = 0.001;
|
||||
normal = mat3(FRAME.colliders[i].transform) *
|
||||
normalize(
|
||||
vec3(
|
||||
texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r,
|
||||
texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r,
|
||||
texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r));
|
||||
}
|
||||
|
||||
} break;
|
||||
case COLLIDER_TYPE_HEIGHT_FIELD: {
|
||||
vec3 local_pos_bottom = local_pos;
|
||||
local_pos_bottom.y -= particle_size;
|
||||
|
||||
if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) {
|
||||
continue;
|
||||
}
|
||||
const float DELTA = 1.0 / 8192.0;
|
||||
|
||||
vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
|
||||
|
||||
float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r;
|
||||
|
||||
if (y > uvw_pos.y) {
|
||||
//inside heightfield
|
||||
|
||||
vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
|
||||
vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
|
||||
vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents;
|
||||
|
||||
normal = normalize(cross(pos1 - pos2, pos1 - pos3));
|
||||
float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
|
||||
|
||||
col = true;
|
||||
depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
|
||||
}
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
if (col) {
|
||||
if (!collided) {
|
||||
collided = true;
|
||||
collision_normal = normal;
|
||||
collision_depth = depth;
|
||||
} else {
|
||||
vec3 c = collision_normal * collision_depth;
|
||||
c += normal * max(0.0, depth - dot(normal, c));
|
||||
collision_normal = normalize(c);
|
||||
collision_depth = length(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,11 @@ layout(push_constant, binding = 0, std430) uniform Params {
|
|||
|
||||
vec3 align_up;
|
||||
uint align_mode;
|
||||
|
||||
bool order_by_lifetime;
|
||||
uint lifetime_split;
|
||||
bool lifetime_reverse;
|
||||
uint pad;
|
||||
}
|
||||
params;
|
||||
|
||||
|
@ -80,7 +85,6 @@ void main() {
|
|||
#ifdef MODE_FILL_INSTANCES
|
||||
|
||||
uint particle = gl_GlobalInvocationID.x;
|
||||
uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom
|
||||
|
||||
if (particle >= params.total_particles) {
|
||||
return; //discard
|
||||
|
@ -93,7 +97,41 @@ void main() {
|
|||
} else {
|
||||
particle = uint(sort_buffer.data[particle].y); //use index from sort buffer
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if (params.order_by_lifetime) {
|
||||
if (params.trail_size > 1) {
|
||||
uint limit = (params.total_particles / params.trail_size) - params.lifetime_split;
|
||||
|
||||
uint base_index = particle / params.trail_size;
|
||||
uint base_offset = particle % params.trail_size;
|
||||
|
||||
if (params.lifetime_reverse) {
|
||||
base_index = (params.total_particles / params.trail_size) - base_index - 1;
|
||||
}
|
||||
|
||||
if (base_index < limit) {
|
||||
base_index = params.lifetime_split + base_index;
|
||||
} else {
|
||||
base_index -= limit;
|
||||
}
|
||||
|
||||
particle = base_index * params.trail_size + base_offset;
|
||||
|
||||
} else {
|
||||
uint limit = params.total_particles - params.lifetime_split;
|
||||
|
||||
if (params.lifetime_reverse) {
|
||||
particle = params.total_particles - particle - 1;
|
||||
}
|
||||
|
||||
if (particle < limit) {
|
||||
particle = params.lifetime_split + particle;
|
||||
} else {
|
||||
particle -= limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // USE_SORT_BUFFER
|
||||
|
||||
mat4 txform;
|
||||
|
||||
|
@ -165,12 +203,17 @@ void main() {
|
|||
|
||||
#ifdef MODE_2D
|
||||
|
||||
uint write_offset = gl_GlobalInvocationID.x * (2 + 1 + 1); //xform + color + custom
|
||||
|
||||
instances.data[write_offset + 0] = txform[0];
|
||||
instances.data[write_offset + 1] = txform[1];
|
||||
instances.data[write_offset + 2] = particles.data[particle].color;
|
||||
instances.data[write_offset + 3] = particles.data[particle].custom;
|
||||
|
||||
#else
|
||||
|
||||
uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom
|
||||
|
||||
instances.data[write_offset + 0] = txform[0];
|
||||
instances.data[write_offset + 1] = txform[1];
|
||||
instances.data[write_offset + 2] = txform[2];
|
||||
|
|
|
@ -534,6 +534,8 @@ public:
|
|||
virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) = 0;
|
||||
virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) = 0;
|
||||
|
||||
virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) = 0;
|
||||
|
||||
virtual void update_particles() = 0;
|
||||
|
||||
/* PARTICLES COLLISION */
|
||||
|
@ -603,6 +605,7 @@ public:
|
|||
|
||||
virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) = 0;
|
||||
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const = 0;
|
||||
virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) = 0;
|
||||
|
||||
virtual RS::InstanceType get_base_type(RID p_rid) const = 0;
|
||||
virtual bool free(RID p_rid) = 0;
|
||||
|
|
|
@ -186,8 +186,11 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
|
|||
}
|
||||
|
||||
RSG::canvas_render->render_sdf(p_viewport->render_target, occluders);
|
||||
RSG::storage->render_target_mark_sdf_enabled(p_viewport->render_target, true);
|
||||
|
||||
p_viewport->sdf_active = false; // if used, gets set active again
|
||||
} else {
|
||||
RSG::storage->render_target_mark_sdf_enabled(p_viewport->render_target, false);
|
||||
}
|
||||
|
||||
Rect2 shadow_rect;
|
||||
|
|
|
@ -672,6 +672,7 @@ public:
|
|||
enum ParticlesDrawOrder {
|
||||
PARTICLES_DRAW_ORDER_INDEX,
|
||||
PARTICLES_DRAW_ORDER_LIFETIME,
|
||||
PARTICLES_DRAW_ORDER_REVERSE_LIFETIME,
|
||||
PARTICLES_DRAW_ORDER_VIEW_DEPTH,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue