353 lines
9.3 KiB
C
353 lines
9.3 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;
|
|
|
|
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->getNumFaces(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);
|
|
|
|
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->getFaceArray(result);
|
|
orig_mface=dm->getFaceArray(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_face_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(result);
|
|
CDDM_calc_normals(result);
|
|
|
|
if(psys->lattice){
|
|
end_latt_deform(psys->lattice);
|
|
psys->lattice= NULL;
|
|
}
|
|
|
|
if(size)
|
|
MEM_freeN(size);
|
|
|
|
return result;
|
|
}
|
|
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
|
|
struct EditMesh *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,
|
|
};
|