From 74808ac4d9176180dc7ecace99723edab8a73e0e Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 6 Apr 2017 23:36:37 -0300 Subject: New particle system, mostly working, some small features missing. --- drivers/gles2/rasterizer_gles2.cpp | 6 +- drivers/gles2/rasterizer_gles2.h | 6 +- drivers/gles3/rasterizer_canvas_gles3.cpp | 2 +- drivers/gles3/rasterizer_scene_gles3.cpp | 156 +++++++++-------- drivers/gles3/rasterizer_scene_gles3.h | 1 - drivers/gles3/rasterizer_storage_gles3.cpp | 268 ++++++++++++++++++++--------- drivers/gles3/rasterizer_storage_gles3.h | 58 ++++--- drivers/gles3/shader_compiler_gles3.cpp | 76 ++++++-- drivers/gles3/shader_compiler_gles3.h | 1 + drivers/gles3/shaders/particles.glsl | 115 ++++++++++--- drivers/gles3/shaders/scene.glsl | 79 +++++---- 11 files changed, 526 insertions(+), 242 deletions(-) (limited to 'drivers') diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index 3f54f887da..fcac0a3e05 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -8699,7 +8699,7 @@ void RasterizerGLES2::_canvas_item_render_commands(CanvasItem *p_item, CanvasIte } } -void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *material, Shader *shader) { +void RasterizerGLES2::_canvas_item_setup_shader_params(ShaderMaterial *material, Shader *shader) { if (canvas_shader.bind()) rebind_texpixel_size = true; @@ -8748,7 +8748,7 @@ void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *mater uses_texpixel_size = shader->uses_texpixel_size; } -void RasterizerGLES2::_canvas_item_setup_shader_uniforms(CanvasItemMaterial *material, Shader *shader) { +void RasterizerGLES2::_canvas_item_setup_shader_uniforms(ShaderMaterial *material, Shader *shader) { //this can be optimized.. int tex_id = 1; @@ -8925,7 +8925,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list, int p_z, cons //begin rect CanvasItem *material_owner = ci->material_owner ? ci->material_owner : ci; - CanvasItemMaterial *material = material_owner->material; + ShaderMaterial *material = material_owner->material; if (material != canvas_last_material || rebind_shader) { diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 9aeb3af61a..f45b51ae57 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -1224,7 +1224,7 @@ class RasterizerGLES2 : public Rasterizer { bool uses_texpixel_size; bool rebind_texpixel_size; Transform canvas_transform; - CanvasItemMaterial *canvas_last_material; + ShaderMaterial *canvas_last_material; bool canvas_texscreen_used; Vector2 normal_flip; _FORCE_INLINE_ void _canvas_normal_set_flip(const Vector2 &p_flip); @@ -1288,8 +1288,8 @@ class RasterizerGLES2 : public Rasterizer { template _FORCE_INLINE_ void _canvas_item_render_commands(CanvasItem *p_item, CanvasItem *current_clip, bool &reclip); - _FORCE_INLINE_ void _canvas_item_setup_shader_params(CanvasItemMaterial *material, Shader *p_shader); - _FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(CanvasItemMaterial *material, Shader *p_shader); + _FORCE_INLINE_ void _canvas_item_setup_shader_params(ShaderMaterial *material, Shader *p_shader); + _FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(ShaderMaterial *material, Shader *p_shader); public: /* TEXTURE API */ diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 34a5858729..43fff5a1b1 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -687,7 +687,7 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur } #if 0 -void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *material,Shader* shader) { +void RasterizerGLES2::_canvas_item_setup_shader_params(ShaderMaterial *material,Shader* shader) { if (canvas_shader.bind()) rebind_texpixel_size=true; diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index d3936801dd..4353d82eec 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1283,6 +1283,35 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) { } } break; + case VS::INSTANCE_PARTICLES: { + + RasterizerStorageGLES3::Particles *particles = static_cast(e->owner); + RasterizerStorageGLES3::Surface *s = static_cast(e->geometry); + + glBindVertexArray(s->instancing_array_id); // use the instancing array ID + glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //modify the buffer + + int stride = sizeof(float) * 4 * 6; + + //transform + + glEnableVertexAttribArray(8); //xform x + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 3); + glVertexAttribDivisor(8, 1); + glEnableVertexAttribArray(9); //xform y + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 4); + glVertexAttribDivisor(9, 1); + glEnableVertexAttribArray(10); //xform z + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 5); + glVertexAttribDivisor(10, 1); + glEnableVertexAttribArray(11); //color + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0); + glVertexAttribDivisor(11, 1); + glEnableVertexAttribArray(12); //custom + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 2); + glVertexAttribDivisor(12, 1); + + } break; } } @@ -1451,6 +1480,30 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { restore_tex = false; } } break; + case VS::INSTANCE_PARTICLES: { + + RasterizerStorageGLES3::Particles *particles = static_cast(e->owner); + RasterizerStorageGLES3::Surface *s = static_cast(e->geometry); + + if (!particles->use_local_coords) //not using local coordinates? then clear transform.. + state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, Transform()); + + int amount = particles->amount; + + if (s->index_array_len > 0) { + + glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount); + + storage->info.render_vertices_count += s->index_array_len * amount; + + } else { + + glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount); + + storage->info.render_vertices_count += s->array_len * amount; + } + + } break; } } @@ -1556,61 +1609,6 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e, const Transform } } -void RasterizerSceneGLES3::_setup_transform(InstanceBase *p_instance, const Transform &p_view_transform, const CameraMatrix &p_projection) { - - if (p_instance->billboard || p_instance->billboard_y || p_instance->depth_scale) { - - Transform xf = p_instance->transform; - if (p_instance->depth_scale) { - - if (p_projection.matrix[3][3]) { - //orthogonal matrix, try to do about the same - //with viewport size - //real_t w = Math::abs( 1.0/(2.0*(p_projection.matrix[0][0])) ); - real_t h = Math::abs(1.0 / (2.0 * p_projection.matrix[1][1])); - float sc = (h * 2.0); //consistent with Y-fov - xf.basis.scale(Vector3(sc, sc, sc)); - } else { - //just scale by depth - real_t sc = Plane(p_view_transform.origin, -p_view_transform.get_basis().get_axis(2)).distance_to(xf.origin); - xf.basis.scale(Vector3(sc, sc, sc)); - } - } - - if (p_instance->billboard && storage->frame.current_rt) { - - Vector3 scale = xf.basis.get_scale(); - - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { - xf.set_look_at(xf.origin, xf.origin + p_view_transform.get_basis().get_axis(2), -p_view_transform.get_basis().get_axis(1)); - } else { - xf.set_look_at(xf.origin, xf.origin + p_view_transform.get_basis().get_axis(2), p_view_transform.get_basis().get_axis(1)); - } - - xf.basis.scale(scale); - } - - if (p_instance->billboard_y && storage->frame.current_rt) { - - Vector3 scale = xf.basis.get_scale(); - Vector3 look_at = p_view_transform.get_origin(); - look_at.y = 0.0; - Vector3 look_at_norm = look_at.normalized(); - - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { - xf.set_look_at(xf.origin, xf.origin + look_at_norm, Vector3(0.0, -1.0, 0.0)); - } else { - xf.set_look_at(xf.origin, xf.origin + look_at_norm, Vector3(0.0, 1.0, 0.0)); - } - xf.basis.scale(scale); - } - state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, xf); - - } else { - state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, p_instance->transform); - } -} - void RasterizerSceneGLES3::_set_cull(bool p_front, bool p_reverse_cull) { bool front = p_front; @@ -1677,6 +1675,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, true); //by default unshaded (easier to set) bool first = true; + bool prev_use_instancing = false; storage->info.render_object_count += p_element_count; @@ -1804,10 +1803,10 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ } } + bool use_instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH || e->instance->base_type == VS::INSTANCE_PARTICLES; - - if ((prev_base_type == VS::INSTANCE_MULTIMESH) != (e->instance->base_type == VS::INSTANCE_MULTIMESH)) { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING, e->instance->base_type == VS::INSTANCE_MULTIMESH); + if (use_instancing != prev_use_instancing) { + state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING, use_instancing); rebind = true; } @@ -1820,7 +1819,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ if (skeleton.is_valid()) { RasterizerStorageGLES3::Skeleton *sk = storage->skeleton_owner.getornull(skeleton); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6); - glBindTexture(GL_TEXTURE_2D,sk->texture); + glBindTexture(GL_TEXTURE_2D, sk->texture); } } @@ -1835,8 +1834,6 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ } } - - if (!(e->sort_key & RenderList::SORT_KEY_UNSHADED_FLAG) && !p_directional_add && !p_shadow) { _setup_light(e, p_view_transform); } @@ -1850,8 +1847,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ _set_cull(e->sort_key & RenderList::SORT_KEY_MIRROR_FLAG, p_reverse_cull); state.scene_shader.set_uniform(SceneShaderGLES3::NORMAL_MULT, e->instance->mirror ? -1.0 : 1.0); - - _setup_transform(e->instance, p_view_transform, p_projection); + state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, e->instance->transform); _render_geometry(e); @@ -1861,6 +1857,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ prev_owner = e->owner; prev_shading = shading; prev_skeleton = skeleton; + prev_use_instancing = use_instancing; first = false; } @@ -1930,7 +1927,7 @@ void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geo if (has_blend_alpha || (has_base_alpha && m->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) return; //bye - if (!m->shader->spatial.uses_vertex && !m->shader->spatial.uses_discard && m->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { + if (!m->shader->spatial.writes_modelview_or_projection && !m->shader->spatial.uses_vertex && !m->shader->spatial.uses_discard && m->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { //shader does not use discard and does not write a vertex position, use generic material if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) m = storage->material_owner.getptr(default_material_twosided); @@ -2729,6 +2726,30 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p } break; case VS::INSTANCE_IMMEDIATE: { + } break; + case VS::INSTANCE_PARTICLES: { + + RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getptr(inst->base); + ERR_CONTINUE(!particles); + + for (int i = 0; i < particles->draw_passes.size(); i++) { + + RID pmesh = particles->draw_passes[i]; + if (!pmesh.is_valid()) + continue; + RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.get(pmesh); + if (!mesh) + continue; //mesh not assigned + + int ssize = mesh->surfaces.size(); + + for (int j = 0; j < ssize; j++) { + + RasterizerStorageGLES3::Surface *s = mesh->surfaces[j]; + _add_geometry(s, inst, particles, -1, p_shadow); + } + } + } break; } } @@ -4419,13 +4440,14 @@ void RasterizerSceneGLES3::initialize() { state.scene_shader.init(); - default_shader = storage->shader_create(VS::SHADER_SPATIAL); + default_shader = storage->shader_create(); + storage->shader_set_code(default_shader, "shader_type spatial;\n"); default_material = storage->material_create(); storage->material_set_shader(default_material, default_shader); - default_shader_twosided = storage->shader_create(VS::SHADER_SPATIAL); + default_shader_twosided = storage->shader_create(); default_material_twosided = storage->material_create(); - storage->shader_set_code(default_shader_twosided, "render_mode cull_disabled;\n"); + storage->shader_set_code(default_shader_twosided, "shader_type spatial; render_mode cull_disabled;\n"); storage->material_set_shader(default_material_twosided, default_shader_twosided); glGenBuffers(1, &state.scene_ubo); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index b27bce726f..68da532824 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -691,7 +691,6 @@ public: _FORCE_INLINE_ void _set_cull(bool p_front, bool p_reverse_cull); _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES3::Material *p_material, bool p_alpha_pass); - _FORCE_INLINE_ void _setup_transform(InstanceBase *p_instance, const Transform &p_view_transform, const CameraMatrix &p_projection); _FORCE_INLINE_ void _setup_geometry(RenderList::Element *e); _FORCE_INLINE_ void _render_geometry(RenderList::Element *e); _FORCE_INLINE_ void _setup_light(RenderList::Element *e, const Transform &p_view_transform); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 4fcd09ed58..d6c8b3b35b 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1338,12 +1338,12 @@ void RasterizerStorageGLES3::skybox_set_texture(RID p_skybox, RID p_cube_map, in /* SHADER API */ -RID RasterizerStorageGLES3::shader_create(VS::ShaderMode p_mode) { +RID RasterizerStorageGLES3::shader_create() { Shader *shader = memnew(Shader); - shader->mode = p_mode; + shader->mode = VS::SHADER_SPATIAL; + shader->shader = &scene->state.scene_shader; RID rid = shader_owner.make_rid(shader); - shader_set_mode(rid, p_mode); _shader_make_dirty(shader); shader->self = rid; @@ -1358,22 +1358,30 @@ void RasterizerStorageGLES3::_shader_make_dirty(Shader *p_shader) { _shader_dirty_list.add(&p_shader->dirty_list); } -void RasterizerStorageGLES3::shader_set_mode(RID p_shader, VS::ShaderMode p_mode) { +void RasterizerStorageGLES3::shader_set_code(RID p_shader, const String &p_code) { - ERR_FAIL_INDEX(p_mode, VS::SHADER_MAX); Shader *shader = shader_owner.get(p_shader); ERR_FAIL_COND(!shader); - if (shader->custom_code_id && p_mode == shader->mode) - return; + shader->code = p_code; + + String mode_string = ShaderLanguage::get_shader_type(p_code); + VS::ShaderMode mode; - if (shader->custom_code_id) { + if (mode_string == "canvas_item") + mode = VS::SHADER_CANVAS_ITEM; + else if (mode_string == "particles") + mode = VS::SHADER_PARTICLES; + else + mode = VS::SHADER_SPATIAL; + + if (shader->custom_code_id && mode != shader->mode) { shader->shader->free_custom_shader(shader->custom_code_id); shader->custom_code_id = 0; } - shader->mode = p_mode; + shader->mode = mode; ShaderGLES3 *shaders[VS::SHADER_MAX] = { &scene->state.scene_shader, @@ -1382,25 +1390,12 @@ void RasterizerStorageGLES3::shader_set_mode(RID p_shader, VS::ShaderMode p_mode }; - shader->shader = shaders[p_mode]; - - shader->custom_code_id = shader->shader->create_custom_shader(); - - _shader_make_dirty(shader); -} -VS::ShaderMode RasterizerStorageGLES3::shader_get_mode(RID p_shader) const { - - const Shader *shader = shader_owner.get(p_shader); - ERR_FAIL_COND_V(!shader, VS::SHADER_MAX); - - return shader->mode; -} -void RasterizerStorageGLES3::shader_set_code(RID p_shader, const String &p_code) { + shader->shader = shaders[mode]; - Shader *shader = shader_owner.get(p_shader); - ERR_FAIL_COND(!shader); + if (shader->custom_code_id == 0) { + shader->custom_code_id = shader->shader->create_custom_shader(); + } - shader->code = p_code; _shader_make_dirty(shader); } String RasterizerStorageGLES3::shader_get_code(RID p_shader) const { @@ -1453,6 +1448,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { p_shader->spatial.ontop = false; p_shader->spatial.uses_sss = false; p_shader->spatial.uses_vertex = false; + p_shader->spatial.writes_modelview_or_projection = false; shaders.actions_scene.render_mode_values["blend_add"] = Pair(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_ADD); shaders.actions_scene.render_mode_values["blend_mix"] = Pair(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MIX); @@ -1477,6 +1473,9 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { shaders.actions_scene.usage_flag_pointers["SSS_STRENGTH"] = &p_shader->spatial.uses_sss; shaders.actions_scene.usage_flag_pointers["DISCARD"] = &p_shader->spatial.uses_discard; + shaders.actions_scene.write_flag_pointers["MODELVIEW_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection; + shaders.actions_scene.write_flag_pointers["PROJECTION_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection; + actions = &shaders.actions_scene; actions->uniforms = &p_shader->uniforms; @@ -4861,6 +4860,8 @@ void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount) Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); + particles->amount = p_amount; + int floats = p_amount * 24; float *data = memnew_arr(float, floats); @@ -4868,17 +4869,25 @@ void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount) data[i] = 0; } - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); - glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_DYNAMIC_DRAW); + for (int i = 0; i < 2; i++) { - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[1]); - glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_DYNAMIC_DRAW); + glBindVertexArray(particles->particle_vaos[i]); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[i]); + glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_DYNAMIC_DRAW); + + for (int i = 0; i < 6; i++) { + glEnableVertexAttribArray(i); + glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, ((uint8_t *)0) + (i * 16)); + } + } + + glBindVertexArray(0); particles->prev_ticks = 0; particles->phase = 0; particles->prev_phase = 0; + particles->clear = true; memdelete_arr(data); } @@ -4927,41 +4936,29 @@ void RasterizerStorageGLES3::particles_set_use_local_coordinates(RID p_particles particles->use_local_coords = p_enable; } -void RasterizerStorageGLES3::particles_set_process_material(RID p_particles, RID p_material) { - - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - particles->process_material = p_material; -} - -void RasterizerStorageGLES3::particles_set_emission_shape(RID p_particles, VS::ParticlesEmissionShape p_shape) { +void RasterizerStorageGLES3::particles_set_fixed_fps(RID p_particles, int p_fps) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - particles->emission_shape = p_shape; + particles->fixed_fps = p_fps; } -void RasterizerStorageGLES3::particles_set_emission_sphere_radius(RID p_particles, float p_radius) { - Particles *particles = particles_owner.getornull(p_particles); - ERR_FAIL_COND(!particles); - - particles->emission_sphere_radius = p_radius; -} -void RasterizerStorageGLES3::particles_set_emission_box_extents(RID p_particles, const Vector3 &p_extents) { +void RasterizerStorageGLES3::particles_set_fractional_delta(RID p_particles, bool p_enable) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - particles->emission_box_extents = p_extents; + particles->fractional_delta = p_enable; } -void RasterizerStorageGLES3::particles_set_emission_points(RID p_particles, const PoolVector &p_points) { + +void RasterizerStorageGLES3::particles_set_process_material(RID p_particles, RID p_material) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - particles->emission_points = p_points; + particles->process_material = p_material; } void RasterizerStorageGLES3::particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) { @@ -4972,26 +4969,30 @@ void RasterizerStorageGLES3::particles_set_draw_order(RID p_particles, VS::Parti particles->draw_order = p_order; } -void RasterizerStorageGLES3::particles_set_draw_passes(RID p_particles, int p_count) { +void RasterizerStorageGLES3::particles_set_draw_passes(RID p_particles, int p_passes) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - particles->draw_passes.resize(p_count); + particles->draw_passes.resize(p_passes); } -void RasterizerStorageGLES3::particles_set_draw_pass_material(RID p_particles, int p_pass, RID p_material) { + +void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_INDEX(p_pass, particles->draw_passes.size()); - particles->draw_passes[p_pass].material = p_material; + particles->draw_passes[p_pass] = p_mesh; } -void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { + +void RasterizerStorageGLES3::particles_request_process(RID p_particles) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - ERR_FAIL_INDEX(p_pass, particles->draw_passes.size()); - particles->draw_passes[p_pass].mesh = p_mesh; + + if (!particles->particle_element.in_list()) { + particle_update_list.add(&particles->particle_element); + } } Rect3 RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) { @@ -5002,10 +5003,86 @@ Rect3 RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) { return particles->computed_aabb; } +Rect3 RasterizerStorageGLES3::particles_get_aabb(RID p_particles) const { + + const Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND_V(!particles, Rect3()); + + return Rect3(Vector3(-1, -1, -1), Vector3(2, 2, 2)); +} + +void RasterizerStorageGLES3::particles_set_emission_transform(RID p_particles, const Transform &p_transform) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->emission_transform = p_transform; +} + +void RasterizerStorageGLES3::_particles_process(Particles *particles, float p_delta) { + + float new_phase = Math::fmod((float)particles->phase + (p_delta / particles->lifetime), (float)1.0); + + if (particles->clear) { + particles->cycle_number = 0; + } else if (new_phase < particles->phase) { + particles->cycle_number++; + } + + shaders.particles.set_uniform(ParticlesShaderGLES3::SYSTEM_PHASE, new_phase); + shaders.particles.set_uniform(ParticlesShaderGLES3::PREV_SYSTEM_PHASE, particles->phase); + particles->phase = new_phase; + + shaders.particles.set_uniform(ParticlesShaderGLES3::DELTA, p_delta); + shaders.particles.set_uniform(ParticlesShaderGLES3::CLEAR, particles->clear); + if (particles->use_local_coords) + shaders.particles.set_uniform(ParticlesShaderGLES3::EMISSION_TRANSFORM, Transform()); + else + shaders.particles.set_uniform(ParticlesShaderGLES3::EMISSION_TRANSFORM, particles->emission_transform); + + glUniform1ui(shaders.particles.get_uniform(ParticlesShaderGLES3::CYCLE), particles->cycle_number); + + particles->clear = false; + + glBindVertexArray(particles->particle_vaos[0]); + + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, particles->particle_buffers[1]); + + // GLint size = 0; + // glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &size); + + glBeginTransformFeedback(GL_POINTS); + glDrawArrays(GL_POINTS, 0, particles->amount); + glEndTransformFeedback(); + + SWAP(particles->particle_buffers[0], particles->particle_buffers[1]); + SWAP(particles->particle_vaos[0], particles->particle_vaos[1]); + + glBindVertexArray(0); + /* //debug particles :D + glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); + + float *data = (float *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, GL_MAP_READ_BIT); + for (int i = 0; i < particles->amount; i++) { + int ofs = i * 24; + print_line(itos(i) + ":"); + print_line("\tColor: " + Color(data[ofs + 0], data[ofs + 1], data[ofs + 2], data[ofs + 3])); + print_line("\tVelocity: " + Vector3(data[ofs + 4], data[ofs + 5], data[ofs + 6])); + print_line("\tActive: " + itos(data[ofs + 7])); + print_line("\tCustom: " + Color(data[ofs + 8], data[ofs + 9], data[ofs + 10], data[ofs + 11])); + print_line("\tXF X: " + Color(data[ofs + 12], data[ofs + 13], data[ofs + 14], data[ofs + 15])); + print_line("\tXF Y: " + Color(data[ofs + 16], data[ofs + 17], data[ofs + 18], data[ofs + 19])); + print_line("\tXF Z: " + Color(data[ofs + 20], data[ofs + 21], data[ofs + 22], data[ofs + 23])); + } + + glUnmapBuffer(GL_ARRAY_BUFFER); + glBindBuffer(GL_ARRAY_BUFFER, 0); + //*/ +} + void RasterizerStorageGLES3::update_particles() { glEnable(GL_RASTERIZER_DISCARD); - glBindVertexArray(0); while (particle_update_list.first()) { @@ -5068,38 +5145,61 @@ void RasterizerStorageGLES3::update_particles() { } } - shaders.particles.bind(); - - shaders.particles.set_uniform(ParticlesShaderGLES3::ORIGIN, particles->origin); - - float new_phase = Math::fmod((float)particles->phase + (frame.delta / particles->lifetime), (float)1.0); + shaders.particles.set_conditional(ParticlesShaderGLES3::USE_FRACTIONAL_DELTA, particles->fractional_delta); - shaders.particles.set_uniform(ParticlesShaderGLES3::SYSTEM_PHASE, new_phase); - shaders.particles.set_uniform(ParticlesShaderGLES3::PREV_SYSTEM_PHASE, particles->phase); - particles->phase = new_phase; + shaders.particles.bind(); shaders.particles.set_uniform(ParticlesShaderGLES3::TOTAL_PARTICLES, particles->amount); - shaders.particles.set_uniform(ParticlesShaderGLES3::TIME, 0.0); + shaders.particles.set_uniform(ParticlesShaderGLES3::TIME, Color(frame.time[0], frame.time[1], frame.time[2], frame.time[3])); shaders.particles.set_uniform(ParticlesShaderGLES3::EXPLOSIVENESS, particles->explosiveness); - shaders.particles.set_uniform(ParticlesShaderGLES3::DELTA, frame.delta); + shaders.particles.set_uniform(ParticlesShaderGLES3::LIFETIME, particles->lifetime); shaders.particles.set_uniform(ParticlesShaderGLES3::GRAVITY, particles->gravity); shaders.particles.set_uniform(ParticlesShaderGLES3::ATTRACTOR_COUNT, 0); + shaders.particles.set_uniform(ParticlesShaderGLES3::EMITTING, particles->emitting); + shaders.particles.set_uniform(ParticlesShaderGLES3::RANDOMNESS, particles->randomness); - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); - glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, particles->particle_buffers[1]); + if (particles->clear && particles->pre_process_time > 0.0) { - for (int i = 0; i < 6; i++) { - glEnableVertexAttribArray(i); - glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, ((uint8_t *)0) + (i * 16)); + float frame_time; + if (particles->fixed_fps > 0) + frame_time = 1.0 / particles->fixed_fps; + else + frame_time = 1.0 / 30.0; + + float delta = particles->pre_process_time; + if (delta > 0.1) { //avoid recursive stalls if fps goes below 10 + delta = 0.1; + } + float todo = delta; + + while (todo >= frame_time) { + _particles_process(particles, frame_time); + todo -= frame_time; + } } - glBeginTransformFeedback(GL_POINTS); - glDrawArrays(GL_POINTS, 0, particles->amount); - glEndTransformFeedback(); + if (particles->fixed_fps > 0) { + float frame_time = 1.0 / particles->fixed_fps; + float delta = frame.delta; + if (delta > 0.1) { //avoid recursive stalls if fps goes below 10 + delta = 0.1; + } else if (delta <= 0.0) { //unlikely but.. + delta = 0.001; + } + float todo = particles->frame_remainder + delta; - particle_update_list.remove(particle_update_list.first()); + while (todo >= frame_time) { + _particles_process(particles, frame_time); + todo -= frame_time; + } + + particles->frame_remainder = todo; + + } else { + _particles_process(particles, frame.delta); + } - SWAP(particles->particle_buffers[0], particles->particle_buffers[1]); + particle_update_list.remove(particle_update_list.first()); } glDisable(GL_RASTERIZER_DISCARD); @@ -5143,6 +5243,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base, RasterizerScene inst = immediate_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_PARTICLES: { + inst = particles_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; case VS::INSTANCE_REFLECTION_PROBE: { inst = reflection_probe_owner.getornull(p_base); ERR_FAIL_COND(!inst); @@ -5182,6 +5286,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base, RasterizerSc inst = immediate_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_PARTICLES: { + inst = particles_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; case VS::INSTANCE_REFLECTION_PROBE: { inst = reflection_probe_owner.getornull(p_base); ERR_FAIL_COND(!inst); @@ -5856,6 +5964,10 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const { return VS::INSTANCE_IMMEDIATE; } + if (particles_owner.owns(p_rid)) { + return VS::INSTANCE_PARTICLES; + } + if (light_owner.owns(p_rid)) { return VS::INSTANCE_LIGHT; } diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 50617b8124..e376c2c0bb 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -408,6 +408,7 @@ public: bool uses_vertex; bool uses_discard; bool uses_sss; + bool writes_modelview_or_projection; } spatial; @@ -433,10 +434,7 @@ public: mutable RID_Owner shader_owner; - virtual RID shader_create(VS::ShaderMode p_mode = VS::SHADER_SPATIAL); - - virtual void shader_set_mode(RID p_shader, VS::ShaderMode p_mode); - virtual VS::ShaderMode shader_get_mode(RID p_shader) const; + virtual RID shader_create(); virtual void shader_set_code(RID p_shader, const String &p_code); virtual String shader_get_code(RID p_shader) const; @@ -778,7 +776,7 @@ public: Skeleton() : update_list(this) { - size=0; + size = 0; use_2d = false; texture = 0; @@ -987,7 +985,7 @@ public: /* PARTICLES */ - struct Particles : public Instantiable { + struct Particles : public GeometryOwner { bool emitting; int amount; @@ -1000,23 +998,14 @@ public: bool use_local_coords; RID process_material; - VS::ParticlesEmissionShape emission_shape; - float emission_sphere_radius; - Vector3 emission_box_extents; - PoolVector emission_points; - GLuint emission_point_texture; - VS::ParticlesDrawOrder draw_order; - struct DrawPass { - RID mesh; - RID material; - }; - Vector draw_passes; + Vector draw_passes; Rect3 computed_aabb; GLuint particle_buffers[2]; + GLuint particle_vaos[2]; SelfList particle_element; @@ -1024,10 +1013,19 @@ public: float prev_phase; uint64_t prev_ticks; - Transform origin; + uint32_t cycle_number; + + int fixed_fps = 0; + bool fractional_delta; + float frame_remainder; + + bool clear; + + Transform emission_transform; Particles() : particle_element(this) { + cycle_number = 0; emitting = false; amount = 0; lifetime = 1.0; @@ -1035,23 +1033,26 @@ public: explosiveness = 0.0; randomness = 0.0; use_local_coords = true; + fixed_fps = 0; + fractional_delta = false; + frame_remainder = 0; draw_order = VS::PARTICLES_DRAW_ORDER_INDEX; - emission_shape = VS::PARTICLES_EMSSION_POINT; - emission_sphere_radius = 1.0; - emission_box_extents = Vector3(1, 1, 1); - emission_point_texture = 0; particle_buffers[0] = 0; particle_buffers[1] = 0; prev_ticks = 0; + clear = true; + glGenBuffers(2, particle_buffers); + glGenVertexArrays(2, particle_vaos); } ~Particles() { glDeleteBuffers(2, particle_buffers); + glDeleteVertexArrays(2, particle_vaos); } }; @@ -1073,19 +1074,20 @@ public: virtual void particles_set_gravity(RID p_particles, const Vector3 &p_gravity); virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable); virtual void particles_set_process_material(RID p_particles, RID p_material); - - virtual void particles_set_emission_shape(RID p_particles, VS::ParticlesEmissionShape p_shape); - virtual void particles_set_emission_sphere_radius(RID p_particles, float p_radius); - virtual void particles_set_emission_box_extents(RID p_particles, const Vector3 &p_extents); - virtual void particles_set_emission_points(RID p_particles, const PoolVector &p_points); + virtual void particles_set_fixed_fps(RID p_particles, int p_fps); + virtual void particles_set_fractional_delta(RID p_particles, bool p_enable); virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order); virtual void particles_set_draw_passes(RID p_particles, int p_count); - virtual void particles_set_draw_pass_material(RID p_particles, int p_pass, RID p_material); virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh); + virtual void particles_request_process(RID p_particles); virtual Rect3 particles_get_current_aabb(RID p_particles); + virtual Rect3 particles_get_aabb(RID p_particles) const; + + virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform); + void _particles_process(Particles *p_particles, float p_delta); /* INSTANCE */ diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 48ca86ebe2..b9d50caa10 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -91,6 +91,16 @@ static String _prestr(SL::DataPrecision p_pres) { return ""; } +static String _qualstr(SL::ArgumentQualifier p_qual) { + + switch (p_qual) { + case SL::ARGUMENT_QUALIFIER_IN: return ""; + case SL::ARGUMENT_QUALIFIER_OUT: return "out "; + case SL::ARGUMENT_QUALIFIER_INOUT: return "inout "; + } + return ""; +} + static String _opstr(SL::Operator p_op) { return SL::get_operator_text(p_op); @@ -174,6 +184,21 @@ static String get_constant_text(SL::DataType p_type, const Vector 0) + text += ","; + + text += f2sp0(p_values[i].real); + } + text += ")"; + return text; + } break; default: ERR_FAIL_V(String()); } @@ -194,6 +219,7 @@ void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const Stri for (Set::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) { + print_line(String(p_node->functions[fidx].name) + " uses function: " + String(E->get())); if (added.has(E->get())) { continue; //was added already } @@ -219,7 +245,7 @@ void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const Stri if (i > 0) header += ", "; - header += _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name); + header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name); } header += ")\n"; @@ -383,6 +409,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener if (fnode->name == "vertex") { + print_line("vertex uses functions: " + itos(pnode->functions[i].uses_function.size())); _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.vertex_global, added_vtx); r_gen_code.vertex = function_code["vertex"]; } @@ -482,6 +509,12 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener case SL::OP_ASSIGN_BIT_AND: case SL::OP_ASSIGN_BIT_OR: case SL::OP_ASSIGN_BIT_XOR: + if (onode->arguments[0]->type == SL::Node::TYPE_VARIABLE) { + SL::VariableNode *vnode = (SL::VariableNode *)onode->arguments[0]; + if (p_actions.write_flag_pointers.has(vnode->name)) { + *p_actions.write_flag_pointers[vnode->name] = true; + } + } code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions); break; case SL::OP_BIT_INVERT: @@ -524,6 +557,23 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } code += ")"; } break; + case SL::OP_INDEX: { + + code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions); + code += "["; + code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions); + code += "]"; + + } break; + case SL::OP_SELECT_IF: { + + code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions); + code += "?"; + code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions); + code += ":"; + code += _dump_node_code(onode->arguments[2], p_level, r_gen_code, p_actions, p_default_actions); + + } break; default: { code = "(" + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions) + ")"; @@ -546,10 +596,10 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) { - if (cfnode->blocks.size()) { - code = "return " + _dump_node_code(cfnode->blocks[0], p_level, r_gen_code, p_actions, p_default_actions); + if (cfnode->expressions.size()) { + code = "return " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions) + ";"; } else { - code = "return"; + code = "return;"; } } @@ -566,7 +616,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) { - Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode)); + Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types()); if (err != OK) { #if 1 @@ -648,7 +698,9 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform"; actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix"; + actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix"; actions[VS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix"; + actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview"; actions[VS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz"; actions[VS::SHADER_SPATIAL].renames["NORMAL"] = "normal"; @@ -686,6 +738,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["DISCARD"] = "_discard"; //actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2; actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord"; + actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom"; actions[VS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n"; actions[VS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT"; @@ -701,16 +754,17 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n"; actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP"; actions[VS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n"; + actions[VS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS_MOTION\n"; actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength"; - actions[VS::SHADER_SPATIAL].render_mode_defines["skip_transform"] = "#define SKIP_TRANSFORM_USED\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["skip_default_transform"] = "#define SKIP_TRANSFORM_USED\n"; /* PARTICLES SHADER */ - actions[VS::SHADER_PARTICLES].renames["COLOR"] = "color"; + actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color"; actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz"; actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass"; actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "active"; @@ -719,13 +773,15 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform"; actions[VS::SHADER_PARTICLES].renames["TIME"] = "time"; actions[VS::SHADER_PARTICLES].renames["LIFETIME"] = "lifetime"; - actions[VS::SHADER_PARTICLES].renames["DELTA"] = "delta"; - actions[VS::SHADER_PARTICLES].renames["SEED"] = "seed"; - actions[VS::SHADER_PARTICLES].renames["ORIGIN"] = "origin"; + actions[VS::SHADER_PARTICLES].renames["DELTA"] = "local_delta"; + actions[VS::SHADER_PARTICLES].renames["NUMBER"] = "particle_number"; actions[VS::SHADER_PARTICLES].renames["INDEX"] = "index"; + actions[VS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity"; + actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform"; actions[VS::SHADER_SPATIAL].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; vertex_name = "vertex"; fragment_name = "fragment"; diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h index 44d6b3a349..17e0eee157 100644 --- a/drivers/gles3/shader_compiler_gles3.h +++ b/drivers/gles3/shader_compiler_gles3.h @@ -41,6 +41,7 @@ public: Map > render_mode_values; Map render_mode_flags; Map usage_flag_pointers; + Map write_flag_pointers; Map *uniforms; }; diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl index e72f12cc5e..347b15d639 100644 --- a/drivers/gles3/shaders/particles.glsl +++ b/drivers/gles3/shaders/particles.glsl @@ -22,16 +22,21 @@ struct Attractor { #define MAX_ATTRACTORS 64 -uniform mat4 origin; +uniform bool emitting; uniform float system_phase; uniform float prev_system_phase; -uniform float total_particles; +uniform int total_particles; uniform float explosiveness; +uniform float randomness; uniform vec4 time; uniform float delta; uniform vec3 gravity; uniform int attractor_count; uniform Attractor attractors[MAX_ATTRACTORS]; +uniform bool clear; +uniform uint cycle; +uniform float lifetime; +uniform mat4 emission_transform; out highp vec4 out_color; //tfb: @@ -53,52 +58,116 @@ MATERIAL_UNIFORMS #endif +uint hash(uint x) { + + x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b); + x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b); + x = (x >> uint(16)) ^ x; + return x; +} + + void main() { bool apply_forces=true; bool apply_velocity=true; + vec3 current_gravity = gravity; + float local_delta=delta; float mass = 1.0; - float restart_phase = float(gl_InstanceID)/total_particles; - restart_phase*= explosiveness; + float restart_phase = float(gl_VertexID)/float(total_particles); + + if (randomness>0.0) { + uint seed = cycle; + if (restart_phase >= system_phase) { + seed-=uint(1); + } + seed*=uint(total_particles); + seed+=uint(gl_VertexID); + float random = float(hash(seed) % uint(65536)) / 65536.0; + restart_phase+=randomness * random * 1.0 / float(total_particles); + } + + restart_phase*= (1.0-explosiveness); bool restart=false; - bool active = out_velocity_active.a > 0.5; + bool active = velocity_active.a > 0.5; if (system_phase > prev_system_phase) { - restart = prev_system_phase < restart_phase && system_phase >= restart_phase; + if (prev_system_phase < restart_phase && system_phase >= restart_phase) { + restart=true; +#ifdef USE_FRACTIONAL_DELTA + local_delta = (system_phase - restart_phase) * lifetime; +#endif + } + } else { - restart = prev_system_phase < restart_phase || system_phase >= restart_phase; + if (prev_system_phase < restart_phase) { + restart=true; +#ifdef USE_FRACTIONAL_DELTA + local_delta = (1.0 - restart_phase + system_phase) * lifetime; +#endif + } else if (system_phase >= restart_phase) { + restart=true; +#ifdef USE_FRACTIONAL_DELTA + local_delta = (system_phase - restart_phase) * lifetime; +#endif + } } - if (restart) { - active=true; + uint current_cycle = cycle; + + if (system_phase < restart_phase) { + current_cycle-=uint(1); } - out_color=color; - out_velocity_active=velocity_active; - out_custom=custom; + uint particle_number = current_cycle * uint(total_particles) + uint(gl_VertexID); - mat4 xform = transpose(mat4(xform_1,xform_2,xform_3,vec4(vec3(0.0),1.0))); + if (restart) { + active=emitting; + } + mat4 xform; - out_rot_active=rot_active; +#if defined(ENABLE_KEEP_DATA) + if (clear) { +#else + if (clear || restart) { +#endif + out_color=vec4(1.0); + out_velocity_active=vec4(0.0); + out_custom=vec4(0.0); + if (!restart) + active=false; + + xform = mat4( + vec4(1.0,0.0,0.0,0.0), + vec4(0.0,1.0,0.0,0.0), + vec4(0.0,0.0,1.0,0.0), + vec4(0.0,0.0,0.0,1.0) + ); + } else { + out_color=color; + out_velocity_active=velocity_active; + out_custom=custom; + xform = transpose(mat4(xform_1,xform_2,xform_3,vec4(vec3(0.0),1.0))); + } if (active) { //execute shader { - VERTEX_SHADER_CODE +VERTEX_SHADER_CODE } #if !defined(DISABLE_FORCE) - { + if (true) { - vec3 force = gravity; + vec3 force = current_gravity; for(int i=0;i