Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2018-04-18 13:14:28 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2018-04-19 11:51:18 +0300
commit63225d7c8b3a45e8189476d537585b011993fb17 (patch)
tree905d1494b20ded621bf1f41d4f98e3ecbaa1f650 /source/blender/modifiers/intern/MOD_particleinstance.c
parentfcac9e841040812f227ecc3f10d4a970b9e174fd (diff)
Port particle instance modifier changes from Gooseberry branch
The work is mainly from Lukas Toenne, with some modifications from myself. Includes following obvious changes: - Particle system selection is now name-based, with lookup menu. - Lots of new options to control varieties. Changes comparing to the Gooseberry branch: - Default values and versioning code ensures same behavior as the old modifier. - Custom data layers are coming from vertex color, the modifier does not create arbitrary layers now. The hope is to keep data more manageable, and maybe make it easier to select in the shader later on. This means, values are quantized to 256 values, but it should be enough to get varieties in practice. Reviewers: brecht, campbellbarton Reviewed By: brecht Subscribers: eyecandy Differential Revision: https://developer.blender.org/D3157
Diffstat (limited to 'source/blender/modifiers/intern/MOD_particleinstance.c')
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c191
1 files changed, 147 insertions, 44 deletions
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 106a84d3765..f0b80cda447 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -40,10 +40,12 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_rand.h"
+#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
+#include "BKE_global.h"
#include "BKE_lattice.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
@@ -53,8 +55,6 @@
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
-#include "MOD_modifiertypes.h"
-
static void initData(ModifierData *md)
{
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
@@ -64,7 +64,12 @@ static void initData(ModifierData *md)
pimd->psys = 1;
pimd->position = 1.0f;
pimd->axis = 2;
+ pimd->space = eParticleInstanceSpace_World;
+ pimd->particle_amount = 1.0f;
+ pimd->particle_offset = 0.0f;
+ STRNCPY(pimd->index_layer_name, "");
+ STRNCPY(pimd->value_layer_name, "");
}
static void copyData(ModifierData *md, ModifierData *target)
{
@@ -75,6 +80,21 @@ static void copyData(ModifierData *md, ModifierData *target)
modifier_copyData_generic(md, target);
}
+static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
+{
+ ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
+ CustomDataMask dataMask = 0;
+
+ if (pimd->index_layer_name[0] != '\0' ||
+ pimd->value_layer_name[0] != '\0')
+ {
+ dataMask |= CD_MASK_MLOOPCOL;
+ }
+
+ return dataMask;
+
+}
+
static bool isDisabled(ModifierData *md, int useRenderParams)
{
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
@@ -142,39 +162,59 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
walk(userData, ob, &pimd->ob, IDWALK_CB_NOP);
}
-static int particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p)
+static bool particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p)
{
+ const bool between = (psys->part->childtype == PART_CHILD_FACES);
ParticleData *pa;
+ int totpart, randp, minp, maxp;
- if (pimd->flag & eParticleInstanceFlag_Parents) {
- if (p >= psys->totpart) {
- if (psys->part->childtype == PART_CHILD_PARTICLES) {
- pa = psys->particles + (psys->child + p - psys->totpart)->parent;
- }
- else {
- pa = NULL;
- }
- }
- else {
- pa = psys->particles + p;
- }
+ if (p >= psys->totpart) {
+ ChildParticle *cpa = psys->child + (p - psys->totpart);
+ pa = psys->particles + (between? cpa->pa[0]: cpa->parent);
}
else {
- if (psys->part->childtype == PART_CHILD_PARTICLES) {
- pa = psys->particles + (psys->child + p)->parent;
- }
- else {
- pa = NULL;
- }
+ pa = psys->particles + p;
}
if (pa) {
- if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) return 1;
- if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) return 1;
- if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) return 1;
+ if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) return true;
+ if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) return true;
+ if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) return true;
}
- return 0;
+ if (pimd->particle_amount == 1.0f) {
+ /* Early output, all particles are to be instanced. */
+ return false;
+ }
+
+ /* Randomly skip particles based on desired amount of visible particles. */
+
+ totpart = psys->totpart + psys->totchild;
+
+ /* TODO make randomization optional? */
+ randp = (int)(psys_frand(psys, 3578 + p) * totpart) % totpart;
+
+ minp = (int)(totpart * pimd->particle_offset) % (totpart+1);
+ maxp = (int)(totpart * (pimd->particle_offset + pimd->particle_amount)) % (totpart+1);
+
+ if (maxp > minp) {
+ return randp < minp || randp >= maxp;
+ }
+ else if (maxp < minp) {
+ return randp < minp && randp >= maxp;
+ }
+ else {
+ return true;
+ }
+
+ return false;
+}
+
+static void store_float_in_vcol(MLoopCol *vcol, float float_value)
+{
+ const uchar value = FTOCHAR(float_value);
+ vcol->r = vcol->g = vcol->b = value;
+ vcol->a = 1.0f;
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
@@ -190,11 +230,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
MLoop *mloop, *orig_mloop;
MVert *mvert, *orig_mvert;
int totvert, totpoly, totloop /* , totedge */;
- int maxvert, maxpoly, maxloop, totpart = 0, first_particle = 0;
+ int maxvert, maxpoly, maxloop, part_end = 0, part_start;
int k, p, p_skip;
short track = ob->trackflag % 3, trackneg, axis = pimd->axis;
float max_co = 0.0, min_co = 0.0, temp_co[3];
float *size = NULL;
+ float spacemat[4][4];
+ const bool use_parents = pimd->flag & eParticleInstanceFlag_Parents;
+ const bool use_children = pimd->flag & eParticleInstanceFlag_Children;
+ bool between;
trackneg = ((ob->trackflag > 2) ? 1 : 0);
@@ -212,25 +256,26 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
return derivedData;
}
- if (pimd->flag & eParticleInstanceFlag_Parents)
- totpart += psys->totpart;
- if (pimd->flag & eParticleInstanceFlag_Children) {
- if (totpart == 0)
- first_particle = psys->totpart;
- totpart += psys->totchild;
- }
+ part_start = use_parents ? 0 : psys->totpart;
+
+ part_end = 0;
+ if (use_parents)
+ part_end += psys->totpart;
+ if (use_children)
+ part_end += psys->totchild;
- if (totpart == 0)
+ if (part_end == 0)
return derivedData;
sim.scene = md->scene;
sim.ob = pimd->ob;
sim.psys = psys;
sim.psmd = psys_get_modifier(pimd->ob, psys);
+ between = (psys->part->childtype == PART_CHILD_FACES);
if (pimd->flag & eParticleInstanceFlag_UseSize) {
float *si;
- si = size = MEM_calloc_arrayN(totpart, sizeof(float), "particle size array");
+ si = size = MEM_calloc_arrayN(part_end, sizeof(float), "particle size array");
if (pimd->flag & eParticleInstanceFlag_Parents) {
for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++)
@@ -246,6 +291,21 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
}
+ switch (pimd->space) {
+ case eParticleInstanceSpace_World:
+ /* particle states are in world space already */
+ unit_m4(spacemat);
+ break;
+ case eParticleInstanceSpace_Local:
+ /* get particle states in the particle object's local space */
+ invert_m4_m4(spacemat, pimd->ob->obmat);
+ break;
+ default:
+ /* should not happen */
+ BLI_assert(false);
+ break;
+ }
+
totvert = dm->getNumVerts(dm);
totpoly = dm->getNumPolys(dm);
totloop = dm->getNumLoops(dm);
@@ -256,7 +316,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
maxpoly = 0;
maxloop = 0;
- for (p = 0; p < totpart; p++) {
+ for (p = part_start; p < part_end; p++) {
if (particle_skip(pimd, psys, p))
continue;
@@ -285,9 +345,21 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
mloop = result->getLoopArray(result);
orig_mloop = dm->getLoopArray(dm);
- for (p = 0, p_skip = 0; p < totpart; p++) {
+ MLoopCol *mloopcols_index = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, pimd->index_layer_name);
+ MLoopCol *mloopcols_value = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, pimd->value_layer_name);
+ int *vert_part_index = NULL;
+ float *vert_part_value = NULL;
+ if (mloopcols_index != NULL) {
+ vert_part_index = MEM_calloc_arrayN(maxvert, sizeof(int), "vertex part index array");
+ }
+ if (mloopcols_value) {
+ vert_part_value = MEM_calloc_arrayN(maxvert, sizeof(float), "vertex part value array");
+ }
+
+ for (p = part_start, p_skip = 0; p < part_end; p++) {
float prev_dir[3];
float frame[4]; /* frame orientation quaternion */
+ float p_random = psys_frand(psys, 77091 + 283*p);
/* skip particle? */
if (particle_skip(pimd, psys, p))
@@ -297,12 +369,20 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
for (k = 0; k < totvert; k++) {
ParticleKey state;
MVert *inMV;
- MVert *mv = mvert + p_skip * totvert + k;
+ int vindex = p_skip * totvert + k;
+ MVert *mv = mvert + vindex;
inMV = orig_mvert + k;
DM_copy_vert_data(dm, result, k, p_skip * totvert + k, 1);
*mv = *inMV;
+ if (vert_part_index != NULL) {
+ vert_part_index[vindex] = p;
+ }
+ if (vert_part_value != NULL) {
+ vert_part_value[vindex] = p_random;
+ }
+
/*change orientation based on object trackflag*/
copy_v3_v3(temp_co, mv->co);
mv->co[axis] = temp_co[track];
@@ -330,7 +410,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
mv->co[axis] = 0.0;
}
- psys_get_particle_on_path(&sim, first_particle + p, &state, 1);
+ psys_get_particle_on_path(&sim, p, &state, 1);
normalize_v3(state.vel);
@@ -339,17 +419,26 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
float hairmat[4][4];
float mat[3][3];
- if (first_particle + p < psys->totpart)
- pa = psys->particles + first_particle + p;
+ if (p < psys->totpart)
+ pa = psys->particles + p;
else {
ChildParticle *cpa = psys->child + (p - psys->totpart);
- pa = psys->particles + cpa->parent;
+ pa = psys->particles + (between? cpa->pa[0]: cpa->parent);
}
psys_mat_hair_to_global(sim.ob, sim.psmd->dm_final, sim.psys->part->from, pa, hairmat);
copy_m3_m4(mat, hairmat);
/* to quaternion */
mat3_to_quat(frame, mat);
+ if (pimd->rotation > 0.0f || pimd->random_rotation > 0.0f) {
+ float angle = 2.0f*M_PI * (pimd->rotation + pimd->random_rotation * (psys_frand(psys, 19957323 + p) - 0.5f));
+ float eul[3] = { 0.0f, 0.0f, angle };
+ float rot[4];
+
+ eul_to_quat(rot, eul);
+ mul_qt_qtqt(frame, frame, rot);
+ }
+
/* note: direction is same as normal vector currently,
* but best to keep this separate so the frame can be
* rotated later if necessary
@@ -386,13 +475,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
else {
state.time = -1.0;
- psys_get_particle_state(&sim, first_particle + p, &state, 1);
+ psys_get_particle_state(&sim, p, &state, 1);
}
mul_qt_v3(state.rot, mv->co);
if (pimd->flag & eParticleInstanceFlag_UseSize)
mul_v3_fl(mv->co, size[p]);
add_v3_v3(mv->co, state.co);
+
+ mul_m4_v3(spacemat, mv->co);
}
/* create polys and loops */
@@ -412,6 +503,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DM_copy_loop_data(dm, result, inMP->loopstart, mp->loopstart, j);
for (; j; j--, ml++, inML++) {
ml->v = inML->v + (p_skip * totvert);
+ const int ml_index = (ml - mloop);
+ if (mloopcols_index != NULL) {
+ const int part_index = vert_part_index[ml->v];
+ store_float_in_vcol(&mloopcols_index[ml_index], (float)part_index / psys->totpart);
+ }
+ if (mloopcols_value != NULL) {
+ const float part_value = vert_part_value[ml->v];
+ store_float_in_vcol(&mloopcols_value[ml_index], part_value);
+ }
}
}
}
@@ -429,6 +529,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (size)
MEM_freeN(size);
+ MEM_SAFE_FREE(vert_part_index);
+ MEM_SAFE_FREE(vert_part_value);
+
result->dirty |= DM_DIRTY_NORMALS;
return result;
@@ -451,7 +554,7 @@ ModifierTypeInfo modifierType_ParticleInstance = {
/* applyModifier */ applyModifier,
/* applyModifierEM */ NULL,
/* initData */ initData,
- /* requiredDataMask */ NULL,
+ /* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,