summaryrefslogtreecommitdiff
path: root/servers/rendering/renderer_rd
diff options
context:
space:
mode:
authorfloppyhammer <tannhauser_chen@outlook.com>2022-02-02 11:49:54 +0800
committerfloppyhammer <tannhauser_chen@outlook.com>2022-02-22 17:50:01 +0800
commit0d5472dd1aa1b5d790daf1c9164d48217c507c19 (patch)
treef74cf79ca463d7219b2f02c253bf360533405a7e /servers/rendering/renderer_rd
parentc77348b4688b7c58b13d7fd59d8e54a242bb8829 (diff)
Fix GPUParticles2D emission offset in global coords
Diffstat (limited to 'servers/rendering/renderer_rd')
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp15
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h2
-rw-r--r--servers/rendering/renderer_rd/shaders/particles_copy.glsl8
3 files changed, 25 insertions, 0 deletions
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index e3829eb5ed..1473a92a1a 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -5712,6 +5712,21 @@ void RendererStorageRD::update_particles() {
total_amount *= particles->trail_bind_poses.size();
}
+ // Affect 2D only.
+ if (particles->use_local_coords) {
+ // In local mode, particle positions are calculated locally (relative to the node position)
+ // and they're also drawn locally.
+ // It works as expected, so we just pass an identity transform.
+ store_transform(Transform3D(), copy_push_constant.inv_emission_transform);
+ } else {
+ // In global mode, particle positions are calculated globally (relative to the canvas origin)
+ // but they're drawn locally.
+ // So, we need to pass the inverse of the emission transform to bring the
+ // particles to local coordinates before drawing.
+ Transform3D inv = particles->emission_transform.affine_inverse();
+ store_transform(inv, copy_push_constant.inv_emission_transform);
+ }
+
copy_push_constant.total_particles = total_amount;
copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0;
copy_push_constant.align_mode = particles->transform_align;
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index ee4d18210a..33a3b8e229 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -852,6 +852,8 @@ private:
uint32_t lifetime_split;
uint32_t lifetime_reverse;
uint32_t copy_mode_2d;
+
+ float inv_emission_transform[16];
};
enum {
diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
index b991880cd9..afbd5a9caa 100644
--- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
@@ -61,6 +61,8 @@ layout(push_constant, std430) uniform Params {
uint lifetime_split;
bool lifetime_reverse;
bool copy_mode_2d;
+
+ mat4 inv_emission_transform;
}
params;
@@ -199,6 +201,12 @@ void main() {
txform = txform * trail_bind_poses.data[part_ofs];
}
+ if (params.copy_mode_2d) {
+ // In global mode, bring 2D particles to local coordinates
+ // as they will be drawn with the node position as origin.
+ txform = params.inv_emission_transform * txform;
+ }
+
txform = transpose(txform);
} else {
txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); //zero scale, becomes invisible