2011-02-23 10:52:22 +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,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2009-07-30 15:00:26 +00:00
|
|
|
*
|
|
|
|
|
* 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 *****
|
|
|
|
|
*/
|
|
|
|
|
|
2011-02-27 20:40:57 +00:00
|
|
|
/** \file blender/blenkernel/intern/smoke.c
|
|
|
|
|
* \ingroup bke
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
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>
|
2010-08-13 15:26:37 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#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"
|
2009-11-10 20:43:45 +00:00
|
|
|
#include "BLI_math.h"
|
2009-07-30 15:00:26 +00:00
|
|
|
#include "BLI_edgehash.h"
|
|
|
|
|
#include "BLI_kdtree.h"
|
|
|
|
|
#include "BLI_kdopbvh.h"
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2009-07-30 15:00:26 +00:00
|
|
|
|
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"
|
2011-01-07 19:18:31 +00:00
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
#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 );
|
|
|
|
|
}
|
2010-12-03 16:45:04 +00:00
|
|
|
static double tval( void )
|
2009-09-09 18:39:40 +00:00
|
|
|
{
|
|
|
|
|
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 );
|
|
|
|
|
}
|
2010-12-03 01:52:28 +00:00
|
|
|
|
|
|
|
|
#if 0 // unused
|
2009-07-30 15:00:26 +00:00
|
|
|
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
|
2010-12-03 01:52:28 +00:00
|
|
|
#endif
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
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.)
|
|
|
|
|
|
2011-07-13 18:40:21 +00:00
|
|
|
/* Stubs to use when smoke is disabled */
|
|
|
|
|
#ifndef WITH_SMOKE
|
|
|
|
|
struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype)) { return NULL; }
|
|
|
|
|
struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(p0)) { return NULL; }
|
|
|
|
|
void smoke_free(struct FLUID_3D *UNUSED(fluid)) {}
|
|
|
|
|
void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) {}
|
|
|
|
|
void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) {}
|
|
|
|
|
void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity), int *UNUSED(border_colli)) {}
|
|
|
|
|
long long smoke_get_mem_req(int UNUSED(xres), int UNUSED(yres), int UNUSED(zres), int UNUSED(amplify)) { return 0; }
|
|
|
|
|
void smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) {}
|
|
|
|
|
#endif // WITH_SMOKE
|
|
|
|
|
|
|
|
|
|
|
2011-02-14 17:55:27 +00:00
|
|
|
static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
|
|
|
|
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);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(ob->obmat, tmp);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
// 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])
|
|
|
|
|
{
|
2010-11-25 22:13:40 +00:00
|
|
|
if(size[0] > size[2])
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
{
|
2010-11-25 22:13:40 +00:00
|
|
|
scale = res / size[2];
|
|
|
|
|
smd->domain->dx = size[2] / res;
|
|
|
|
|
smd->domain->res[2] = res;
|
2009-07-30 15:00:26 +00:00
|
|
|
smd->domain->res[0] = (int)(size[0] * scale + 0.5);
|
2010-11-25 22:13:40 +00:00
|
|
|
smd->domain->res[1] = (int)(size[1] * scale + 0.5);
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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
|
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
|
|
|
smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0);
|
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 Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
|
|
|
smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta), &(smd->domain->time_scale), &(smd->domain->vorticity), &(smd->domain->border_collisions));
|
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
|
2009-11-10 20:43:45 +00:00
|
|
|
// copy_m4_m4(smd->flow->mat, ob->obmat);
|
|
|
|
|
// copy_m4_m4(smd->flow->mat_old, ob->obmat);
|
2009-08-12 17:32:02 +00:00
|
|
|
}
|
|
|
|
|
*/
|
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
|
2009-11-10 20:43:45 +00:00
|
|
|
copy_m4_m4(scs->mat, ob->obmat);
|
|
|
|
|
copy_m4_m4(scs->mat_old, ob->obmat);
|
2009-08-06 16:50:02 +00:00
|
|
|
|
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
|
|
|
|
2010-08-01 15:00:53 +00:00
|
|
|
return 2;
|
2009-10-02 14:40:51 +00:00
|
|
|
}
|
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);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(ob->obmat, tmpvec);
|
2009-10-02 14:40:51 +00:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
cross_v3_v3v3(trinormorg, side1, side2);
|
|
|
|
|
normalize_v3(trinormorg);
|
2009-10-02 14:40:51 +00:00
|
|
|
VECCOPY(trinorm, trinormorg);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(trinorm, 0.25 * cell_len);
|
2009-10-02 14:40:51 +00:00
|
|
|
|
|
|
|
|
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-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(p1, (1.0-uf-vf));
|
|
|
|
|
mul_v3_fl(p2, uf);
|
|
|
|
|
mul_v3_fl(p3, vf);
|
2009-10-02 14:40:51 +00:00
|
|
|
|
|
|
|
|
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);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(ob->obmat, tmpvec);
|
2009-10-02 14:40:51 +00:00
|
|
|
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);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(ob->obmat, tmpvec);
|
2009-10-02 14:40:51 +00:00
|
|
|
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 */
|
2010-10-16 14:32:17 +00:00
|
|
|
void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
|
|
|
|
// 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);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(ob->obmat, p0);
|
2009-07-30 15:00:26 +00:00
|
|
|
VECCOPY(p1, verts[faces[i].v2].co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(ob->obmat, p1);
|
2009-07-30 15:00:26 +00:00
|
|
|
VECCOPY(p2, verts[faces[i].v3].co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(ob->obmat, p2);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
VECSUB(side1, p1, p0);
|
|
|
|
|
VECSUB(side2, p2, p0);
|
|
|
|
|
VECSUB(side3, p1, p2);
|
|
|
|
|
|
|
|
|
|
if(INPR(side1, side1) > fsTri*fsTri)
|
|
|
|
|
{
|
2009-11-10 20:43:45 +00:00
|
|
|
float tmp = normalize_v3(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)
|
|
|
|
|
{
|
2009-11-10 20:43:45 +00:00
|
|
|
float tmp = normalize_v3(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);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(ob->obmat, p0);
|
2009-08-06 16:50:02 +00:00
|
|
|
VECCOPY(p1, verts[faces[i].v4].co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(ob->obmat, p1);
|
2009-08-06 16:50:02 +00:00
|
|
|
VECCOPY(p2, verts[faces[i].v1].co);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_m4_v3(ob->obmat, p2);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
VECSUB(side1, p1, p0);
|
|
|
|
|
VECSUB(side2, p2, p0);
|
|
|
|
|
VECSUB(side3, p1, p2);
|
|
|
|
|
|
|
|
|
|
if(INPR(side1, side1) > fsTri*fsTri)
|
|
|
|
|
{
|
2009-11-10 20:43:45 +00:00
|
|
|
float tmp = normalize_v3(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)
|
|
|
|
|
{
|
2009-11-10 20:43:45 +00:00
|
|
|
float tmp = normalize_v3(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;
|
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-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;
|
|
|
|
|
|
2010-11-30 21:31:18 +00:00
|
|
|
/* Deprecated */
|
|
|
|
|
smd->domain->point_cache[1] = NULL;
|
|
|
|
|
smd->domain->ptcaches[1].first = smd->domain->ptcaches[1].last = NULL;
|
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;
|
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
|
|
|
smd->domain->time_scale = 1.0;
|
|
|
|
|
smd->domain->vorticity = 2.0;
|
|
|
|
|
smd->domain->border_collisions = 1; // vertically non-colliding
|
|
|
|
|
smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG | MOD_SMOKE_HIGH_SMOOTH;
|
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;
|
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
|
|
|
// init 3dview buffer
|
|
|
|
|
|
|
|
|
|
smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG;
|
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;
|
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
|
|
|
smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE;
|
|
|
|
|
smd->flow->vel_multi = 1.0;
|
2009-07-30 15:00:26 +00:00
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-14 07:09:15 +00:00
|
|
|
void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData *tsmd)
|
|
|
|
|
{
|
|
|
|
|
tsmd->type = smd->type;
|
|
|
|
|
tsmd->time = smd->time;
|
|
|
|
|
|
|
|
|
|
smokeModifier_createType(tsmd);
|
|
|
|
|
|
|
|
|
|
if (tsmd->domain) {
|
|
|
|
|
tsmd->domain->maxres = smd->domain->maxres;
|
|
|
|
|
tsmd->domain->amplify = smd->domain->amplify;
|
|
|
|
|
tsmd->domain->omega = smd->domain->omega;
|
|
|
|
|
tsmd->domain->alpha = smd->domain->alpha;
|
|
|
|
|
tsmd->domain->beta = smd->domain->beta;
|
|
|
|
|
tsmd->domain->flags = smd->domain->flags;
|
|
|
|
|
tsmd->domain->strength = smd->domain->strength;
|
|
|
|
|
tsmd->domain->noise = smd->domain->noise;
|
|
|
|
|
tsmd->domain->diss_speed = smd->domain->diss_speed;
|
|
|
|
|
tsmd->domain->viewsettings = smd->domain->viewsettings;
|
|
|
|
|
tsmd->domain->fluid_group = smd->domain->fluid_group;
|
|
|
|
|
tsmd->domain->coll_group = smd->domain->coll_group;
|
2010-12-01 02:28:08 +00:00
|
|
|
tsmd->domain->vorticity = smd->domain->vorticity;
|
|
|
|
|
tsmd->domain->time_scale = smd->domain->time_scale;
|
|
|
|
|
tsmd->domain->border_collisions = smd->domain->border_collisions;
|
2010-05-14 07:09:15 +00:00
|
|
|
|
|
|
|
|
MEM_freeN(tsmd->domain->effector_weights);
|
|
|
|
|
tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights);
|
|
|
|
|
} else if (tsmd->flow) {
|
|
|
|
|
tsmd->flow->density = smd->flow->density;
|
|
|
|
|
tsmd->flow->temp = smd->flow->temp;
|
|
|
|
|
tsmd->flow->psys = smd->flow->psys;
|
|
|
|
|
tsmd->flow->type = smd->flow->type;
|
2010-12-01 02:28:08 +00:00
|
|
|
tsmd->flow->flags = smd->flow->flags;
|
|
|
|
|
tsmd->flow->vel_multi = smd->flow->vel_multi;
|
2010-05-14 07:09:15 +00:00
|
|
|
} else if (tsmd->coll) {
|
|
|
|
|
;
|
|
|
|
|
/* leave it as initialised, collision settings is mostly caches */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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);
|
2011-07-13 18:40:21 +00:00
|
|
|
|
|
|
|
|
#ifdef WITH_SMOKE
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
static int get_lamp(Scene *scene, float *light)
|
|
|
|
|
{
|
|
|
|
|
Base *base_tmp = NULL;
|
2010-09-30 20:19:54 +00:00
|
|
|
int found_lamp = 0;
|
|
|
|
|
|
|
|
|
|
// try to find a lamp, preferably local
|
|
|
|
|
for(base_tmp = scene->base.first; base_tmp; base_tmp= base_tmp->next) {
|
|
|
|
|
if(base_tmp->object->type == OB_LAMP) {
|
|
|
|
|
Lamp *la = base_tmp->object->data;
|
|
|
|
|
|
|
|
|
|
if(la->type == LA_LOCAL) {
|
|
|
|
|
copy_v3_v3(light, base_tmp->object->obmat[3]);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else if(!found_lamp) {
|
|
|
|
|
copy_v3_v3(light, base_tmp->object->obmat[3]);
|
|
|
|
|
found_lamp = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return found_lamp;
|
2009-09-09 18:39:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd)
|
|
|
|
|
{
|
|
|
|
|
SmokeDomainSettings *sds = smd->domain;
|
|
|
|
|
GroupObject *go = NULL;
|
|
|
|
|
Base *base = NULL;
|
|
|
|
|
|
2010-11-23 14:40:27 +00:00
|
|
|
// do collisions, needs to be done before emission, so that smoke isn't emitted inside collision cells
|
|
|
|
|
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 && smd2->coll->points)
|
|
|
|
|
{
|
|
|
|
|
// 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;
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(sds->coll_group)
|
|
|
|
|
go = go->next;
|
|
|
|
|
else
|
|
|
|
|
base= base->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
// do flows and fluids
|
|
|
|
|
if(1)
|
2010-11-23 14:40:27 +00:00
|
|
|
{
|
2009-09-09 18:39:40 +00:00
|
|
|
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;
|
|
|
|
|
|
2009-10-29 19:26:13 +00:00
|
|
|
if(sfs && sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
|
2009-09-09 18:39:40 +00:00
|
|
|
{
|
2010-12-15 17:05:34 +00:00
|
|
|
ParticleSimulationData sim;
|
2009-09-09 18:39:40 +00:00
|
|
|
ParticleSystem *psys = sfs->psys;
|
|
|
|
|
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);
|
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
|
|
|
int bigres[3];
|
|
|
|
|
short absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
|
|
|
|
|
short high_emission_smoothing = bigdensity ? (smd->domain->flags & MOD_SMOKE_HIGH_SMOOTH) : 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* A temporary volume map used to store whole emissive
|
|
|
|
|
* area to be added to smoke density and interpolated
|
|
|
|
|
* for high resolution smoke.
|
|
|
|
|
*/
|
|
|
|
|
float *temp_emission_map = NULL;
|
|
|
|
|
|
2010-12-15 17:05:34 +00:00
|
|
|
sim.scene = scene;
|
|
|
|
|
sim.ob = otherobj;
|
|
|
|
|
sim.psys = psys;
|
|
|
|
|
|
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
|
|
|
// initialize temp emission map
|
|
|
|
|
if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW))
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
temp_emission_map = MEM_callocN(sizeof(float) * sds->res[0]*sds->res[1]*sds->res[2], "SmokeTempEmission");
|
|
|
|
|
// set whole volume to 0.0f
|
|
|
|
|
for (i=0; i<sds->res[0]*sds->res[1]*sds->res[2]; i++) {
|
|
|
|
|
temp_emission_map[i] = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-09 18:39:40 +00:00
|
|
|
|
|
|
|
|
// mostly copied from particle code
|
2010-12-15 17:05:34 +00:00
|
|
|
for(p=0; p<psys->totpart; p++)
|
|
|
|
|
{
|
|
|
|
|
int cell[3];
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
size_t index = 0;
|
|
|
|
|
int badcell = 0;
|
|
|
|
|
ParticleKey state;
|
|
|
|
|
|
|
|
|
|
if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
state.time = smd->time;
|
|
|
|
|
|
|
|
|
|
if(psys_get_particle_state(&sim, p, &state, 0) == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
// VECCOPY(pos, pa->state.co);
|
2009-11-10 20:43:45 +00:00
|
|
|
// mul_m4_v3(ob->imat, pos);
|
2009-09-14 00:01:08 +00:00
|
|
|
// 1. get corresponding cell
|
2010-12-15 17:05:34 +00:00
|
|
|
get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, state.co, cell, 0);
|
2009-09-09 18:39:40 +00:00
|
|
|
// 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]);
|
2010-11-23 14:40:27 +00:00
|
|
|
if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) && !(obstacle[index])) // this is inflow
|
2009-09-09 18:39:40 +00:00
|
|
|
{
|
|
|
|
|
// heat[index] += sfs->temp * 0.1;
|
|
|
|
|
// density[index] += sfs->density * 0.1;
|
|
|
|
|
heat[index] = sfs->temp;
|
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
|
|
|
|
|
|
|
|
// Add emitter density to temp emission map
|
|
|
|
|
temp_emission_map[index] = sfs->density;
|
2009-09-09 18:39:40 +00:00
|
|
|
|
2010-01-25 15:10:14 +00:00
|
|
|
// Uses particle velocity as initial velocity for smoke
|
2010-07-27 16:18:12 +00:00
|
|
|
if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO))
|
|
|
|
|
{
|
2010-12-15 17:05:34 +00:00
|
|
|
velocity_x[index] = state.vel[0]*sfs->vel_multi;
|
|
|
|
|
velocity_y[index] = state.vel[1]*sfs->vel_multi;
|
|
|
|
|
velocity_z[index] = state.vel[2]*sfs->vel_multi;
|
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
|
|
|
}
|
2009-09-09 18:39:40 +00:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} // particles loop
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// apply emission values
|
|
|
|
|
if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) {
|
|
|
|
|
|
|
|
|
|
// initialize variables
|
|
|
|
|
int ii, jj, kk, x, y, z, block_size;
|
|
|
|
|
size_t index, index_big;
|
|
|
|
|
|
|
|
|
|
smoke_turbulence_get_res(smd->domain->wt, bigres);
|
|
|
|
|
block_size = smd->domain->amplify + 1; // high res block size
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// loop through every low res cell
|
|
|
|
|
for(x = 0; x < sds->res[0]; x++)
|
|
|
|
|
for(y = 0; y < sds->res[1]; y++)
|
|
|
|
|
for(z = 0; z < sds->res[2]; z++)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// neighbour cell emission densities (for high resolution smoke smooth interpolation)
|
|
|
|
|
float c000, c001, c010, c011, c100, c101, c110, c111;
|
|
|
|
|
|
|
|
|
|
c000 = (x>0 && y>0 && z>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y-1, sds->res[1], z-1)] : 0;
|
|
|
|
|
c001 = (x>0 && y>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y-1, sds->res[1], z)] : 0;
|
|
|
|
|
c010 = (x>0 && z>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y, sds->res[1], z-1)] : 0;
|
|
|
|
|
c011 = (x>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y, sds->res[1], z)] : 0;
|
|
|
|
|
|
|
|
|
|
c100 = (y>0 && z>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y-1, sds->res[1], z-1)] : 0;
|
|
|
|
|
c101 = (y>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y-1, sds->res[1], z)] : 0;
|
|
|
|
|
c110 = (z>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y, sds->res[1], z-1)] : 0;
|
|
|
|
|
c111 = temp_emission_map[smoke_get_index(x, sds->res[0], y, sds->res[1], z)]; // this cell
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// get cell index
|
|
|
|
|
index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
|
|
|
|
|
|
|
|
|
|
// add emission to low resolution density
|
|
|
|
|
if (absolute_flow) {if (temp_emission_map[index]>0) density[index] = temp_emission_map[index];}
|
|
|
|
|
else {
|
|
|
|
|
density[index] += temp_emission_map[index];
|
|
|
|
|
if (density[index]>1) density[index]=1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smoke_turbulence_get_res(smd->domain->wt, bigres);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
loop through high res blocks if high res enabled
|
|
|
|
|
*/
|
|
|
|
|
if (bigdensity)
|
|
|
|
|
for(ii = 0; ii < block_size; ii++)
|
|
|
|
|
for(jj = 0; jj < block_size; jj++)
|
|
|
|
|
for(kk = 0; kk < block_size; kk++)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
float fx,fy,fz, interpolated_value;
|
|
|
|
|
int shift_x, shift_y, shift_z;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Do volume interpolation if emitter smoothing
|
|
|
|
|
* is enabled
|
|
|
|
|
*/
|
|
|
|
|
if (high_emission_smoothing) {
|
|
|
|
|
// convert block position to relative
|
|
|
|
|
// for interpolation smoothing
|
|
|
|
|
fx = (float)ii/block_size + 0.5f/block_size;
|
|
|
|
|
fy = (float)jj/block_size + 0.5f/block_size;
|
|
|
|
|
fz = (float)kk/block_size + 0.5f/block_size;
|
|
|
|
|
|
|
|
|
|
// calculate trilinear interpolation
|
|
|
|
|
interpolated_value = c000 * (1-fx) * (1-fy) * (1-fz) +
|
|
|
|
|
c100 * fx * (1-fy) * (1-fz) +
|
|
|
|
|
c010 * (1-fx) * fy * (1-fz) +
|
|
|
|
|
c001 * (1-fx) * (1-fy) * fz +
|
|
|
|
|
c101 * fx * (1-fy) * fz +
|
|
|
|
|
c011 * (1-fx) * fy * fz +
|
|
|
|
|
c110 * fx * fy * (1-fz) +
|
|
|
|
|
c111 * fx * fy * fz;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// add some contrast / sharpness
|
|
|
|
|
// depending on hi-res block size
|
|
|
|
|
|
|
|
|
|
interpolated_value = (interpolated_value-0.4f*sfs->density)*(block_size/2) + 0.4f*sfs->density;
|
|
|
|
|
if (interpolated_value<0.0f) interpolated_value = 0.0f;
|
|
|
|
|
if (interpolated_value>1.0f) interpolated_value = 1.0f;
|
|
|
|
|
|
|
|
|
|
// shift smoke block index
|
|
|
|
|
// (because pixel center is actually
|
|
|
|
|
// in halfway of the low res block)
|
|
|
|
|
shift_x = (x < 1) ? 0 : block_size/2;
|
|
|
|
|
shift_y = (y < 1) ? 0 : block_size/2;
|
|
|
|
|
shift_z = (z < 1) ? 0 : block_size/2;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// without interpolation use same low resolution
|
|
|
|
|
// block value for all hi-res blocks
|
|
|
|
|
interpolated_value = c111;
|
|
|
|
|
shift_x = 0;
|
|
|
|
|
shift_y = 0;
|
|
|
|
|
shift_z = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get shifted index for current high resolution block
|
|
|
|
|
index_big = smoke_get_index(block_size * x + ii - shift_x, bigres[0], block_size * y + jj - shift_y, bigres[1], block_size * z + kk - shift_z);
|
|
|
|
|
|
|
|
|
|
// add emission data to high resolution density
|
|
|
|
|
if (absolute_flow) {if (interpolated_value > 0) bigdensity[index_big] = interpolated_value;}
|
|
|
|
|
else {
|
|
|
|
|
bigdensity[index_big] += interpolated_value;
|
|
|
|
|
if (bigdensity[index_big]>1) bigdensity[index_big]=1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // end of hires loop
|
|
|
|
|
|
|
|
|
|
} // end of low res loop
|
|
|
|
|
|
|
|
|
|
// free temporary emission map
|
|
|
|
|
if (temp_emission_map) MEM_freeN(temp_emission_map);
|
|
|
|
|
|
|
|
|
|
} // end emission
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}*/
|
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
|
|
|
}
|
2009-09-09 18:39:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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;
|
2009-10-08 15:19:57 +00:00
|
|
|
float voxelCenter[3] = {0,0,0} , vel[3] = {0,0,0} , retvel[3] = {0,0,0};
|
2009-10-08 10:18:14 +00:00
|
|
|
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!
|
2009-10-08 15:19:57 +00:00
|
|
|
force_x[index] = MIN2(MAX2(-1.0, retvel[0] * 0.2), 1.0);
|
|
|
|
|
force_y[index] = MIN2(MAX2(-1.0, retvel[1] * 0.2), 1.0);
|
|
|
|
|
force_z[index] = MIN2(MAX2(-1.0, retvel[2] * 0.2), 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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2010-10-21 01:10:22 +00:00
|
|
|
void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
|
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
|
|
|
|
|
/*
|
2009-11-10 20:43:45 +00:00
|
|
|
copy_m4_m4(smd->flow->mat_old, smd->flow->mat);
|
|
|
|
|
copy_m4_m4(smd->flow->mat, ob->obmat);
|
2009-08-12 17:32:02 +00:00
|
|
|
*/
|
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
|
2009-11-10 20:43:45 +00:00
|
|
|
copy_m4_m4(smd->coll->mat_old, smd->coll->mat);
|
|
|
|
|
copy_m4_m4(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-14 00:01:08 +00:00
|
|
|
int startframe, endframe, framenr;
|
2009-08-20 00:33:59 +00:00
|
|
|
float timescale;
|
|
|
|
|
|
|
|
|
|
framenr = scene->r.cfra;
|
|
|
|
|
|
2010-11-30 21:31:18 +00:00
|
|
|
//printf("time: %d\n", scene->r.cfra);
|
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);
|
|
|
|
|
|
2010-09-27 12:24:12 +00:00
|
|
|
if(!smd->domain->fluid || framenr == startframe)
|
2009-09-14 17:22:51 +00:00
|
|
|
{
|
|
|
|
|
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
|
2010-09-27 12:24:12 +00:00
|
|
|
BKE_ptcache_validate(cache, framenr);
|
|
|
|
|
cache->flag &= ~PTCACHE_REDO_NEEDED;
|
2009-09-14 17:22:51 +00:00
|
|
|
}
|
|
|
|
|
|
2010-11-23 14:04:05 +00:00
|
|
|
if(!smd->domain->fluid && (framenr != startframe) && (smd->domain->flags & MOD_SMOKE_FILE_LOAD)==0 && (cache->flag & PTCACHE_BAKED)==0)
|
2009-08-20 00:33:59 +00:00
|
|
|
return;
|
2009-09-09 18:39:40 +00:00
|
|
|
|
2010-11-23 14:04:05 +00:00
|
|
|
smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD;
|
|
|
|
|
|
2010-11-30 21:31:18 +00:00
|
|
|
CLAMP(framenr, startframe, endframe);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2010-11-11 17:59:52 +00:00
|
|
|
/* If already viewing a pre/after frame, no need to reload */
|
|
|
|
|
if ((smd->time == framenr) && (framenr != scene->r.cfra))
|
2009-09-14 17:22:51 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// printf("startframe: %d, framenr: %d\n", startframe, framenr);
|
2009-09-09 18:39:40 +00:00
|
|
|
|
2010-11-30 21:31:18 +00:00
|
|
|
if(smokeModifier_init(smd, ob, scene, dm)==0)
|
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 */
|
2011-01-02 06:52:47 +00:00
|
|
|
if(BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT) {
|
2010-03-21 20:36:06 +00:00
|
|
|
BKE_ptcache_validate(cache, framenr);
|
2010-09-27 12:24:12 +00:00
|
|
|
smd->time = framenr;
|
2010-11-30 21:31:18 +00:00
|
|
|
return;
|
2009-08-20 00:33:59 +00:00
|
|
|
}
|
2010-11-30 21:31:18 +00:00
|
|
|
|
2010-09-27 12:24:12 +00:00
|
|
|
/* only calculate something when we advanced a single frame */
|
2010-11-30 21:31:18 +00:00
|
|
|
if(framenr != (int)smd->time+1)
|
2010-04-01 14:44:31 +00:00
|
|
|
return;
|
|
|
|
|
|
2010-11-11 17:59:52 +00:00
|
|
|
/* don't simulate if viewing start frame, but scene frame is not real start frame */
|
|
|
|
|
if (framenr != scene->r.cfra)
|
|
|
|
|
return;
|
|
|
|
|
|
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);
|
2010-09-27 12:24:12 +00:00
|
|
|
|
|
|
|
|
/* if on second frame, write cache for first frame */
|
|
|
|
|
if((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) {
|
2010-10-30 08:51:50 +00:00
|
|
|
// create shadows straight after domain initialization so we get nice shadows for startframe, 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);
|
|
|
|
|
|
2010-09-27 12:24:12 +00:00
|
|
|
if(sds->wt)
|
2010-11-30 21:31:18 +00:00
|
|
|
{
|
|
|
|
|
if(sds->flags & MOD_SMOKE_DISSOLVE)
|
|
|
|
|
smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
|
|
|
|
|
smoke_turbulence_step(sds->wt, sds->fluid);
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-18 15:03:31 +00:00
|
|
|
BKE_ptcache_write(&pid, startframe);
|
2010-09-27 12:24:12 +00:00
|
|
|
}
|
2009-09-09 18:39:40 +00:00
|
|
|
|
|
|
|
|
// 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
|
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);
|
2010-07-27 15:33:21 +00:00
|
|
|
smoke_step(sds->fluid, smd->time, scene->r.frs_sec / scene->r.frs_sec_base);
|
2009-10-02 11:09:05 +00:00
|
|
|
}
|
2009-09-14 10:21:41 +00:00
|
|
|
|
2010-10-30 08:51:50 +00:00
|
|
|
// create shadows before writing cache so they get stored
|
2009-09-14 10:21:41 +00:00
|
|
|
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-07-30 15:00:26 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
if(sds->wt)
|
|
|
|
|
{
|
2010-11-30 21:31:18 +00:00
|
|
|
if(sds->flags & MOD_SMOKE_DISSOLVE)
|
|
|
|
|
smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
|
|
|
|
|
smoke_turbulence_step(sds->wt, sds->fluid);
|
2009-09-09 18:39:40 +00:00
|
|
|
}
|
2010-11-30 21:31:18 +00:00
|
|
|
|
|
|
|
|
BKE_ptcache_validate(cache, framenr);
|
|
|
|
|
if(framenr != startframe)
|
2010-12-18 15:03:31 +00:00
|
|
|
BKE_ptcache_write(&pid, framenr);
|
2009-08-20 00:33:59 +00:00
|
|
|
|
2009-09-09 18:39:40 +00:00
|
|
|
tend();
|
2010-11-30 21:31:18 +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)
|
|
|
|
|
{
|
2011-04-21 15:53:30 +00:00
|
|
|
int totalCells = xres * yres * zres;
|
|
|
|
|
int amplifiedCells = totalCells * amplify * amplify * amplify;
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2011-04-21 15:53:30 +00:00
|
|
|
// print out memory requirements
|
|
|
|
|
long long int coarseSize = sizeof(float) * totalCells * 22 +
|
|
|
|
|
sizeof(unsigned char) * totalCells;
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2011-04-21 15:53:30 +00:00
|
|
|
long long int fineSize = sizeof(float) * amplifiedCells * 7 + // big grids
|
|
|
|
|
sizeof(float) * totalCells * 8 + // small grids
|
|
|
|
|
sizeof(float) * 128 * 128 * 128; // noise tile
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2011-04-21 15:53:30 +00:00
|
|
|
long long int totalMB = (coarseSize + fineSize) / (1024 * 1024);
|
2009-07-30 15:00:26 +00:00
|
|
|
|
2011-04-21 15:53:30 +00:00
|
|
|
return totalMB;
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
2010-03-22 09:30:00 +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++) {
|
|
|
|
|
if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
|
|
|
|
|
break;
|
|
|
|
|
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++) {
|
|
|
|
|
if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
|
|
|
|
|
break;
|
|
|
|
|
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++) {
|
|
|
|
|
if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
|
|
|
|
|
break;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(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
|
|
|
{
|
|
|
|
|
float bv[6];
|
2010-03-12 14:42:03 +00:00
|
|
|
int a, z, slabsize=res[0]*res[1], size= res[0]*res[1]*res[2];
|
|
|
|
|
|
|
|
|
|
for(a=0; a<size; a++)
|
|
|
|
|
result[a]= -1.0f;
|
2009-07-30 15:00:26 +00:00
|
|
|
|
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
|
|
|
|
2010-01-25 15:10:14 +00:00
|
|
|
#pragma omp parallel for schedule(static,1)
|
|
|
|
|
for(z = 0; z < res[2]; z++)
|
|
|
|
|
{
|
|
|
|
|
size_t index = z*slabsize;
|
|
|
|
|
int x,y;
|
|
|
|
|
|
2009-07-30 15:00:26 +00:00
|
|
|
for(y = 0; y < res[1]; y++)
|
2010-01-25 15:10:14 +00:00
|
|
|
for(x = 0; x < res[0]; x++, index++)
|
2009-07-30 15:00:26 +00:00
|
|
|
{
|
|
|
|
|
float voxelCenter[3];
|
|
|
|
|
float pos[3];
|
|
|
|
|
int cell[3];
|
|
|
|
|
float tRay = 1.0;
|
|
|
|
|
|
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
|
|
|
}
|
2010-01-25 15:10:14 +00:00
|
|
|
}
|
2009-07-30 15:00:26 +00:00
|
|
|
}
|
|
|
|
|
|
2011-07-13 18:40:21 +00:00
|
|
|
#endif // WITH_SMOKE
|