2009-07-30 15:00:26 +00:00
|
|
|
/**
|
2009-08-10 14:09:56 +00:00
|
|
|
* smoke.c
|
2009-07-30 15:00:26 +00:00
|
|
|
*
|
|
|
|
|
* $Id$
|
|
|
|
|
*
|
|
|
|
|
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) Blender Foundation.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
|
*
|
|
|
|
|
* Contributor(s): Daniel Genrich
|
|
|
|
|
*
|
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
|
*/
|
|
|
|
|
|
2009-07-30 20:12:40 +00:00
|
|
|
/* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
|
|
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
#include <GL/glew.h>
|
|
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
|
|
#include <float.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include "stdio.h"
|
2009-09-12 14:12:37 +00:00
|
|
|
#include "string.h" /* memset */
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
#include "BLI_linklist.h"
|
|
|
|
|
#include "BLI_rand.h"
|
|
|
|
|
#include "BLI_jitter.h"
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
|
#include "BLI_arithb.h"
|
|
|
|
|
#include "BLI_edgehash.h"
|
|
|
|
|
#include "BLI_kdtree.h"
|
|
|
|
|
#include "BLI_kdopbvh.h"
|
|
|
|
|
|
2009-08-03 16:39:12 +00:00
|
|
|
#include "BKE_bvhutils.h"
|
2009-07-30 15:00:26 +00:00
|
|
|
#include "BKE_cdderivedmesh.h"
|
|
|
|
|
#include "BKE_customdata.h"
|
|
|
|
|
#include "BKE_DerivedMesh.h"
|
2009-10-08 10:18:14 +00:00
|
|
|
#include "BKE_effect.h"
|
2009-07-30 15:00:26 +00:00
|
|
|
#include "BKE_modifier.h"
|
|
|
|
|
#include "BKE_particle.h"
|
2009-08-20 00:33:59 +00:00
|
|
|
#include "BKE_pointcache.h"
|
|
|
|
|
#include "BKE_smoke.h"
|
2009-07-30 15:00:26 +00:00
|
|
|
#include "BKE_utildefines.h"
|
|
|
|
|
|
|
|
|
|
#include "DNA_customdata_types.h"
|
|
|
|
|
#include "DNA_group_types.h"
|
2009-08-20 00:33:59 +00:00
|
|
|
#include "DNA_lamp_types.h"
|
2009-07-30 15:00:26 +00:00
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
|
#include "DNA_modifier_types.h"
|
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
#include "DNA_particle_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
#include "DNA_smoke_types.h"
|
|
|
|
|
|
|
|
|
|
#include "smoke_API.h"
|
|
|
|
|
|
|
|
|
|
#include "BKE_smoke.h"
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <conio.h>
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
|
|
static LARGE_INTEGER liFrequency;
|
|
|
|
|
static LARGE_INTEGER liStartTime;
|
|
|
|
|
static LARGE_INTEGER liCurrentTime;
|
|
|
|
|
|
|
|
|
|
static void tstart ( void )
|
|
|
|
|
{
|
|
|
|
|
QueryPerformanceFrequency ( &liFrequency );
|
|
|
|
|
QueryPerformanceCounter ( &liStartTime );
|
|
|
|
|
}
|
|
|
|
|
static void tend ( void )
|
|
|
|
|
{
|
|
|
|
|
QueryPerformanceCounter ( &liCurrentTime );
|
|
|
|
|
}
|
2009-09-09 18:39:40 +00:00
|
|
|
static double tval()
|
|
|
|
|
{
|
|
|
|
|
return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart ));
|
|
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
#else
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
static struct timeval _tstart, _tend;
|
|
|
|
|
static struct timezone tz;
|
|
|
|
|
static void tstart ( void )
|
|
|
|
|
{
|
|
|
|
|
gettimeofday ( &_tstart, &tz );
|
|
|
|
|
}
|
|
|
|
|
static void tend ( void )
|
|
|
|
|
{
|
|
|
|
|
gettimeofday ( &_tend,&tz );
|
|
|
|
|
}
|
|
|
|
|
static double tval()
|
|
|
|
|
{
|
|
|
|
|
double t1, t2;
|
|
|
|
|
t1 = ( double ) _tstart.tv_sec*1000 + ( double ) _tstart.tv_usec/ ( 1000 );
|
|
|
|
|
t2 = ( double ) _tend.tv_sec*1000 + ( double ) _tend.tv_usec/ ( 1000 );
|
|
|
|
|
return t2-t1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
struct Object;
|
|
|
|
|
struct Scene;
|
|
|
|
|
struct DerivedMesh;
|
|
|
|
|
struct SmokeModifierData;
|
|
|
|
|
|
|
|
|
|
// forward declerations
|
2009-08-20 00:37:27 +00:00
|
|
|
static void get_cell(float *p0, int res[3], float dx, float *pos, int *cell, int correct);
|
2009-07-30 15:00:26 +00:00
|
|
|
void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int numfaces, int numtris, int **tridivs, float cell_len);
|
2009-10-02 14:40:51 +00:00
|
|
|
static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
#define TRI_UVOFFSET (1./4.)
|
|
|
|
|
|
|
|
|
|
int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
|
|
|
|
|
{
|
|
|
|
|
if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
|
|
|
|
|
float size[3];
|
|
|
|
|
MVert *verts = dm->getVertArray(dm);
|
|
|
|
|
float scale = 0.0;
|
2009-08-03 16:39:12 +00:00
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
res = smd->domain->maxres;
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
// get BB of domain
|
|
|
|
|
for(i = 0; i < dm->getNumVerts(dm); i++)
|
|
|
|
|
{
|
|
|
|
|
float tmp[3];
|
|
|
|
|
|
|
|
|
|
VECCOPY(tmp, verts[i].co);
|
|
|
|
|
Mat4MulVecfl(ob->obmat, tmp);
|
|
|
|
|
|
|
|
|
|
// min BB
|
|
|
|
|
min[0] = MIN2(min[0], tmp[0]);
|
|
|
|
|
min[1] = MIN2(min[1], tmp[1]);
|
|
|
|
|
min[2] = MIN2(min[2], tmp[2]);
|
|
|
|
|
|
|
|
|
|
// max BB
|
|
|
|
|
max[0] = MAX2(max[0], tmp[0]);
|
|
|
|
|
max[1] = MAX2(max[1], tmp[1]);
|
|
|
|
|
max[2] = MAX2(max[2], tmp[2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VECCOPY(smd->domain->p0, min);
|
|
|
|
|
VECCOPY(smd->domain->p1, max);
|
|
|
|
|
|
|
|
|
|
// calc other res with max_res provided
|
|
|
|
|
VECSUB(size, max, min);
|
2009-08-25 23:39:49 +00:00
|
|
|
|
2009-09-15 10:26:36 +00:00
|
|
|
// printf("size: %f, %f, %f\n", size[0], size[1], size[2]);
|
2009-09-14 00:01:08 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
// prevent crash when initializing a plane as domain
|
2009-08-25 23:39:49 +00:00
|
|
|
if((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
if(size[0] > size[1])
|
|
|
|
|
{
|
|
|
|
|
if(size[0] > size[1])
|
|
|
|
|
{
|
|
|
|
|
scale = res / size[0];
|
|
|
|
|
smd->domain->dx = size[0] / res;
|
|
|
|
|
smd->domain->res[0] = res;
|
|
|
|
|
smd->domain->res[1] = (int)(size[1] * scale + 0.5);
|
|
|
|
|
smd->domain->res[2] = (int)(size[2] * scale + 0.5);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
scale = res / size[1];
|
|
|
|
|
smd->domain->dx = size[1] / res;
|
|
|
|
|
smd->domain->res[1] = res;
|
|
|
|
|
smd->domain->res[0] = (int)(size[0] * scale + 0.5);
|
|
|
|
|
smd->domain->res[2] = (int)(size[2] * scale + 0.5);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if(size[1] > size[2])
|
|
|
|
|
{
|
|
|
|
|
scale = res / size[1];
|
|
|
|
|
smd->domain->dx = size[1] / res;
|
|
|
|
|
smd->domain->res[1] = res;
|
|
|
|
|
smd->domain->res[0] = (int)(size[0] * scale + 0.5);
|
|
|
|
|
smd->domain->res[2] = (int)(size[2] * scale + 0.5);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
scale = res / size[2];
|
|
|
|
|
smd->domain->dx = size[2] / res;
|
|
|
|
|
smd->domain->res[2] = res;
|
|
|
|
|
smd->domain->res[0] = (int)(size[0] * scale + 0.5);
|
|
|
|
|
smd->domain->res[1] = (int)(size[1] * scale + 0.5);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-15 10:26:36 +00:00
|
|
|
// printf("smd->domain->dx: %f\n", smd->domain->dx);
|
2009-09-14 00:01:08 +00:00
|
|
|
|
2009-08-02 23:30:44 +00:00
|
|
|
// TODO: put in failsafe if res<=0 - dg
|
|
|
|
|
|
|
|
|
|
// printf("res[0]: %d, res[1]: %d, res[2]: %d\n", smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]);
|
2009-07-30 15:00:26 +00:00
|
|
|
// dt max is 0.1
|
2009-08-12 17:32:02 +00:00
|
|
|
smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0, 0.1);
|
2009-07-30 15:00:26 +00:00
|
|
|
smd->time = scene->r.cfra;
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
if(smd->domain->flags & MOD_SMOKE_HIGHRES)
|
2009-08-25 21:53:52 +00:00
|
|
|
{
|
2009-09-09 18:39:40 +00:00
|
|
|
smd->domain->wt = smoke_turbulence_init(smd->domain->res, smd->domain->amplify + 1, smd->domain->noise);
|
|
|
|
|
smd->domain->res_wt[0] = smd->domain->res[0] * (smd->domain->amplify + 1);
|
|
|
|
|
smd->domain->res_wt[1] = smd->domain->res[1] * (smd->domain->amplify + 1);
|
|
|
|
|
smd->domain->res_wt[2] = smd->domain->res[2] * (smd->domain->amplify + 1);
|
|
|
|
|
smd->domain->dx_wt = smd->domain->dx / (smd->domain->amplify + 1);
|
2009-09-15 10:26:36 +00:00
|
|
|
// printf("smd->domain->amplify: %d\n", smd->domain->amplify);
|
|
|
|
|
// printf("(smd->domain->flags & MOD_SMOKE_HIGHRES)\n");
|
2009-08-25 21:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
if(!smd->domain->shadow)
|
|
|
|
|
smd->domain->shadow = MEM_callocN(sizeof(float) * smd->domain->res[0] * smd->domain->res[1] * smd->domain->res[2], "SmokeDomainShadow");
|
2009-08-20 00:33:59 +00:00
|
|
|
|
|
|
|
|
smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta));
|
2009-08-09 01:30:32 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
if(smd->domain->wt)
|
|
|
|
|
{
|
|
|
|
|
smoke_initWaveletBlenderRNA(smd->domain->wt, &(smd->domain->strength));
|
2009-09-15 10:26:36 +00:00
|
|
|
// printf("smoke_initWaveletBlenderRNA\n");
|
2009-09-09 18:39:40 +00:00
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
|
|
|
|
|
{
|
|
|
|
|
// handle flow object here
|
|
|
|
|
// XXX TODO
|
|
|
|
|
|
|
|
|
|
smd->time = scene->r.cfra;
|
|
|
|
|
|
|
|
|
|
// update particle lifetime to be one frame
|
|
|
|
|
// smd->flow->psys->part->lifetime = scene->r.efra + 1;
|
2009-08-12 17:32:02 +00:00
|
|
|
/*
|
|
|
|
|
if(!smd->flow->bvh)
|
|
|
|
|
{
|
|
|
|
|
// smd->flow->bvh = MEM_callocN(sizeof(BVHTreeFromMesh), "smoke_bvhfromfaces");
|
|
|
|
|
// bvhtree_from_mesh_faces(smd->flow->bvh, dm, 0.0, 2, 6);
|
|
|
|
|
|
|
|
|
|
// copy obmat
|
|
|
|
|
// Mat4CpyMat4(smd->flow->mat, ob->obmat);
|
|
|
|
|
// Mat4CpyMat4(smd->flow->mat_old, ob->obmat);
|
|
|
|
|
}
|
|
|
|
|
*/
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2009-08-02 23:30:44 +00:00
|
|
|
else if((smd->type & MOD_SMOKE_TYPE_COLL))
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
|
|
|
|
smd->time = scene->r.cfra;
|
|
|
|
|
|
2009-08-02 23:30:44 +00:00
|
|
|
// todo: delete this when loading colls work -dg
|
|
|
|
|
if(!smd->coll)
|
|
|
|
|
smokeModifier_createType(smd);
|
|
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
if(!smd->coll->points)
|
|
|
|
|
{
|
|
|
|
|
// init collision points
|
|
|
|
|
SmokeCollSettings *scs = smd->coll;
|
|
|
|
|
|
2009-08-06 16:50:02 +00:00
|
|
|
// copy obmat
|
|
|
|
|
Mat4CpyMat4(scs->mat, ob->obmat);
|
|
|
|
|
Mat4CpyMat4(scs->mat_old, ob->obmat);
|
|
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
fill_scs_points(ob, dm, scs);
|
|
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
if(!smd->coll->bvhtree)
|
|
|
|
|
{
|
|
|
|
|
smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
return 1;
|
|
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
|
|
|
|
|
{
|
|
|
|
|
MVert *mvert = dm->getVertArray(dm);
|
|
|
|
|
MFace *mface = dm->getFaceArray(dm);
|
|
|
|
|
int i = 0, divs = 0;
|
|
|
|
|
int *tridivs = NULL;
|
|
|
|
|
float cell_len = 1.0 / 50.0; // for res = 50
|
|
|
|
|
int newdivs = 0;
|
|
|
|
|
int quads = 0, facecounter = 0;
|
|
|
|
|
|
|
|
|
|
// count quads
|
|
|
|
|
for(i = 0; i < dm->getNumFaces(dm); i++)
|
|
|
|
|
{
|
|
|
|
|
if(mface[i].v4)
|
|
|
|
|
quads++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len);
|
|
|
|
|
|
|
|
|
|
// count triangle divisions
|
|
|
|
|
for(i = 0; i < dm->getNumFaces(dm) + quads; i++)
|
|
|
|
|
{
|
|
|
|
|
divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1);
|
|
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
// printf("divs: %d\n", divs);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints");
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < dm->getNumVerts(dm); i++)
|
|
|
|
|
{
|
|
|
|
|
float tmpvec[3];
|
|
|
|
|
VECCOPY(tmpvec, mvert[i].co);
|
|
|
|
|
Mat4MulVecfl (ob->obmat, tmpvec);
|
|
|
|
|
VECCOPY(&scs->points[i * 3], tmpvec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++)
|
|
|
|
|
{
|
|
|
|
|
int again = 0;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
int j, k;
|
|
|
|
|
int divs1 = tridivs[3 * facecounter + 0];
|
|
|
|
|
int divs2 = tridivs[3 * facecounter + 1];
|
|
|
|
|
//int divs3 = tridivs[3 * facecounter + 2];
|
|
|
|
|
float side1[3], side2[3], trinormorg[3], trinorm[3];
|
|
|
|
|
|
|
|
|
|
if(again == 1 && mface[i].v4)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
2009-10-02 14:40:51 +00:00
|
|
|
VECSUB(side1, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
|
|
|
|
|
VECSUB(side2, mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
2009-10-02 14:40:51 +00:00
|
|
|
else
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
2009-10-02 14:40:51 +00:00
|
|
|
VECSUB(side1, mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co);
|
|
|
|
|
VECSUB(side2, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Crossf(trinormorg, side1, side2);
|
|
|
|
|
Normalize(trinormorg);
|
|
|
|
|
VECCOPY(trinorm, trinormorg);
|
|
|
|
|
VecMulf(trinorm, 0.25 * cell_len);
|
|
|
|
|
|
|
|
|
|
for(j = 0; j <= divs1; j++)
|
|
|
|
|
{
|
|
|
|
|
for(k = 0; k <= divs2; k++)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
2009-10-02 14:40:51 +00:00
|
|
|
float p1[3], p2[3], p3[3], p[3]={0,0,0};
|
|
|
|
|
const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0);
|
|
|
|
|
const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0);
|
|
|
|
|
float tmpvec[3];
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
if(uf+vf > 1.0)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
2009-10-02 14:40:51 +00:00
|
|
|
// printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2);
|
|
|
|
|
continue;
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
VECCOPY(p1, mvert[ mface[i].v1 ].co);
|
|
|
|
|
if(again == 1 && mface[i].v4)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
2009-10-02 14:40:51 +00:00
|
|
|
VECCOPY(p2, mvert[ mface[i].v3 ].co);
|
|
|
|
|
VECCOPY(p3, mvert[ mface[i].v4 ].co);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
else
|
2009-10-02 14:40:51 +00:00
|
|
|
{
|
|
|
|
|
VECCOPY(p2, mvert[ mface[i].v2 ].co);
|
|
|
|
|
VECCOPY(p3, mvert[ mface[i].v3 ].co);
|
|
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
VecMulf(p1, (1.0-uf-vf));
|
|
|
|
|
VecMulf(p2, uf);
|
|
|
|
|
VecMulf(p3, vf);
|
|
|
|
|
|
|
|
|
|
VECADD(p, p1, p2);
|
|
|
|
|
VECADD(p, p, p3);
|
|
|
|
|
|
|
|
|
|
if(newdivs > divs)
|
|
|
|
|
printf("mem problem\n");
|
|
|
|
|
|
|
|
|
|
// mMovPoints.push_back(p + trinorm);
|
|
|
|
|
VECCOPY(tmpvec, p);
|
|
|
|
|
VECADD(tmpvec, tmpvec, trinorm);
|
|
|
|
|
Mat4MulVecfl (ob->obmat, tmpvec);
|
|
|
|
|
VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
|
|
|
|
|
newdivs++;
|
|
|
|
|
|
|
|
|
|
if(newdivs > divs)
|
|
|
|
|
printf("mem problem\n");
|
|
|
|
|
|
|
|
|
|
// mMovPoints.push_back(p - trinorm);
|
|
|
|
|
VECCOPY(tmpvec, p);
|
|
|
|
|
VECSUB(tmpvec, tmpvec, trinorm);
|
|
|
|
|
Mat4MulVecfl (ob->obmat, tmpvec);
|
|
|
|
|
VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
|
|
|
|
|
newdivs++;
|
|
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
if(again == 0 && mface[i].v4)
|
|
|
|
|
again++;
|
|
|
|
|
else
|
|
|
|
|
again = 0;
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
facecounter++;
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
} while(again!=0);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2009-10-02 14:40:51 +00:00
|
|
|
scs->numpoints = dm->getNumVerts(dm) + newdivs;
|
|
|
|
|
|
|
|
|
|
MEM_freeN(tridivs);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*! init triangle divisions */
|
|
|
|
|
void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len)
|
|
|
|
|
{
|
|
|
|
|
// mTriangleDivs1.resize( faces.size() );
|
|
|
|
|
// mTriangleDivs2.resize( faces.size() );
|
|
|
|
|
// mTriangleDivs3.resize( faces.size() );
|
|
|
|
|
|
|
|
|
|
size_t i = 0, facecounter = 0;
|
|
|
|
|
float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale);
|
|
|
|
|
float maxpart = ABS(maxscale[0]);
|
|
|
|
|
float scaleFac = 0;
|
|
|
|
|
float fsTri = 0;
|
|
|
|
|
if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
|
|
|
|
|
if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
|
|
|
|
|
scaleFac = 1.0 / maxpart;
|
|
|
|
|
// featureSize = mLevel[mMaxRefine].nodeSize
|
|
|
|
|
fsTri = cell_len * 0.5 * scaleFac;
|
|
|
|
|
|
|
|
|
|
if(*tridivs)
|
|
|
|
|
MEM_freeN(*tridivs);
|
|
|
|
|
|
|
|
|
|
*tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs");
|
|
|
|
|
|
|
|
|
|
for(i = 0, facecounter = 0; i < numfaces; i++)
|
|
|
|
|
{
|
|
|
|
|
float p0[3], p1[3], p2[3];
|
|
|
|
|
float side1[3];
|
|
|
|
|
float side2[3];
|
|
|
|
|
float side3[3];
|
|
|
|
|
int divs1=0, divs2=0, divs3=0;
|
|
|
|
|
|
|
|
|
|
VECCOPY(p0, verts[faces[i].v1].co);
|
|
|
|
|
Mat4MulVecfl (ob->obmat, p0);
|
|
|
|
|
VECCOPY(p1, verts[faces[i].v2].co);
|
|
|
|
|
Mat4MulVecfl (ob->obmat, p1);
|
|
|
|
|
VECCOPY(p2, verts[faces[i].v3].co);
|
|
|
|
|
Mat4MulVecfl (ob->obmat, p2);
|
|
|
|
|
|
|
|
|
|
VECSUB(side1, p1, p0);
|
|
|
|
|
VECSUB(side2, p2, p0);
|
|
|
|
|
VECSUB(side3, p1, p2);
|
|
|
|
|
|
|
|
|
|
if(INPR(side1, side1) > fsTri*fsTri)
|
|
|
|
|
{
|
|
|
|
|
float tmp = Normalize(side1);
|
2009-08-06 16:50:02 +00:00
|
|
|
divs1 = (int)ceil(tmp/fsTri);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
if(INPR(side2, side2) > fsTri*fsTri)
|
|
|
|
|
{
|
|
|
|
|
float tmp = Normalize(side2);
|
2009-08-06 16:50:02 +00:00
|
|
|
divs2 = (int)ceil(tmp/fsTri);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
// debug
|
|
|
|
|
if(i==0)
|
|
|
|
|
printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2);
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(*tridivs)[3 * facecounter + 0] = divs1;
|
|
|
|
|
(*tridivs)[3 * facecounter + 1] = divs2;
|
|
|
|
|
(*tridivs)[3 * facecounter + 2] = divs3;
|
|
|
|
|
|
|
|
|
|
// TODO quad case
|
|
|
|
|
if(faces[i].v4)
|
|
|
|
|
{
|
|
|
|
|
divs1=0, divs2=0, divs3=0;
|
|
|
|
|
|
|
|
|
|
facecounter++;
|
|
|
|
|
|
2009-08-06 16:50:02 +00:00
|
|
|
VECCOPY(p0, verts[faces[i].v3].co);
|
|
|
|
|
Mat4MulVecfl (ob->obmat, p0);
|
|
|
|
|
VECCOPY(p1, verts[faces[i].v4].co);
|
2009-07-30 15:00:26 +00:00
|
|
|
Mat4MulVecfl (ob->obmat, p1);
|
2009-08-06 16:50:02 +00:00
|
|
|
VECCOPY(p2, verts[faces[i].v1].co);
|
2009-07-30 15:00:26 +00:00
|
|
|
Mat4MulVecfl (ob->obmat, p2);
|
|
|
|
|
|
|
|
|
|
VECSUB(side1, p1, p0);
|
|
|
|
|
VECSUB(side2, p2, p0);
|
|
|
|
|
VECSUB(side3, p1, p2);
|
|
|
|
|
|
|
|
|
|
if(INPR(side1, side1) > fsTri*fsTri)
|
|
|
|
|
{
|
|
|
|
|
float tmp = Normalize(side1);
|
2009-08-06 16:50:02 +00:00
|
|
|
divs1 = (int)ceil(tmp/fsTri);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
if(INPR(side2, side2) > fsTri*fsTri)
|
|
|
|
|
{
|
|
|
|
|
float tmp = Normalize(side2);
|
2009-08-06 16:50:02 +00:00
|
|
|
divs2 = (int)ceil(tmp/fsTri);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(*tridivs)[3 * facecounter + 0] = divs1;
|
|
|
|
|
(*tridivs)[3 * facecounter + 1] = divs2;
|
|
|
|
|
(*tridivs)[3 * facecounter + 2] = divs3;
|
|
|
|
|
}
|
|
|
|
|
facecounter++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-14 16:52:06 +00:00
|
|
|
static void smokeModifier_freeDomain(SmokeModifierData *smd)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
|
|
|
|
if(smd->domain)
|
|
|
|
|
{
|
2009-09-09 18:39:40 +00:00
|
|
|
if(smd->domain->shadow)
|
|
|
|
|
MEM_freeN(smd->domain->shadow);
|
|
|
|
|
smd->domain->shadow = NULL;
|
|
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
if(smd->domain->fluid)
|
|
|
|
|
smoke_free(smd->domain->fluid);
|
2009-08-09 01:30:32 +00:00
|
|
|
|
2009-08-25 21:53:52 +00:00
|
|
|
if(smd->domain->wt)
|
|
|
|
|
smoke_turbulence_free(smd->domain->wt);
|
|
|
|
|
|
2009-10-08 10:18:14 +00:00
|
|
|
if(smd->domain->effector_weights)
|
|
|
|
|
MEM_freeN(smd->domain->effector_weights);
|
|
|
|
|
smd->domain->effector_weights = NULL;
|
|
|
|
|
|
2009-08-25 23:39:49 +00:00
|
|
|
BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
|
|
|
|
|
smd->domain->point_cache[0] = NULL;
|
|
|
|
|
BKE_ptcache_free_list(&(smd->domain->ptcaches[1]));
|
|
|
|
|
smd->domain->point_cache[1] = NULL;
|
2009-08-09 01:30:32 +00:00
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
MEM_freeN(smd->domain);
|
|
|
|
|
smd->domain = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-14 16:52:06 +00:00
|
|
|
static void smokeModifier_freeFlow(SmokeModifierData *smd)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
|
|
|
|
if(smd->flow)
|
|
|
|
|
{
|
2009-08-12 17:32:02 +00:00
|
|
|
/*
|
|
|
|
|
if(smd->flow->bvh)
|
|
|
|
|
{
|
|
|
|
|
free_bvhtree_from_mesh(smd->flow->bvh);
|
|
|
|
|
MEM_freeN(smd->flow->bvh);
|
|
|
|
|
}
|
|
|
|
|
smd->flow->bvh = NULL;
|
|
|
|
|
*/
|
2009-07-30 15:00:26 +00:00
|
|
|
MEM_freeN(smd->flow);
|
|
|
|
|
smd->flow = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-14 16:52:06 +00:00
|
|
|
static void smokeModifier_freeCollision(SmokeModifierData *smd)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
|
|
|
|
if(smd->coll)
|
|
|
|
|
{
|
|
|
|
|
if(smd->coll->points)
|
|
|
|
|
{
|
|
|
|
|
MEM_freeN(smd->coll->points);
|
|
|
|
|
smd->coll->points = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-03 16:39:12 +00:00
|
|
|
if(smd->coll->bvhtree)
|
|
|
|
|
{
|
|
|
|
|
BLI_bvhtree_free(smd->coll->bvhtree);
|
|
|
|
|
smd->coll->bvhtree = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-06 16:50:02 +00:00
|
|
|
if(smd->coll->dm)
|
|
|
|
|
smd->coll->dm->release(smd->coll->dm);
|
|
|
|
|
smd->coll->dm = NULL;
|
|
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
MEM_freeN(smd->coll);
|
|
|
|
|
smd->coll = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
void smokeModifier_reset_turbulence(struct SmokeModifierData *smd)
|
|
|
|
|
{
|
|
|
|
|
if(smd && smd->domain && smd->domain->wt)
|
|
|
|
|
{
|
|
|
|
|
smoke_turbulence_free(smd->domain->wt);
|
|
|
|
|
smd->domain->wt = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
void smokeModifier_reset(struct SmokeModifierData *smd)
|
|
|
|
|
{
|
|
|
|
|
if(smd)
|
|
|
|
|
{
|
|
|
|
|
if(smd->domain)
|
|
|
|
|
{
|
2009-09-09 18:39:40 +00:00
|
|
|
if(smd->domain->shadow)
|
|
|
|
|
MEM_freeN(smd->domain->shadow);
|
|
|
|
|
smd->domain->shadow = NULL;
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
if(smd->domain->fluid)
|
|
|
|
|
{
|
|
|
|
|
smoke_free(smd->domain->fluid);
|
|
|
|
|
smd->domain->fluid = NULL;
|
|
|
|
|
}
|
2009-09-14 00:01:08 +00:00
|
|
|
|
2009-08-25 23:39:49 +00:00
|
|
|
smd->domain->point_cache[0]->flag |= PTCACHE_OUTDATED;
|
2009-09-14 00:01:08 +00:00
|
|
|
smd->domain->point_cache[1]->flag |= PTCACHE_OUTDATED;
|
2009-08-25 23:39:49 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
smokeModifier_reset_turbulence(smd);
|
2009-08-20 00:33:59 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
smd->time = -1;
|
|
|
|
|
|
2009-09-15 10:26:36 +00:00
|
|
|
// printf("reset domain end\n");
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
else if(smd->flow)
|
|
|
|
|
{
|
2009-08-12 17:32:02 +00:00
|
|
|
/*
|
|
|
|
|
if(smd->flow->bvh)
|
|
|
|
|
{
|
|
|
|
|
free_bvhtree_from_mesh(smd->flow->bvh);
|
|
|
|
|
MEM_freeN(smd->flow->bvh);
|
|
|
|
|
}
|
|
|
|
|
smd->flow->bvh = NULL;
|
|
|
|
|
*/
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
else if(smd->coll)
|
|
|
|
|
{
|
|
|
|
|
if(smd->coll->points)
|
|
|
|
|
{
|
|
|
|
|
MEM_freeN(smd->coll->points);
|
|
|
|
|
smd->coll->points = NULL;
|
|
|
|
|
}
|
2009-08-03 16:39:12 +00:00
|
|
|
|
|
|
|
|
if(smd->coll->bvhtree)
|
|
|
|
|
{
|
|
|
|
|
BLI_bvhtree_free(smd->coll->bvhtree);
|
|
|
|
|
smd->coll->bvhtree = NULL;
|
|
|
|
|
}
|
2009-08-06 16:50:02 +00:00
|
|
|
|
|
|
|
|
if(smd->coll->dm)
|
|
|
|
|
smd->coll->dm->release(smd->coll->dm);
|
|
|
|
|
smd->coll->dm = NULL;
|
|
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void smokeModifier_free (SmokeModifierData *smd)
|
|
|
|
|
{
|
|
|
|
|
if(smd)
|
|
|
|
|
{
|
|
|
|
|
smokeModifier_freeDomain(smd);
|
|
|
|
|
smokeModifier_freeFlow(smd);
|
|
|
|
|
smokeModifier_freeCollision(smd);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void smokeModifier_createType(struct SmokeModifierData *smd)
|
|
|
|
|
{
|
|
|
|
|
if(smd)
|
|
|
|
|
{
|
|
|
|
|
if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
|
|
|
|
|
{
|
|
|
|
|
if(smd->domain)
|
|
|
|
|
smokeModifier_freeDomain(smd);
|
|
|
|
|
|
|
|
|
|
smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
|
|
|
|
|
|
|
|
|
|
smd->domain->smd = smd;
|
|
|
|
|
|
2009-08-25 23:39:49 +00:00
|
|
|
smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0]));
|
|
|
|
|
smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE;
|
|
|
|
|
smd->domain->point_cache[0]->step = 1;
|
|
|
|
|
|
|
|
|
|
smd->domain->point_cache[1] = BKE_ptcache_add(&(smd->domain->ptcaches[1]));
|
|
|
|
|
smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE;
|
|
|
|
|
smd->domain->point_cache[1]->step = 1;
|
2009-08-20 00:33:59 +00:00
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
/* set some standard values */
|
|
|
|
|
smd->domain->fluid = NULL;
|
2009-09-09 18:39:40 +00:00
|
|
|
smd->domain->wt = NULL;
|
2009-07-30 15:00:26 +00:00
|
|
|
smd->domain->eff_group = NULL;
|
|
|
|
|
smd->domain->fluid_group = NULL;
|
|
|
|
|
smd->domain->coll_group = NULL;
|
2009-08-02 23:30:44 +00:00
|
|
|
smd->domain->maxres = 32;
|
2009-09-09 18:39:40 +00:00
|
|
|
smd->domain->amplify = 1;
|
|
|
|
|
smd->domain->omega = 1.0;
|
2009-07-30 15:00:26 +00:00
|
|
|
smd->domain->alpha = -0.001;
|
|
|
|
|
smd->domain->beta = 0.1;
|
2009-08-12 17:32:02 +00:00
|
|
|
smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG;
|
2009-09-09 18:39:40 +00:00
|
|
|
smd->domain->strength = 2.0;
|
2009-08-25 21:53:52 +00:00
|
|
|
smd->domain->noise = MOD_SMOKE_NOISEWAVE;
|
2009-09-09 18:39:40 +00:00
|
|
|
smd->domain->diss_speed = 5;
|
2009-07-30 15:00:26 +00:00
|
|
|
// init 3dview buffer
|
2009-09-09 18:39:40 +00:00
|
|
|
smd->domain->viewsettings = 0;
|
2009-10-08 10:18:14 +00:00
|
|
|
smd->domain->effector_weights = BKE_add_effector_weights(NULL);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
else if(smd->type & MOD_SMOKE_TYPE_FLOW)
|
|
|
|
|
{
|
|
|
|
|
if(smd->flow)
|
|
|
|
|
smokeModifier_freeFlow(smd);
|
|
|
|
|
|
|
|
|
|
smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
|
|
|
|
|
|
|
|
|
|
smd->flow->smd = smd;
|
|
|
|
|
|
|
|
|
|
/* set some standard values */
|
|
|
|
|
smd->flow->density = 1.0;
|
|
|
|
|
smd->flow->temp = 1.0;
|
|
|
|
|
|
|
|
|
|
smd->flow->psys = NULL;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else if(smd->type & MOD_SMOKE_TYPE_COLL)
|
|
|
|
|
{
|
|
|
|
|
if(smd->coll)
|
|
|
|
|
smokeModifier_freeCollision(smd);
|
|
|
|
|
|
|
|
|
|
smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
|
|
|
|
|
|
|
|
|
|
smd->coll->smd = smd;
|
|
|
|
|
smd->coll->points = NULL;
|
|
|
|
|
smd->coll->numpoints = 0;
|
2009-08-03 16:39:12 +00:00
|
|
|
smd->coll->bvhtree = NULL;
|
2009-08-06 16:50:02 +00:00
|
|
|
smd->coll->dm = NULL;
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
// forward decleration
|
2009-09-14 16:52:06 +00:00
|
|
|
static void smoke_calc_transparency(float *result, float *input, float *p0, float *p1, int res[3], float dx, float *light, bresenham_callback cb, float correct);
|
2009-09-09 18:39:40 +00:00
|
|
|
static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
|
|
|
|
|
static int get_lamp(Scene *scene, float *light)
|
|
|
|
|
{
|
|
|
|
|
Base *base_tmp = NULL;
|
|
|
|
|
for(base_tmp = scene->base.first; base_tmp; base_tmp= base_tmp->next)
|
|
|
|
|
{
|
|
|
|
|
if(base_tmp->object->type == OB_LAMP)
|
|
|
|
|
{
|
|
|
|
|
Lamp *la = (Lamp *)base_tmp->object->data;
|
|
|
|
|
|
|
|
|
|
if(la->type == LA_LOCAL)
|
|
|
|
|
{
|
|
|
|
|
VECCOPY(light, base_tmp->object->obmat[3]);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd)
|
|
|
|
|
{
|
|
|
|
|
SmokeDomainSettings *sds = smd->domain;
|
|
|
|
|
GroupObject *go = NULL;
|
|
|
|
|
Base *base = NULL;
|
|
|
|
|
|
|
|
|
|
// do flows and fluids
|
|
|
|
|
if(1)
|
|
|
|
|
{
|
|
|
|
|
Object *otherobj = NULL;
|
|
|
|
|
ModifierData *md = NULL;
|
|
|
|
|
if(sds->fluid_group) // we use groups since we have 2 domains
|
|
|
|
|
go = sds->fluid_group->gobject.first;
|
|
|
|
|
else
|
|
|
|
|
base = scene->base.first;
|
|
|
|
|
while(base || go)
|
|
|
|
|
{
|
|
|
|
|
otherobj = NULL;
|
|
|
|
|
if(sds->fluid_group)
|
|
|
|
|
{
|
|
|
|
|
if(go->ob)
|
|
|
|
|
otherobj = go->ob;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
otherobj = base->object;
|
|
|
|
|
if(!otherobj)
|
|
|
|
|
{
|
|
|
|
|
if(sds->fluid_group)
|
|
|
|
|
go = go->next;
|
|
|
|
|
else
|
|
|
|
|
base= base->next;
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
md = modifiers_findByType(otherobj, eModifierType_Smoke);
|
|
|
|
|
|
|
|
|
|
// check for active smoke modifier
|
|
|
|
|
if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
|
|
|
|
|
{
|
|
|
|
|
SmokeModifierData *smd2 = (SmokeModifierData *)md;
|
|
|
|
|
|
|
|
|
|
// check for initialized smoke object
|
|
|
|
|
if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
|
|
|
|
|
{
|
|
|
|
|
// we got nice flow object
|
|
|
|
|
SmokeFlowSettings *sfs = smd2->flow;
|
|
|
|
|
|
|
|
|
|
if(sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
|
|
|
|
|
{
|
|
|
|
|
ParticleSystem *psys = sfs->psys;
|
|
|
|
|
ParticleSettings *part=psys->part;
|
|
|
|
|
ParticleData *pa = NULL;
|
|
|
|
|
int p = 0;
|
|
|
|
|
float *density = smoke_get_density(sds->fluid);
|
|
|
|
|
float *bigdensity = smoke_turbulence_get_density(sds->wt);
|
|
|
|
|
float *heat = smoke_get_heat(sds->fluid);
|
|
|
|
|
float *velocity_x = smoke_get_velocity_x(sds->fluid);
|
|
|
|
|
float *velocity_y = smoke_get_velocity_y(sds->fluid);
|
|
|
|
|
float *velocity_z = smoke_get_velocity_z(sds->fluid);
|
|
|
|
|
unsigned char *obstacle = smoke_get_obstacle(sds->fluid);
|
|
|
|
|
int bigres[3];
|
|
|
|
|
|
|
|
|
|
// mostly copied from particle code
|
|
|
|
|
for(p=0, pa=psys->particles; p<psys->totpart; p++, pa++)
|
|
|
|
|
{
|
|
|
|
|
int cell[3];
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
size_t index = 0;
|
|
|
|
|
int badcell = 0;
|
Unified effector functionality for particles, cloth and softbody
* Unified scene wide gravity (currently in scene buttons)
instead of each simulation having it's own gravity.
* Weight parameters for all effectors and an effector group
setting.
* Every effector can use noise.
* Most effectors have "shapes" point, plane, surface, every point.
- "Point" is most like the old effectors and uses the
effector location as the effector point.
- "Plane" uses the closest point on effectors local xy-plane
as the effector point.
- "Surface" uses the closest point on an effector object's
surface as the effector point.
- "Every Point" uses every point in a mesh effector object
as an effector point.
- The falloff is calculated from this point, so for example
with "surface" shape and "use only negative z axis" it's
possible to apply force only "inside" the effector object.
* Spherical effector is now renamed as "force" as it's no longer
just spherical.
* New effector parameter "flow", which makes the effector act as
surrounding air velocity, so the resulting force is
proportional to the velocity difference of the point and "air
velocity". For example a wind field with flow=1.0 results in
proper non-accelerating wind.
* New effector fields "turbulence", which creates nice random
flow paths, and "drag", which slows the points down.
* Much improved vortex field.
* Effectors can now effect particle rotation as well as location.
* Use full, or only positive/negative z-axis to apply force
(note. the z-axis is the surface normal in the case of
effector shape "surface")
* New "force field" submenu in add menu, which adds an empty
with the chosen effector (curve object for corve guides).
* Other dynamics should be quite easy to add to the effector
system too if wanted.
* "Unified" doesn't mean that force fields give the exact same results for
particles, softbody & cloth, since their final effect depends on many external
factors, like for example the surface area of the effected faces.
Code changes
* Subversion bump for correct handling of global gravity.
* Separate ui py file for common dynamics stuff.
* Particle settings updating is flushed with it's id through
DAG_id_flush_update(..).
Known issues
* Curve guides don't yet have all ui buttons in place, but they
should work none the less.
* Hair dynamics don't yet respect force fields.
Other changes
* Particle emission defaults now to frames 1-200 with life of 50
frames to fill the whole default timeline.
* Many particles drawing related crashes fixed.
* Sometimes particles didn't update on first frame properly.
* Hair with object/group visualization didn't work properly.
* Memory leaks with PointCacheID lists (Genscher, remember to
free pidlists after use :).
2009-09-30 22:10:14 +00:00
|
|
|
if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue;
|
2009-09-09 18:39:40 +00:00
|
|
|
else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0) continue;
|
|
|
|
|
else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue;
|
|
|
|
|
// VECCOPY(pos, pa->state.co);
|
|
|
|
|
// Mat4MulVecfl (ob->imat, pos);
|
2009-09-14 00:01:08 +00:00
|
|
|
// 1. get corresponding cell
|
2009-09-09 18:39:40 +00:00
|
|
|
get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, pa->state.co, cell, 0);
|
|
|
|
|
// check if cell is valid (in the domain boundary)
|
|
|
|
|
for(i = 0; i < 3; i++)
|
|
|
|
|
{
|
|
|
|
|
if((cell[i] > sds->res[i] - 1) || (cell[i] < 0))
|
|
|
|
|
{
|
|
|
|
|
badcell = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(badcell)
|
|
|
|
|
continue;
|
|
|
|
|
// 2. set cell values (heat, density and velocity)
|
|
|
|
|
index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);
|
|
|
|
|
if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) && !(obstacle[index] & 2)) // this is inflow
|
|
|
|
|
{
|
|
|
|
|
// heat[index] += sfs->temp * 0.1;
|
|
|
|
|
// density[index] += sfs->density * 0.1;
|
|
|
|
|
heat[index] = sfs->temp;
|
|
|
|
|
density[index] = sfs->density;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
velocity_x[index] = pa->state.vel[0];
|
|
|
|
|
velocity_y[index] = pa->state.vel[1];
|
|
|
|
|
velocity_z[index] = pa->state.vel[2];
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// obstacle[index] |= 2;
|
|
|
|
|
// we need different handling for the high-res feature
|
|
|
|
|
if(bigdensity)
|
|
|
|
|
{
|
|
|
|
|
// init all surrounding cells according to amplification, too
|
|
|
|
|
int i, j, k;
|
|
|
|
|
|
|
|
|
|
smoke_turbulence_get_res(smd->domain->wt, bigres);
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < smd->domain->amplify + 1; i++)
|
|
|
|
|
for(j = 0; j < smd->domain->amplify + 1; j++)
|
|
|
|
|
for(k = 0; k < smd->domain->amplify + 1; k++)
|
|
|
|
|
{
|
|
|
|
|
index = smoke_get_index((smd->domain->amplify + 1)* cell[0] + i, bigres[0], (smd->domain->amplify + 1)* cell[1] + j, bigres[1], (smd->domain->amplify + 1)* cell[2] + k);
|
|
|
|
|
bigdensity[index] = sfs->density;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) // outflow
|
|
|
|
|
{
|
|
|
|
|
heat[index] = 0.f;
|
|
|
|
|
density[index] = 0.f;
|
|
|
|
|
velocity_x[index] = 0.f;
|
|
|
|
|
velocity_y[index] = 0.f;
|
|
|
|
|
velocity_z[index] = 0.f;
|
|
|
|
|
// we need different handling for the high-res feature
|
|
|
|
|
if(bigdensity)
|
|
|
|
|
{
|
|
|
|
|
// init all surrounding cells according to amplification, too
|
|
|
|
|
int i, j, k;
|
|
|
|
|
smoke_turbulence_get_res(smd->domain->wt, bigres);
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < smd->domain->amplify + 1; i++)
|
|
|
|
|
for(j = 0; j < smd->domain->amplify + 1; j++)
|
|
|
|
|
for(k = 0; k < smd->domain->amplify + 1; k++)
|
|
|
|
|
{
|
|
|
|
|
index = smoke_get_index((smd->domain->amplify + 1)* cell[0] + i, bigres[0], (smd->domain->amplify + 1)* cell[1] + j, bigres[1], (smd->domain->amplify + 1)* cell[2] + k);
|
|
|
|
|
bigdensity[index] = 0.f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} // particles loop
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
for()
|
|
|
|
|
{
|
|
|
|
|
// no psys
|
|
|
|
|
BVHTreeNearest nearest;
|
|
|
|
|
nearest.index = -1;
|
|
|
|
|
nearest.dist = FLT_MAX;
|
|
|
|
|
|
|
|
|
|
BLI_bvhtree_find_nearest(sfs->bvh->tree, pco, &nearest, sfs->bvh->nearest_callback, sfs->bvh);
|
|
|
|
|
}*/
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(sds->fluid_group)
|
|
|
|
|
go = go->next;
|
|
|
|
|
else
|
|
|
|
|
base= base->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do effectors
|
|
|
|
|
{
|
2009-10-08 10:18:14 +00:00
|
|
|
ListBase *effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights);
|
|
|
|
|
|
|
|
|
|
if(effectors)
|
2009-09-09 18:39:40 +00:00
|
|
|
{
|
2009-10-08 10:18:14 +00:00
|
|
|
float *density = smoke_get_density(sds->fluid);
|
|
|
|
|
float *force_x = smoke_get_force_x(sds->fluid);
|
|
|
|
|
float *force_y = smoke_get_force_y(sds->fluid);
|
|
|
|
|
float *force_z = smoke_get_force_z(sds->fluid);
|
|
|
|
|
float *velocity_x = smoke_get_velocity_x(sds->fluid);
|
|
|
|
|
float *velocity_y = smoke_get_velocity_y(sds->fluid);
|
|
|
|
|
float *velocity_z = smoke_get_velocity_z(sds->fluid);
|
|
|
|
|
int x, y, z;
|
|
|
|
|
|
|
|
|
|
// precalculate wind forces
|
|
|
|
|
for(x = 0; x < sds->res[0]; x++)
|
|
|
|
|
for(y = 0; y < sds->res[1]; y++)
|
|
|
|
|
for(z = 0; z < sds->res[2]; z++)
|
|
|
|
|
{
|
|
|
|
|
EffectedPoint epoint;
|
|
|
|
|
float voxelCenter[3], vel[3], retvel[3];
|
|
|
|
|
|
|
|
|
|
unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
|
|
|
|
|
|
|
|
|
|
if(density[index] < FLT_EPSILON)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
vel[0] = velocity_x[index];
|
|
|
|
|
vel[1] = velocity_y[index];
|
|
|
|
|
vel[2] = velocity_z[index];
|
|
|
|
|
|
|
|
|
|
voxelCenter[0] = sds->p0[0] + sds->dx * x + sds->dx * 0.5;
|
|
|
|
|
voxelCenter[1] = sds->p0[1] + sds->dx * y + sds->dx * 0.5;
|
|
|
|
|
voxelCenter[2] = sds->p0[2] + sds->dx * z + sds->dx * 0.5;
|
|
|
|
|
|
|
|
|
|
pd_point_from_loc(scene, voxelCenter, vel, index, &epoint);
|
|
|
|
|
pdDoEffectors(effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
|
|
|
|
|
|
|
|
|
|
// TODO dg - do in force!
|
|
|
|
|
force_x[index] += MIN2(MAX2(-1.0, retvel[0] * 0.002), 1.0);
|
|
|
|
|
force_y[index] += MIN2(MAX2(-1.0, retvel[1] * 0.002), 1.0);
|
|
|
|
|
force_z[index] += MIN2(MAX2(-1.0, retvel[2] * 0.002), 1.0);
|
2009-09-09 18:39:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-10-08 10:18:14 +00:00
|
|
|
|
|
|
|
|
pdEndEffectors(&effectors);
|
2009-09-09 18:39:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do collisions
|
|
|
|
|
if(1)
|
|
|
|
|
{
|
|
|
|
|
Object *otherobj = NULL;
|
|
|
|
|
ModifierData *md = NULL;
|
|
|
|
|
|
|
|
|
|
if(sds->coll_group) // we use groups since we have 2 domains
|
|
|
|
|
go = sds->coll_group->gobject.first;
|
|
|
|
|
else
|
|
|
|
|
base = scene->base.first;
|
|
|
|
|
|
|
|
|
|
while(base || go)
|
|
|
|
|
{
|
|
|
|
|
otherobj = NULL;
|
|
|
|
|
if(sds->coll_group)
|
|
|
|
|
{
|
|
|
|
|
if(go->ob)
|
|
|
|
|
otherobj = go->ob;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
otherobj = base->object;
|
|
|
|
|
if(!otherobj)
|
|
|
|
|
{
|
|
|
|
|
if(sds->coll_group)
|
|
|
|
|
go = go->next;
|
|
|
|
|
else
|
|
|
|
|
base= base->next;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
md = modifiers_findByType(otherobj, eModifierType_Smoke);
|
|
|
|
|
|
|
|
|
|
// check for active smoke modifier
|
|
|
|
|
if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
|
|
|
|
|
{
|
|
|
|
|
SmokeModifierData *smd2 = (SmokeModifierData *)md;
|
|
|
|
|
|
|
|
|
|
if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
|
|
|
|
|
{
|
|
|
|
|
// we got nice collision object
|
|
|
|
|
SmokeCollSettings *scs = smd2->coll;
|
|
|
|
|
size_t i, j;
|
|
|
|
|
unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid);
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < scs->numpoints; i++)
|
|
|
|
|
{
|
|
|
|
|
int badcell = 0;
|
|
|
|
|
size_t index = 0;
|
|
|
|
|
int cell[3];
|
|
|
|
|
|
|
|
|
|
// 1. get corresponding cell
|
|
|
|
|
get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, &scs->points[3 * i], cell, 0);
|
|
|
|
|
|
|
|
|
|
// check if cell is valid (in the domain boundary)
|
|
|
|
|
for(j = 0; j < 3; j++)
|
|
|
|
|
if((cell[j] > sds->res[j] - 1) || (cell[j] < 0))
|
|
|
|
|
{
|
|
|
|
|
badcell = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(badcell)
|
|
|
|
|
continue;
|
|
|
|
|
// 2. set cell values (heat, density and velocity)
|
|
|
|
|
index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);
|
|
|
|
|
|
|
|
|
|
// printf("cell[0]: %d, cell[1]: %d, cell[2]: %d\n", cell[0], cell[1], cell[2]);
|
|
|
|
|
// printf("res[0]: %d, res[1]: %d, res[2]: %d, index: %d\n\n", sds->res[0], sds->res[1], sds->res[2], index);
|
|
|
|
|
obstacles[index] = 1;
|
|
|
|
|
// for moving gobstacles
|
|
|
|
|
/*
|
|
|
|
|
const LbmFloat maxVelVal = 0.1666;
|
|
|
|
|
const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5;
|
|
|
|
|
|
|
|
|
|
LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec);
|
|
|
|
|
{
|
|
|
|
|
const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5;
|
|
|
|
|
USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz);
|
|
|
|
|
if(usqr>maxusqr) {
|
|
|
|
|
// cutoff at maxVelVal
|
|
|
|
|
for(int jj=0; jj<3; jj++) {
|
|
|
|
|
if(objvel[jj]>0.) objvel[jj] = maxVelVal;
|
|
|
|
|
if(objvel[jj]<0.) objvel[jj] = -maxVelVal;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) );
|
|
|
|
|
const LbmVec oldov=objvel; // debug
|
|
|
|
|
objvel = vec2L((*pNormals)[n]) *dp;
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
if(sds->coll_group)
|
|
|
|
|
go = go->next;
|
|
|
|
|
else
|
|
|
|
|
base= base->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-08-03 16:39:12 +00:00
|
|
|
void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc)
|
2009-08-02 23:30:44 +00:00
|
|
|
{
|
2009-07-30 15:00:26 +00:00
|
|
|
if((smd->type & MOD_SMOKE_TYPE_FLOW))
|
|
|
|
|
{
|
2009-08-20 00:33:59 +00:00
|
|
|
if(scene->r.cfra >= smd->time)
|
|
|
|
|
smokeModifier_init(smd, ob, scene, dm);
|
|
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
if(scene->r.cfra > smd->time)
|
|
|
|
|
{
|
|
|
|
|
// XXX TODO
|
2009-08-03 16:39:12 +00:00
|
|
|
smd->time = scene->r.cfra;
|
2009-08-12 17:32:02 +00:00
|
|
|
|
|
|
|
|
// rigid movement support
|
|
|
|
|
/*
|
|
|
|
|
Mat4CpyMat4(smd->flow->mat_old, smd->flow->mat);
|
|
|
|
|
Mat4CpyMat4(smd->flow->mat, ob->obmat);
|
|
|
|
|
*/
|
2009-08-03 16:39:12 +00:00
|
|
|
}
|
|
|
|
|
else if(scene->r.cfra < smd->time)
|
|
|
|
|
{
|
|
|
|
|
smd->time = scene->r.cfra;
|
|
|
|
|
smokeModifier_reset(smd);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(smd->type & MOD_SMOKE_TYPE_COLL)
|
|
|
|
|
{
|
2009-08-20 00:33:59 +00:00
|
|
|
if(scene->r.cfra >= smd->time)
|
|
|
|
|
smokeModifier_init(smd, ob, scene, dm);
|
|
|
|
|
|
2009-08-03 16:39:12 +00:00
|
|
|
if(scene->r.cfra > smd->time)
|
|
|
|
|
{
|
|
|
|
|
// XXX TODO
|
|
|
|
|
smd->time = scene->r.cfra;
|
|
|
|
|
|
2009-08-06 16:50:02 +00:00
|
|
|
if(smd->coll->dm)
|
|
|
|
|
smd->coll->dm->release(smd->coll->dm);
|
|
|
|
|
|
|
|
|
|
smd->coll->dm = CDDM_copy(dm);
|
|
|
|
|
|
|
|
|
|
// rigid movement support
|
|
|
|
|
Mat4CpyMat4(smd->coll->mat_old, smd->coll->mat);
|
|
|
|
|
Mat4CpyMat4(smd->coll->mat, ob->obmat);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
else if(scene->r.cfra < smd->time)
|
|
|
|
|
{
|
|
|
|
|
smd->time = scene->r.cfra;
|
|
|
|
|
smokeModifier_reset(smd);
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-08-03 16:39:12 +00:00
|
|
|
else if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
2009-09-14 00:01:08 +00:00
|
|
|
SmokeDomainSettings *sds = smd->domain;
|
|
|
|
|
float light[3];
|
2009-09-09 18:39:40 +00:00
|
|
|
PointCache *cache = NULL;
|
2009-08-20 00:33:59 +00:00
|
|
|
PTCacheID pid;
|
2009-09-09 18:39:40 +00:00
|
|
|
PointCache *cache_wt = NULL;
|
|
|
|
|
PTCacheID pid_wt;
|
2009-09-14 00:01:08 +00:00
|
|
|
int startframe, endframe, framenr;
|
2009-08-20 00:33:59 +00:00
|
|
|
float timescale;
|
2009-09-09 18:39:40 +00:00
|
|
|
int cache_result = 0, cache_result_wt = 0;
|
2009-08-20 00:33:59 +00:00
|
|
|
|
|
|
|
|
framenr = scene->r.cfra;
|
|
|
|
|
|
2009-09-15 10:26:36 +00:00
|
|
|
// printf("time: %d\n", scene->r.cfra);
|
2009-09-14 00:01:08 +00:00
|
|
|
|
|
|
|
|
if(framenr == smd->time)
|
|
|
|
|
return;
|
2009-08-20 00:33:59 +00:00
|
|
|
|
2009-09-14 00:01:08 +00:00
|
|
|
cache = sds->point_cache[0];
|
2009-08-20 00:33:59 +00:00
|
|
|
BKE_ptcache_id_from_smoke(&pid, ob, smd);
|
|
|
|
|
BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale);
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
cache_wt = sds->point_cache[1];
|
|
|
|
|
BKE_ptcache_id_from_smoke_turbulence(&pid_wt, ob, smd);
|
|
|
|
|
|
2009-09-14 17:22:51 +00:00
|
|
|
if(!smd->domain->fluid)
|
|
|
|
|
{
|
|
|
|
|
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
|
|
|
|
|
BKE_ptcache_id_reset(scene, &pid_wt, PTCACHE_RESET_OUTDATED);
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-20 00:33:59 +00:00
|
|
|
if(framenr < startframe)
|
|
|
|
|
return;
|
2009-09-09 18:39:40 +00:00
|
|
|
|
2009-09-14 00:01:08 +00:00
|
|
|
if(framenr > endframe)
|
|
|
|
|
return;
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-09-14 17:22:51 +00:00
|
|
|
if(!smd->domain->fluid && (framenr != startframe))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// printf("startframe: %d, framenr: %d\n", startframe, framenr);
|
2009-09-09 18:39:40 +00:00
|
|
|
|
2009-08-25 23:39:49 +00:00
|
|
|
if(!smokeModifier_init(smd, ob, scene, dm))
|
2009-09-14 00:01:08 +00:00
|
|
|
{
|
|
|
|
|
printf("bad smokeModifier_init\n");
|
2009-08-25 23:39:49 +00:00
|
|
|
return;
|
2009-09-14 00:01:08 +00:00
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-08-20 00:33:59 +00:00
|
|
|
/* try to read from cache */
|
2009-09-09 18:39:40 +00:00
|
|
|
cache_result = BKE_ptcache_read_cache(&pid, (float)framenr, scene->r.frs_sec);
|
2009-09-15 10:26:36 +00:00
|
|
|
// printf("cache_result: %d\n", cache_result);
|
2009-08-20 00:33:59 +00:00
|
|
|
|
|
|
|
|
if(cache_result == PTCACHE_READ_EXACT)
|
|
|
|
|
{
|
|
|
|
|
cache->flag |= PTCACHE_SIMULATION_VALID;
|
|
|
|
|
cache->simframe= framenr;
|
2009-09-09 18:39:40 +00:00
|
|
|
|
|
|
|
|
if(sds->wt)
|
|
|
|
|
{
|
|
|
|
|
cache_result_wt = BKE_ptcache_read_cache(&pid_wt, (float)framenr, scene->r.frs_sec);
|
2009-09-14 00:01:08 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
if(cache_result_wt == PTCACHE_READ_EXACT)
|
|
|
|
|
{
|
|
|
|
|
cache_wt->flag |= PTCACHE_SIMULATION_VALID;
|
|
|
|
|
cache_wt->simframe= framenr;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-08-20 00:33:59 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2009-09-09 18:39:40 +00:00
|
|
|
|
2009-09-14 00:01:08 +00:00
|
|
|
tstart();
|
2009-08-20 00:33:59 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
smoke_calc_domain(scene, ob, smd);
|
|
|
|
|
|
|
|
|
|
// set new time
|
|
|
|
|
smd->time = scene->r.cfra;
|
2009-08-20 00:33:59 +00:00
|
|
|
|
2009-09-14 00:01:08 +00:00
|
|
|
/* do simulation */
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-09-14 00:01:08 +00:00
|
|
|
// low res
|
|
|
|
|
cache->flag |= PTCACHE_SIMULATION_VALID;
|
|
|
|
|
cache->simframe= framenr;
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
// simulate the actual smoke (c++ code in intern/smoke)
|
2009-09-15 16:05:59 +00:00
|
|
|
// DG: interesting commenting this line + deactivating loading of noise files
|
2009-09-14 00:01:08 +00:00
|
|
|
if(framenr!=startframe)
|
2009-10-02 11:09:05 +00:00
|
|
|
{
|
|
|
|
|
if(sds->flags & MOD_SMOKE_DISSOLVE)
|
|
|
|
|
smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
|
2009-09-14 00:01:08 +00:00
|
|
|
smoke_step(sds->fluid, smd->time);
|
2009-10-02 11:09:05 +00:00
|
|
|
}
|
2009-09-14 10:21:41 +00:00
|
|
|
|
|
|
|
|
// create shadows before writing cache so we get nice shadows for sstartframe, too
|
|
|
|
|
if(get_lamp(scene, light))
|
|
|
|
|
smoke_calc_transparency(sds->shadow, smoke_get_density(sds->fluid), sds->p0, sds->p1, sds->res, sds->dx, light, calc_voxel_transp, -7.0*sds->dx);
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
BKE_ptcache_write_cache(&pid, framenr);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
if(sds->wt)
|
|
|
|
|
{
|
2009-09-14 00:01:08 +00:00
|
|
|
if(framenr!=startframe)
|
2009-10-02 11:09:05 +00:00
|
|
|
{
|
|
|
|
|
if(sds->flags & MOD_SMOKE_DISSOLVE)
|
|
|
|
|
smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
|
2009-09-14 00:01:08 +00:00
|
|
|
smoke_turbulence_step(sds->wt, sds->fluid);
|
2009-10-02 11:09:05 +00:00
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-09-14 00:01:08 +00:00
|
|
|
cache_wt->flag |= PTCACHE_SIMULATION_VALID;
|
|
|
|
|
cache_wt->simframe= framenr;
|
2009-09-09 18:39:40 +00:00
|
|
|
BKE_ptcache_write_cache(&pid_wt, framenr);
|
|
|
|
|
}
|
2009-08-20 00:33:59 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
tend();
|
2009-09-14 00:01:08 +00:00
|
|
|
printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() );
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct)
|
2009-08-20 00:33:59 +00:00
|
|
|
{
|
|
|
|
|
const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
|
|
|
|
|
|
|
|
|
|
// T_ray *= T_vox
|
2009-09-09 18:39:40 +00:00
|
|
|
*tRay *= exp(input[index]*correct);
|
|
|
|
|
|
|
|
|
|
if(result[index] < 0.0f)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
2009-09-09 18:39:40 +00:00
|
|
|
#pragma omp critical
|
|
|
|
|
result[index] = *tRay;
|
|
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
return *tRay;
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long long smoke_get_mem_req(int xres, int yres, int zres, int amplify)
|
|
|
|
|
{
|
|
|
|
|
int totalCells = xres * yres * zres;
|
|
|
|
|
int amplifiedCells = totalCells * amplify * amplify * amplify;
|
|
|
|
|
|
|
|
|
|
// print out memory requirements
|
|
|
|
|
long long int coarseSize = sizeof(float) * totalCells * 22 +
|
|
|
|
|
sizeof(unsigned char) * totalCells;
|
|
|
|
|
|
|
|
|
|
long long int fineSize = sizeof(float) * amplifiedCells * 7 + // big grids
|
|
|
|
|
sizeof(float) * totalCells * 8 + // small grids
|
|
|
|
|
sizeof(float) * 128 * 128 * 128; // noise tile
|
|
|
|
|
|
|
|
|
|
long long int totalMB = (coarseSize + fineSize) / (1024 * 1024);
|
|
|
|
|
|
|
|
|
|
return totalMB;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, float *tRay, bresenham_callback cb, float *result, float *input, int res[3], float correct)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
|
|
|
|
int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
|
|
|
|
|
int pixel[3];
|
|
|
|
|
|
|
|
|
|
pixel[0] = x1;
|
|
|
|
|
pixel[1] = y1;
|
|
|
|
|
pixel[2] = z1;
|
|
|
|
|
|
|
|
|
|
dx = x2 - x1;
|
|
|
|
|
dy = y2 - y1;
|
|
|
|
|
dz = z2 - z1;
|
|
|
|
|
|
|
|
|
|
x_inc = (dx < 0) ? -1 : 1;
|
|
|
|
|
l = abs(dx);
|
|
|
|
|
y_inc = (dy < 0) ? -1 : 1;
|
|
|
|
|
m = abs(dy);
|
|
|
|
|
z_inc = (dz < 0) ? -1 : 1;
|
|
|
|
|
n = abs(dz);
|
|
|
|
|
dx2 = l << 1;
|
|
|
|
|
dy2 = m << 1;
|
|
|
|
|
dz2 = n << 1;
|
|
|
|
|
|
|
|
|
|
if ((l >= m) && (l >= n)) {
|
|
|
|
|
err_1 = dy2 - l;
|
|
|
|
|
err_2 = dz2 - l;
|
|
|
|
|
for (i = 0; i < l; i++) {
|
2009-09-09 18:39:40 +00:00
|
|
|
if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
|
|
|
|
|
break;
|
2009-07-30 15:00:26 +00:00
|
|
|
if (err_1 > 0) {
|
|
|
|
|
pixel[1] += y_inc;
|
|
|
|
|
err_1 -= dx2;
|
|
|
|
|
}
|
|
|
|
|
if (err_2 > 0) {
|
|
|
|
|
pixel[2] += z_inc;
|
|
|
|
|
err_2 -= dx2;
|
|
|
|
|
}
|
|
|
|
|
err_1 += dy2;
|
|
|
|
|
err_2 += dz2;
|
|
|
|
|
pixel[0] += x_inc;
|
|
|
|
|
}
|
|
|
|
|
} else if ((m >= l) && (m >= n)) {
|
|
|
|
|
err_1 = dx2 - m;
|
|
|
|
|
err_2 = dz2 - m;
|
|
|
|
|
for (i = 0; i < m; i++) {
|
2009-09-09 18:39:40 +00:00
|
|
|
if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
|
|
|
|
|
break;
|
2009-07-30 15:00:26 +00:00
|
|
|
if (err_1 > 0) {
|
|
|
|
|
pixel[0] += x_inc;
|
|
|
|
|
err_1 -= dy2;
|
|
|
|
|
}
|
|
|
|
|
if (err_2 > 0) {
|
|
|
|
|
pixel[2] += z_inc;
|
|
|
|
|
err_2 -= dy2;
|
|
|
|
|
}
|
|
|
|
|
err_1 += dx2;
|
|
|
|
|
err_2 += dz2;
|
|
|
|
|
pixel[1] += y_inc;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
err_1 = dy2 - n;
|
|
|
|
|
err_2 = dx2 - n;
|
|
|
|
|
for (i = 0; i < n; i++) {
|
2009-09-09 18:39:40 +00:00
|
|
|
if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
|
|
|
|
|
break;
|
2009-07-30 15:00:26 +00:00
|
|
|
if (err_1 > 0) {
|
|
|
|
|
pixel[1] += y_inc;
|
|
|
|
|
err_1 -= dz2;
|
|
|
|
|
}
|
|
|
|
|
if (err_2 > 0) {
|
|
|
|
|
pixel[0] += x_inc;
|
|
|
|
|
err_2 -= dz2;
|
|
|
|
|
}
|
|
|
|
|
err_1 += dy2;
|
|
|
|
|
err_2 += dx2;
|
|
|
|
|
pixel[2] += z_inc;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-09 18:39:40 +00:00
|
|
|
cb(result, input, res, pixel, tRay, correct);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2009-08-20 00:33:59 +00:00
|
|
|
static void get_cell(float *p0, int res[3], float dx, float *pos, int *cell, int correct)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
|
|
|
|
float tmp[3];
|
|
|
|
|
|
2009-08-20 00:33:59 +00:00
|
|
|
VECSUB(tmp, pos, p0);
|
|
|
|
|
VecMulf(tmp, 1.0 / dx);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
if(correct)
|
|
|
|
|
{
|
2009-08-02 18:32:56 +00:00
|
|
|
cell[0] = MIN2(res[0] - 1, MAX2(0, (int)floor(tmp[0])));
|
|
|
|
|
cell[1] = MIN2(res[1] - 1, MAX2(0, (int)floor(tmp[1])));
|
|
|
|
|
cell[2] = MIN2(res[2] - 1, MAX2(0, (int)floor(tmp[2])));
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-08-02 18:32:56 +00:00
|
|
|
cell[0] = (int)floor(tmp[0]);
|
|
|
|
|
cell[1] = (int)floor(tmp[1]);
|
|
|
|
|
cell[2] = (int)floor(tmp[2]);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-14 16:52:06 +00:00
|
|
|
static void smoke_calc_transparency(float *result, float *input, float *p0, float *p1, int res[3], float dx, float *light, bresenham_callback cb, float correct)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
|
|
|
|
int x, y, z;
|
|
|
|
|
float bv[6];
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
memset(result, -1, sizeof(float)*res[0]*res[1]*res[2]); // x
|
2009-08-20 00:33:59 +00:00
|
|
|
bv[0] = p0[0];
|
|
|
|
|
bv[1] = p1[0];
|
2009-07-30 15:00:26 +00:00
|
|
|
// y
|
2009-08-20 00:33:59 +00:00
|
|
|
bv[2] = p0[1];
|
|
|
|
|
bv[3] = p1[1];
|
2009-07-30 15:00:26 +00:00
|
|
|
// z
|
2009-08-20 00:33:59 +00:00
|
|
|
bv[4] = p0[2];
|
|
|
|
|
bv[5] = p1[2];
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
#pragma omp parallel for schedule(static) private(y, z)
|
2009-07-30 15:00:26 +00:00
|
|
|
for(x = 0; x < res[0]; x++)
|
|
|
|
|
for(y = 0; y < res[1]; y++)
|
|
|
|
|
for(z = 0; z < res[2]; z++)
|
|
|
|
|
{
|
|
|
|
|
float voxelCenter[3];
|
|
|
|
|
size_t index;
|
|
|
|
|
float pos[3];
|
|
|
|
|
int cell[3];
|
|
|
|
|
float tRay = 1.0;
|
|
|
|
|
|
2009-07-30 20:12:40 +00:00
|
|
|
index = smoke_get_index(x, res[0], y, res[1], z);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
if(result[index] >= 0.0f)
|
|
|
|
|
continue;
|
2009-08-20 00:33:59 +00:00
|
|
|
voxelCenter[0] = p0[0] + dx * x + dx * 0.5;
|
|
|
|
|
voxelCenter[1] = p0[1] + dx * y + dx * 0.5;
|
|
|
|
|
voxelCenter[2] = p0[2] + dx * z + dx * 0.5;
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
// get starting position (in voxel coords)
|
|
|
|
|
if(BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON)
|
|
|
|
|
{
|
|
|
|
|
// we're ouside
|
2009-08-20 00:33:59 +00:00
|
|
|
get_cell(p0, res, dx, pos, cell, 1);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// we're inside
|
2009-08-20 00:33:59 +00:00
|
|
|
get_cell(p0, res, dx, light, cell, 1);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
bresenham_linie_3D(cell[0], cell[1], cell[2], x, y, z, &tRay, cb, result, input, res, correct);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2009-08-20 00:33:59 +00:00
|
|
|
// convention -> from a RGBA float array, use G value for tRay
|
2009-09-09 18:39:40 +00:00
|
|
|
// #pragma omp critical
|
|
|
|
|
result[index] = tRay;
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|