summaryrefslogtreecommitdiff
path: root/servers/rendering/renderer_rd
diff options
context:
space:
mode:
authorreduz <reduzio@gmail.com>2021-05-20 11:25:06 -0300
committerreduz <reduzio@gmail.com>2021-05-23 16:43:36 -0300
commit789713b00883e7c9d3a912d1b088441ab17c1244 (patch)
tree59e0069f8e453123bd815bf87128ffbb166636cc /servers/rendering/renderer_rd
parent809948f977294c8bb61a6e46dfa132ea6e0478d8 (diff)
Support for 2D particles to collide against SDF
-Added SDF collision support for 2D particles -Changed the SDF generation to be fully signed
Diffstat (limited to 'servers/rendering/renderer_rd')
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp45
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h3
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp85
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h29
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl26
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_sdf.glsl60
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl238
-rw-r--r--servers/rendering/renderer_rd/shaders/particles_copy.glsl47
8 files changed, 405 insertions, 128 deletions
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index f448698976..1f27dd54ec 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -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 *&current_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 *&current_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;
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 8129cc6c9b..890a4e3649 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -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 *&current_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 *&current_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);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index f419875d58..26ddd74a80 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -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());
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index 49f7f3dba6..67fbeb3008 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -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);
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index cf4c77db0d..2186bd174b 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -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;
}
diff --git a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
index 65a554e839..2bdfbabfcf 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
@@ -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;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
float d = length(vec2(rel - pos));
- 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
@@ -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
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index beaff10793..9f8410fd8a 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -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);
+
+ float d = texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos).r * SDF_MAX_LENGTH;
+
+ d -= sdf_particle_size;
+
+ 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));
+
+ 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]));
+
+ n = pos - pos2;
+
+ collision_normal = normalize(vec3(n, 0.0));
+ collision_depth = length(n);
+ }
+ }
+
+ } else {
+ for (uint i = 0; i < FRAME.collider_count; i++) {
+ vec3 normal;
+ float depth;
+ bool col = false;
- if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) {
- //point outside box
+ vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz;
+ vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform);
- vec3 closest = min(abs_pos, FRAME.colliders[i].extents);
- vec3 rel = abs_pos - closest;
- depth = length(rel) - particle_size;
- if (depth < 0.0) {
+ 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;
- normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos);
- depth = -depth;
+ depth = -d;
+ normal = normalize(rel_vec);
}
- } 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);
+
+ } 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 {
- normal = vec3(0, 0, 1);
+ //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);
}
- 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);
+ }
- } 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;
+ }
- 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));
+ }
- 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;
- } 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;
- if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) {
- continue;
- }
+ vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
- const float DELTA = 1.0 / 8192.0;
+ float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r;
- vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
+ if (y > uvw_pos.y) {
+ //inside heightfield
- float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r;
+ 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;
- if (y > uvw_pos.y) {
- //inside heightfield
+ normal = normalize(cross(pos1 - pos2, pos1 - pos3));
+ float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
- 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;
+ col = true;
+ depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
+ }
- normal = normalize(cross(pos1 - pos2, pos1 - pos3));
- float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
+ } break;
+ }
- col = true;
- depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
+ 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);
}
-
- } 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);
}
}
}
diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
index e2bebadf1a..4dceeea995 100644
--- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
@@ -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];