summaryrefslogtreecommitdiff
path: root/drivers/gles3
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2017-04-06 23:36:37 -0300
committerJuan Linietsky <reduzio@gmail.com>2017-04-06 23:49:27 -0300
commit74808ac4d9176180dc7ecace99723edab8a73e0e (patch)
tree065e903073bbdebe864bb6322ca0abc2fca108bb /drivers/gles3
parent25d09b92be0f5d86cdee6eada80823cdcc2d42bc (diff)
New particle system, mostly working, some small features missing.
Diffstat (limited to 'drivers/gles3')
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp156
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h1
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp268
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h58
-rw-r--r--drivers/gles3/shader_compiler_gles3.cpp76
-rw-r--r--drivers/gles3/shader_compiler_gles3.h1
-rw-r--r--drivers/gles3/shaders/particles.glsl115
-rw-r--r--drivers/gles3/shaders/scene.glsl79
9 files changed, 520 insertions, 236 deletions
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<RasterizerStorageGLES3::Particles *>(e->owner);
+ RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(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<RasterizerStorageGLES3::Particles *>(e->owner);
+ RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(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);
@@ -2730,6 +2727,30 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p
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<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_ADD);
shaders.actions_scene.render_mode_values["blend_mix"] = Pair<int *, int>(&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<Vector3> &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> 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<Vector3> emission_points;
- GLuint emission_point_texture;
-
VS::ParticlesDrawOrder draw_order;
- struct DrawPass {
- RID mesh;
- RID material;
- };
- Vector<DrawPass> draw_passes;
+ Vector<RID> draw_passes;
Rect3 computed_aabb;
GLuint particle_buffers[2];
+ GLuint particle_vaos[2];
SelfList<Particles> 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<Vector3> &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);
@@ -175,6 +185,21 @@ static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNo
return text;
} break;
+ case SL::TYPE_MAT2:
+ case SL::TYPE_MAT3:
+ case SL::TYPE_MAT4: {
+
+ String text = "mat" + itos(p_type - SL::TYPE_MAT2 + 2) + "(";
+ for (int i = 0; i < p_values.size(); i++) {
+ if (i > 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<StringName>::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<StringName, Pair<int *, int> > render_mode_values;
Map<StringName, bool *> render_mode_flags;
Map<StringName, bool *> usage_flag_pointers;
+ Map<StringName, bool *> write_flag_pointers;
Map<StringName, ShaderLanguage::ShaderNode::Uniform> *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<attractor_count;i++) {
- vec3 rel_vec = out_pos_lifetime.xyz - attractors[i].pos;
+ vec3 rel_vec = xform[3].xyz - attractors[i].pos;
float dist = rel_vec.length();
if (attractors[i].radius < dist)
continue;
@@ -119,17 +188,19 @@ void main() {
}
}
- out_velocity_seed.xyz += force * delta;
+ out_velocity_active.xyz += force * local_delta;
}
#endif
#if !defined(DISABLE_VELOCITY)
- {
+ if (true) {
- out_pos_lifetime.xyz += out_velocity_seed.xyz * delta;
+ xform[3].xyz += out_velocity_active.xyz * local_delta;
}
#endif
+ } else {
+ xform=mat4(0.0);
}
xform = transpose(xform);
@@ -162,6 +233,6 @@ MATERIAL_UNIFORMS
void main() {
{
- FRAGMENT_SHADER_CODE
+FRAGMENT_SHADER_CODE
}
}
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index ffc41e611b..43a391631f 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -52,6 +52,10 @@ layout(location=9) in highp vec4 instance_xform1;
layout(location=10) in highp vec4 instance_xform2;
layout(location=11) in lowp vec4 instance_color;
+#if defined(ENABLE_INSTANCE_CUSTOM)
+layout(location=12) in highp vec4 instance_custom_data;
+#endif
+
#endif
layout(std140) uniform SceneData { //ubo:0
@@ -157,9 +161,21 @@ out highp vec4 position_interp;
void main() {
highp vec4 vertex = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0);
- highp mat4 modelview = camera_inverse_matrix * world_transform;
+
+ mat4 world_matrix = world_transform;
+
+
+#ifdef USE_INSTANCING
+
+ {
+ highp mat4 m=mat4(instance_xform0,instance_xform1,instance_xform2,vec4(0.0,0.0,0.0,1.0));
+ world_matrix = world_matrix * transpose(m);
+ }
+#endif
+
vec3 normal = normal_attrib * normal_mult;
+
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
vec3 tangent = tangent_attrib.xyz;
tangent*=normal_mult;
@@ -168,6 +184,10 @@ void main() {
#if defined(ENABLE_COLOR_INTERP)
color_interp = color_attrib;
+#if defined(USE_INSTANCING)
+ color_interp *= instance_color;
+#endif
+
#endif
#ifdef USE_SKELETON
@@ -215,40 +235,12 @@ void main() {
}
#endif
-#ifdef USE_INSTANCING
-
- {
- highp mat3x4 m=mat3x4(instance_xform0,instance_xform1,instance_xform2);
- vertex.xyz = vertex * m;
- normal = vec4(normal,0.0) * m;
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
- tangent.xyz = vec4(tangent.xyz,0.0) * mn;
-#endif
-#if defined(ENABLE_COLOR_INTERP)
- color_interp*=instance_color;
-#endif
- }
-#endif //USE_INSTANCING
-
-#if !defined(SKIP_TRANSFORM_USED)
-
- vertex = modelview * vertex;
- normal = normalize((modelview * vec4(normal,0.0)).xyz);
-#endif
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-# if !defined(SKIP_TRANSFORM_USED)
-
- tangent=normalize((modelview * vec4(tangent,0.0)).xyz);
-# endif
vec3 binormal = normalize( cross(normal,tangent) * binormalf );
#endif
-
-
-
#if defined(ENABLE_UV_INTERP)
uv_interp = uv_attrib;
#endif
@@ -257,16 +249,45 @@ void main() {
uv2_interp = uv2_attrib;
#endif
+#if defined(USE_INSTANCING) && defined(ENABLE_INSTANCE_CUSTOM)
+ vec4 instance_custom = instance_custom_data;
+#else
+ vec4 instance_custom = vec4(0.0);
+#endif
+
+ highp mat4 modelview = camera_inverse_matrix * world_matrix;
+ highp mat4 local_projection = projection_matrix;
+
+//defines that make writing custom shaders easier
+#define projection_matrix local_projection
+#define world_transform world_matrix
{
VERTEX_SHADER_CODE
}
+
+
+
+#if !defined(SKIP_TRANSFORM_USED)
+
+ vertex = modelview * vertex;
+ normal = normalize((modelview * vec4(normal,0.0)).xyz);
+#endif
+
+
vertex_interp = vertex.xyz;
normal_interp = normal;
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+
+#if !defined(SKIP_TRANSFORM_USED)
+
+ tangent = normalize((modelview * vec4(tangent,0.0)).xyz);
+ binormal = normalize((modelview * vec4(binormal,0.0)).xyz);
+
+#endif
tangent_interp = tangent;
binormal_interp = binormal;
#endif