Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement blending in particle flipbook animation #50442

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/classes/BaseMaterial3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@
</member>
<member name="orm_texture" type="Texture2D" setter="set_texture" getter="get_texture">
</member>
<member name="particles_anim_blend" type="bool" setter="set_particles_anim_blend" getter="get_particles_anim_blend">
If [code]true[/code], enables blending between frames in the particle flipbook animation. This results in a smoother animation appearance, especially for fire or smoke effects. Only enabled when using [constant BILLBOARD_PARTICLES]. See [member billboard_mode].
</member>
<member name="particles_anim_h_frames" type="int" setter="set_particles_anim_h_frames" getter="get_particles_anim_h_frames">
The number of horizontal frames in the particle sprite sheet. Only enabled when using [constant BILLBOARD_PARTICLES]. See [member billboard_mode].
</member>
Expand Down
49 changes: 48 additions & 1 deletion scene/resources/material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ void BaseMaterial3D::init_shaders() {
shader_names->particles_anim_h_frames = "particles_anim_h_frames";
shader_names->particles_anim_v_frames = "particles_anim_v_frames";
shader_names->particles_anim_loop = "particles_anim_loop";
shader_names->particles_anim_blend = "particles_anim_blend";
shader_names->heightmap_min_layers = "heightmap_min_layers";
shader_names->heightmap_max_layers = "heightmap_max_layers";
shader_names->heightmap_flip = "heightmap_flip";
Expand Down Expand Up @@ -659,6 +660,12 @@ void BaseMaterial3D::_update_shader() {
code += "uniform sampler2D texture_orm : hint_roughness_g," + texfilter_str + ";\n";
}

// This uniform and varyings below are always used, so they must always be defined.
code += "uniform bool particles_anim_blend;\n";
// Required to pass particle flipbook blending frame UV coordinates and progress from `vertex()` to `fragment()`.
code += "varying vec2 particles_anim_next_frame_uv_coord;\n";
code += "varying float particles_anim_next_frame_mix;\n";

if (billboard_mode == BILLBOARD_PARTICLES) {
code += "uniform int particles_anim_h_frames;\n";
code += "uniform int particles_anim_v_frames;\n";
Expand Down Expand Up @@ -773,6 +780,10 @@ void BaseMaterial3D::_update_shader() {
code += "\tUV=UV*uv1_scale.xy+uv1_offset.xy;\n";
}

// Assigned to make the shader compile, even if it's unused.
code += "\tparticles_anim_next_frame_uv_coord = UV;\n";
code += "\tparticles_anim_next_frame_mix = 0.0;\n";

switch (billboard_mode) {
case BILLBOARD_DISABLED: {
} break;
Expand Down Expand Up @@ -812,6 +823,18 @@ void BaseMaterial3D::_update_shader() {
code += "\t}";
code += "\tUV /= vec2(h_frames, v_frames);\n";
code += "\tUV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n";
code += "\tif (particles_anim_blend) {\n";
// Store the next frame UV coordinates in a varying for animation blending.
code += "\t\tparticles_anim_next_frame_uv_coord /= vec2(h_frames, v_frames);\n";
code += "\t\tif (!particles_anim_loop) {\n";
code += "\t\t\tparticle_frame = clamp(particle_frame + 1.0, 0.0, particle_total_frames - 1.0);\n";
code += "\t\t} else {\n";
code += "\t\t\tparticle_frame = mod(particle_frame + 1.0, particle_total_frames);\n";
code += "\t\t}";
code += "\t\tparticles_anim_next_frame_uv_coord += vec2(mod(particle_frame, h_frames) / h_frames, floor((particle_frame) / h_frames) / v_frames);\n";
// Calculate the blending factor (between 0.0 and 1.0) and store it in a varying for use in `fragment()`.
code += "\t\tparticles_anim_next_frame_mix = mod(INSTANCE_CUSTOM.y * particle_total_frames, 1.0);\n";
code += "\t}\n";
} break;
case BILLBOARD_MAX:
break; // Internal value, skip.
Expand Down Expand Up @@ -985,7 +1008,13 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_ALBEDO_FROM_VERTEX_COLOR]) {
code += "\talbedo_tex *= COLOR;\n";
}
code += "\tALBEDO = albedo.rgb * albedo_tex.rgb;\n";

// Use particle flipbook animation if specified.
code += "\tif (particles_anim_blend) {\n";
code += "\t\tALBEDO = albedo.rgb * mix(albedo_tex.rgb, texture(texture_albedo, particles_anim_next_frame_uv_coord).rgb, particles_anim_next_frame_mix);\n";
code += "\t} else {\n";
Comment on lines +1013 to +1015
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should read and store the albedo_blend_tex here. This will allow you to only read the texture once. Below when reading alpha, you can just use albedo_blend_tex.a.

Suggested change
code += "\tif (particles_anim_blend) {\n";
code += "\t\tALBEDO = albedo.rgb * mix(albedo_tex.rgb, texture(texture_albedo, particles_anim_next_frame_uv_coord).rgb, particles_anim_next_frame_mix);\n";
code += "\t} else {\n";
code += "\tvec4 albedo_blend_tex = vec4(1.0);\n";
code += "\tif (particles_anim_blend) {\n";
code += "\t\talbedo_blend_tex = texture(texture_albedo, particles_anim_next_frame_uv_coord);\n";
code += "\t\tALBEDO = albedo.rgb * mix(albedo_tex.rgb, albedo_blend_tex.rgb, particles_anim_next_frame_mix);\n";
code += "\t} else {\n";

code += "\t\tALBEDO = albedo.rgb * albedo_tex.rgb;\n";
code += "\t}\n";

if (!orm) {
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
Expand Down Expand Up @@ -1084,7 +1113,11 @@ void BaseMaterial3D::_update_shader() {
code += "\tALPHA = 1.0;\n";

} else if (transparency != TRANSPARENCY_DISABLED || flags[FLAG_USE_SHADOW_TO_OPACITY] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) {
code += "\tif (particles_anim_blend) {\n";
code += "\t\tALPHA = albedo.a * mix(albedo_tex.a, texture(texture_albedo, particles_anim_next_frame_uv_coord).a, particles_anim_next_frame_mix);\n";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
code += "\t\tALPHA = albedo.a * mix(albedo_tex.a, texture(texture_albedo, particles_anim_next_frame_uv_coord).a, particles_anim_next_frame_mix);\n";
code += "\t\tALPHA = albedo.a * mix(albedo_tex.a, albedo_blend_tex.a, particles_anim_next_frame_mix);\n";

code += "\t} else {\n";
code += "\tALPHA = albedo.a * albedo_tex.a;\n";
code += "\t}\n";
}
if (transparency == TRANSPARENCY_ALPHA_HASH) {
code += "\tALPHA_HASH_SCALE = alpha_hash_scale;\n";
Expand Down Expand Up @@ -1946,6 +1979,15 @@ bool BaseMaterial3D::get_particles_anim_loop() const {
return particles_anim_loop;
}

void BaseMaterial3D::set_particles_anim_blend(bool p_blend) {
particles_anim_blend = p_blend;
RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_blend, particles_anim_blend);
}

bool BaseMaterial3D::get_particles_anim_blend() const {
return particles_anim_blend;
}

void BaseMaterial3D::set_heightmap_deep_parallax(bool p_enable) {
deep_parallax = p_enable;
_queue_shader_change();
Expand Down Expand Up @@ -2357,6 +2399,9 @@ void BaseMaterial3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "loop"), &BaseMaterial3D::set_particles_anim_loop);
ClassDB::bind_method(D_METHOD("get_particles_anim_loop"), &BaseMaterial3D::get_particles_anim_loop);

ClassDB::bind_method(D_METHOD("set_particles_anim_blend", "blend"), &BaseMaterial3D::set_particles_anim_blend);
ClassDB::bind_method(D_METHOD("get_particles_anim_blend"), &BaseMaterial3D::get_particles_anim_blend);

ClassDB::bind_method(D_METHOD("set_heightmap_deep_parallax", "enable"), &BaseMaterial3D::set_heightmap_deep_parallax);
ClassDB::bind_method(D_METHOD("is_heightmap_deep_parallax_enabled"), &BaseMaterial3D::is_heightmap_deep_parallax_enabled);

Expand Down Expand Up @@ -2567,6 +2612,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_h_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_h_frames", "get_particles_anim_h_frames");
ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_v_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_v_frames", "get_particles_anim_v_frames");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_anim_loop"), "set_particles_anim_loop", "get_particles_anim_loop");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_anim_blend"), "set_particles_anim_blend", "get_particles_anim_blend");

ADD_GROUP("Grow", "grow_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "grow"), "set_grow_enabled", "is_grow_enabled");
Expand Down Expand Up @@ -2745,6 +2791,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_particles_anim_h_frames(1);
set_particles_anim_v_frames(1);
set_particles_anim_loop(false);
set_particles_anim_blend(false);

set_transparency(TRANSPARENCY_DISABLED);
set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF);
Expand Down
5 changes: 5 additions & 0 deletions scene/resources/material.h
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ class BaseMaterial3D : public Material {
StringName particles_anim_h_frames;
StringName particles_anim_v_frames;
StringName particles_anim_loop;
StringName particles_anim_blend;
StringName heightmap_min_layers;
StringName heightmap_max_layers;
StringName heightmap_flip;
Expand Down Expand Up @@ -473,6 +474,7 @@ class BaseMaterial3D : public Material {
int particles_anim_h_frames;
int particles_anim_v_frames;
bool particles_anim_loop;
bool particles_anim_blend;
Transparency transparency = TRANSPARENCY_DISABLED;
ShadingMode shading_mode = SHADING_MODE_PER_PIXEL;

Expand Down Expand Up @@ -690,6 +692,9 @@ class BaseMaterial3D : public Material {
void set_particles_anim_loop(bool p_loop);
bool get_particles_anim_loop() const;

void set_particles_anim_blend(bool p_blend);
bool get_particles_anim_blend() const;

void set_grow_enabled(bool p_enable);
bool is_grow_enabled() const;

Expand Down