Particle system is complete. Rejoice!

This commit is contained in:
Juan Linietsky 2017-04-08 22:38:11 -03:00
parent 6075dfe511
commit 4286aef693
16 changed files with 610 additions and 131 deletions

View file

@ -105,23 +105,23 @@ public:
}
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 @@ public:
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) {

View file

@ -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<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
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<RasterizerGLES3Particle, RasterizerGLES3ParticleSort> 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
glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount);
int stride = sizeof(float) * 4 * 6;
int split = int(Math::ceil(particles->phase * particles->amount));
storage->info.render_vertices_count += s->index_array_len * 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);
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 - 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++;
}

View file

@ -692,7 +692,7 @@ 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_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);

View file

@ -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);

View file

@ -995,7 +995,6 @@ public:
float explosiveness;
float randomness;
Rect3 custom_aabb;
Vector3 gravity;
bool use_local_coords;
RID process_material;
@ -1003,11 +1002,14 @@ public:
Vector<RID> 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<Particles> particle_element;
float phase;
@ -1016,6 +1018,8 @@ public:
uint32_t cycle_number;
float speed_scale;
int fixed_fps;
bool fractional_delta;
float frame_remainder;
@ -1037,6 +1041,10 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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);

View file

@ -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;i<attractor_count;i++) {
vec3 rel_vec = xform[3].xyz - attractors[i].pos;
@ -211,6 +221,7 @@ VERTEX_SHADER_CODE
out_xform_2 = xform[1];
out_xform_3 = xform[2];
#endif //PARTICLES_COPY
}

View file

@ -113,48 +113,7 @@ void ParticlesEditor::_menu_option(int p_option) {
switch (p_option) {
case MENU_OPTION_GENERATE_AABB: {
#if 0
Transform globalizer = node->get_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);
}

View file

@ -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<Face3> geometry;
void _generate_aabb();
void _generate_emission_points();
void _resource_seleted(const String &p_res);
void _node_selected(const NodePath &p_path);

View file

@ -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<Vector3> 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<Vector3> 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<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) {
return misg;
}
if (p_spatial->cast_to<Particles>()) {
Ref<ParticlesGizmo> misg = memnew(ParticlesGizmo(p_spatial->cast_to<Particles>()));
return misg;
}
if (p_spatial->cast_to<ReflectionProbe>()) {
Ref<ReflectionProbeGizmo> misg = memnew(ReflectionProbeGizmo(p_spatial->cast_to<ReflectionProbe>()));
@ -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));

View file

@ -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 @@ public:
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 @@ public:
Ref<SpatialMaterial> portal_material;
Ref<SpatialMaterial> raycast_material;
Ref<SpatialMaterial> visibility_notifier_material;
Ref<SpatialMaterial> particles_material;
Ref<SpatialMaterial> car_wheel_material;
Ref<SpatialMaterial> joint_material;

View file

@ -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<Material> &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 {
Rect3 Particles::get_visibility_aabb() const {
return custom_aabb;
}
Vector3 Particles::get_gravity() const {
return gravity;
return visibility_aabb;
}
bool Particles::get_use_local_coordinates() const {
@ -136,6 +137,11 @@ Ref<Material> 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<Mesh> &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<Mesh> 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<GradientTexture> 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++) {

View file

@ -63,8 +63,8 @@ private:
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 @@ public:
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<Material> &p_material);
void set_speed_scale(float p_scale);
bool is_emitting() const;
int get_amount() const;
@ -100,10 +100,10 @@ public:
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<Material> 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 @@ public:
void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh);
Ref<Mesh> get_draw_pass_mesh(int p_pass) const;
virtual String get_configuration_warning() const;
Rect3 capture_aabb() const;
Particles();
~Particles();
};
@ -270,6 +273,8 @@ private:
StringName trail_divisor;
StringName trail_size_modifier;
StringName trail_color_modifier;
StringName gravity;
};
static ShaderNames *shader_names;
@ -304,6 +309,8 @@ private:
Ref<CurveTexture> trail_size_modifier;
Ref<GradientTexture> trail_color_modifier;
Vector3 gravity;
//do not save emission points here
protected:
@ -358,6 +365,9 @@ public:
void set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier);
Ref<GradientTexture> 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();

View file

@ -441,7 +441,7 @@ public:
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;

View file

@ -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");

View file

@ -852,7 +852,7 @@ public:
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)

View file

@ -480,7 +480,7 @@ public:
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;