diff --git a/core/math/geometry.h b/core/math/geometry.h index 2469e799a05f..909d8164c3be 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -105,23 +105,23 @@ class Geometry { } static void get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2, Vector3 &c1, Vector3 &c2) { -#if 0 - //do the function 'd' as defined by pb. I think is is dot product of some sort +#if 1 +//do the function 'd' as defined by pb. I think is is dot product of some sort #define d_of(m, n, o, p) ((m.x - n.x) * (o.x - p.x) + (m.y - n.y) * (o.y - p.y) + (m.z - n.z) * (o.z - p.z)) //calculate the parametric position on the 2 curves, mua and mub - real_t mua = ( d_of(p1,q1,q2,q1) * d_of(q2,q1,p2,p1) - d_of(p1,q1,p2,p1) * d_of(q2,q1,q2,q1) ) / ( d_of(p2,p1,p2,p1) * d_of(q2,q1,q2,q1) - d_of(q2,q1,p2,p1) * d_of(q2,q1,p2,p1) ); - real_t mub = ( d_of(p1,q1,q2,q1) + mua * d_of(q2,q1,p2,p1) ) / d_of(q2,q1,q2,q1); + real_t mua = (d_of(p1, q1, q2, q1) * d_of(q2, q1, p2, p1) - d_of(p1, q1, p2, p1) * d_of(q2, q1, q2, q1)) / (d_of(p2, p1, p2, p1) * d_of(q2, q1, q2, q1) - d_of(q2, q1, p2, p1) * d_of(q2, q1, p2, p1)); + real_t mub = (d_of(p1, q1, q2, q1) + mua * d_of(q2, q1, p2, p1)) / d_of(q2, q1, q2, q1); //clip the value between [0..1] constraining the solution to lie on the original curves if (mua < 0) mua = 0; if (mub < 0) mub = 0; if (mua > 1) mua = 1; if (mub > 1) mub = 1; - c1 = p1.linear_interpolate(p2,mua); - c2 = q1.linear_interpolate(q2,mub); -#endif - + c1 = p1.linear_interpolate(p2, mua); + c2 = q1.linear_interpolate(q2, mub); +#else + //this is broken do not use Vector3 u = p2 - p1; Vector3 v = q2 - q1; Vector3 w = p1 - q1; @@ -144,8 +144,9 @@ class Geometry { c1 = w + sc * u; c2 = w + tc * v; - // get the difference of the two closest points - //Vector dP = w + (sc * u) - (tc * v); // = L1(sc) - L2(tc) +// get the difference of the two closest points +//Vector dP = w + (sc * u) - (tc * v); // = L1(sc) - L2(tc) +#endif } static real_t get_closest_distance_between_segments(const Vector3 &p_from_a, const Vector3 &p_to_a, const Vector3 &p_from_b, const Vector3 &p_to_b) { diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 0e97e2d4598e..9cb44349bf70 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1216,7 +1216,26 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m return rebind; } -void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) { +struct RasterizerGLES3Particle { + + float color[4]; + float velocity_active[4]; + float custom[4]; + float xform_1[4]; + float xform_2[4]; + float xform_3[4]; +}; + +struct RasterizerGLES3ParticleSort { + + Vector3 z_dir; + bool operator()(const RasterizerGLES3Particle &p_a, const RasterizerGLES3Particle &p_b) const { + + return z_dir.dot(Vector3(p_a.xform_1[3], p_a.xform_2[3], p_a.xform_3[3])) < z_dir.dot(Vector3(p_b.xform_1[3], p_b.xform_2[3], p_b.xform_3[3])); + } +}; + +void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transform &p_view_transform) { switch (e->instance->base_type) { @@ -1289,28 +1308,54 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) { 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 + if (particles->draw_order == VS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->particle_valid_histories[1]) { + + glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffer_histories[1]); //modify the buffer, this was used 2 frames ago so it should be good enough for flushing + RasterizerGLES3Particle *particle_array = (RasterizerGLES3Particle *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 24 * sizeof(float), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT); + + SortArray sorter; + + if (particles->use_local_coords) { + sorter.compare.z_dir = e->instance->transform.affine_inverse().xform(p_view_transform.basis.get_axis(2)).normalized(); + } else { + sorter.compare.z_dir = p_view_transform.basis.get_axis(2).normalized(); + } + + sorter.sort(particle_array, particles->amount); + + glUnmapBuffer(GL_ARRAY_BUFFER); + + glBindVertexArray(s->instancing_array_id); // use the instancing array ID + glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffer_histories[1]); //modify the buffer + + } else { + + 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); + if (particles->draw_order != VS::PARTICLES_DRAW_ORDER_LIFETIME) { + + 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; } @@ -1491,17 +1536,88 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { int amount = particles->amount; - if (s->index_array_len > 0) { + if (particles->draw_order == VS::PARTICLES_DRAW_ORDER_LIFETIME) { + //split + + int stride = sizeof(float) * 4 * 6; + int split = int(Math::ceil(particles->phase * particles->amount)); + + if (amount - split > 0) { + glEnableVertexAttribArray(8); //xform x + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 3); + glVertexAttribDivisor(8, 1); + glEnableVertexAttribArray(9); //xform y + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 4); + glVertexAttribDivisor(9, 1); + glEnableVertexAttribArray(10); //xform z + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 5); + glVertexAttribDivisor(10, 1); + glEnableVertexAttribArray(11); //color + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + 0); + glVertexAttribDivisor(11, 1); + glEnableVertexAttribArray(12); //custom + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 2); + glVertexAttribDivisor(12, 1); - glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount); + if (s->index_array_len > 0) { - storage->info.render_vertices_count += s->index_array_len * amount; + glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount - split); + + storage->info.render_vertices_count += s->index_array_len * (amount - split); + + } else { + + glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount - split); + + storage->info.render_vertices_count += s->array_len * (amount - split); + } + } + + if (split > 0) { + 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); + + 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, split); + + storage->info.render_vertices_count += s->index_array_len * split; + + } else { + + glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, split); + + storage->info.render_vertices_count += s->array_len * split; + } + } } else { - glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount); + if (s->index_array_len > 0) { - storage->info.render_vertices_count += s->array_len * amount; + 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; @@ -1841,7 +1957,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ if (e->owner != prev_owner || prev_base_type != e->instance->base_type || prev_geometry != e->geometry) { - _setup_geometry(e); + _setup_geometry(e, p_view_transform); storage->info.render_surface_switch_count++; } diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 10136ff8d78e..33698fc26799 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -692,7 +692,7 @@ class RasterizerSceneGLES3 : public RasterizerScene { _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_geometry(RenderList::Element *e); + _FORCE_INLINE_ void _setup_geometry(RenderList::Element *e, const Transform &p_view_transform); _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 7fc2185e9ad2..ced308c1b4ce 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -3005,6 +3005,7 @@ void RasterizerStorageGLES3::mesh_set_custom_aabb(RID p_mesh, const Rect3 &p_aab mesh->custom_aabb = p_aabb; } + Rect3 RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const { const Mesh *mesh = mesh_owner.getornull(p_mesh); @@ -4883,6 +4884,22 @@ void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount) } } + if (particles->histories_enabled) { + + for (int i = 0; i < 2; i++) { + glBindVertexArray(particles->particle_vao_histories[i]); + + glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffer_histories[i]); + glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_DYNAMIC_COPY); + + for (int j = 0; j < 6; j++) { + glEnableVertexAttribArray(j); + glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, ((uint8_t *)0) + (j * 16)); + } + particles->particle_valid_histories[i] = false; + } + } + glBindVertexArray(0); particles->prev_ticks = 0; @@ -4917,18 +4934,61 @@ void RasterizerStorageGLES3::particles_set_randomness_ratio(RID p_particles, flo ERR_FAIL_COND(!particles); particles->randomness = p_ratio; } + +void RasterizerStorageGLES3::_particles_update_histories(Particles *particles) { + + bool needs_histories = particles->draw_order == VS::PARTICLES_DRAW_ORDER_VIEW_DEPTH; + + if (needs_histories == particles->histories_enabled) + return; + + particles->histories_enabled = needs_histories; + + int floats = particles->amount * 24; + + if (!needs_histories) { + + glDeleteBuffers(2, particles->particle_buffer_histories); + glDeleteVertexArrays(2, particles->particle_vao_histories); + + } else { + + glGenBuffers(2, particles->particle_buffer_histories); + glGenVertexArrays(2, particles->particle_vao_histories); + + for (int i = 0; i < 2; i++) { + glBindVertexArray(particles->particle_vao_histories[i]); + + glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffer_histories[i]); + glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), NULL, GL_DYNAMIC_COPY); + + for (int j = 0; j < 6; j++) { + glEnableVertexAttribArray(j); + glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, ((uint8_t *)0) + (j * 16)); + } + + particles->particle_valid_histories[i] = false; + } + } + + particles->clear = true; +} + void RasterizerStorageGLES3::particles_set_custom_aabb(RID p_particles, const Rect3 &p_aabb) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->custom_aabb = p_aabb; + _particles_update_histories(particles); + particles->instance_change_notify(); } -void RasterizerStorageGLES3::particles_set_gravity(RID p_particles, const Vector3 &p_gravity) { + +void RasterizerStorageGLES3::particles_set_speed_scale(RID p_particles, float p_scale) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - particles->gravity = p_gravity; + particles->speed_scale = p_scale; } void RasterizerStorageGLES3::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { @@ -4968,6 +5028,7 @@ void RasterizerStorageGLES3::particles_set_draw_order(RID p_particles, VS::Parti ERR_FAIL_COND(!particles); particles->draw_order = p_order; + _particles_update_histories(particles); } void RasterizerStorageGLES3::particles_set_draw_passes(RID p_particles, int p_passes) { @@ -5001,7 +5062,39 @@ Rect3 RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, Rect3()); - return particles->computed_aabb; + glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); + + float *data = (float *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, GL_MAP_READ_BIT); + Rect3 aabb; + + Transform inv = particles->emission_transform.affine_inverse(); + + for (int i = 0; i < particles->amount; i++) { + int ofs = i * 24; + Vector3 pos = Vector3(data[ofs + 15], data[ofs + 19], data[ofs + 23]); + if (!particles->use_local_coords) { + pos = inv.xform(pos); + } + if (i == 0) + aabb.pos = pos; + else + aabb.expand_to(pos); + } + + glUnmapBuffer(GL_ARRAY_BUFFER); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + float longest_axis = 0; + for (int i = 0; i < particles->draw_passes.size(); i++) { + if (particles->draw_passes[i].is_valid()) { + Rect3 maabb = mesh_get_aabb(particles->draw_passes[i], RID()); + longest_axis = MAX(maabb.get_longest_axis_size(), longest_axis); + } + } + + aabb.grow_by(longest_axis); + + return aabb; } Rect3 RasterizerStorageGLES3::particles_get_aabb(RID p_particles) const { @@ -5009,7 +5102,7 @@ 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)); + return particles->custom_aabb; } void RasterizerStorageGLES3::particles_set_emission_transform(RID p_particles, const Transform &p_transform) { @@ -5022,7 +5115,7 @@ void RasterizerStorageGLES3::particles_set_emission_transform(RID p_particles, c void RasterizerStorageGLES3::_particles_process(Particles *particles, float p_delta) { - float new_phase = Math::fmod((float)particles->phase + (p_delta / particles->lifetime), (float)1.0); + float new_phase = Math::fmod((float)particles->phase + (p_delta / particles->lifetime) * particles->speed_scale, (float)1.0); if (particles->clear) { particles->cycle_number = 0; @@ -5034,7 +5127,7 @@ void RasterizerStorageGLES3::_particles_process(Particles *particles, float p_de 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::DELTA, p_delta * particles->speed_scale); shaders.particles.set_uniform(ParticlesShaderGLES3::CLEAR, particles->clear); if (particles->use_local_coords) shaders.particles.set_uniform(ParticlesShaderGLES3::EMISSION_TRANSFORM, Transform()); @@ -5154,7 +5247,6 @@ void RasterizerStorageGLES3::update_particles() { 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::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); @@ -5201,6 +5293,20 @@ void RasterizerStorageGLES3::update_particles() { } particle_update_list.remove(particle_update_list.first()); + + if (particles->histories_enabled) { + + SWAP(particles->particle_buffer_histories[0], particles->particle_buffer_histories[1]); + SWAP(particles->particle_vao_histories[0], particles->particle_vao_histories[1]); + SWAP(particles->particle_valid_histories[0], particles->particle_valid_histories[1]); + + //copy + glBindBuffer(GL_COPY_READ_BUFFER, particles->particle_buffers[0]); + glBindBuffer(GL_COPY_WRITE_BUFFER, particles->particle_buffer_histories[0]); + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, particles->amount * 24 * sizeof(float)); + + particles->particle_valid_histories[0] = true; + } } glDisable(GL_RASTERIZER_DISCARD); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 6ae9fd18a206..bb4a7e23a1e2 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -995,7 +995,6 @@ class RasterizerStorageGLES3 : public RasterizerStorage { float explosiveness; float randomness; Rect3 custom_aabb; - Vector3 gravity; bool use_local_coords; RID process_material; @@ -1003,11 +1002,14 @@ class RasterizerStorageGLES3 : public RasterizerStorage { Vector draw_passes; - Rect3 computed_aabb; - GLuint particle_buffers[2]; GLuint particle_vaos[2]; + GLuint particle_buffer_histories[2]; + GLuint particle_vao_histories[2]; + bool particle_valid_histories[2]; + bool histories_enabled; + SelfList particle_element; float phase; @@ -1016,6 +1018,8 @@ class RasterizerStorageGLES3 : public RasterizerStorage { uint32_t cycle_number; + float speed_scale; + int fixed_fps; bool fractional_delta; float frame_remainder; @@ -1037,6 +1041,10 @@ class RasterizerStorageGLES3 : public RasterizerStorage { fixed_fps = 0; fractional_delta = false; frame_remainder = 0; + histories_enabled = false; + speed_scale = 1.0; + + custom_aabb = Rect3(Vector3(-4, -4, -4), Vector3(8, 8, 8)); draw_order = VS::PARTICLES_DRAW_ORDER_INDEX; particle_buffers[0] = 0; @@ -1054,6 +1062,10 @@ class RasterizerStorageGLES3 : public RasterizerStorage { glDeleteBuffers(2, particle_buffers); glDeleteVertexArrays(2, particle_vaos); + if (histories_enabled) { + glDeleteBuffers(2, particle_buffer_histories); + glDeleteVertexArrays(2, particle_vao_histories); + } } }; @@ -1072,7 +1084,7 @@ class RasterizerStorageGLES3 : public RasterizerStorage { virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio); virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio); virtual void particles_set_custom_aabb(RID p_particles, const Rect3 &p_aabb); - virtual void particles_set_gravity(RID p_particles, const Vector3 &p_gravity); + virtual void particles_set_speed_scale(RID p_particles, float p_scale); 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_fixed_fps(RID p_particles, int p_fps); @@ -1087,6 +1099,8 @@ class RasterizerStorageGLES3 : public RasterizerStorage { virtual Rect3 particles_get_current_aabb(RID p_particles); virtual Rect3 particles_get_aabb(RID p_particles) const; + virtual void _particles_update_histories(Particles *particles); + virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform); void _particles_process(Particles *p_particles, float p_delta); diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl index 347b15d639a9..f789be24cfe7 100644 --- a/drivers/gles3/shaders/particles.glsl +++ b/drivers/gles3/shaders/particles.glsl @@ -30,7 +30,7 @@ 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; @@ -69,9 +69,19 @@ uint hash(uint x) { void main() { +#ifdef PARTICLES_COPY + + out_color=color; + out_velocity_active=velocity_active; + out_custom = custom; + out_xform_1 = xform_1; + out_xform_2 = xform_2; + out_xform_3 = xform_3; + +#else + bool apply_forces=true; bool apply_velocity=true; - vec3 current_gravity = gravity; float local_delta=delta; float mass = 1.0; @@ -164,7 +174,7 @@ VERTEX_SHADER_CODE if (true) { - vec3 force = current_gravity; + vec3 force = vec3(0.0); for(int i=0;iget_global_transform(); - ParticleSystemSW pssw; - for (int i = 0; i < VS::PARTICLE_VAR_MAX; i++) { - - pssw.particle_vars[i] = node->get_variable((Particles::Variable)i); - pssw.particle_randomness[i] = node->get_randomness((Particles::Variable)i); - } - - pssw.emission_half_extents = node->get_emission_half_extents(); - pssw.emission_points = node->get_emission_points(); - pssw.emission_base_velocity = node->get_emission_base_velocity(); - pssw.amount = node->get_amount(); - pssw.gravity_normal = node->get_gravity_normal(); - pssw.emitting = true; - pssw.height_from_velocity = node->has_height_from_velocity(); - pssw.color_phase_count = 1; - - ParticleSystemProcessSW pp; - float delta = 0.01; - float lifetime = pssw.particle_vars[VS::PARTICLE_LIFETIME]; - - Transform localizer = globalizer.affine_inverse(); - AABB aabb; - for (float t = 0; t < lifetime; t += delta) { - - pp.process(&pssw, globalizer, delta); - for (int i = 0; i < pp.particle_data.size(); i++) { - - Vector3 p = localizer.xform(pp.particle_data[i].pos); - - if (t == 0 && i == 0) - aabb.pos = p; - else - aabb.expand_to(p); - } - } - - aabb.grow_by(aabb.get_longest_axis_size() * 0.2); - - node->set_visibility_aabb(aabb); -#endif + generate_aabb->popup_centered_minsize(); } break; case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: { @@ -186,6 +145,33 @@ void ParticlesEditor::_menu_option(int p_option) { } } +void ParticlesEditor::_generate_aabb() { + + float time = generate_seconds->get_value(); + + float running = 0.0; + + EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time)); + + Rect3 rect; + while (running < time) { + + uint64_t ticks = OS::get_singleton()->get_ticks_usec(); + ep.step("Generating..", int(running), true); + OS::get_singleton()->delay_usec(1000); + + Rect3 capture = node->capture_aabb(); + if (rect == Rect3()) + rect = capture; + else + rect.merge_with(capture); + + running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0; + } + + node->set_visibility_aabb(rect); +} + void ParticlesEditor::edit(Particles *p_particles) { node = p_particles; @@ -392,6 +378,7 @@ void ParticlesEditor::_bind_methods() { ClassDB::bind_method("_resource_seleted", &ParticlesEditor::_resource_seleted); ClassDB::bind_method("_node_selected", &ParticlesEditor::_node_selected); ClassDB::bind_method("_generate_emission_points", &ParticlesEditor::_generate_emission_points); + ClassDB::bind_method("_generate_aabb", &ParticlesEditor::_generate_aabb); //ClassDB::bind_method("_populate",&ParticlesEditor::_populate); } @@ -456,6 +443,20 @@ ParticlesEditor::ParticlesEditor() { emission_file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); + generate_aabb = memnew(ConfirmationDialog); + generate_aabb->set_title(TTR("Generate Visibility AABB")); + VBoxContainer *genvb = memnew(VBoxContainer); + generate_aabb->add_child(genvb); + generate_seconds = memnew(SpinBox); + genvb->add_margin_child(TTR("Generation Time (sec):"), generate_seconds); + generate_seconds->set_min(0.1); + generate_seconds->set_max(25); + generate_seconds->set_value(2); + + add_child(generate_aabb); + + generate_aabb->connect("confirmed", this, "_generate_aabb"); + //options->set_anchor(MARGIN_LEFT,Control::ANCHOR_END); //options->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END); } diff --git a/editor/plugins/particles_editor_plugin.h b/editor/plugins/particles_editor_plugin.h index 15881fe6a11e..e9f9f43468b8 100644 --- a/editor/plugins/particles_editor_plugin.h +++ b/editor/plugins/particles_editor_plugin.h @@ -57,6 +57,9 @@ class ParticlesEditor : public Control { SpinBox *emission_amount; OptionButton *emission_fill; + ConfirmationDialog *generate_aabb; + SpinBox *generate_seconds; + enum Menu { MENU_OPTION_GENERATE_AABB, @@ -68,6 +71,7 @@ class ParticlesEditor : public Control { PoolVector geometry; + void _generate_aabb(); void _generate_emission_points(); void _resource_seleted(const String &p_res); void _node_selected(const NodePath &p_path); diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 136490eb104a..4781bb6a3bcd 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -2021,6 +2021,131 @@ VisibilityNotifierGizmo::VisibilityNotifierGizmo(VisibilityNotifier *p_notifier) /// +String ParticlesGizmo::get_handle_name(int p_idx) const { + + switch (p_idx) { + case 0: return "Size X"; + case 1: return "Size Y"; + case 2: return "Size Z"; + case 3: return "Pos X"; + case 4: return "Pos Y"; + case 5: return "Pos Z"; + } + + return ""; +} +Variant ParticlesGizmo::get_handle_value(int p_idx) const { + + return particles->get_visibility_aabb(); +} +void ParticlesGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { + + Transform gt = particles->get_global_transform(); + //gt.orthonormalize(); + Transform gi = gt.affine_inverse(); + + bool move = p_idx >= 3; + p_idx = p_idx % 3; + + Rect3 aabb = particles->get_visibility_aabb(); + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + Vector3 ofs = aabb.pos + aabb.size * 0.5; + + Vector3 axis; + axis[p_idx] = 1.0; + + if (move) { + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_idx]; + + aabb.pos[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5; + particles->set_visibility_aabb(aabb); + + } else { + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_idx] - ofs[p_idx]; + if (d < 0.001) + d = 0.001; + //resize + aabb.pos[p_idx] = (aabb.pos[p_idx] + aabb.size[p_idx] * 0.5) - d; + aabb.size[p_idx] = d * 2; + particles->set_visibility_aabb(aabb); + } +} + +void ParticlesGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { + + if (p_cancel) { + particles->set_visibility_aabb(p_restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Particles AABB")); + ur->add_do_method(particles, "set_custom_aabb", particles->get_visibility_aabb()); + ur->add_undo_method(particles, "set_custom_aabb", p_restore); + ur->commit_action(); +} + +void ParticlesGizmo::redraw() { + + clear(); + + Vector lines; + Rect3 aabb = particles->get_visibility_aabb(); + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + Vector handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.pos[i] + aabb.size[i]; + ax[(i + 1) % 3] = aabb.pos[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5; + ax[(i + 2) % 3] = aabb.pos[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5; + handles.push_back(ax); + } + + Vector3 center = aabb.pos + aabb.size * 0.5; + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = 1.0; + handles.push_back(center + ax); + lines.push_back(center); + lines.push_back(center + ax); + } + + add_lines(lines, SpatialEditorGizmos::singleton->particles_material); + add_collision_segments(lines); + //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05); + add_handles(handles); +} +ParticlesGizmo::ParticlesGizmo(Particles *p_particles) { + + particles = p_particles; + set_spatial_node(p_particles); +} + +//////// + +/// + String ReflectionProbeGizmo::get_handle_name(int p_idx) const { switch (p_idx) { @@ -2938,6 +3063,12 @@ Ref SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { return misg; } + if (p_spatial->cast_to()) { + + Ref misg = memnew(ParticlesGizmo(p_spatial->cast_to())); + return misg; + } + if (p_spatial->cast_to()) { Ref misg = memnew(ReflectionProbeGizmo(p_spatial->cast_to())); @@ -3152,6 +3283,7 @@ SpatialEditorGizmos::SpatialEditorGizmos() { raycast_material = create_line_material(Color(1.0, 0.8, 0.6)); car_wheel_material = create_line_material(Color(0.6, 0.8, 1.0)); visibility_notifier_material = create_line_material(Color(1.0, 0.5, 1.0)); + particles_material = create_line_material(Color(1.0, 1.0, 0.5)); reflection_probe_material = create_line_material(Color(0.5, 1.0, 0.7)); reflection_probe_material_internal = create_line_material(Color(0.3, 0.8, 0.5, 0.15)); gi_probe_material = create_line_material(Color(0.7, 1.0, 0.5)); diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index 3aecc8fc0259..095586ab9158 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -33,22 +33,22 @@ #include "editor/plugins/spatial_editor_plugin.h" #include "scene/3d/body_shape.h" #include "scene/3d/camera.h" +#include "scene/3d/collision_polygon.h" #include "scene/3d/gi_probe.h" #include "scene/3d/light.h" #include "scene/3d/listener.h" #include "scene/3d/mesh_instance.h" #include "scene/3d/navigation_mesh.h" +#include "scene/3d/particles.h" +#include "scene/3d/physics_joint.h" #include "scene/3d/portal.h" #include "scene/3d/position_3d.h" #include "scene/3d/ray_cast.h" #include "scene/3d/reflection_probe.h" #include "scene/3d/room_instance.h" #include "scene/3d/test_cube.h" -#include "scene/3d/visibility_notifier.h" - -#include "scene/3d/collision_polygon.h" -#include "scene/3d/physics_joint.h" #include "scene/3d/vehicle_body.h" +#include "scene/3d/visibility_notifier.h" class Camera; @@ -244,6 +244,22 @@ class VisibilityNotifierGizmo : public EditorSpatialGizmo { VisibilityNotifierGizmo(VisibilityNotifier *p_notifier = NULL); }; +class ParticlesGizmo : public EditorSpatialGizmo { + + GDCLASS(ParticlesGizmo, EditorSpatialGizmo); + + Particles *particles; + +public: + virtual String get_handle_name(int p_idx) const; + virtual Variant get_handle_value(int p_idx) const; + virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); + virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + + void redraw(); + ParticlesGizmo(Particles *p_particles = NULL); +}; + class ReflectionProbeGizmo : public EditorSpatialGizmo { GDCLASS(ReflectionProbeGizmo, EditorSpatialGizmo); @@ -420,6 +436,7 @@ class SpatialEditorGizmos { Ref portal_material; Ref raycast_material; Ref visibility_notifier_material; + Ref particles_material; Ref car_wheel_material; Ref joint_material; diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index b7ee26de57df..038ca33a41af 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -71,15 +71,12 @@ void Particles::set_randomness_ratio(float p_ratio) { randomness_ratio = p_ratio; VS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio); } -void Particles::set_custom_aabb(const Rect3 &p_aabb) { +void Particles::set_visibility_aabb(const Rect3 &p_aabb) { - custom_aabb = p_aabb; - VS::get_singleton()->particles_set_custom_aabb(particles, custom_aabb); -} -void Particles::set_gravity(const Vector3 &p_gravity) { - - gravity = p_gravity; - VS::get_singleton()->particles_set_gravity(particles, gravity); + visibility_aabb = p_aabb; + VS::get_singleton()->particles_set_custom_aabb(particles, visibility_aabb); + update_gizmo(); + _change_notify("visibility_aabb"); } void Particles::set_use_local_coordinates(bool p_enable) { @@ -93,6 +90,14 @@ void Particles::set_process_material(const Ref &p_material) { if (process_material.is_valid()) material_rid = process_material->get_rid(); VS::get_singleton()->particles_set_process_material(particles, material_rid); + + update_configuration_warning(); +} + +void Particles::set_speed_scale(float p_scale) { + + speed_scale = p_scale; + VS::get_singleton()->particles_set_speed_scale(particles, p_scale); } bool Particles::is_emitting() const { @@ -119,13 +124,9 @@ float Particles::get_randomness_ratio() const { return randomness_ratio; } -Rect3 Particles::get_custom_aabb() const { - - return custom_aabb; -} -Vector3 Particles::get_gravity() const { +Rect3 Particles::get_visibility_aabb() const { - return gravity; + return visibility_aabb; } bool Particles::get_use_local_coordinates() const { @@ -136,6 +137,11 @@ Ref Particles::get_process_material() const { return process_material; } +float Particles::get_speed_scale() const { + + return speed_scale; +} + void Particles::set_draw_order(DrawOrder p_order) { draw_order = p_order; @@ -170,6 +176,8 @@ void Particles::set_draw_pass_mesh(int p_pass, const Ref &p_mesh) { mesh_rid = p_mesh->get_rid(); VS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid); + + update_configuration_warning(); } Ref Particles::get_draw_pass_mesh(int p_pass) const { @@ -197,6 +205,37 @@ bool Particles::get_fractional_delta() const { return fractional_delta; } +String Particles::get_configuration_warning() const { + + String warnings; + + bool meshes_found = false; + + for (int i = 0; i < draw_passes.size(); i++) { + if (draw_passes[i].is_valid()) { + meshes_found = true; + break; + } + } + + if (!meshes_found) { + warnings += "- " + TTR("Nothing is visible because meshes have not been assigned to draw passes."); + } + + if (process_material.is_null()) { + if (warnings != String()) + warnings += "\n"; + warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted."); + } + + return warnings; +} + +Rect3 Particles::capture_aabb() const { + + return VS::get_singleton()->particles_get_current_aabb(particles); +} + void Particles::_validate_property(PropertyInfo &property) const { if (property.name.begins_with("draw_pass_")) { @@ -216,12 +255,12 @@ void Particles::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles::set_pre_process_time); ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles::set_explosiveness_ratio); ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles::set_randomness_ratio); - ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &Particles::set_custom_aabb); - ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &Particles::set_gravity); + ClassDB::bind_method(D_METHOD("set_visibility_aabb", "aabb"), &Particles::set_visibility_aabb); ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &Particles::set_use_local_coordinates); ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &Particles::set_fixed_fps); ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &Particles::set_fractional_delta); ClassDB::bind_method(D_METHOD("set_process_material", "material:Material"), &Particles::set_process_material); + ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &Particles::set_speed_scale); ClassDB::bind_method(D_METHOD("is_emitting"), &Particles::is_emitting); ClassDB::bind_method(D_METHOD("get_amount"), &Particles::get_amount); @@ -229,12 +268,12 @@ void Particles::_bind_methods() { ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles::get_pre_process_time); ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles::get_explosiveness_ratio); ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles::get_randomness_ratio); - ClassDB::bind_method(D_METHOD("get_custom_aabb"), &Particles::get_custom_aabb); - ClassDB::bind_method(D_METHOD("get_gravity"), &Particles::get_gravity); + ClassDB::bind_method(D_METHOD("get_visibility_aabb"), &Particles::get_visibility_aabb); ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &Particles::get_use_local_coordinates); ClassDB::bind_method(D_METHOD("get_fixed_fps"), &Particles::get_fixed_fps); ClassDB::bind_method(D_METHOD("get_fractional_delta"), &Particles::get_fractional_delta); ClassDB::bind_method(D_METHOD("get_process_material:Material"), &Particles::get_process_material); + ClassDB::bind_method(D_METHOD("get_speed_scale"), &Particles::get_speed_scale); ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &Particles::set_draw_order); @@ -246,20 +285,23 @@ void Particles::_bind_methods() { ClassDB::bind_method(D_METHOD("get_draw_passes"), &Particles::get_draw_passes); ClassDB::bind_method(D_METHOD("get_draw_pass_mesh:Mesh", "pass"), &Particles::get_draw_pass_mesh); + ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb); + ADD_GROUP("Parameters", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); - ADD_PROPERTY(PropertyInfo(Variant::RECT3, "custom_aabb"), "set_custom_aabb", "get_custom_aabb"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity"); + ADD_PROPERTY(PropertyInfo(Variant::RECT3, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ParticlesMaterial,ShaderMaterial"), "set_process_material", "get_process_material"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order"); + ADD_GROUP("Process Material", ""); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ParticlesMaterial,ShaderMaterial"), "set_process_material", "get_process_material"); ADD_GROUP("Draw Passes", "draw_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_passes", PROPERTY_HINT_RANGE, "0," + itos(MAX_DRAW_PASSES) + ",1"), "set_draw_passes", "get_draw_passes"); for (int i = 0; i < MAX_DRAW_PASSES; i++) { @@ -278,16 +320,18 @@ Particles::Particles() { particles = VS::get_singleton()->particles_create(); set_base(particles); set_emitting(true); - set_amount(100); + set_amount(8); set_lifetime(1); set_fixed_fps(0); set_fractional_delta(true); set_pre_process_time(0); set_explosiveness_ratio(0); set_randomness_ratio(0); - set_gravity(Vector3(0, -9.8, 0)); + set_visibility_aabb(Rect3(Vector3(-4, -4, -4), Vector3(8, 8, 8))); set_use_local_coordinates(true); set_draw_passes(1); + set_draw_order(DRAW_ORDER_INDEX); + set_speed_scale(1); } Particles::~Particles() { @@ -362,6 +406,8 @@ void ParticlesMaterial::init_shaders() { shader_names->trail_divisor = "trail_divisor"; shader_names->trail_size_modifier = "trail_size_modifier"; shader_names->trail_color_modifier = "trail_color_modifier"; + + shader_names->gravity = "gravity"; } void ParticlesMaterial::finish_shaders() { @@ -437,6 +483,8 @@ void ParticlesMaterial::_update_shader() { code += "uniform int trail_divisor;\n"; + code += "uniform vec3 gravity;\n"; + if (color_ramp.is_valid()) code += "uniform sampler2D color_ramp;\n"; @@ -633,7 +681,7 @@ void ParticlesMaterial::_update_shader() { else code += " float tex_anim_offset = 0.0;\n"; - code += " vec3 force = vec3(0.0); \n"; + code += " vec3 force = gravity; \n"; code += " vec3 pos = TRANSFORM[3].xyz; \n"; code += " //apply linear acceleration\n"; code += " force+=normalize(VELOCITY) * (linear_accel+tex_linear_accel)*mix(1.0,rand_from_seed(alt_seed),linear_accel_random);\n"; @@ -643,7 +691,7 @@ void ParticlesMaterial::_update_shader() { code += " //org=p_transform.origin;\n"; code += " force+=normalize(pos-org) * (radial_accel+tex_radial_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random);\n"; code += " //apply tangential acceleration;\n"; - code += " force+=normalize(cross(normalize(pos-org),normalize(GRAVITY))) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random));\n"; + code += " force+=normalize(cross(normalize(pos-org),normalize(gravity))) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random));\n"; code += " //apply attractor forces\n"; code += " VELOCITY+=force * DELTA;\n"; if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) @@ -1168,6 +1216,21 @@ Ref ParticlesMaterial::get_trail_color_modifier() const { return trail_color_modifier; } +void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) { + + gravity = p_gravity; + Vector3 gset = gravity; + if (gset == Vector3()) { + gset = Vector3(0, -0.000001, 0); //as gravity is used as upvector in some calculations + } + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->gravity, gset); +} + +Vector3 ParticlesMaterial::get_gravity() const { + + return gravity; +} + void ParticlesMaterial::_validate_property(PropertyInfo &property) const { if (property.name == "color" && color_ramp.is_valid()) { @@ -1248,6 +1311,9 @@ void ParticlesMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_trail_color_modifier", "texture:GradientTexture"), &ParticlesMaterial::set_trail_color_modifier); ClassDB::bind_method(D_METHOD("get_trail_color_modifier:GradientTexture"), &ParticlesMaterial::get_trail_color_modifier); + ClassDB::bind_method(D_METHOD("get_gravity"), &ParticlesMaterial::get_gravity); + ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticlesMaterial::set_gravity); + ADD_GROUP("Trail", "trail_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_divisor", PROPERTY_HINT_RANGE, "1,1000000,1"), "set_trail_divisor", "get_trail_divisor"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_size_modifier", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_trail_size_modifier", "get_trail_size_modifier"); @@ -1265,6 +1331,8 @@ void ParticlesMaterial::_bind_methods() { ADD_GROUP("Spread", ""); ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness"); + ADD_GROUP("Gravity", ""); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity"); ADD_GROUP("Initial Velocity", "initial_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY); @@ -1361,6 +1429,7 @@ ParticlesMaterial::ParticlesMaterial() set_emission_sphere_radius(1); set_emission_box_extents(Vector3(1, 1, 1)); set_trail_divisor(1); + set_gravity(Vector3(0, -9.8, 0)); emission_point_count = 1; for (int i = 0; i < PARAM_MAX; i++) { diff --git a/scene/3d/particles.h b/scene/3d/particles.h index 3a46269396e3..63ebd7ed7bbf 100644 --- a/scene/3d/particles.h +++ b/scene/3d/particles.h @@ -63,8 +63,8 @@ class Particles : public GeometryInstance { float pre_process_time; float explosiveness_ratio; float randomness_ratio; - Rect3 custom_aabb; - Vector3 gravity; + float speed_scale; + Rect3 visibility_aabb; bool local_coords; int fixed_fps; bool fractional_delta; @@ -89,10 +89,10 @@ class Particles : public GeometryInstance { void set_pre_process_time(float p_time); void set_explosiveness_ratio(float p_ratio); void set_randomness_ratio(float p_ratio); - void set_custom_aabb(const Rect3 &p_aabb); - void set_gravity(const Vector3 &p_gravity); + void set_visibility_aabb(const Rect3 &p_aabb); void set_use_local_coordinates(bool p_enable); void set_process_material(const Ref &p_material); + void set_speed_scale(float p_scale); bool is_emitting() const; int get_amount() const; @@ -100,10 +100,10 @@ class Particles : public GeometryInstance { float get_pre_process_time() const; float get_explosiveness_ratio() const; float get_randomness_ratio() const; - Rect3 get_custom_aabb() const; - Vector3 get_gravity() const; + Rect3 get_visibility_aabb() const; bool get_use_local_coordinates() const; Ref get_process_material() const; + float get_speed_scale() const; void set_fixed_fps(int p_count); int get_fixed_fps() const; @@ -120,6 +120,9 @@ class Particles : public GeometryInstance { void set_draw_pass_mesh(int p_pass, const Ref &p_mesh); Ref get_draw_pass_mesh(int p_pass) const; + virtual String get_configuration_warning() const; + + Rect3 capture_aabb() const; Particles(); ~Particles(); }; @@ -270,6 +273,8 @@ class ParticlesMaterial : public Material { StringName trail_divisor; StringName trail_size_modifier; StringName trail_color_modifier; + + StringName gravity; }; static ShaderNames *shader_names; @@ -304,6 +309,8 @@ class ParticlesMaterial : public Material { Ref trail_size_modifier; Ref trail_color_modifier; + Vector3 gravity; + //do not save emission points here protected: @@ -358,6 +365,9 @@ class ParticlesMaterial : public Material { void set_trail_color_modifier(const Ref &p_trail_color_modifier); Ref get_trail_color_modifier() const; + void set_gravity(const Vector3 &p_gravity); + Vector3 get_gravity() const; + static void init_shaders(); static void finish_shaders(); static void flush_changes(); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 3a8126f30032..a420f7a08115 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -441,7 +441,7 @@ class RasterizerStorage { virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0; virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0; virtual void particles_set_custom_aabb(RID p_particles, const Rect3 &p_aabb) = 0; - virtual void particles_set_gravity(RID p_particles, const Vector3 &p_gravity) = 0; + virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0; virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0; virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0; diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index cbde41427cf7..8d72ee3f348b 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -203,8 +203,6 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["DELTA"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["NUMBER"] = ShaderLanguage::TYPE_UINT; shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["INDEX"] = ShaderLanguage::TYPE_INT; - shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["SEED"] = ShaderLanguage::TYPE_UINT; - shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["GRAVITY"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["EMISSION_TRANSFORM"] = ShaderLanguage::TYPE_MAT4; shader_modes[VS::SHADER_PARTICLES].modes.insert("billboard"); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 11f6d58f9512..7de497d52990 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -852,7 +852,7 @@ class VisualServerRaster : public VisualServer { BIND2(particles_set_explosiveness_ratio, RID, float) BIND2(particles_set_randomness_ratio, RID, float) BIND2(particles_set_custom_aabb, RID, const Rect3 &) - BIND2(particles_set_gravity, RID, const Vector3 &) + BIND2(particles_set_speed_scale, RID, float) BIND2(particles_set_use_local_coordinates, RID, bool) BIND2(particles_set_process_material, RID, RID) BIND2(particles_set_fixed_fps, RID, int) diff --git a/servers/visual_server.h b/servers/visual_server.h index 04afc6dfaf86..7accc7d90430 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -480,7 +480,7 @@ class VisualServer : public Object { virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0; virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0; virtual void particles_set_custom_aabb(RID p_particles, const Rect3 &p_aabb) = 0; - virtual void particles_set_gravity(RID p_particles, const Vector3 &p_gravity) = 0; + virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0; virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0; virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;