Remove animation loop from ParticlesMaterial + improvements to CPUParticles2D

Remove animation loop from ParticlesMaterial and move it to
SpatialMaterial for 3D particles and Particles2D for the 2D case.

Added animation to CPUParticles2D as well as the "Convert to
CPUParticles2D" to the PAarticles2D menu.
This commit is contained in:
JFonS 2018-09-27 13:05:57 +02:00
parent f84893f709
commit 85ce4a67ed
26 changed files with 235 additions and 150 deletions

View file

@ -429,6 +429,7 @@ public:
int light_mode;
*/
bool uses_screen_texture;
bool uses_screen_uv;
bool uses_time;

View file

@ -967,7 +967,6 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
//enable instancing
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, true);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, true);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true);
//reset shader and force rebind
state.using_texture_rect = true;
@ -976,10 +975,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map);
if (texture) {
Size2 texpixel_size(1.0 / (texture->width / particles_cmd->h_frames), 1.0 / (texture->height / particles_cmd->v_frames));
Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
} else {
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0));
}
if (!particles->use_local_coords) {
@ -993,9 +990,6 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf);
}
state.canvas_shader.set_uniform(CanvasShaderGLES3::H_FRAMES, particles_cmd->h_frames);
state.canvas_shader.set_uniform(CanvasShaderGLES3::V_FRAMES, particles_cmd->v_frames);
glBindVertexArray(data.particle_quad_array); //use particle quad array
glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer
@ -1073,7 +1067,6 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false);
state.using_texture_rect = true;
_set_texture_rect_mode(false);

View file

@ -449,6 +449,7 @@ public:
};
int light_mode;
bool uses_screen_texture;
bool uses_screen_uv;
bool uses_time;

View file

@ -92,11 +92,6 @@ const bool at_light_pass = true;
const bool at_light_pass = false;
#endif
#ifdef USE_PARTICLES
uniform int h_frames;
uniform int v_frames;
#endif
#if defined(USE_MATERIAL)
/* clang-format off */
@ -143,20 +138,6 @@ void main() {
highp vec4 outvec = vec4(vertex, 0.0, 1.0);
#endif
#ifdef USE_PARTICLES
//scale by texture size
outvec.xy /= color_texpixel_size;
//compute h and v frames and adjust UV interp for animation
int total_frames = h_frames * v_frames;
int frame = min(int(float(total_frames) * instance_custom.z), total_frames - 1);
float frame_w = 1.0 / float(h_frames);
float frame_h = 1.0 / float(v_frames);
uv_interp.x = uv_interp.x * frame_w + frame_w * float(frame % h_frames);
uv_interp.y = uv_interp.y * frame_h + frame_h * float(frame / h_frames);
#endif
#define extra_matrix extra_matrix_instance
{

View file

@ -32,6 +32,7 @@
#include "canvas_item_editor_plugin.h"
#include "core/io/image_loader.h"
#include "scene/2d/cpu_particles_2d.h"
#include "scene/gui/separator.h"
#include "scene/resources/particles_material.h"
@ -82,6 +83,25 @@ void Particles2DEditorPlugin::_menu_callback(int p_idx) {
emission_mask->popup_centered_minsize();
} break;
case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: {
UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
CPUParticles2D *cpu_particles = memnew(CPUParticles2D);
cpu_particles->convert_from_particles(particles);
cpu_particles->set_name(particles->get_name());
cpu_particles->set_transform(particles->get_transform());
cpu_particles->set_visible(particles->is_visible());
cpu_particles->set_pause_mode(particles->get_pause_mode());
undo_redo->create_action("Replace Particles by CPUParticles");
undo_redo->add_do_method(particles, "replace_by", cpu_particles);
undo_redo->add_undo_method(cpu_particles, "replace_by", particles);
undo_redo->add_do_reference(cpu_particles);
undo_redo->add_undo_reference(particles);
undo_redo->commit_action();
} break;
}
}
@ -355,6 +375,8 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
menu->get_popup()->add_separator();
menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
// menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
menu->get_popup()->add_separator();
menu->get_popup()->add_item(TTR("Convert to CPUParticles"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES);
menu->set_text(TTR("Particles"));
toolbar->add_child(menu);

View file

@ -46,7 +46,8 @@ class Particles2DEditorPlugin : public EditorPlugin {
MENU_GENERATE_VISIBILITY_RECT,
MENU_LOAD_EMISSION_MASK,
MENU_CLEAR_EMISSION_MASK
MENU_CLEAR_EMISSION_MASK,
MENU_OPTION_CONVERT_TO_CPU_PARTICLES
};
enum EmissionMode {

View file

@ -44,12 +44,19 @@
Mutex *CanvasItemMaterial::material_mutex = NULL;
SelfList<CanvasItemMaterial>::List CanvasItemMaterial::dirty_materials;
Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map;
CanvasItemMaterial::ShaderNames *CanvasItemMaterial::shader_names = NULL;
void CanvasItemMaterial::init_shaders() {
#ifndef NO_THREADS
material_mutex = Mutex::create();
#endif
shader_names = memnew(ShaderNames);
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";
}
void CanvasItemMaterial::finish_shaders() {
@ -102,7 +109,37 @@ void CanvasItemMaterial::_update_shader() {
case LIGHT_MODE_UNSHADED: code += ",unshaded"; break;
case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break;
}
code += ";\n"; //that's it.
code += ";\n";
if (particles_animation) {
code += "uniform int particles_anim_h_frames;\n";
code += "uniform int particles_anim_v_frames;\n";
code += "uniform bool particles_anim_loop;\n";
code += "void vertex() {\n";
code += "\tfloat h_frames = float(particles_anim_h_frames);\n";
code += "\tfloat v_frames = float(particles_anim_v_frames);\n";
code += "\tVERTEX.xy /= TEXTURE_PIXEL_SIZE * vec2(h_frames, v_frames);\n";
code += "\tint total_frames = particles_anim_h_frames * particles_anim_v_frames;\n";
code += "\tint frame = int(float(total_frames) * INSTANCE_CUSTOM.z);\n";
code += "\tif (particles_anim_loop) {\n";
code += "\t\tframe = abs(frame) % total_frames;\n";
code += "\t} else {\n";
code += "\t\tframe = clamp(frame, 0, total_frames - 1);\n";
code += "\t}\n";
code += "\tfloat frame_w = 1.0 / h_frames;\n";
code += "\tfloat frame_h = 1.0 / v_frames;\n";
code += "\tUV.x = UV.x * frame_w + frame_w * float(frame % particles_anim_h_frames);\n";
code += "\tUV.y = UV.y * frame_h + frame_h * float(frame / particles_anim_v_frames);\n";
code += "}\n";
}
ShaderData shader_data;
shader_data.shader = VS::get_singleton()->shader_create();
@ -177,7 +214,52 @@ CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const {
return light_mode;
}
void CanvasItemMaterial::set_particles_animation(bool p_particles_anim) {
particles_animation = p_particles_anim;
_queue_shader_change();
_change_notify();
}
bool CanvasItemMaterial::get_particles_animation() const {
return particles_animation;
}
void CanvasItemMaterial::set_particles_anim_h_frames(int p_frames) {
particles_anim_h_frames = p_frames;
VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames);
}
int CanvasItemMaterial::get_particles_anim_h_frames() const {
return particles_anim_h_frames;
}
void CanvasItemMaterial::set_particles_anim_v_frames(int p_frames) {
particles_anim_v_frames = p_frames;
VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames);
}
int CanvasItemMaterial::get_particles_anim_v_frames() const {
return particles_anim_v_frames;
}
void CanvasItemMaterial::set_particles_anim_loop(bool p_loop) {
particles_anim_loop = p_loop;
VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
}
bool CanvasItemMaterial::get_particles_anim_loop() const {
return particles_anim_loop;
}
void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
if (property.name.begins_with("particles_anim_") && !particles_animation) {
property.usage = 0;
}
}
RID CanvasItemMaterial::get_shader_rid() const {
@ -199,8 +281,25 @@ void CanvasItemMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode);
ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode);
ClassDB::bind_method(D_METHOD("set_particles_animation", "particles_anim"), &CanvasItemMaterial::set_particles_animation);
ClassDB::bind_method(D_METHOD("get_particles_animation"), &CanvasItemMaterial::get_particles_animation);
ClassDB::bind_method(D_METHOD("set_particles_anim_h_frames", "frames"), &CanvasItemMaterial::set_particles_anim_h_frames);
ClassDB::bind_method(D_METHOD("get_particles_anim_h_frames"), &CanvasItemMaterial::get_particles_anim_h_frames);
ClassDB::bind_method(D_METHOD("set_particles_anim_v_frames", "frames"), &CanvasItemMaterial::set_particles_anim_v_frames);
ClassDB::bind_method(D_METHOD("get_particles_anim_v_frames"), &CanvasItemMaterial::get_particles_anim_v_frames);
ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "loop"), &CanvasItemMaterial::set_particles_anim_loop);
ClassDB::bind_method(D_METHOD("get_particles_anim_loop"), &CanvasItemMaterial::get_particles_anim_loop);
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_animation"), "set_particles_animation", "get_particles_animation");
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");
BIND_ENUM_CONSTANT(BLEND_MODE_MIX);
BIND_ENUM_CONSTANT(BLEND_MODE_ADD);
@ -218,6 +317,11 @@ CanvasItemMaterial::CanvasItemMaterial() :
blend_mode = BLEND_MODE_MIX;
light_mode = LIGHT_MODE_NORMAL;
particles_animation = false;
set_particles_anim_h_frames(1);
set_particles_anim_v_frames(1);
set_particles_anim_loop(false);
current_key.key = 0;
current_key.invalid_key = 1;

View file

@ -70,6 +70,7 @@ private:
struct {
uint32_t blend_mode : 4;
uint32_t light_mode : 4;
uint32_t particles_animation : 1;
uint32_t invalid_key : 1;
};
@ -80,6 +81,14 @@ private:
}
};
struct ShaderNames {
StringName particles_anim_h_frames;
StringName particles_anim_v_frames;
StringName particles_anim_loop;
};
static ShaderNames *shader_names;
struct ShaderData {
RID shader;
int users;
@ -95,6 +104,7 @@ private:
mk.key = 0;
mk.blend_mode = blend_mode;
mk.light_mode = light_mode;
mk.particles_animation = particles_animation;
return mk;
}
@ -108,6 +118,11 @@ private:
BlendMode blend_mode;
LightMode light_mode;
bool particles_animation;
int particles_anim_h_frames;
int particles_anim_v_frames;
bool particles_anim_loop;
protected:
static void _bind_methods();
@ -120,6 +135,17 @@ public:
void set_light_mode(LightMode p_light_mode);
LightMode get_light_mode() const;
void set_particles_animation(bool p_particles_anim);
bool get_particles_animation() const;
void set_particles_anim_h_frames(int p_frames);
int get_particles_anim_h_frames() const;
void set_particles_anim_v_frames(int p_frames);
int get_particles_anim_v_frames() const;
void set_particles_anim_loop(bool p_frames);
bool get_particles_anim_loop() const;
static void init_shaders();
static void finish_shaders();
static void flush_changes();

View file

@ -29,8 +29,9 @@
/*************************************************************************/
#include "cpu_particles_2d.h"
//#include "scene/resources/particles_material.h"
#include "particles_2d.h"
#include "scene/2d/canvas_item.h"
#include "scene/resources/particles_material.h"
#include "servers/visual_server.h"
void CPUParticles2D::set_emitting(bool p_emitting) {
@ -152,19 +153,13 @@ CPUParticles2D::DrawOrder CPUParticles2D::get_draw_order() const {
return draw_order;
}
void CPUParticles2D::_update_mesh_texture() {
void CPUParticles2D::_generate_mesh_texture() {
Size2 tex_size;
if (texture.is_valid()) {
tex_size = texture->get_size();
} else {
tex_size = Size2(1, 1);
}
PoolVector<Vector2> vertices;
vertices.push_back(-tex_size * 0.5);
vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, 0));
vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, tex_size.y));
vertices.push_back(-tex_size * 0.5 + Vector2(0, tex_size.y));
vertices.push_back(Vector2(-0.5, -0.5));
vertices.push_back(Vector2(0.5, -0.5));
vertices.push_back(Vector2(0.5, 0.5));
vertices.push_back(Vector2(-0.5, 0.5));
PoolVector<Vector2> uvs;
uvs.push_back(Vector2(0, 0));
uvs.push_back(Vector2(1, 0));
@ -198,7 +193,6 @@ void CPUParticles2D::set_texture(const Ref<Texture> &p_texture) {
texture = p_texture;
update();
_update_mesh_texture();
}
Ref<Texture> CPUParticles2D::get_texture() const {
@ -237,6 +231,14 @@ String CPUParticles2D::get_configuration_warning() const {
String warnings;
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
if (warnings != String())
warnings += "\n";
warnings += "- " + TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
}
return warnings;
}
@ -396,6 +398,7 @@ bool CPUParticles2D::get_particle_flag(Flags p_flag) const {
void CPUParticles2D::set_emission_shape(EmissionShape p_shape) {
emission_shape = p_shape;
_change_notify();
}
void CPUParticles2D::set_emission_sphere_radius(float p_radius) {
@ -479,6 +482,15 @@ void CPUParticles2D::_validate_property(PropertyInfo &property) const {
if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
property.usage = 0;
}
if (property.name == "emission_points" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
property.usage = 0;
}
if (property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
property.usage = 0;
}
/*
if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
property.usage = 0;
@ -531,7 +543,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
if (!local_coords) {
emission_xform = get_global_transform();
velocity_xform = emission_xform;
emission_xform[2] = Vector2();
velocity_xform[2] = Vector2();
}
for (int i = 0; i < pcount; i++) {
@ -618,9 +630,12 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
p.custom[0] = Math::deg2rad(base_angle); //angle
p.custom[1] = 0.0; //phase
p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1)
p.rotation = Math::deg2rad(base_angle);
p.custom[0] = 0.0; // unused
p.custom[1] = 0.0; // phase [0..1]
p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation phase [0..1]
p.custom[3] = 0.0;
p.transform = Transform2D();
p.time = 0;
p.base_color = Color(1, 1, 1, 1);
@ -767,14 +782,9 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
p.custom[0] = Math::deg2rad(base_angle); //angle
p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); //angle
if (flags[FLAG_ANIM_LOOP]) {
p.custom[2] = Math::fmod(p.custom[2], 1.0f); //loop
} else {
p.custom[2] = CLAMP(p.custom[2], 0.0f, 1.0); //0 to 1 only
}
p.rotation = Math::deg2rad(base_angle); //angle
float animation_phase = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]);
p.custom[2] = animation_phase;
}
//apply color
//apply hue rotation
@ -825,8 +835,8 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
} else {
p.transform.elements[0] = Vector2(Math::cos(p.custom[0]), -Math::sin(p.custom[0]));
p.transform.elements[1] = Vector2(Math::sin(p.custom[0]), Math::cos(p.custom[0]));
p.transform.elements[0] = Vector2(Math::cos(p.rotation), -Math::sin(p.rotation));
p.transform.elements[1] = Vector2(Math::sin(p.rotation), Math::cos(p.rotation));
}
//scale by scale
@ -1058,8 +1068,7 @@ void CPUParticles2D::_notification(int p_what) {
}
void CPUParticles2D::convert_from_particles(Node *p_particles) {
#if 0
Particles *particles = Object::cast_to<Particles>(p_particles);
Particles2D *particles = Object::cast_to<Particles2D>(p_particles);
ERR_FAIL_COND(!particles);
set_emitting(particles->is_emitting());
@ -1074,7 +1083,12 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
set_fractional_delta(particles->get_fractional_delta());
set_speed_scale(particles->get_speed_scale());
set_draw_order(DrawOrder(particles->get_draw_order()));
set_mesh(particles->get_draw_pass_mesh(0));
set_texture(particles->get_texture());
Ref<Material> mat = particles->get_material();
if (mat.is_valid()) {
set_material(mat);
}
Ref<ParticlesMaterial> material = particles->get_process_material();
if (material.is_null())
@ -1091,15 +1105,14 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
}
set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y));
set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z));
set_particle_flag(FLAG_ANIM_LOOP, material->get_flag(ParticlesMaterial::FLAG_ANIM_LOOP));
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
set_emission_rect_extents(material->get_emission_rect_extents());
Vector2 rect_extents = Vector2(material->get_emission_box_extents().x, material->get_emission_box_extents().y);
set_emission_rect_extents(rect_extents);
set_gravity(material->get_gravity());
Vector2 gravity = Vector2(material->get_gravity().x, material->get_gravity().y);
set_gravity(gravity);
#define CONVERT_PARAM(m_param) \
set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
@ -1123,7 +1136,6 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
CONVERT_PARAM(PARAM_ANIM_OFFSET);
#undef CONVERT_PARAM
#endif
}
void CPUParticles2D::_bind_methods() {
@ -1301,7 +1313,6 @@ void CPUParticles2D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_particle_flag", "get_particle_flag", FLAG_ANIM_LOOP);
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
@ -1385,7 +1396,7 @@ CPUParticles2D::CPUParticles2D() {
update_mutex = Mutex::create();
#endif
_update_mesh_texture();
_generate_mesh_texture();
}
CPUParticles2D::~CPUParticles2D() {

View file

@ -68,7 +68,6 @@ public:
enum Flags {
FLAG_ALIGN_Y_TO_VELOCITY,
FLAG_ANIM_LOOP,
FLAG_MAX
};
@ -87,6 +86,7 @@ private:
Transform2D transform;
Color color;
float custom[4];
float rotation;
Vector2 velocity;
bool active;
float angle_rand;
@ -168,7 +168,6 @@ private:
PoolVector<Color> emission_colors;
int emission_point_count;
bool anim_loop;
Vector2 gravity;
void _particles_process(float p_delta);
@ -178,7 +177,7 @@ private:
void _update_render_thread();
void _update_mesh_texture();
void _generate_mesh_texture();
protected:
static void _bind_methods();
@ -223,6 +222,15 @@ public:
void set_texture(const Ref<Texture> &p_texture);
Ref<Texture> get_texture() const;
void set_h_frames(int p_frames);
int get_h_frames();
void set_v_frames(int p_frames);
int get_v_frames();
void set_loop_animation(bool p_loop);
bool get_loop_animation() const;
void set_normalmap(const Ref<Texture> &p_normalmap);
Ref<Texture> get_normalmap() const;

View file

@ -257,30 +257,6 @@ Ref<Texture> Particles2D::get_normal_map() const {
void Particles2D::_validate_property(PropertyInfo &property) const {
}
void Particles2D::set_v_frames(int p_count) {
ERR_FAIL_COND(p_count < 1);
v_frames = p_count;
update();
}
int Particles2D::get_v_frames() const {
return v_frames;
}
void Particles2D::set_h_frames(int p_count) {
ERR_FAIL_COND(p_count < 1);
h_frames = p_count;
update();
}
int Particles2D::get_h_frames() const {
return h_frames;
}
void Particles2D::restart() {
VS::get_singleton()->particles_restart(particles);
}
@ -296,7 +272,7 @@ void Particles2D::_notification(int p_what) {
if (normal_map.is_valid())
normal_rid = normal_map->get_rid();
VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid, h_frames, v_frames);
VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid);
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) {
@ -361,12 +337,6 @@ void Particles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("capture_rect"), &Particles2D::capture_rect);
ClassDB::bind_method(D_METHOD("set_v_frames", "frames"), &Particles2D::set_v_frames);
ClassDB::bind_method(D_METHOD("get_v_frames"), &Particles2D::get_v_frames);
ClassDB::bind_method(D_METHOD("set_h_frames", "frames"), &Particles2D::set_h_frames);
ClassDB::bind_method(D_METHOD("get_h_frames"), &Particles2D::get_h_frames);
ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
@ -389,8 +359,6 @@ void Particles2D::_bind_methods() {
ADD_GROUP("Textures", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
ADD_PROPERTY(PropertyInfo(Variant::INT, "h_frames", PROPERTY_HINT_RANGE, "1,1024,1"), "set_h_frames", "get_h_frames");
ADD_PROPERTY(PropertyInfo(Variant::INT, "v_frames", PROPERTY_HINT_RANGE, "1,1024,1"), "set_v_frames", "get_v_frames");
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
@ -413,8 +381,6 @@ Particles2D::Particles2D() {
set_use_local_coordinates(true);
set_draw_order(DRAW_ORDER_INDEX);
set_speed_scale(1);
h_frames = 1;
v_frames = 1;
}
Particles2D::~Particles2D() {

View file

@ -59,8 +59,6 @@ private:
bool local_coords;
int fixed_fps;
bool fractional_delta;
int v_frames;
int h_frames;
Ref<Material> process_material;
@ -118,12 +116,6 @@ public:
virtual String get_configuration_warning() const;
void set_v_frames(int p_count);
int get_v_frames() const;
void set_h_frames(int p_count);
int get_h_frames() const;
void restart();
Rect2 capture_rect() const;
Particles2D();

View file

@ -781,12 +781,6 @@ void CPUParticles::_particles_process(float p_delta) {
base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
p.custom[0] = Math::deg2rad(base_angle); //angle
p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); //angle
if (flags[FLAG_ANIM_LOOP]) {
p.custom[2] = Math::fmod(p.custom[2], 1.0f); //loop
} else {
p.custom[2] = CLAMP(p.custom[2], 0.0f, 1.0); //0 to 1 only
}
}
//apply color
//apply hue rotation
@ -1151,7 +1145,6 @@ void CPUParticles::convert_from_particles(Node *p_particles) {
set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y));
set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z));
set_particle_flag(FLAG_ANIM_LOOP, material->get_flag(ParticlesMaterial::FLAG_ANIM_LOOP));
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
@ -1357,7 +1350,6 @@ void CPUParticles::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_particle_flag", "get_particle_flag", FLAG_ANIM_LOOP);
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);

View file

@ -70,7 +70,6 @@ public:
FLAG_ALIGN_Y_TO_VELOCITY,
FLAG_ROTATE_Y,
FLAG_DISABLE_Z,
FLAG_ANIM_LOOP,
FLAG_MAX
};
@ -170,7 +169,6 @@ private:
PoolVector<Color> emission_colors;
int emission_point_count;
bool anim_loop;
Vector3 gravity;
void _particles_process(float p_delta);

View file

@ -612,7 +612,7 @@ void SpatialMaterial::_update_shader() {
//handle animation
code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n";
code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n";
code += "\tif (particles_anim_loop) particle_frame=clamp(particle_frame,0.0,particle_total_frames-1.0); else particle_frame=mod(particle_frame,float(particle_total_frames));\n";
code += "\tif (!particles_anim_loop) particle_frame=clamp(particle_frame,0.0,particle_total_frames-1.0); else particle_frame=mod(particle_frame,float(particle_total_frames));\n";
code += "\tUV /= vec2(float(particles_anim_h_frames),float(particles_anim_v_frames));\n";
code += "\tUV += vec2(mod(particle_frame,float(particles_anim_h_frames)) / float(particles_anim_h_frames), floor(particle_frame / float(particles_anim_h_frames)) / float(particles_anim_v_frames));\n";
} break;
@ -1541,13 +1541,13 @@ int SpatialMaterial::get_particles_anim_v_frames() const {
return particles_anim_v_frames;
}
void SpatialMaterial::set_particles_anim_loop(int p_frames) {
void SpatialMaterial::set_particles_anim_loop(bool p_loop) {
particles_anim_loop = p_frames;
VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, p_frames);
particles_anim_loop = p_loop;
VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
}
int SpatialMaterial::get_particles_anim_loop() const {
bool SpatialMaterial::get_particles_anim_loop() const {
return particles_anim_loop;
}
@ -1898,7 +1898,7 @@ void SpatialMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_particles_anim_v_frames", "frames"), &SpatialMaterial::set_particles_anim_v_frames);
ClassDB::bind_method(D_METHOD("get_particles_anim_v_frames"), &SpatialMaterial::get_particles_anim_v_frames);
ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "frames"), &SpatialMaterial::set_particles_anim_loop);
ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "loop"), &SpatialMaterial::set_particles_anim_loop);
ClassDB::bind_method(D_METHOD("get_particles_anim_loop"), &SpatialMaterial::get_particles_anim_loop);
ClassDB::bind_method(D_METHOD("set_depth_deep_parallax", "enable"), &SpatialMaterial::set_depth_deep_parallax);

View file

@ -574,8 +574,8 @@ public:
void set_particles_anim_v_frames(int p_frames);
int get_particles_anim_v_frames() const;
void set_particles_anim_loop(int p_frames);
int get_particles_anim_loop() const;
void set_particles_anim_loop(bool p_loop);
bool get_particles_anim_loop() const;
void set_grow_enabled(bool p_enable);
bool is_grow_enabled() const;

View file

@ -463,12 +463,6 @@ void ParticlesMaterial::_update_shader() {
code += " base_angle += CUSTOM.y * LIFETIME * (angular_velocity + tex_angular_velocity) * mix(1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, angular_velocity_random);\n";
code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random) + CUSTOM.y * (anim_speed + tex_anim_speed) * mix(1.0, rand_from_seed(alt_seed), anim_speed_random);\n"; // angle
if (flags[FLAG_ANIM_LOOP]) {
code += " CUSTOM.z = mod(CUSTOM.z, 1.0);\n"; // loop
} else {
code += " CUSTOM.z = clamp(CUSTOM.z, 0.0, 1.0);\n"; // 0 to 1 only
}
code += " }\n";
// apply color
// apply hue rotation
@ -1175,7 +1169,6 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_flag", "get_flag", FLAG_ANIM_LOOP);
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);

View file

@ -60,7 +60,6 @@ public:
FLAG_ALIGN_Y_TO_VELOCITY,
FLAG_ROTATE_Y,
FLAG_DISABLE_Z,
FLAG_ANIM_LOOP,
FLAG_MAX
};

View file

@ -800,8 +800,6 @@ public:
RID particles;
RID texture;
RID normal_map;
int h_frames;
int v_frames;
CommandParticles() { type = TYPE_PARTICLES; }
};

View file

@ -199,6 +199,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false;
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);

View file

@ -776,7 +776,7 @@ void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID
canvas_item->commands.push_back(m);
}
void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal, int p_h_frames, int p_v_frames) {
void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
@ -786,8 +786,6 @@ void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles,
part->particles = p_particles;
part->texture = p_texture;
part->normal_map = p_normal;
part->h_frames = p_h_frames;
part->v_frames = p_v_frames;
//take the chance and request processing for them, at least once until they become visible again
VSG::storage->particles_request_process(p_particles);

View file

@ -186,7 +186,7 @@ public:
void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID());
void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID());
void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID());
void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal, int p_h_frames, int p_v_frames);
void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal);
void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform);
void canvas_item_add_clip_ignore(RID p_item, bool p_ignore);
void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable);

View file

@ -599,7 +599,7 @@ public:
BIND10(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID)
BIND4(canvas_item_add_mesh, RID, const RID &, RID, RID)
BIND4(canvas_item_add_multimesh, RID, RID, RID, RID)
BIND6(canvas_item_add_particles, RID, RID, RID, RID, int, int)
BIND4(canvas_item_add_particles, RID, RID, RID, RID)
BIND2(canvas_item_add_set_transform, RID, const Transform2D &)
BIND2(canvas_item_add_clip_ignore, RID, bool)
BIND2(canvas_item_set_sort_children_by_y, RID, bool)

View file

@ -516,7 +516,7 @@ public:
FUNC10(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID)
FUNC4(canvas_item_add_mesh, RID, const RID &, RID, RID)
FUNC4(canvas_item_add_multimesh, RID, RID, RID, RID)
FUNC6(canvas_item_add_particles, RID, RID, RID, RID, int, int)
FUNC4(canvas_item_add_particles, RID, RID, RID, RID)
FUNC2(canvas_item_add_set_transform, RID, const Transform2D &)
FUNC2(canvas_item_add_clip_ignore, RID, bool)
FUNC2(canvas_item_set_sort_children_by_y, RID, bool)

View file

@ -1978,7 +1978,7 @@ void VisualServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count", "normal_map"), &VisualServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1), DEFVAL(RID()));
ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "texture", "normal_map"), &VisualServer::canvas_item_add_mesh, DEFVAL(RID()));
ClassDB::bind_method(D_METHOD("canvas_item_add_multimesh", "item", "mesh", "texture", "normal_map"), &VisualServer::canvas_item_add_multimesh, DEFVAL(RID()));
ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture", "normal_map", "h_frames", "v_frames"), &VisualServer::canvas_item_add_particles);
ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture", "normal_map"), &VisualServer::canvas_item_add_particles);
ClassDB::bind_method(D_METHOD("canvas_item_add_set_transform", "item", "transform"), &VisualServer::canvas_item_add_set_transform);
ClassDB::bind_method(D_METHOD("canvas_item_add_clip_ignore", "item", "ignore"), &VisualServer::canvas_item_add_clip_ignore);
ClassDB::bind_method(D_METHOD("canvas_item_set_sort_children_by_y", "item", "enabled"), &VisualServer::canvas_item_set_sort_children_by_y);

View file

@ -895,7 +895,7 @@ public:
virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()) = 0;
virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0;
virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0;
virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, int p_h_frames, int p_v_frames) = 0;
virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map) = 0;
virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0;
virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore) = 0;
virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) = 0;