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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/smoke.c')
-rw-r--r--source/blender/blenkernel/intern/smoke.c1536
1 files changed, 954 insertions, 582 deletions
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 9d13397859d..f3939a2ebfc 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -21,6 +21,7 @@
* The Original Code is: all of this file.
*
* Contributor(s): Daniel Genrich
+ * Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -53,6 +54,7 @@
#include "BKE_bvhutils.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_collision.h"
#include "BKE_customdata.h"
#include "BKE_DerivedMesh.h"
#include "BKE_effect.h"
@@ -118,7 +120,6 @@ static void tend ( void )
gettimeofday ( &_tend,&tz );
}
-#if 0 // unused
static double tval()
{
double t1, t2;
@@ -127,14 +128,16 @@ static double tval()
return t2-t1;
}
#endif
-#endif
struct Object;
struct Scene;
struct DerivedMesh;
struct SmokeModifierData;
-#define TRI_UVOFFSET (1.0 / 4.0)
+#define TRI_UVOFFSET (1./4.)
+
+// timestep default value for nice appearance 0.1f
+#define DT_DEFAULT 0.1f
/* forward declerations */
static void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int numfaces, int numtris, int **tridivs, float cell_len);
@@ -159,7 +162,7 @@ void smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Obje
static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
{
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
+ 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};
@@ -171,7 +174,7 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene,
res = smd->domain->maxres;
// get BB of domain
- for (i = 0; i < dm->getNumVerts(dm); i++)
+ for(i = 0; i < dm->getNumVerts(dm); i++)
{
float tmp[3];
@@ -198,32 +201,32 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene,
// printf("size: %f, %f, %f\n", size[0], size[1], size[2]);
// prevent crash when initializing a plane as domain
- if ((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON))
+ if((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON))
return 0;
- if (size[0] > size[1])
+ if(size[0] > size[1])
{
- if (size[0] > size[2])
+ if(size[0] > size[2])
{
scale = res / size[0];
- smd->domain->dx = size[0] / res;
+ smd->domain->dx = size[0] / res; // dx is in global coords
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[2];
- smd->domain->dx = size[2] / res;
+ smd->domain->dx = size[2] / res; // dx is in global coords
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);
}
}
else {
- if (size[1] > size[2])
+ if(size[1] > size[2])
{
scale = res / size[1];
- smd->domain->dx = size[1] / res;
+ smd->domain->dx = size[1] / res; // dx is in global coords
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);
@@ -243,10 +246,10 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene,
// printf("res[0]: %d, res[1]: %d, res[2]: %d\n", smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]);
// dt max is 0.1
- smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0);
+ smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0, DT_DEFAULT);
smd->time = scene->r.cfra;
- if (smd->domain->flags & MOD_SMOKE_HIGHRES)
+ if(smd->domain->flags & MOD_SMOKE_HIGHRES)
{
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);
@@ -257,19 +260,19 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene,
// printf("(smd->domain->flags & MOD_SMOKE_HIGHRES)\n");
}
- if (!smd->domain->shadow)
+ if(!smd->domain->shadow)
smd->domain->shadow = MEM_callocN(sizeof(float) * smd->domain->res[0] * smd->domain->res[1] * smd->domain->res[2], "SmokeDomainShadow");
smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta), &(smd->domain->time_scale), &(smd->domain->vorticity), &(smd->domain->border_collisions));
- if (smd->domain->wt)
+ if(smd->domain->wt)
{
smoke_initWaveletBlenderRNA(smd->domain->wt, &(smd->domain->strength));
// printf("smoke_initWaveletBlenderRNA\n");
}
return 1;
}
- else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
+ else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
{
// handle flow object here
// XXX TODO
@@ -288,7 +291,7 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene,
}
/*
- if (!smd->flow->bvh)
+ 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);
@@ -301,28 +304,33 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene,
return 1;
}
- else if ((smd->type & MOD_SMOKE_TYPE_COLL))
+ else if((smd->type & MOD_SMOKE_TYPE_COLL))
{
- smd->time = scene->r.cfra;
-
// todo: delete this when loading colls work -dg
- if (!smd->coll)
+
+ if(!smd->coll)
+ {
smokeModifier_createType(smd);
+ }
- if (!smd->coll->points)
+ if(!smd->coll->points)
{
// init collision points
SmokeCollSettings *scs = smd->coll;
+ smd->time = scene->r.cfra;
+
// copy obmat
copy_m4_m4(scs->mat, ob->obmat);
copy_m4_m4(scs->mat_old, ob->obmat);
DM_ensure_tessface(dm);
fill_scs_points(ob, dm, scs);
+
+ // DEBUG printf("scs->dx: %f\n", scs->dx);
}
- if (!smd->coll->bvhtree)
+ if(!smd->coll->bvhtree)
{
smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getTessFaceArray(dm), dm->getNumTessFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
}
@@ -337,50 +345,52 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
MVert *mvert = dm->getVertArray(dm);
MFace *mface = dm->getTessFaceArray(dm);
int i = 0, divs = 0;
- int *tridivs = NULL;
- float cell_len = 1.0 / 50.0; // for res = 50
+
+ // DG TODO: need to do this dynamically according to the domain object!
+ float cell_len = scs->dx;
int newdivs = 0;
int quads = 0, facecounter = 0;
// count quads
- for (i = 0; i < dm->getNumTessFaces(dm); i++)
+ for(i = 0; i < dm->getNumTessFaces(dm); i++)
{
- if (mface[i].v4)
+ if(mface[i].v4)
quads++;
}
- calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumTessFaces(dm), dm->getNumTessFaces(dm) + quads, &tridivs, cell_len);
+ scs->numtris = dm->getNumTessFaces(dm) + quads;
+ scs->tridivs = NULL;
+ calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumTessFaces(dm), scs->numtris, &(scs->tridivs), cell_len);
// count triangle divisions
- for (i = 0; i < dm->getNumTessFaces(dm) + quads; i++)
+ for(i = 0; i < dm->getNumTessFaces(dm) + quads; i++)
{
- divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1);
+ divs += (scs->tridivs[3 * i] + 1) * (scs->tridivs[3 * i + 1] + 1) * (scs->tridivs[3 * i + 2] + 1);
}
- // printf("divs: %d\n", divs);
-
scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints");
+ scs->points_old = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPointsOld");
- for (i = 0; i < dm->getNumVerts(dm); i++)
+ for(i = 0; i < dm->getNumVerts(dm); i++)
{
float tmpvec[3];
copy_v3_v3(tmpvec, mvert[i].co);
- mul_m4_v3(ob->obmat, tmpvec);
+ // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
copy_v3_v3(&scs->points[i * 3], tmpvec);
}
- for (i = 0, facecounter = 0; i < dm->getNumTessFaces(dm); i++)
+ for(i = 0, facecounter = 0; i < dm->getNumTessFaces(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];
+ int divs1 = scs->tridivs[3 * facecounter + 0];
+ int divs2 = scs->tridivs[3 * facecounter + 1];
+ //int divs3 = scs->tridivs[3 * facecounter + 2];
float side1[3], side2[3], trinormorg[3], trinorm[3];
- if (again == 1 && mface[i].v4)
+ if(again == 1 && mface[i].v4)
{
sub_v3_v3v3(side1, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
sub_v3_v3v3(side2, mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co);
@@ -395,23 +405,23 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
copy_v3_v3(trinorm, trinormorg);
mul_v3_fl(trinorm, 0.25 * cell_len);
- for (j = 0; j <= divs1; j++)
+ for(j = 0; j <= divs1; j++)
{
- for (k = 0; k <= divs2; k++)
+ for(k = 0; k <= divs2; k++)
{
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];
- if (uf+vf > 1.0)
+ if(uf+vf > 1.0)
{
// printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2);
continue;
}
copy_v3_v3(p1, mvert[ mface[i].v1 ].co);
- if (again == 1 && mface[i].v4)
+ if(again == 1 && mface[i].v4)
{
copy_v3_v3(p2, mvert[ mface[i].v3 ].co);
copy_v3_v3(p3, mvert[ mface[i].v4 ].co);
@@ -428,40 +438,211 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
add_v3_v3v3(p, p1, p2);
add_v3_v3(p, p3);
- if (newdivs > divs)
+ if(newdivs > divs)
printf("mem problem\n");
// mMovPoints.push_back(p + trinorm);
add_v3_v3v3(tmpvec, p, trinorm);
- mul_m4_v3(ob->obmat, tmpvec);
+ // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
newdivs++;
- if (newdivs > divs)
+ if(newdivs > divs)
printf("mem problem\n");
// mMovPoints.push_back(p - trinorm);
copy_v3_v3(tmpvec, p);
sub_v3_v3(tmpvec, trinorm);
- mul_m4_v3(ob->obmat, tmpvec);
+ // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
newdivs++;
}
}
- if (again == 0 && mface[i].v4)
+ if(again == 0 && mface[i].v4)
again++;
else
again = 0;
facecounter++;
- } while (again!=0);
+ } while(again!=0);
}
+ scs->numverts = dm->getNumVerts(dm);
+ // DG TODO: also save triangle count?
+
scs->numpoints = dm->getNumVerts(dm) + newdivs;
- MEM_freeN(tridivs);
+ for(i = 0; i < scs->numpoints * 3; i++)
+ {
+ scs->points_old[i] = scs->points[i];
+ }
+}
+
+
+static void fill_scs_points_anim(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
+{
+ MVert *mvert = dm->getVertArray(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
+ int quads = 0, numtris = 0, facecounter = 0;
+ unsigned int i = 0;
+ int divs = 0, newdivs = 0;
+
+ // DG TODO: need to do this dynamically according to the domain object!
+ float cell_len = scs->dx;
+
+ // count quads
+ for(i = 0; i < dm->getNumTessFaces(dm); i++)
+ {
+ if(mface[i].v4)
+ quads++;
+ }
+
+ numtris = dm->getNumTessFaces(dm) + quads;
+
+ // check if mesh changed topology
+ if(scs->numtris != numtris)
+ return;
+ if(scs->numverts != dm->getNumVerts(dm))
+ return;
+
+ // update new positions
+ for(i = 0; i < dm->getNumVerts(dm); i++)
+ {
+ float tmpvec[3];
+ copy_v3_v3(tmpvec, mvert[i].co);
+ copy_v3_v3(&scs->points[i * 3], tmpvec);
+ }
+
+ // for every triangle // update div points
+ for(i = 0, facecounter = 0; i < dm->getNumTessFaces(dm); i++)
+ {
+ int again = 0;
+ do
+ {
+ int j, k;
+ int divs1 = scs->tridivs[3 * facecounter + 0];
+ int divs2 = scs->tridivs[3 * facecounter + 1];
+ float srcside1[3], srcside2[3], destside1[3], destside2[3], src_trinormorg[3], dest_trinormorg[3], src_trinorm[3], dest_trinorm[3];
+
+ if(again == 1 && mface[i].v4)
+ {
+ sub_v3_v3v3(srcside1, &scs->points_old[mface[i].v3 * 3], &scs->points_old[mface[i].v1 * 3]);
+ sub_v3_v3v3(destside1, &scs->points[mface[i].v3 * 3], &scs->points[mface[i].v1 * 3]);
+
+ sub_v3_v3v3(srcside2, &scs->points_old[mface[i].v4 * 3], &scs->points_old[mface[i].v1 * 3]);
+ sub_v3_v3v3(destside2, &scs->points[mface[i].v4 * 3], &scs->points[mface[i].v1 * 3]);
+ }
+ else {
+ sub_v3_v3v3(srcside1, &scs->points_old[mface[i].v2 * 3], &scs->points_old[mface[i].v1 * 3]);
+ sub_v3_v3v3(destside1, &scs->points[mface[i].v2 * 3], &scs->points[mface[i].v1 * 3]);
+
+ sub_v3_v3v3(srcside2, &scs->points_old[mface[i].v3 * 3], &scs->points_old[mface[i].v1 * 3]);
+ sub_v3_v3v3(destside2, &scs->points[mface[i].v3 * 3], &scs->points[mface[i].v1 * 3]);
+ }
+
+ cross_v3_v3v3(src_trinormorg, srcside1, srcside2);
+ cross_v3_v3v3(dest_trinormorg, destside1, destside2);
+
+ normalize_v3(src_trinormorg);
+ normalize_v3(dest_trinormorg);
+
+ copy_v3_v3(src_trinorm, src_trinormorg);
+ copy_v3_v3(dest_trinorm, dest_trinormorg);
+
+ mul_v3_fl(src_trinorm, 0.25 * cell_len);
+ mul_v3_fl(dest_trinorm, 0.25 * cell_len);
+
+ for(j = 0; j <= divs1; j++)
+ {
+ for(k = 0; k <= divs2; k++)
+ {
+ float src_p1[3], src_p2[3], src_p3[3], src_p[3]={0,0,0};
+ float dest_p1[3], dest_p2[3], dest_p3[3], dest_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 src_tmpvec[3], dest_tmpvec[3];
+
+ if(uf+vf > 1.0)
+ {
+ // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2);
+ continue;
+ }
+
+ copy_v3_v3(src_p1, &scs->points_old[mface[i].v1 * 3]);
+ copy_v3_v3(dest_p1, &scs->points[mface[i].v1 * 3]);
+ if(again == 1 && mface[i].v4)
+ {
+ copy_v3_v3(src_p2, &scs->points_old[mface[i].v3 * 3]);
+ copy_v3_v3(dest_p2, &scs->points[mface[i].v3 * 3]);
+
+ copy_v3_v3(src_p3,&scs->points_old[mface[i].v4 * 3]);
+ copy_v3_v3(dest_p3, &scs->points[mface[i].v4 * 3]);
+ }
+ else {
+ copy_v3_v3(src_p2, &scs->points_old[mface[i].v2 * 3]);
+ copy_v3_v3(dest_p2, &scs->points[mface[i].v2 * 3]);
+ copy_v3_v3(src_p3, &scs->points_old[mface[i].v3 * 3]);
+ copy_v3_v3(dest_p3, &scs->points[mface[i].v3 * 3]);
+ }
+
+ mul_v3_fl(src_p1, (1.0-uf-vf));
+ mul_v3_fl(dest_p1, (1.0-uf-vf));
+
+ mul_v3_fl(src_p2, uf);
+ mul_v3_fl(dest_p2, uf);
+
+ mul_v3_fl(src_p3, vf);
+ mul_v3_fl(dest_p3, vf);
+
+ add_v3_v3v3(src_p, src_p1, src_p2);
+ add_v3_v3v3(dest_p, dest_p1, dest_p2);
+
+ add_v3_v3(src_p, src_p3);
+ add_v3_v3(dest_p, dest_p3);
+
+ if(newdivs > divs)
+ printf("mem problem\n");
+
+ // mMovPoints.push_back(p + trinorm);
+ add_v3_v3v3(src_tmpvec, src_p, src_trinorm);
+ add_v3_v3v3(dest_tmpvec, dest_p, dest_trinorm);
+
+ // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
+ copy_v3_v3(&scs->points_old[3 * (dm->getNumVerts(dm) + newdivs)], src_tmpvec);
+ copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], dest_tmpvec);
+ newdivs++;
+
+ if(newdivs > divs)
+ printf("mem problem\n");
+
+ // mMovPoints.push_back(p - trinorm);
+ copy_v3_v3(src_tmpvec, src_p);
+ copy_v3_v3(dest_tmpvec, dest_p);
+
+ sub_v3_v3(src_tmpvec, src_trinorm);
+ sub_v3_v3(dest_tmpvec, dest_trinorm);
+
+ // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
+ copy_v3_v3(&scs->points_old[3 * (dm->getNumVerts(dm) + newdivs)], src_tmpvec);
+ copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], dest_tmpvec);
+ newdivs++;
+ }
+ }
+
+ if(again == 0 && mface[i].v4)
+ again++;
+ else
+ again = 0;
+
+ facecounter++;
+
+ } while(again!=0);
+ }
+
+ // scs->numpoints = dm->getNumVerts(dm) + newdivs;
+
}
/*! init triangle divisions */
@@ -472,22 +653,22 @@ static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFa
// mTriangleDivs3.resize( faces.size() );
size_t i = 0, facecounter = 0;
- float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale);
+ float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale); get max scale value
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]);
+ 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;
+ fsTri = cell_len * 0.75 * scaleFac; // fsTri = cell_len * 0.9;
- if (*tridivs)
+ if(*tridivs)
MEM_freeN(*tridivs);
*tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs");
- for (i = 0, facecounter = 0; i < numfaces; i++)
+ for(i = 0, facecounter = 0; i < numfaces; i++)
{
float p0[3], p1[3], p2[3];
float side1[3];
@@ -506,21 +687,22 @@ static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFa
sub_v3_v3v3(side2, p2, p0);
sub_v3_v3v3(side3, p1, p2);
- if (dot_v3v3(side1, side1) > fsTri*fsTri)
+ if(dot_v3v3(side1, side1) > fsTri*fsTri)
{
float tmp = normalize_v3(side1);
divs1 = (int)ceil(tmp/fsTri);
}
- if (dot_v3v3(side2, side2) > fsTri*fsTri)
+ if(dot_v3v3(side2, side2) > fsTri*fsTri)
{
float tmp = normalize_v3(side2);
divs2 = (int)ceil(tmp/fsTri);
- /*
+ /*
// debug
- if (i==0)
+ if(i==0)
printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2);
*/
+
}
(*tridivs)[3 * facecounter + 0] = divs1;
@@ -528,7 +710,7 @@ static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFa
(*tridivs)[3 * facecounter + 2] = divs3;
// TODO quad case
- if (faces[i].v4)
+ if(faces[i].v4)
{
divs1=0, divs2=0, divs3=0;
@@ -545,12 +727,12 @@ static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFa
sub_v3_v3v3(side2, p2, p0);
sub_v3_v3v3(side3, p1, p2);
- if (dot_v3v3(side1, side1) > fsTri*fsTri)
+ if(dot_v3v3(side1, side1) > fsTri*fsTri)
{
float tmp = normalize_v3(side1);
divs1 = (int)ceil(tmp/fsTri);
}
- if (dot_v3v3(side2, side2) > fsTri*fsTri)
+ if(dot_v3v3(side2, side2) > fsTri*fsTri)
{
float tmp = normalize_v3(side2);
divs2 = (int)ceil(tmp/fsTri);
@@ -568,19 +750,19 @@ static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFa
static void smokeModifier_freeDomain(SmokeModifierData *smd)
{
- if (smd->domain)
+ if(smd->domain)
{
- if (smd->domain->shadow)
+ if(smd->domain->shadow)
MEM_freeN(smd->domain->shadow);
smd->domain->shadow = NULL;
- if (smd->domain->fluid)
+ if(smd->domain->fluid)
smoke_free(smd->domain->fluid);
- if (smd->domain->wt)
+ if(smd->domain->wt)
smoke_turbulence_free(smd->domain->wt);
- if (smd->domain->effector_weights)
+ if(smd->domain->effector_weights)
MEM_freeN(smd->domain->effector_weights);
smd->domain->effector_weights = NULL;
@@ -594,10 +776,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd)
static void smokeModifier_freeFlow(SmokeModifierData *smd)
{
- if (smd->flow)
+ if(smd->flow)
{
/*
- if (smd->flow->bvh)
+ if(smd->flow->bvh)
{
free_bvhtree_from_mesh(smd->flow->bvh);
MEM_freeN(smd->flow->bvh);
@@ -611,22 +793,37 @@ static void smokeModifier_freeFlow(SmokeModifierData *smd)
static void smokeModifier_freeCollision(SmokeModifierData *smd)
{
- if (smd->coll)
+ if(smd->coll)
{
- if (smd->coll->points)
+ SmokeCollSettings *scs = smd->coll;
+
+ if(scs->numpoints)
{
- MEM_freeN(smd->coll->points);
- smd->coll->points = NULL;
+ if(scs->points)
+ {
+ MEM_freeN(scs->points);
+ scs->points = NULL;
+ }
+ if(scs->points_old)
+ {
+ MEM_freeN(scs->points_old);
+ scs->points_old = NULL;
+ }
+ if(scs->tridivs)
+ {
+ MEM_freeN(scs->tridivs);
+ scs->tridivs = NULL;
+ }
}
- if (smd->coll->bvhtree)
+ if(scs->bvhtree)
{
- BLI_bvhtree_free(smd->coll->bvhtree);
- smd->coll->bvhtree = NULL;
+ BLI_bvhtree_free(scs->bvhtree);
+ scs->bvhtree = NULL;
}
#ifdef USE_SMOKE_COLLISION_DM
- if (smd->coll->dm)
+ if(smd->coll->dm)
smd->coll->dm->release(smd->coll->dm);
smd->coll->dm = NULL;
#endif
@@ -638,7 +835,7 @@ static void smokeModifier_freeCollision(SmokeModifierData *smd)
void smokeModifier_reset_turbulence(struct SmokeModifierData *smd)
{
- if (smd && smd->domain && smd->domain->wt)
+ if(smd && smd->domain && smd->domain->wt)
{
smoke_turbulence_free(smd->domain->wt);
smd->domain->wt = NULL;
@@ -647,15 +844,15 @@ void smokeModifier_reset_turbulence(struct SmokeModifierData *smd)
void smokeModifier_reset(struct SmokeModifierData *smd)
{
- if (smd)
+ if(smd)
{
- if (smd->domain)
+ if(smd->domain)
{
- if (smd->domain->shadow)
+ if(smd->domain->shadow)
MEM_freeN(smd->domain->shadow);
smd->domain->shadow = NULL;
- if (smd->domain->fluid)
+ if(smd->domain->fluid)
{
smoke_free(smd->domain->fluid);
smd->domain->fluid = NULL;
@@ -667,10 +864,10 @@ void smokeModifier_reset(struct SmokeModifierData *smd)
// printf("reset domain end\n");
}
- else if (smd->flow)
+ else if(smd->flow)
{
/*
- if (smd->flow->bvh)
+ if(smd->flow->bvh)
{
free_bvhtree_from_mesh(smd->flow->bvh);
MEM_freeN(smd->flow->bvh);
@@ -678,33 +875,33 @@ void smokeModifier_reset(struct SmokeModifierData *smd)
smd->flow->bvh = NULL;
*/
}
- else if (smd->coll)
+ else if(smd->coll)
{
- if (smd->coll->points)
- {
- MEM_freeN(smd->coll->points);
- smd->coll->points = NULL;
- }
+ SmokeCollSettings *scs = smd->coll;
- if (smd->coll->bvhtree)
+ if(scs->numpoints && scs->points)
{
- BLI_bvhtree_free(smd->coll->bvhtree);
- smd->coll->bvhtree = NULL;
+ MEM_freeN(scs->points);
+ scs->points = NULL;
+
+ if(scs->points_old)
+ {
+ MEM_freeN(scs->points_old);
+ scs->points_old = NULL;
+ }
+ if(scs->tridivs)
+ {
+ MEM_freeN(scs->tridivs);
+ scs->tridivs = NULL;
+ }
}
-
-#ifdef USE_SMOKE_COLLISION_DM
- if (smd->coll->dm)
- smd->coll->dm->release(smd->coll->dm);
- smd->coll->dm = NULL;
-#endif
-
}
}
}
void smokeModifier_free (SmokeModifierData *smd)
{
- if (smd)
+ if(smd)
{
smokeModifier_freeDomain(smd);
smokeModifier_freeFlow(smd);
@@ -714,11 +911,11 @@ void smokeModifier_free (SmokeModifierData *smd)
void smokeModifier_createType(struct SmokeModifierData *smd)
{
- if (smd)
+ if(smd)
{
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN)
+ if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
{
- if (smd->domain)
+ if(smd->domain)
smokeModifier_freeDomain(smd);
smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
@@ -745,7 +942,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->beta = 0.1;
smd->domain->time_scale = 1.0;
smd->domain->vorticity = 2.0;
- smd->domain->border_collisions = 1; // vertically non-colliding
+ smd->domain->border_collisions = SM_BORDER_OPEN; // open domain
smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG | MOD_SMOKE_HIGH_SMOOTH;
smd->domain->strength = 2.0;
smd->domain->noise = MOD_SMOKE_NOISEWAVE;
@@ -755,9 +952,9 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG;
smd->domain->effector_weights = BKE_add_effector_weights(NULL);
}
- else if (smd->type & MOD_SMOKE_TYPE_FLOW)
+ else if(smd->type & MOD_SMOKE_TYPE_FLOW)
{
- if (smd->flow)
+ if(smd->flow)
smokeModifier_freeFlow(smd);
smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
@@ -773,17 +970,23 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->flow->psys = NULL;
}
- else if (smd->type & MOD_SMOKE_TYPE_COLL)
+ else if(smd->type & MOD_SMOKE_TYPE_COLL)
{
- if (smd->coll)
+ if(smd->coll)
smokeModifier_freeCollision(smd);
smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
smd->coll->smd = smd;
smd->coll->points = NULL;
+ smd->coll->points_old = NULL;
+ smd->coll->tridivs = NULL;
+ smd->coll->vel = NULL;
smd->coll->numpoints = 0;
+ smd->coll->numtris = 0;
smd->coll->bvhtree = NULL;
+ smd->coll->type = 0; // static obstacle
+ smd->coll->dx = 1.0f / 50.0f;
#ifdef USE_SMOKE_COLLISION_DM
smd->coll->dm = NULL;
@@ -818,7 +1021,7 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
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;
@@ -845,15 +1048,15 @@ static int get_lamp(Scene *scene, float *light)
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) {
+ 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) {
+ if(la->type == LA_LOCAL) {
copy_v3_v3(light, base_tmp->object->obmat[3]);
return 1;
}
- else if (!found_lamp) {
+ else if(!found_lamp) {
copy_v3_v3(light, base_tmp->object->obmat[3]);
found_lamp = 1;
}
@@ -865,497 +1068,603 @@ static int get_lamp(Scene *scene, float *light)
static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd)
{
+#if 0
SmokeDomainSettings *sds = smd->domain;
GroupObject *go = NULL;
- Base *base = NULL;
+ Base *base = NULL;
- // do collisions, needs to be done before emission, so that smoke isn't emitted inside collision cells
- if (1)
+ /* 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;
+ unsigned int i;
+ Object **collobjs = NULL;
+ unsigned int numcollobj = 0;
+ collobjs = get_collisionobjects(scene, ob, sds->coll_group, &numcollobj);
- 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)
+ for(i = 0; i < numcollobj; i++)
{
- 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);
+ Object *collob= collobjs[i];
+ SmokeModifierData *smd2 = (SmokeModifierData*)modifiers_findByType(collob, eModifierType_Smoke);
// check for active smoke modifier
- if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
+ // if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
+ // SmokeModifierData *smd2 = (SmokeModifierData *)md;
+
+ if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points && smd2->coll->points_old)
{
- SmokeModifierData *smd2 = (SmokeModifierData *)md;
+ // ??? anything to do here?
+
+ // TODO: only something to do for ANIMATED obstacles: need to update positions
+
+ }
+ }
+
+ if(collobjs)
+ MEM_freeN(collobjs);
+ }
+
+#endif
+}
- if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points)
+/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */
+static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt, int substep, int totalsteps)
+{
+ Object **collobjs = NULL;
+ unsigned int numcollobj = 0;
+
+ unsigned int collIndex;
+ unsigned char *obstacles = smoke_get_obstacle(sds->fluid);
+ float *velx = NULL;
+ float *vely = NULL;
+ float *velz = NULL;
+ float *velxOrig = smoke_get_velocity_x(sds->fluid);
+ float *velyOrig = smoke_get_velocity_y(sds->fluid);
+ float *velzOrig = smoke_get_velocity_z(sds->fluid);
+ // float *density = smoke_get_density(sds->fluid);
+ unsigned int z;
+
+ smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
+
+ // TODO: delete old obstacle flags
+ for(z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
+ {
+ if(obstacles[z])
+ {
+ // density[z] = 0;
+
+ velxOrig[z] = 0;
+ velyOrig[z] = 0;
+ velzOrig[z] = 0;
+ }
+
+ if(obstacles[z] & 8) // Do not delete static obstacles
+ {
+ obstacles[z] = 0;
+ }
+
+ velx[z] = 0;
+ vely[z] = 0;
+ velz[z] = 0;
+ }
+
+ collobjs = get_collisionobjects(scene, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
+
+ // update obstacle tags in cells
+ for(collIndex = 0; collIndex < numcollobj; collIndex++)
+ {
+ Object *collob= collobjs[collIndex];
+ SmokeModifierData *smd2 = (SmokeModifierData*)modifiers_findByType(collob, eModifierType_Smoke);
+
+ // DG TODO: check if modifier is active?
+
+ if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points && smd2->coll->points_old)
+ {
+ SmokeCollSettings *scs = smd2->coll;
+ unsigned int i;
+
+ /*
+ // DG TODO: support static cobstacles, but basicly we could even support static + rigid with one set of code
+ if(scs->type > SM_COLL_STATIC)
+ */
+
+ /* Handle collisions */
+ for(i = 0; i < scs->numpoints; i++)
+ {
+ // 1. get corresponding cell
+ int cell[3];
+ float pos[3], oldpos[3], vel[3];
+ float cPos[3], cOldpos[3]; /* current position in substeps */
+ int badcell = 0;
+ size_t index;
+ int j;
+
+ // translate local points into global positions
+ copy_v3_v3(cPos, &scs->points[3 * i]);
+ mul_m4_v3(scs->mat, cPos);
+ copy_v3_v3(pos, cPos);
+
+ copy_v3_v3(cOldpos, &scs->points_old[3 * i]);
+ mul_m4_v3(scs->mat_old, cOldpos);
+ copy_v3_v3(oldpos, cOldpos);
+
+ /* support for rigid bodies, armatures etc */
{
- // we got nice collision object
- SmokeCollSettings *scs = smd2->coll;
- size_t i, j;
- unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid);
+ float tmp[3];
- for (i = 0; i < scs->numpoints; i++)
- {
- int badcell = 0;
- size_t index = 0;
- int cell[3];
+ /* x_current = x_old + (x_new - x_old) * step_current / steps_total */
+ float mulStep = (float)(((float)substep) / ((float)totalsteps));
- // 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.0) objvel[jj] = maxVelVal;
- if (objvel[jj] < 0.0) objvel[jj] = -maxVelVal;
- }
- }
- }
- const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) );
- const LbmVec oldov=objvel; // debug
- objvel = vec2L((*pNormals)[n]) *dp;
- */
+ sub_v3_v3v3(tmp, cPos, cOldpos);
+ mul_v3_fl(tmp, mulStep);
+ add_v3_v3(cOldpos, tmp);
+ }
+
+ sub_v3_v3v3(vel, pos, oldpos);
+ /* Scale velocity to incorperate the object movement during this step */
+ mul_v3_fl(vel, 1.0 / (totalsteps * dt));
+ // mul_v3_fl(vel, 1.0 / dt);
+
+ // DG TODO: cap velocity to maxVelMag (or maxvel)
+
+ // oldpos + velocity * dt = newpos
+ get_cell(sds->p0, sds->res, sds->dx, cOldpos /* use current position here instead of "pos" */, 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]);
+
+ // Don't overwrite existing obstacles
+ if(obstacles[index])
+ continue;
+
+ // 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 | 8 /* ANIMATED */;
+
+ if(len_v3(vel) > FLT_EPSILON)
+ {
+ // Collision object is moving
+
+ velx[index] = vel[0]; // use "+="?
+ vely[index] = vel[1];
+ velz[index] = vel[2];
}
}
-
- if (sds->coll_group)
- go = go->next;
- else
- base= base->next;
}
}
- // do flows and fluids
- if (1)
+ if(collobjs)
+ MEM_freeN(collobjs);
+}
+
+static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sds, float time)
+{
+ Object **flowobjs = NULL;
+ unsigned int numflowobj = 0;
+ unsigned int flowIndex;
+
+ flowobjs = get_collisionobjects(scene, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
+
+ // update obstacle tags in cells
+ for(flowIndex = 0; flowIndex < numflowobj; flowIndex++)
{
- 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;
+ Object *collob= flowobjs[flowIndex];
+ SmokeModifierData *smd2 = (SmokeModifierData*)modifiers_findByType(collob, eModifierType_Smoke);
- continue;
- }
+ // check for initialized smoke object
+ if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
+ {
+ // we got nice flow object
+ SmokeFlowSettings *sfs = smd2->flow;
- md = modifiers_findByType(otherobj, eModifierType_Smoke);
-
- // check for active smoke modifier
- if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
+ if(sfs && sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
{
- SmokeModifierData *smd2 = (SmokeModifierData *)md;
-
- // check for initialized smoke object
- if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
+ ParticleSimulationData sim;
+ ParticleSystem *psys = sfs->psys;
+ int totpart=psys->totpart, totchild;
+ 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);
+ // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid);
+ int bigres[3];
+ short absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
+ short high_emission_smoothing = bigdensity ? (sds->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;
+
+ sim.scene = scene;
+ sim.ob = collob;
+ sim.psys = psys;
+
+ // initialize temp emission map
+ if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW))
{
- // we got nice flow object
- SmokeFlowSettings *sfs = smd2->flow;
-
- if (sfs && sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
+ 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;
+ }
+ }
+
+ // mostly copied from particle code
+ if(psys->part->type==PART_HAIR)
+ {
+ /*
+ if(psys->childcache)
{
- ParticleSimulationData sim;
- ParticleSystem *psys = sfs->psys;
- int totpart=psys->totpart, totchild;
- 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];
- 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;
-
- sim.scene = scene;
- sim.ob = otherobj;
- sim.psys = psys;
-
- // initialize temp emission map
- if (!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW))
+ totchild = psys->totchildcache;
+ }
+ else
+ */
+
+ // TODO: PART_HAIR not supported whatsoever
+ totchild=0;
+ }
+ else
+ totchild=psys->totchild*psys->part->disp/100;
+
+ for(p=0; p<totpart+totchild; p++)
+ {
+ int cell[3];
+ size_t i = 0;
+ size_t index = 0;
+ int badcell = 0;
+ ParticleKey state;
+
+ if(p < totpart)
+ {
+ if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
+ continue;
+ }
+ else {
+ /* handle child particle */
+ ChildParticle *cpa = &psys->child[p - totpart];
+
+ if(psys->particles[cpa->parent].flag & (PARS_NO_DISP|PARS_UNEXIST))
+ continue;
+ }
+
+ state.time = time;
+ if(psys_get_particle_state(&sim, p, &state, 0) == 0)
+ continue;
+
+ // copy_v3_v3(pos, pa->state.co);
+ // mul_m4_v3(ob->imat, pos);
+ // 1. get corresponding cell
+ get_cell(sds->p0, sds->res, sds->dx, 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])) // this is inflow
+ {
+ // heat[index] += sfs->temp * 0.1;
+ // density[index] += sfs->density * 0.1;
+ heat[index] = sfs->temp;
+
+ // Add emitter density to temp emission map
+ temp_emission_map[index] = sfs->density;
+
+ // Uses particle velocity as initial velocity for smoke
+ if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO))
{
- 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;
- }
- }
-
- // mostly copied from particle code
- if (psys->part->type==PART_HAIR)
+ 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;
+ }
+ }
+ 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)
{
- /*
- if (psys->childcache)
- {
- totchild = psys->totchildcache;
- }
- else
- */
-
- // TODO: PART_HAIR not supported whatsoever
- totchild=0;
+ // init all surrounding cells according to amplification, too
+ int i, j, k;
+ smoke_turbulence_get_res(sds->wt, bigres);
+
+ for(i = 0; i < sds->amplify + 1; i++)
+ for(j = 0; j < sds->amplify + 1; j++)
+ for(k = 0; k < sds->amplify + 1; k++)
+ {
+ index = smoke_get_index((sds->amplify + 1)* cell[0] + i, bigres[0], (sds->amplify + 1)* cell[1] + j, bigres[1], (sds->amplify + 1)* cell[2] + k);
+ bigdensity[index] = 0.f;
+ }
}
- else
- totchild=psys->totchild*psys->part->disp/100;
-
- for (p=0; p<totpart+totchild; p++)
- {
- int cell[3];
- size_t i = 0;
- size_t index = 0;
- int badcell = 0;
- ParticleKey state;
+ }
+ } // 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(sds->wt, bigres);
+ block_size = sds->amplify + 1; // high res block size
- if (p < totpart)
+ // 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++)
{
- if (psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
- continue;
- }
- else {
- /* handle child particle */
- ChildParticle *cpa = &psys->child[p - totpart];
-
- if (psys->particles[cpa->parent].flag & (PARS_NO_DISP|PARS_UNEXIST))
- continue;
- }
+ // neighbor cell emission densities (for high resolution smoke smooth interpolation)
+ float c000, c001, c010, c011, c100, c101, c110, c111;
- state.time = smd->time;
- if (psys_get_particle_state(&sim, p, &state, 0) == 0)
- continue;
-
- // copy_v3_v3(pos, pa->state.co);
- // mul_m4_v3(ob->imat, pos);
- // 1. get corresponding cell
- get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, 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])) // this is inflow
- {
- // heat[index] += sfs->temp * 0.1;
- // density[index] += sfs->density * 0.1;
- heat[index] = sfs->temp;
-
- // Add emitter density to temp emission map
- temp_emission_map[index] = sfs->density;
-
- // Uses particle velocity as initial velocity for smoke
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO))
- {
- 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;
- }
- }
- 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)
+ 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)
{
- // 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;
- }
+ if (temp_emission_map[index]>0)
+ density[index] = temp_emission_map[index];
}
- }
- } // particles loop
+ else
+ {
+ density[index] += temp_emission_map[index];
+ if (density[index]>1)
+ density[index]=1.0f;
+ }
- // apply emission values
- if (!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) {
+ smoke_turbulence_get_res(sds->wt, bigres);
- // initialize variables
- int ii, jj, kk, x, y, z, block_size;
- size_t index, index_big;
+ /* 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++)
+ {
- smoke_turbulence_get_res(smd->domain->wt, bigres);
- block_size = smd->domain->amplify + 1; // high res block size
+ float fx,fy,fz, interpolated_value;
+ int shift_x, shift_y, shift_z;
- // 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++)
- {
+ /*
+ * 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;
+ }
- // neighbor cell emission densities (for high resolution smoke smooth interpolation)
- float c000, c001, c010, c011, c100, c101, c110, c111;
+ // 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);
- 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;
+ // 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;
- 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
+ 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);
- // get cell index
- index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
+ } // end emission
+ }
+ }
+ }
- // 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;
- }
+ if(flowobjs)
+ MEM_freeN(flowobjs);
+}
- smoke_turbulence_get_res(smd->domain->wt, bigres);
+static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
+{
+ ListBase *effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights);
+ if(effectors)
+ {
+ 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);
+ unsigned char *obstacle = smoke_get_obstacle(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] = {0,0,0} , vel[3] = {0,0,0} , retvel[3] = {0,0,0};
+ unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
+
+ if((density[index] < FLT_EPSILON) || obstacle[index])
+ 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.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);
+ }
+ }
+ pdEndEffectors(&effectors);
+}
- /*
- 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;
- }
+static void step(Scene *scene, Object *ob, SmokeModifierData *smd, float fps)
+{
+ /* stability values copied from wturbulence.cpp */
+ const int maxSubSteps = 25;
+ float maxVel;
+ // maxVel should be 1.5 (1.5 cell max movement) * dx (cell size)
- } // end of hires loop
+ float dt = DT_DEFAULT;
+ float maxVelMag = 0.0f;
+ int totalSubsteps;
+ int substep = 0;
+ float dtSubdiv;
- } // end of low res loop
+ SmokeDomainSettings *sds = smd->domain;
- // free temporary emission map
- if (temp_emission_map) MEM_freeN(temp_emission_map);
+ /* get max velocity and lower the dt value if it is too high */
+ size_t size= sds->res[0] * sds->res[1] * sds->res[2];
- } // end emission
+ float *velX = smoke_get_velocity_x(sds->fluid);
+ float *velY = smoke_get_velocity_y(sds->fluid);
+ float *velZ = smoke_get_velocity_z(sds->fluid);
+ size_t i;
+ /* adapt timestep for different framerates, dt = 0.1 is at 25fps */
+ dt *= (25.0f / fps);
-
- }
- else {
- /*
- for ()
- {
- // no psys
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist = FLT_MAX;
+ // printf("test maxVel: %f\n", (sds->dx * 1.5) / dt); // gives 0.9
+ maxVel = (sds->dx * 1.5);
- 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;
- }
+ for(i = 0; i < size; i++)
+ {
+ float vtemp = (velX[i]*velX[i]+velY[i]*velY[i]+velZ[i]*velZ[i]);
+ if(vtemp > maxVelMag)
+ maxVelMag = vtemp;
}
- // do effectors
+ maxVelMag = sqrt(maxVelMag) * dt * sds->time_scale;
+ totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */
+ totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
+ totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
+
+ // totalSubsteps = 2.0f; // DEBUG
+
+ dtSubdiv = (float)dt / (float)totalSubsteps;
+
+ // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt);
+
+ for(substep = 0; substep < totalSubsteps; substep++)
{
- ListBase *effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights);
+ // calc animated obstacle velocities
+ update_obstacles(scene, ob, sds, dtSubdiv, substep, totalSubsteps);
+ update_flowsfluids(scene, ob, sds, smd->time);
+ update_effectors(scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
- if (effectors)
- {
- 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] = {0,0,0} , vel[3] = {0,0,0} , retvel[3] = {0,0,0};
- 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.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);
- }
- }
+ smoke_step(sds->fluid, dtSubdiv);
- pdEndEffectors(&effectors);
- }
+ // move animated obstacle: Done in update_obstacles() */
+ // where to delete old obstacles from array? Done in update_obstacles() */
+ }
}
+
void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
{
- if ((smd->type & MOD_SMOKE_TYPE_FLOW))
+ if((smd->type & MOD_SMOKE_TYPE_FLOW))
{
- if (scene->r.cfra >= smd->time)
+ if(scene->r.cfra >= smd->time)
smokeModifier_init(smd, ob, scene, dm);
- if (scene->r.cfra > smd->time)
+ if(scene->r.cfra > smd->time)
{
// XXX TODO
smd->time = scene->r.cfra;
@@ -1366,40 +1675,102 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
copy_m4_m4(smd->flow->mat, ob->obmat);
*/
}
- else if (scene->r.cfra < smd->time)
+ else if(scene->r.cfra < smd->time)
{
smd->time = scene->r.cfra;
smokeModifier_reset(smd);
}
}
- else if (smd->type & MOD_SMOKE_TYPE_COLL)
+ else if(smd->type & MOD_SMOKE_TYPE_COLL)
{
- if (scene->r.cfra >= smd->time)
+ /* Check if domain resolution changed */
+ /* DG TODO: can this be solved more elegant using dependancy graph? */
+ {
+ SmokeCollSettings *scs = smd->coll;
+ Base *base = scene->base.first;
+ int changed = 0;
+ float dx = FLT_MAX;
+ int haveDomain = 0;
+
+ for ( ; base; base = base->next)
+ {
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(base->object, eModifierType_Smoke);
+
+ if (smd2 && (smd2->type & MOD_SMOKE_TYPE_DOMAIN) && smd2->domain)
+ {
+ SmokeDomainSettings *sds = smd2->domain;
+
+ if(sds->dx < dx)
+ {
+ dx = sds->dx;
+ changed = 1;
+ }
+
+ haveDomain = 1;
+ }
+ }
+
+ if(!haveDomain)
+ return;
+
+ if(changed)
+ {
+ if(dx != scs->dx)
+ {
+ scs->dx = dx;
+ smokeModifier_reset(smd);
+ }
+ }
+ }
+
+ if(scene->r.cfra >= smd->time)
smokeModifier_init(smd, ob, scene, dm);
- if (scene->r.cfra > smd->time)
+ if(scene->r.cfra > smd->time)
{
- // XXX TODO
+ unsigned int i;
+ SmokeCollSettings *scs = smd->coll;
+ float *points_old = scs->points_old;
+ float *points = scs->points;
+ unsigned int numpoints = scs->numpoints;
+
+ // XXX TODO <-- DG: what is TODO here?
smd->time = scene->r.cfra;
-#ifdef USE_SMOKE_COLLISION_DM
- if (smd->coll->dm)
- smd->coll->dm->release(smd->coll->dm);
+ // rigid movement support
+ copy_m4_m4(scs->mat_old, scs->mat);
+ copy_m4_m4(scs->mat, ob->obmat);
- smd->coll->dm = CDDM_copy_from_tessface(dm);
-#endif
+ if(scs->type != SM_COLL_ANIMATED) // if(not_animated)
+ {
+ // nothing to do, "mat" is already up to date
+ }
+ else
+ {
+ // XXX TODO: need to update positions + divs
- // rigid movement support
- copy_m4_m4(smd->coll->mat_old, smd->coll->mat);
- copy_m4_m4(smd->coll->mat, ob->obmat);
+ if(scs->numverts != dm->getNumVerts(dm))
+ {
+ // DG TODO: reset modifier?
+ return;
+ }
+
+ for(i = 0; i < numpoints * 3; i++)
+ {
+ points_old[i] = points[i];
+ }
+
+ DM_ensure_tessface(dm);
+ fill_scs_points_anim(ob, dm, scs);
+ }
}
- else if (scene->r.cfra < smd->time)
+ else if(scene->r.cfra < smd->time)
{
smd->time = scene->r.cfra;
smokeModifier_reset(smd);
}
}
- else if (smd->type & MOD_SMOKE_TYPE_DOMAIN)
+ else if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
{
SmokeDomainSettings *sds = smd->domain;
float light[3];
@@ -1416,14 +1787,14 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
BKE_ptcache_id_from_smoke(&pid, ob, smd);
BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
- if (!smd->domain->fluid || framenr == startframe)
+ if(!smd->domain->fluid || framenr == startframe)
{
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
BKE_ptcache_validate(cache, framenr);
cache->flag &= ~PTCACHE_REDO_NEEDED;
}
- if (!smd->domain->fluid && (framenr != startframe) && (smd->domain->flags & MOD_SMOKE_FILE_LOAD)==0 && (cache->flag & PTCACHE_BAKED)==0)
+ if(!smd->domain->fluid && (framenr != startframe) && (smd->domain->flags & MOD_SMOKE_FILE_LOAD)==0 && (cache->flag & PTCACHE_BAKED)==0)
return;
smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD;
@@ -1436,21 +1807,21 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
// printf("startframe: %d, framenr: %d\n", startframe, framenr);
- if (smokeModifier_init(smd, ob, scene, dm)==0)
+ if(smokeModifier_init(smd, ob, scene, dm)==0)
{
printf("bad smokeModifier_init\n");
return;
}
/* try to read from cache */
- if (BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT) {
+ if(BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT) {
BKE_ptcache_validate(cache, framenr);
smd->time = framenr;
return;
}
/* only calculate something when we advanced a single frame */
- if (framenr != (int)smd->time+1)
+ if(framenr != (int)smd->time+1)
return;
/* don't simulate if viewing start frame, but scene frame is not real start frame */
@@ -1462,14 +1833,14 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
smoke_calc_domain(scene, ob, smd);
/* if on second frame, write cache for first frame */
- if ((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) {
+ if((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) {
// create shadows straight after domain initialization so we get nice shadows for startframe, too
- if (get_lamp(scene, light))
+ 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);
- if (sds->wt)
+ if(sds->wt)
{
- if (sds->flags & MOD_SMOKE_DISSOLVE)
+ 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);
}
@@ -1486,30 +1857,31 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
// simulate the actual smoke (c++ code in intern/smoke)
// DG: interesting commenting this line + deactivating loading of noise files
- if (framenr!=startframe)
+ if(framenr!=startframe)
{
- if (sds->flags & MOD_SMOKE_DISSOLVE)
+ if(sds->flags & MOD_SMOKE_DISSOLVE)
smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
- smoke_step(sds->fluid, smd->time, scene->r.frs_sec / scene->r.frs_sec_base);
+
+ step(scene, ob, smd, scene->r.frs_sec / scene->r.frs_sec_base);
}
// create shadows before writing cache so they get stored
- if (get_lamp(scene, light))
+ 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);
- if (sds->wt)
+ if(sds->wt)
{
- if (sds->flags & MOD_SMOKE_DISSOLVE)
+ 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);
}
BKE_ptcache_validate(cache, framenr);
- if (framenr != startframe)
+ if(framenr != startframe)
BKE_ptcache_write(&pid, framenr);
tend();
- //printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() );
+ // printf ( "Frame: %d, Time: %f\n\n", (int)smd->time, ( float ) tval() );
}
}
@@ -1520,7 +1892,7 @@ static float calc_voxel_transp(float *result, float *input, int res[3], int *pix
// T_ray *= T_vox
*tRay *= exp(input[index]*correct);
- if (result[index] < 0.0f)
+ if(result[index] < 0.0f)
{
#pragma omp critical
result[index] = *tRay;
@@ -1574,7 +1946,7 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f
err_1 = dy2 - l;
err_2 = dz2 - l;
for (i = 0; i < l; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
+ if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
break;
if (err_1 > 0) {
pixel[1] += y_inc;
@@ -1588,12 +1960,12 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f
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)
+ if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
break;
if (err_1 > 0) {
pixel[0] += x_inc;
@@ -1607,12 +1979,12 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f
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)
+ if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
break;
if (err_1 > 0) {
pixel[1] += y_inc;
@@ -1654,7 +2026,7 @@ static void smoke_calc_transparency(float *result, float *input, float *p0, floa
float bv[6];
int a, z, slabsize=res[0]*res[1], size= res[0]*res[1]*res[2];
- for (a=0; a<size; a++)
+ for(a=0; a<size; a++)
result[a]= -1.0f;
bv[0] = p0[0];
@@ -1667,27 +2039,27 @@ static void smoke_calc_transparency(float *result, float *input, float *p0, floa
bv[5] = p1[2];
#pragma omp parallel for schedule(static,1)
- for (z = 0; z < res[2]; z++)
+ for(z = 0; z < res[2]; z++)
{
size_t index = z*slabsize;
int x,y;
- for (y = 0; y < res[1]; y++)
- for (x = 0; x < res[0]; x++, index++)
+ for(y = 0; y < res[1]; y++)
+ for(x = 0; x < res[0]; x++, index++)
{
float voxelCenter[3];
float pos[3];
int cell[3];
float tRay = 1.0;
- if (result[index] >= 0.0f)
+ if(result[index] >= 0.0f)
continue;
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;
// get starting position (in voxel coords)
- if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON)
+ if(BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON)
{
// we're ouside
get_cell(p0, res, dx, pos, cell, 1);