diff options
Diffstat (limited to 'source/blender/blenkernel/intern/particle_system.c')
-rw-r--r-- | source/blender/blenkernel/intern/particle_system.c | 108 |
1 files changed, 95 insertions, 13 deletions
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 9840852ad7e..16ea71204cc 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -1660,17 +1660,22 @@ void psys_get_birth_coordinates(ParticleSimulationData *sim, ParticleData *pa, P { Object *ob = sim->ob; ParticleSystem *psys = sim->psys; - ParticleSettings *part; + ParticleSettings *part = psys->part; ParticleTexture ptex; float fac, phasefac, nor[3] = {0,0,0},loc[3],vel[3] = {0.0,0.0,0.0},rot[4],q2[4]; float r_vel[3],r_ave[3],r_rot[4],vec[3],p_vel[3] = {0.0,0.0,0.0}; float x_vec[3] = {1.0,0.0,0.0}, utan[3] = {0.0,1.0,0.0}, vtan[3] = {0.0,0.0,1.0}, rot_vec[3] = {0.0,0.0,0.0}; float q_phase[4]; + + const bool use_boids = ((part->phystype == PART_PHYS_BOIDS) && + (pa->boid != NULL)); + const bool use_tangents = ((use_boids == false) && + ((part->tanfac != 0.0f) || (part->rotmode == PART_ROT_NOR_TAN))); + int p = pa - psys->particles; - part=psys->part; /* get birth location from object */ - if (part->tanfac != 0.f) + if (use_tangents) psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0,0); else psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0,0); @@ -1688,7 +1693,7 @@ void psys_get_birth_coordinates(ParticleSimulationData *sim, ParticleData *pa, P normalize_v3(nor); /* -tangent */ - if (part->tanfac!=0.0f) { + if (use_tangents) { //float phase=vg_rot?2.0f*(psys_particle_value_from_verts(sim->psmd->dm,part->from,pa,vg_rot)-0.5f):0.0f; float phase=0.0f; mul_v3_fl(vtan,-cosf((float)M_PI*(part->tanphase+phase))); @@ -1737,7 +1742,7 @@ void psys_get_birth_coordinates(ParticleSimulationData *sim, ParticleData *pa, P mul_qt_qtqt(r_rot,r_rot,rot); } - if (part->phystype==PART_PHYS_BOIDS && pa->boid) { + if (use_boids) { float dvec[3], q[4], mat[3][3]; copy_v3_v3(state->co,loc); @@ -1823,35 +1828,112 @@ void psys_get_birth_coordinates(ParticleSimulationData *sim, ParticleData *pa, P unit_qt(state->rot); if (part->rotmode) { + bool use_global_space; + /* create vector into which rotation is aligned */ switch (part->rotmode) { case PART_ROT_NOR: + case PART_ROT_NOR_TAN: copy_v3_v3(rot_vec, nor); + use_global_space = false; break; case PART_ROT_VEL: copy_v3_v3(rot_vec, vel); + use_global_space = true; break; case PART_ROT_GLOB_X: case PART_ROT_GLOB_Y: case PART_ROT_GLOB_Z: rot_vec[part->rotmode - PART_ROT_GLOB_X] = 1.0f; + use_global_space = true; break; case PART_ROT_OB_X: case PART_ROT_OB_Y: case PART_ROT_OB_Z: copy_v3_v3(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]); + use_global_space = false; + break; + default: + use_global_space = true; break; } /* create rotation quat */ - negate_v3(rot_vec); - vec_to_quat( q2,rot_vec, OB_POSX, OB_POSZ); - /* randomize rotation quat */ - if (part->randrotfac!=0.0f) - interp_qt_qtqt(rot, q2, r_rot, part->randrotfac); - else - copy_qt_qt(rot,q2); + + if (use_global_space) { + negate_v3(rot_vec); + vec_to_quat(q2, rot_vec, OB_POSX, OB_POSZ); + + /* randomize rotation quat */ + if (part->randrotfac != 0.0f) { + interp_qt_qtqt(rot, q2, r_rot, part->randrotfac); + } + else { + copy_qt_qt(rot, q2); + } + } + else { + /* calculate rotation in local-space */ + float q_obmat[4]; + float q_imat[4]; + + mat4_to_quat(q_obmat, ob->obmat); + invert_qt_qt(q_imat, q_obmat); + + + if (part->rotmode != PART_ROT_NOR_TAN) { + float rot_vec_local[3]; + + /* rot_vec */ + negate_v3(rot_vec); + copy_v3_v3(rot_vec_local, rot_vec); + mul_qt_v3(q_imat, rot_vec_local); + normalize_v3(rot_vec_local); + + vec_to_quat(q2, rot_vec_local, OB_POSX, OB_POSZ); + } + else { + /* (part->rotmode == PART_ROT_NOR_TAN) */ + float tmat[3][3]; + + /* note: utan_local is not taken from 'utan', we calculate from rot_vec/vtan */ + /* note: it looks like rotation phase may be applied twice (once with vtan, again below) + * however this isn't the case - campbell */ + float *rot_vec_local = tmat[0]; + float *vtan_local = tmat[1]; + float *utan_local = tmat[2]; + + /* use tangents */ + BLI_assert(use_tangents == true); + + /* rot_vec */ + copy_v3_v3(rot_vec_local, rot_vec); + mul_qt_v3(q_imat, rot_vec_local); + + /* vtan_local */ + copy_v3_v3(vtan_local, vtan); /* flips, cant use */ + mul_qt_v3(q_imat, vtan_local); + + /* ensure orthogonal matrix (rot_vec aligned) */ + cross_v3_v3v3(utan_local, vtan_local, rot_vec_local); + cross_v3_v3v3(vtan_local, utan_local, rot_vec_local); + + /* note: no need to normalize */ + mat3_to_quat(q2, tmat); + } + + /* randomize rotation quat */ + if (part->randrotfac != 0.0f) { + mul_qt_qtqt(r_rot, r_rot, q_imat); + interp_qt_qtqt(rot, q2, r_rot, part->randrotfac); + } + else { + copy_qt_qt(rot, q2); + } + + mul_qt_qtqt(rot, q_obmat, rot); + } /* rotation phase */ phasefac = part->phasefac; @@ -4313,7 +4395,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) /* SPH_SOLVER_CLASSICAL */ /* Apply SPH forces using classical algorithm (due to Gingold * and Monaghan). Note that, unlike double-density relaxation, - * this algorthim is separated into distinct loops. */ + * this algorithm is separated into distinct loops. */ #pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5) LOOP_DYNAMIC_PARTICLES { |