365 lines
10 KiB
C
365 lines
10 KiB
C
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2005 by the Blender Foundation.
|
|
* All rights reserved.
|
|
*
|
|
* Contributor(s): Daniel Dunbar
|
|
* Ton Roosendaal,
|
|
* Ben Batt,
|
|
* Brecht Van Lommel,
|
|
* Campbell Barton
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*
|
|
*/
|
|
|
|
/** \file blender/modifiers/intern/MOD_particleinstance.c
|
|
* \ingroup modifiers
|
|
*/
|
|
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_math.h"
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_rand.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "BKE_cdderivedmesh.h"
|
|
#include "BKE_lattice.h"
|
|
#include "BKE_modifier.h"
|
|
#include "BKE_particle.h"
|
|
#include "BKE_pointcache.h"
|
|
|
|
#include "MOD_util.h"
|
|
|
|
#include "depsgraph_private.h"
|
|
|
|
|
|
static void initData(ModifierData *md)
|
|
{
|
|
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
|
|
|
|
pimd->flag = eParticleInstanceFlag_Parents | eParticleInstanceFlag_Unborn |
|
|
eParticleInstanceFlag_Alive | eParticleInstanceFlag_Dead;
|
|
pimd->psys = 1;
|
|
pimd->position = 1.0f;
|
|
pimd->axis = 2;
|
|
|
|
}
|
|
static void copyData(ModifierData *md, ModifierData *target)
|
|
{
|
|
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
|
|
ParticleInstanceModifierData *tpimd = (ParticleInstanceModifierData *) target;
|
|
|
|
tpimd->ob = pimd->ob;
|
|
tpimd->psys = pimd->psys;
|
|
tpimd->flag = pimd->flag;
|
|
tpimd->axis = pimd->axis;
|
|
tpimd->position = pimd->position;
|
|
tpimd->random_position = pimd->random_position;
|
|
}
|
|
|
|
static int dependsOnTime(ModifierData *UNUSED(md))
|
|
{
|
|
return 0;
|
|
}
|
|
static void updateDepgraph(ModifierData *md, DagForest *forest,
|
|
struct Scene *UNUSED(scene),
|
|
Object *UNUSED(ob),
|
|
DagNode *obNode)
|
|
{
|
|
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
|
|
|
|
if (pimd->ob) {
|
|
DagNode *curNode = dag_get_node(forest, pimd->ob);
|
|
|
|
dag_add_relation(forest, curNode, obNode,
|
|
DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
|
|
"Particle Instance Modifier");
|
|
}
|
|
}
|
|
|
|
static void foreachObjectLink(ModifierData *md, Object *ob,
|
|
ObjectWalkFunc walk, void *userData)
|
|
{
|
|
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
|
|
|
|
walk(userData, ob, &pimd->ob);
|
|
}
|
|
|
|
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
|
|
DerivedMesh *derivedData,
|
|
int UNUSED(useRenderParams),
|
|
int UNUSED(isFinalCalc))
|
|
{
|
|
DerivedMesh *dm = derivedData, *result;
|
|
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
|
|
ParticleSimulationData sim;
|
|
ParticleSystem *psys = NULL;
|
|
ParticleData *pa = NULL, *pars = NULL;
|
|
MFace *mface, *orig_mface;
|
|
MVert *mvert, *orig_mvert;
|
|
int i, totvert, totpart = 0, totface, maxvert, maxface, first_particle = 0;
|
|
short track = ob->trackflag % 3, trackneg, axis = pimd->axis;
|
|
float max_co = 0.0, min_co = 0.0, temp_co[3], cross[3];
|
|
float *size = NULL;
|
|
|
|
DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
|
|
|
|
trackneg = ((ob->trackflag > 2) ? 1 : 0);
|
|
|
|
if (pimd->ob == ob) {
|
|
pimd->ob = NULL;
|
|
return derivedData;
|
|
}
|
|
|
|
if (pimd->ob) {
|
|
psys = BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1);
|
|
if (psys == NULL || psys->totpart == 0)
|
|
return derivedData;
|
|
}
|
|
else 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;
|
|
}
|
|
|
|
if (totpart == 0)
|
|
return derivedData;
|
|
|
|
sim.scene = md->scene;
|
|
sim.ob = pimd->ob;
|
|
sim.psys = psys;
|
|
sim.psmd = psys_get_modifier(pimd->ob, psys);
|
|
|
|
if (pimd->flag & eParticleInstanceFlag_UseSize) {
|
|
int p;
|
|
float *si;
|
|
si = size = MEM_callocN(totpart * sizeof(float), "particle size array");
|
|
|
|
if (pimd->flag & eParticleInstanceFlag_Parents) {
|
|
for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++)
|
|
*si = pa->size;
|
|
}
|
|
|
|
if (pimd->flag & eParticleInstanceFlag_Children) {
|
|
ChildParticle *cpa = psys->child;
|
|
|
|
for (p = 0; p < psys->totchild; p++, cpa++, si++) {
|
|
*si = psys_get_child_size(psys, cpa, 0.0f, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
pars = psys->particles;
|
|
|
|
totvert = dm->getNumVerts(dm);
|
|
totface = dm->getNumTessFaces(dm);
|
|
|
|
maxvert = totvert * totpart;
|
|
maxface = totface * totpart;
|
|
|
|
psys->lattice = psys_get_lattice(&sim);
|
|
|
|
if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) {
|
|
|
|
float min_r[3], max_r[3];
|
|
INIT_MINMAX(min_r, max_r);
|
|
dm->getMinMax(dm, min_r, max_r);
|
|
min_co = min_r[track];
|
|
max_co = max_r[track];
|
|
}
|
|
|
|
result = CDDM_from_template(dm, maxvert, dm->getNumEdges(dm) * totpart, maxface, 0, 0);
|
|
|
|
mvert = result->getVertArray(result);
|
|
orig_mvert = dm->getVertArray(dm);
|
|
|
|
for (i = 0; i < maxvert; i++) {
|
|
MVert *inMV;
|
|
MVert *mv = mvert + i;
|
|
ParticleKey state;
|
|
|
|
inMV = orig_mvert + i % totvert;
|
|
DM_copy_vert_data(dm, result, i % totvert, i, 1);
|
|
*mv = *inMV;
|
|
|
|
/*change orientation based on object trackflag*/
|
|
copy_v3_v3(temp_co, mv->co);
|
|
mv->co[axis] = temp_co[track];
|
|
mv->co[(axis + 1) % 3] = temp_co[(track + 1) % 3];
|
|
mv->co[(axis + 2) % 3] = temp_co[(track + 2) % 3];
|
|
|
|
if ((psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) &&
|
|
(pimd->flag & eParticleInstanceFlag_Path))
|
|
{
|
|
float ran = 0.0f;
|
|
if (pimd->random_position != 0.0f) {
|
|
BLI_srandom(psys->seed + (i / totvert) % totpart);
|
|
ran = pimd->random_position * BLI_frand();
|
|
}
|
|
|
|
if (pimd->flag & eParticleInstanceFlag_KeepShape) {
|
|
state.time = pimd->position * (1.0f - ran);
|
|
}
|
|
else {
|
|
state.time = (mv->co[axis] - min_co) / (max_co - min_co) * pimd->position * (1.0f - ran);
|
|
|
|
if (trackneg)
|
|
state.time = 1.0f - state.time;
|
|
|
|
mv->co[axis] = 0.0;
|
|
}
|
|
|
|
psys_get_particle_on_path(&sim, first_particle + i / totvert, &state, 1);
|
|
|
|
normalize_v3(state.vel);
|
|
|
|
/* TODO: incremental rotations somehow */
|
|
if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) {
|
|
state.rot[0] = 1;
|
|
state.rot[1] = state.rot[2] = state.rot[3] = 0.0f;
|
|
}
|
|
else {
|
|
float temp[3] = {0.0f, 0.0f, 0.0f};
|
|
temp[axis] = 1.0f;
|
|
|
|
cross_v3_v3v3(cross, temp, state.vel);
|
|
|
|
/* state.vel[axis] is the only component surviving from a dot product with the axis */
|
|
axis_angle_to_quat(state.rot, cross, saacos(state.vel[axis]));
|
|
}
|
|
|
|
}
|
|
else {
|
|
state.time = -1.0;
|
|
psys_get_particle_state(&sim, first_particle + i / totvert, &state, 1);
|
|
}
|
|
|
|
mul_qt_v3(state.rot, mv->co);
|
|
if (pimd->flag & eParticleInstanceFlag_UseSize)
|
|
mul_v3_fl(mv->co, size[i / totvert]);
|
|
add_v3_v3(mv->co, state.co);
|
|
}
|
|
|
|
mface = result->getTessFaceArray(result);
|
|
orig_mface = dm->getTessFaceArray(dm);
|
|
|
|
for (i = 0; i < maxface; i++) {
|
|
MFace *inMF;
|
|
MFace *mf = mface + i;
|
|
|
|
if (pimd->flag & eParticleInstanceFlag_Parents) {
|
|
if (i / totface >= psys->totpart) {
|
|
if (psys->part->childtype == PART_CHILD_PARTICLES) {
|
|
pa = psys->particles + (psys->child + i / totface - psys->totpart)->parent;
|
|
}
|
|
else {
|
|
pa = NULL;
|
|
}
|
|
}
|
|
else {
|
|
pa = pars + i / totface;
|
|
}
|
|
}
|
|
else {
|
|
if (psys->part->childtype == PART_CHILD_PARTICLES) {
|
|
pa = psys->particles + (psys->child + i / totface)->parent;
|
|
}
|
|
else {
|
|
pa = NULL;
|
|
}
|
|
}
|
|
|
|
if (pa) {
|
|
if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) continue;
|
|
if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) continue;
|
|
if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) continue;
|
|
}
|
|
|
|
inMF = orig_mface + i % totface;
|
|
DM_copy_poly_data(dm, result, i % totface, i, 1);
|
|
*mf = *inMF;
|
|
|
|
mf->v1 += (i / totface) * totvert;
|
|
mf->v2 += (i / totface) * totvert;
|
|
mf->v3 += (i / totface) * totvert;
|
|
if (mf->v4) {
|
|
mf->v4 += (i / totface) * totvert;
|
|
}
|
|
}
|
|
|
|
CDDM_calc_edges_tessface(result);
|
|
|
|
if (psys->lattice) {
|
|
end_latt_deform(psys->lattice);
|
|
psys->lattice = NULL;
|
|
}
|
|
|
|
if (size)
|
|
MEM_freeN(size);
|
|
|
|
CDDM_tessfaces_to_faces(result); /*builds ngon faces from tess (mface) faces*/
|
|
CDDM_calc_normals(result);
|
|
|
|
return result;
|
|
}
|
|
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
|
|
struct BMEditMesh *UNUSED(editData),
|
|
DerivedMesh *derivedData)
|
|
{
|
|
return applyModifier(md, ob, derivedData, 0, 1);
|
|
}
|
|
|
|
|
|
ModifierTypeInfo modifierType_ParticleInstance = {
|
|
/* name */ "ParticleInstance",
|
|
/* structName */ "ParticleInstanceModifierData",
|
|
/* structSize */ sizeof(ParticleInstanceModifierData),
|
|
/* type */ eModifierTypeType_Constructive,
|
|
/* flags */ eModifierTypeFlag_AcceptsMesh |
|
|
eModifierTypeFlag_SupportsMapping |
|
|
eModifierTypeFlag_SupportsEditmode |
|
|
eModifierTypeFlag_EnableInEditmode,
|
|
|
|
/* copyData */ copyData,
|
|
/* deformVerts */ NULL,
|
|
/* deformMatrices */ NULL,
|
|
/* deformVertsEM */ NULL,
|
|
/* deformMatricesEM */ NULL,
|
|
/* applyModifier */ applyModifier,
|
|
/* applyModifierEM */ applyModifierEM,
|
|
/* initData */ initData,
|
|
/* requiredDataMask */ NULL,
|
|
/* freeData */ NULL,
|
|
/* isDisabled */ NULL,
|
|
/* updateDepgraph */ updateDepgraph,
|
|
/* dependsOnTime */ dependsOnTime,
|
|
/* dependsOnNormals */ NULL,
|
|
/* foreachObjectLink */ foreachObjectLink,
|
|
/* foreachIDLink */ NULL,
|
|
/* foreachTexLink */ NULL,
|
|
};
|