diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp index 4f3b13aad7f2..09f95295cfbe 100644 --- a/drivers/gles3/storage/particles_storage.cpp +++ b/drivers/gles3/storage/particles_storage.cpp @@ -324,6 +324,30 @@ void ParticlesStorage::particles_set_transform_align(RID p_particles, RS::Partic particles->transform_align = p_transform_align; } +void ParticlesStorage::particles_set_transform_align_custom_src(RID p_particles, RS::ParticlesAlignCustomSrc p_custom_src) { + Particles *particles = particles_owner.get_or_null(p_particles); + ERR_FAIL_NULL(particles); + + //TODO FIXME + //particles-> = p_transform_align; +} + +void ParticlesStorage::particles_set_transform_align_flags(RID p_particles, uint32_t p_flags) { + Particles *particles = particles_owner.get_or_null(p_particles); + ERR_FAIL_NULL(particles); + + //TODO FIXME + //particles-> = p_transform_align; +} + +void ParticlesStorage::particles_set_transform_align_rotation_axis(RID p_particles, RS::ParticlesAlignRotationAxis p_rotation_axis) { + Particles *particles = particles_owner.get_or_null(p_particles); + ERR_FAIL_NULL(particles); + + //TODO FIXME + //particles-> = p_transform_align; +} + void ParticlesStorage::particles_set_process_material(RID p_particles, RID p_material) { Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL(particles); diff --git a/drivers/gles3/storage/particles_storage.h b/drivers/gles3/storage/particles_storage.h index 60449faa678c..49b6947c17d3 100644 --- a/drivers/gles3/storage/particles_storage.h +++ b/drivers/gles3/storage/particles_storage.h @@ -345,6 +345,9 @@ class ParticlesStorage : public RendererParticlesStorage { virtual void particles_set_collision_base_size(RID p_particles, real_t p_size) override; virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override; + virtual void particles_set_transform_align_custom_src(RID p_particles, RS::ParticlesAlignCustomSrc p_custom_src) override; + virtual void particles_set_transform_align_rotation_axis(RID p_particles, RS::ParticlesAlignRotationAxis p_rotation_axis) override; + virtual void particles_set_transform_align_flags(RID p_particles, uint32_t p_flags) override; virtual void particles_set_seed(RID p_particles, uint32_t p_seed) override; virtual void particles_set_trails(RID p_particles, bool p_enable, double p_length) override; diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index 96afd066353d..a7f6db1bb0d8 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -627,7 +627,7 @@ Ref GPUParticles3D::get_skin() const { } void GPUParticles3D::set_transform_align(TransformAlign p_align) { - ERR_FAIL_INDEX(uint32_t(p_align), 4); + ERR_FAIL_INDEX(uint32_t(p_align), uint32_t(RS::ParticlesTransformAlign::PARTICLES_TRANSFORM_MAX)); transform_align = p_align; RS::get_singleton()->particles_set_transform_align(particles, RS::ParticlesTransformAlign(transform_align)); } @@ -636,6 +636,40 @@ GPUParticles3D::TransformAlign GPUParticles3D::get_transform_align() const { return transform_align; } +void GPUParticles3D::set_transform_align_custom_src(RS::ParticlesAlignCustomSrc p_align_custom_src) { + ERR_FAIL_INDEX(uint32_t(p_align_custom_src), uint32_t(RS::ParticlesAlignCustomSrc::PARTICLES_ALIGN_CUSTOM_SRC_MAX)); + transform_align_custom_src = p_align_custom_src; + RS::get_singleton()->particles_set_transform_align_custom_src(particles, transform_align_custom_src); +} + +RS::ParticlesAlignCustomSrc GPUParticles3D::get_transform_align_custom_src() const { + return transform_align_custom_src; +} + +void GPUParticles3D::set_transform_align_rotation_axis(RS::ParticlesAlignRotationAxis p_axis) { + ERR_FAIL_INDEX(uint32_t(p_axis), uint32_t(RS::ParticlesAlignRotationAxis::PARTICLES_ALIGN_AXIS_MAX)); + transform_align_rotation_axis = p_axis; + RS::get_singleton()->particles_set_transform_align_rotation_axis(particles, p_axis); +} + +RS::ParticlesAlignRotationAxis GPUParticles3D::get_transform_align_rotation_axis() const { + return transform_align_rotation_axis; +} + +uint32_t GPUParticles3D::compute_align_flags() const { + return uint32_t(transform_align_use_velocity) & uint32_t(1); +} + +void GPUParticles3D::set_transform_align_use_velocity(bool p_align_to_velocity){ + transform_align_use_velocity = p_align_to_velocity; + RS::get_singleton()->particles_set_transform_align_flags(particles, compute_align_flags()); + +} + +bool GPUParticles3D::get_transform_align_use_velocity() const{ + return transform_align_use_velocity; +} + void GPUParticles3D::convert_from_particles(Node *p_particles) { CPUParticles3D *cpu_particles = Object::cast_to(p_particles); ERR_FAIL_NULL_MSG(cpu_particles, "Only CPUParticles3D nodes can be converted to GPUParticles3D."); @@ -807,6 +841,16 @@ void GPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transform_align", "align"), &GPUParticles3D::set_transform_align); ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align); + ClassDB::bind_method(D_METHOD("set_transform_align_custom_src", "align"), &GPUParticles3D::set_transform_align_custom_src); + ClassDB::bind_method(D_METHOD("get_transform_align_custom_src"), &GPUParticles3D::get_transform_align_custom_src); + + ClassDB::bind_method(D_METHOD("set_transform_align_rotation_axis", "align"), &GPUParticles3D::set_transform_align_rotation_axis); + ClassDB::bind_method(D_METHOD("get_transform_align_rotation_axis"), &GPUParticles3D::get_transform_align_rotation_axis); + + ClassDB::bind_method(D_METHOD("set_transform_align_use_velocity", "align_use_velocity"), &GPUParticles3D::set_transform_align_use_velocity); + ClassDB::bind_method(D_METHOD("get_transform_align_use_velocity"), &GPUParticles3D::get_transform_align_use_velocity); + + ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &GPUParticles3D::convert_from_particles); ClassDB::bind_method(D_METHOD("set_amount_ratio", "ratio"), &GPUParticles3D::set_amount_ratio); @@ -841,7 +885,11 @@ void GPUParticles3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_aabb", PROPERTY_HINT_NONE, "suffix:m"), "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,Reverse Lifetime,View Depth"), "set_draw_order", "get_draw_order"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,Z-Billboard,Y to Velocity,Z-Billboard + Y to Velocity"), "set_transform_align", "get_transform_align"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,Z-Billboard,Y to Velocity,Z-Billboard + Y to Velocity,Rotate around Axis, Local Billboard"), "set_transform_align", "get_transform_align"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align_custom_src", PROPERTY_HINT_ENUM, "Disabled, X, Y, Z, W"), "set_transform_align_custom_src", "get_transform_align_custom_src"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align_rotation_axis", PROPERTY_HINT_ENUM, "X, Y, Z"), "set_transform_align_rotation_axis", "get_transform_align_rotation_axis"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transform_align_use_velocity"), "set_transform_align_use_velocity", "get_transform_align_use_velocity"); + ADD_GROUP("Trails", "trail_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled", PROPERTY_HINT_GROUP_ENABLE), "set_trail_enabled", "is_trail_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_lifetime", PROPERTY_HINT_RANGE, "0.01,10,0.01,or_greater,suffix:s"), "set_trail_lifetime", "get_trail_lifetime"); @@ -900,6 +948,9 @@ GPUParticles3D::GPUParticles3D() { set_speed_scale(1); set_collision_base_size(collision_base_size); set_transform_align(TRANSFORM_ALIGN_DISABLED); + set_transform_align_custom_src(RS::ParticlesAlignCustomSrc::PARTICLES_ALIGN_CUSTOM_SRC_X); + set_transform_align_rotation_axis(RS::ParticlesAlignRotationAxis::PARTICLES_ALIGN_AXIS_Y); + set_transform_align_use_velocity(true); set_use_fixed_seed(false); } diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index d76fc4c6c173..27d1c1f31839 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -84,6 +84,9 @@ class GPUParticles3D : public GeometryInstance3D { double trail_lifetime = 0.3; TransformAlign transform_align = TRANSFORM_ALIGN_DISABLED; + RS::ParticlesAlignCustomSrc transform_align_custom_src = RS::ParticlesAlignCustomSrc::PARTICLES_ALIGN_CUSTOM_SRC_X; + RS::ParticlesAlignRotationAxis transform_align_rotation_axis = RS::ParticlesAlignRotationAxis::PARTICLES_ALIGN_AXIS_Y; + bool transform_align_use_velocity = true; Ref process_material; @@ -181,6 +184,17 @@ class GPUParticles3D : public GeometryInstance3D { void set_transform_align(TransformAlign p_align); TransformAlign get_transform_align() const; + void set_transform_align_custom_src(RS::ParticlesAlignCustomSrc p_align_custom_src); + RS::ParticlesAlignCustomSrc get_transform_align_custom_src() const; + + void set_transform_align_rotation_axis(RS::ParticlesAlignRotationAxis p_axis); + RS::ParticlesAlignRotationAxis get_transform_align_rotation_axis() const; + + void set_transform_align_use_velocity(bool p_align_to_velocity); + bool get_transform_align_use_velocity() const; + + uint32_t compute_align_flags() const; + void restart(bool p_keep_seed = false); void set_use_fixed_seed(bool p_use_fixed_seed); diff --git a/servers/rendering/dummy/storage/particles_storage.h b/servers/rendering/dummy/storage/particles_storage.h index e3e7d6aa0613..3a2914f110a2 100644 --- a/servers/rendering/dummy/storage/particles_storage.h +++ b/servers/rendering/dummy/storage/particles_storage.h @@ -67,6 +67,9 @@ class ParticlesStorage : public RendererParticlesStorage { virtual void particles_set_collision_base_size(RID p_particles, real_t p_size) override {} virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override {} + virtual void particles_set_transform_align_custom_src(RID p_particles, RS::ParticlesAlignCustomSrc p_transform_align_custom_src) override {} + virtual void particles_set_transform_align_rotation_axis(RID p_particles, RS::ParticlesAlignRotationAxis p_rotation_axis) override {} + virtual void particles_set_transform_align_flags(RID p_particles, uint32_t p_flags) override {} virtual void particles_set_trails(RID p_particles, bool p_enable, double p_length) override {} virtual void particles_set_trail_bind_poses(RID p_particles, const Vector &p_bind_poses) override {} diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl index 93c4d1009d47..43db77c31aad 100644 --- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl +++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl @@ -65,14 +65,34 @@ layout(push_constant, std430) uniform Params { uint motion_vectors_current_offset; uint flags; - mat4 inv_emission_transform; + float inv_emission_transform[12]; + + uint align_custom_src; + uint align_axis; + uint align_flags; + uint pad1; } params; -#define TRANSFORM_ALIGN_DISABLED 0 -#define TRANSFORM_ALIGN_Z_BILLBOARD 1 -#define TRANSFORM_ALIGN_Y_TO_VELOCITY 2 -#define TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY 3 +#define ALIGN_DISABLED 0 +#define ALIGN_BILLBOARD 1 +#define ALIGN_Y_TO_VELOCITY 2 +#define ALIGN_Z_BILLBOARD_Y_TO_VELOCITY 3 +#define ALIGN_ROTATE_AXIS 4 +#define ALIGN_LOCAL_BILLBOARD 5 + +#define CUSTOM_SRC_NONE 0 +#define CUSTOM_SRC_X 1 +#define CUSTOM_SRC_Y 2 +#define CUSTOM_SRC_Z 3 +#define CUSTOM_SRC_W 4 + +#define ALIGN_AXIS_X 0 +#define ALIGN_AXIS_Y 1 +#define ALIGN_AXIS_Z 2 + +#define ALIGN_FLAGS_ALIGN_TO_VELOCITY uint(1); + void main() { #ifdef MODE_FILL_SORT_BUFFER @@ -155,17 +175,97 @@ void main() { } switch (params.align_mode) { - case TRANSFORM_ALIGN_DISABLED: { + case ALIGN_DISABLED: { } break; //nothing - case TRANSFORM_ALIGN_Z_BILLBOARD: { - mat3 local = mat3(normalize(cross(params.align_up, params.sort_direction)), params.align_up, params.sort_direction); + case ALIGN_BILLBOARD: { + float angle = 0.; + switch (params.align_custom_src) { + case CUSTOM_SRC_X: { + angle = particles.data[particle].custom.x; + } break; + case CUSTOM_SRC_Y: { + angle = particles.data[particle].custom.y; + } break; + case CUSTOM_SRC_Z: { + angle = particles.data[particle].custom.z; + } break; + case CUSTOM_SRC_W: { + angle = particles.data[particle].custom.w; + } break; + } + vec3 axis = normalize(params.sort_direction); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + mat3 rotated = mat3( + oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c + ); + vec3 new_up = rotated * params.align_up; + mat3 local = mat3(normalize(cross(new_up, params.sort_direction)), new_up, params.sort_direction); local = local * mat3(txform); txform[0].xyz = local[0]; txform[1].xyz = local[1]; txform[2].xyz = local[2]; } break; - case TRANSFORM_ALIGN_Y_TO_VELOCITY: { + case ALIGN_ROTATE_AXIS: { + vec3 axis = vec3(1.0, 0.0, 0.0); + switch (params.align_axis) { + case ALIGN_AXIS_X: { + axis = vec3(1.0, 0.0, 0.0); + } break; + case ALIGN_AXIS_Y: { + axis = vec3(0.0, 1.0, 0.0); + } break; + case ALIGN_AXIS_Z: { + axis = vec3(0.0, 0.0, 1.0); + } break; + } + float angle = 0.; + switch (params.align_custom_src) { + case CUSTOM_SRC_X: { + angle = particles.data[particle].custom.x; + } break; + case CUSTOM_SRC_Y: { + angle = particles.data[particle].custom.y; + } break; + case CUSTOM_SRC_Z: { + angle = particles.data[particle].custom.z; + } break; + case CUSTOM_SRC_W: { + angle = particles.data[particle].custom.w; + } break; + } + axis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + vec3 len = vec3( + length(txform[0].xyz), + length(txform[1].xyz), + length(txform[2].xyz) + ); + mat3 rotated = mat3( + oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c + ); + mat3 txform_normalized = mat3(txform); + txform_normalized[0] /= len.x; + txform_normalized[1] /= len.y; + txform_normalized[2] /= len.z; + rotated = txform_normalized * rotated * mat3( + len.x, 0.0,0.0, + 0.0,len.y, 0.0, + 0.0, 0.0,len.z + ); + vec4 origin = txform[3]; + txform = mat4(rotated); + txform[3] = origin; + } break; + case ALIGN_Y_TO_VELOCITY: { vec3 v = particles.data[particle].velocity; float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0; if (length(v) > 0.0) { @@ -179,7 +279,7 @@ void main() { txform[0].xyz *= s; txform[1].xyz *= s; } break; - case TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY: { + case ALIGN_Z_BILLBOARD_Y_TO_VELOCITY: { vec3 v = particles.data[particle].velocity; vec3 sv = v - params.sort_direction * dot(params.sort_direction, v); //screen velocity @@ -194,6 +294,78 @@ void main() { txform[2].xyz = params.sort_direction * length(txform[2]); } break; + case ALIGN_LOCAL_BILLBOARD: { + vec3 v = particles.data[particle].velocity; + v = normalize(v); + + if(bool(params.align_flags & uint(1))){ + switch (params.align_axis) { + case ALIGN_AXIS_X: { + vec3 len = vec3( + length(txform[0].xyz), + length(txform[1].xyz), + length(txform[2].xyz) + ); + + txform[0].xyz = v; + txform[1].xyz = normalize(cross(params.sort_direction, v)); + txform[2].xyz = cross(txform[0].xyz, txform[1].xyz); + + txform[0].xyz *= len.x; + txform[1].xyz *= len.y; + txform[2].xyz *= len.z; + } break; + case ALIGN_AXIS_Y: { + vec3 len = vec3( + length(txform[0].xyz), + length(txform[1].xyz), + length(txform[2].xyz) + ); + + txform[0].xyz = normalize(cross(v, params.sort_direction)); + txform[1].xyz = v; + txform[2].xyz = cross(txform[0].xyz, txform[1].xyz); + + txform[0].xyz *= len.x; + txform[1].xyz *= len.y; + txform[2].xyz *= len.z; + } break; + } + } else { + switch (params.align_axis) { + case ALIGN_AXIS_X: { + vec3 len = vec3( + length(txform[0].xyz), + length(txform[1].xyz), + length(txform[2].xyz) + ); + + //txform[0].xyz = v; + txform[1].xyz = normalize(cross(params.sort_direction, txform[0].xyz)); + txform[2].xyz = cross(txform[0].xyz, txform[1].xyz); + + txform[0].xyz *= len.x; + txform[1].xyz *= len.y; + txform[2].xyz *= len.z; + } break; + case ALIGN_AXIS_Y: { + vec3 len = vec3( + length(txform[0].xyz), + length(txform[1].xyz), + length(txform[2].xyz) + ); + + txform[0].xyz = normalize(cross(txform[1].xyz, params.sort_direction)); + txform[2].xyz = cross(txform[0].xyz, txform[1].xyz); + + txform[0].xyz *= len.x; + txform[1].xyz *= len.y; + txform[2].xyz *= len.z; + } break; + } + } + + }break; } txform[3].xyz += particles.data[particle].velocity * params.frame_remainder; @@ -206,7 +378,13 @@ void main() { if (bool(params.flags & PARAMS_FLAG_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; + mat4 inv_emission_transform; + inv_emission_transform[0] = vec4(params.inv_emission_transform[0], params.inv_emission_transform[1], params.inv_emission_transform[2], 0.0); + inv_emission_transform[1] = vec4(params.inv_emission_transform[3], params.inv_emission_transform[4], params.inv_emission_transform[5], 0.0); + inv_emission_transform[2] = vec4(params.inv_emission_transform[6], params.inv_emission_transform[7], params.inv_emission_transform[8], 0.0); + inv_emission_transform[3] = vec4(params.inv_emission_transform[9], params.inv_emission_transform[10], params.inv_emission_transform[11], 1.0); + inv_emission_transform = transpose(inv_emission_transform); + txform = inv_emission_transform * txform; } } else { // Set scale to zero and translate to -INF so particle will be invisible diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index cc7b172fe9d6..2f75ad92fa92 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -491,6 +491,28 @@ void ParticlesStorage::particles_set_transform_align(RID p_particles, RS::Partic particles->transform_align = p_transform_align; } +void ParticlesStorage::particles_set_transform_align_flags(RID p_particles, uint32_t p_flags) { + Particles *particles = particles_owner.get_or_null(p_particles); + ERR_FAIL_NULL(particles); + + particles->align_flags = p_flags; +} + + +void ParticlesStorage::particles_set_transform_align_custom_src(RID p_particles, RS::ParticlesAlignCustomSrc p_transform_align_custom_src) { + Particles *particles = particles_owner.get_or_null(p_particles); + ERR_FAIL_NULL(particles); + + particles->transform_align_src = p_transform_align_custom_src; +} + +void ParticlesStorage::particles_set_transform_align_rotation_axis(RID p_particles, RS::ParticlesAlignRotationAxis p_rotation_axis) { + Particles *particles = particles_owner.get_or_null(p_particles); + ERR_FAIL_NULL(particles); + + particles->rotation_axis = p_rotation_axis; +} + void ParticlesStorage::particles_set_process_material(RID p_particles, RID p_material) { Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL(particles); @@ -1220,7 +1242,7 @@ void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL(particles); - if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) { + if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_LOCAL) { return; } @@ -1295,6 +1317,9 @@ void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p copy_push_constant.align_up[2] = p_up_axis.z; copy_push_constant.align_mode = particles->transform_align; + copy_push_constant.transform_align_src = particles->transform_align_src; + copy_push_constant.subtype = uint32_t(particles->rotation_axis); + copy_push_constant.align_flags = particles->align_flags; if (do_sort) { RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); @@ -1619,7 +1644,19 @@ void ParticlesStorage::update_particles() { // 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(); - RendererRD::MaterialStorage::store_transform(inv, copy_push_constant.inv_emission_transform); + //RendererRD::MaterialStorage::store_transform(inv, copy_push_constant.inv_emission_transform); + copy_push_constant.inv_emission_transform[0] = inv.basis.rows[0][0]; + copy_push_constant.inv_emission_transform[1] = inv.basis.rows[1][0]; + copy_push_constant.inv_emission_transform[2] = inv.basis.rows[2][0]; + copy_push_constant.inv_emission_transform[3] = inv.basis.rows[0][1]; + copy_push_constant.inv_emission_transform[4] = inv.basis.rows[1][1]; + copy_push_constant.inv_emission_transform[5] = inv.basis.rows[2][1]; + copy_push_constant.inv_emission_transform[6] = inv.basis.rows[0][2]; + copy_push_constant.inv_emission_transform[7] = inv.basis.rows[1][2]; + copy_push_constant.inv_emission_transform[8] = inv.basis.rows[2][2]; + copy_push_constant.inv_emission_transform[9] = inv.origin.x; + copy_push_constant.inv_emission_transform[10] = inv.origin.y; + copy_push_constant.inv_emission_transform[11] = inv.origin.z; } copy_push_constant.total_particles = total_amount; @@ -1628,6 +1665,9 @@ void ParticlesStorage::update_particles() { copy_push_constant.align_up[0] = 0; copy_push_constant.align_up[1] = 0; copy_push_constant.align_up[2] = 0; + copy_push_constant.transform_align_src = particles->transform_align_src; + copy_push_constant.subtype = uint32_t(particles->rotation_axis); + copy_push_constant.align_flags = particles->align_flags; if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { copy_push_constant.trail_size = particles->trail_bind_poses.size(); diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h index a1c82d7f9a05..82f18becd7c0 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h @@ -182,6 +182,9 @@ class ParticlesStorage : public RendererParticlesStorage { RID process_material; uint32_t frame_counter = 0; RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED; + RS::ParticlesAlignCustomSrc transform_align_src = RS::PARTICLES_ALIGN_CUSTOM_SRC_X; + RS::ParticlesAlignRotationAxis rotation_axis = RS::ParticlesAlignRotationAxis::PARTICLES_ALIGN_AXIS_Y; + uint32_t align_flags; RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX; @@ -315,7 +318,12 @@ class ParticlesStorage : public RendererParticlesStorage { uint32_t copy_mode_2d : 1; }; - float inv_emission_transform[16]; + float inv_emission_transform[12]; + + uint32_t transform_align_src; + uint32_t subtype; + uint32_t align_flags; + uint32_t pad1; }; enum { @@ -459,6 +467,9 @@ class ParticlesStorage : public RendererParticlesStorage { virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) override; virtual void particles_set_collision_base_size(RID p_particles, real_t p_size) override; virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override; + virtual void particles_set_transform_align_custom_src(RID p_particles, RS::ParticlesAlignCustomSrc p_transform_align_custom_src) override; + virtual void particles_set_transform_align_rotation_axis(RID p_particles, RS::ParticlesAlignRotationAxis p_rotation_axis) override; + virtual void particles_set_transform_align_flags(RID p_particles, uint32_t p_flags) override; virtual void particles_set_seed(RID p_particles, uint32_t p_seed) override; virtual void particles_set_trails(RID p_particles, bool p_enable, double p_length) override; diff --git a/servers/rendering/rendering_server.cpp b/servers/rendering/rendering_server.cpp index 6e0db2c8ce4e..11d75cb7fe97 100644 --- a/servers/rendering/rendering_server.cpp +++ b/servers/rendering/rendering_server.cpp @@ -2773,6 +2773,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("particles_set_fractional_delta", "particles", "enable"), &RenderingServer::particles_set_fractional_delta); ClassDB::bind_method(D_METHOD("particles_set_collision_base_size", "particles", "size"), &RenderingServer::particles_set_collision_base_size); ClassDB::bind_method(D_METHOD("particles_set_transform_align", "particles", "align"), &RenderingServer::particles_set_transform_align); + ClassDB::bind_method(D_METHOD("particles_set_transform_align_custom_src", "particles", "custom_src"), &RenderingServer::particles_set_transform_align_custom_src); + ClassDB::bind_method(D_METHOD("particles_set_transform_align_flags", "particles", "flags"), &RenderingServer::particles_set_transform_align_flags); + ClassDB::bind_method(D_METHOD("particles_set_transform_align_rotation_axis", "particles", "p_rotation_axis"), &RenderingServer::particles_set_transform_align_rotation_axis); ClassDB::bind_method(D_METHOD("particles_set_trails", "particles", "enable", "length_sec"), &RenderingServer::particles_set_trails); ClassDB::bind_method(D_METHOD("particles_set_trail_bind_poses", "particles", "bind_poses"), &RenderingServer::_particles_set_trail_bind_poses); @@ -2796,6 +2799,13 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD); BIND_ENUM_CONSTANT(PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY); BIND_ENUM_CONSTANT(PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY); + BIND_ENUM_CONSTANT(PARTICLES_TRANSFORM_ALIGN_LOCAL); + BIND_ENUM_CONSTANT(PARTICLES_TRANSFORM_ALIGN_ROTATION); + + BIND_ENUM_CONSTANT(PARTICLES_ALIGN_CUSTOM_SRC_DISABLED); + BIND_ENUM_CONSTANT(PARTICLES_ALIGN_CUSTOM_SRC_X); + BIND_ENUM_CONSTANT(PARTICLES_ALIGN_CUSTOM_SRC_Y); + BIND_ENUM_CONSTANT(PARTICLES_ALIGN_CUSTOM_SRC_W); BIND_CONSTANT(PARTICLES_EMIT_FLAG_POSITION); BIND_CONSTANT(PARTICLES_EMIT_FLAG_ROTATION_SCALE); diff --git a/servers/rendering/rendering_server.h b/servers/rendering/rendering_server.h index 6cf24e66355d..32c553b4d4ff 100644 --- a/servers/rendering/rendering_server.h +++ b/servers/rendering/rendering_server.h @@ -803,9 +803,31 @@ class RenderingServer : public Object { PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD, PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY, PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY, + PARTICLES_TRANSFORM_ALIGN_ROTATION, + PARTICLES_TRANSFORM_ALIGN_LOCAL, + PARTICLES_TRANSFORM_MAX, + }; + + enum ParticlesAlignCustomSrc { + PARTICLES_ALIGN_CUSTOM_SRC_DISABLED, + PARTICLES_ALIGN_CUSTOM_SRC_X, + PARTICLES_ALIGN_CUSTOM_SRC_Y, + PARTICLES_ALIGN_CUSTOM_SRC_Z, + PARTICLES_ALIGN_CUSTOM_SRC_W, + PARTICLES_ALIGN_CUSTOM_SRC_MAX, + }; + + enum ParticlesAlignRotationAxis { + PARTICLES_ALIGN_AXIS_X, + PARTICLES_ALIGN_AXIS_Y, + PARTICLES_ALIGN_AXIS_Z, + PARTICLES_ALIGN_AXIS_MAX, }; virtual void particles_set_transform_align(RID p_particles, ParticlesTransformAlign p_transform_align) = 0; + virtual void particles_set_transform_align_custom_src(RID p_particles, ParticlesAlignCustomSrc p_transform_align_custom_src) = 0; + virtual void particles_set_transform_align_rotation_axis(RID p_particles, ParticlesAlignRotationAxis p_rotation_axis) = 0; + virtual void particles_set_transform_align_flags(RID p_particles, uint32_t p_flags) = 0; virtual void particles_set_trails(RID p_particles, bool p_enable, float p_length_sec) = 0; virtual void particles_set_trail_bind_poses(RID p_particles, const Vector &p_bind_poses) = 0; @@ -1967,6 +1989,8 @@ VARIANT_ENUM_CAST(RenderingServer::DecalTexture); VARIANT_ENUM_CAST(RenderingServer::DecalFilter); VARIANT_ENUM_CAST(RenderingServer::ParticlesMode); VARIANT_ENUM_CAST(RenderingServer::ParticlesTransformAlign); +VARIANT_ENUM_CAST(RenderingServer::ParticlesAlignCustomSrc); +VARIANT_ENUM_CAST(RenderingServer::ParticlesAlignRotationAxis); VARIANT_ENUM_CAST(RenderingServer::ParticlesDrawOrder); VARIANT_ENUM_CAST(RenderingServer::ParticlesEmitFlags); VARIANT_ENUM_CAST(RenderingServer::ParticlesCollisionType); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 6fdc1917e80d..8446ff54ddc0 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -608,6 +608,10 @@ class RenderingServerDefault : public RenderingServer { FUNC2(particles_set_collision_base_size, RID, float) FUNC2(particles_set_transform_align, RID, RS::ParticlesTransformAlign) + FUNC2(particles_set_transform_align_custom_src, RID, RS::ParticlesAlignCustomSrc) + FUNC2(particles_set_transform_align_rotation_axis, RID, RS::ParticlesAlignRotationAxis) + FUNC2(particles_set_transform_align_flags, RID, uint32_t) + FUNC2(particles_set_draw_order, RID, RS::ParticlesDrawOrder) diff --git a/servers/rendering/storage/particles_storage.h b/servers/rendering/storage/particles_storage.h index 4570f69d703c..444e176e8c33 100644 --- a/servers/rendering/storage/particles_storage.h +++ b/servers/rendering/storage/particles_storage.h @@ -66,6 +66,9 @@ class RendererParticlesStorage { virtual void particles_set_collision_base_size(RID p_particles, real_t p_size) = 0; virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) = 0; + virtual void particles_set_transform_align_custom_src(RID p_particles, RS::ParticlesAlignCustomSrc p_custom_src) = 0; + virtual void particles_set_transform_align_flags(RID p_particles, uint32_t p_flags) = 0; + virtual void particles_set_transform_align_rotation_axis(RID p_particles, RS::ParticlesAlignRotationAxis p_rotation_axis) = 0; virtual void particles_set_seed(RID p_particles, uint32_t p_seed) = 0;