Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) Blender Foundation. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Daniel Genrich 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 /* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */ 00034 00035 #include <GL/glew.h> 00036 00037 #include "MEM_guardedalloc.h" 00038 00039 #include <float.h> 00040 #include <math.h> 00041 #include <stdio.h> 00042 #include <string.h> /* memset */ 00043 00044 #include "BLI_linklist.h" 00045 #include "BLI_rand.h" 00046 #include "BLI_jitter.h" 00047 #include "BLI_blenlib.h" 00048 #include "BLI_math.h" 00049 #include "BLI_edgehash.h" 00050 #include "BLI_kdtree.h" 00051 #include "BLI_kdopbvh.h" 00052 #include "BLI_utildefines.h" 00053 00054 #include "BKE_bvhutils.h" 00055 #include "BKE_cdderivedmesh.h" 00056 #include "BKE_customdata.h" 00057 #include "BKE_DerivedMesh.h" 00058 #include "BKE_effect.h" 00059 #include "BKE_modifier.h" 00060 #include "BKE_particle.h" 00061 #include "BKE_pointcache.h" 00062 #include "BKE_smoke.h" 00063 00064 00065 #include "DNA_customdata_types.h" 00066 #include "DNA_group_types.h" 00067 #include "DNA_lamp_types.h" 00068 #include "DNA_mesh_types.h" 00069 #include "DNA_meshdata_types.h" 00070 #include "DNA_modifier_types.h" 00071 #include "DNA_object_types.h" 00072 #include "DNA_particle_types.h" 00073 #include "DNA_scene_types.h" 00074 #include "DNA_smoke_types.h" 00075 00076 #include "smoke_API.h" 00077 00078 #include "BKE_smoke.h" 00079 00080 #ifdef WITH_SMOKE 00081 00082 #ifdef _WIN32 00083 #include <time.h> 00084 #include <stdio.h> 00085 #include <conio.h> 00086 #include <windows.h> 00087 00088 static LARGE_INTEGER liFrequency; 00089 static LARGE_INTEGER liStartTime; 00090 static LARGE_INTEGER liCurrentTime; 00091 00092 static void tstart ( void ) 00093 { 00094 QueryPerformanceFrequency ( &liFrequency ); 00095 QueryPerformanceCounter ( &liStartTime ); 00096 } 00097 static void tend ( void ) 00098 { 00099 QueryPerformanceCounter ( &liCurrentTime ); 00100 } 00101 static double tval( void ) 00102 { 00103 return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart )); 00104 } 00105 #else 00106 #include <sys/time.h> 00107 static struct timeval _tstart, _tend; 00108 static struct timezone tz; 00109 static void tstart ( void ) 00110 { 00111 gettimeofday ( &_tstart, &tz ); 00112 } 00113 static void tend ( void ) 00114 { 00115 gettimeofday ( &_tend,&tz ); 00116 } 00117 00118 #if 0 // unused 00119 static double tval() 00120 { 00121 double t1, t2; 00122 t1 = ( double ) _tstart.tv_sec*1000 + ( double ) _tstart.tv_usec/ ( 1000 ); 00123 t2 = ( double ) _tend.tv_sec*1000 + ( double ) _tend.tv_usec/ ( 1000 ); 00124 return t2-t1; 00125 } 00126 #endif 00127 #endif 00128 00129 struct Object; 00130 struct Scene; 00131 struct DerivedMesh; 00132 struct SmokeModifierData; 00133 00134 #define TRI_UVOFFSET (1./4.) 00135 00136 /* forward declerations */ 00137 static void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int numfaces, int numtris, int **tridivs, float cell_len); 00138 static void get_cell(float *p0, int res[3], float dx, float *pos, int *cell, int correct); 00139 static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs); 00140 00141 #else /* WITH_SMOKE */ 00142 00143 /* Stubs to use when smoke is disabled */ 00144 struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype)) { return NULL; } 00145 struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(p0)) { return NULL; } 00146 void smoke_free(struct FLUID_3D *UNUSED(fluid)) {} 00147 void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) {} 00148 void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) {} 00149 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)) {} 00150 long long smoke_get_mem_req(int UNUSED(xres), int UNUSED(yres), int UNUSED(zres), int UNUSED(amplify)) { return 0; } 00151 void smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) {} 00152 00153 #endif /* WITH_SMOKE */ 00154 00155 #ifdef WITH_SMOKE 00156 00157 static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm) 00158 { 00159 if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) 00160 { 00161 size_t i; 00162 float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; 00163 float size[3]; 00164 MVert *verts = dm->getVertArray(dm); 00165 float scale = 0.0; 00166 int res; 00167 00168 res = smd->domain->maxres; 00169 00170 // get BB of domain 00171 for(i = 0; i < dm->getNumVerts(dm); i++) 00172 { 00173 float tmp[3]; 00174 00175 copy_v3_v3(tmp, verts[i].co); 00176 mul_m4_v3(ob->obmat, tmp); 00177 00178 // min BB 00179 min[0] = MIN2(min[0], tmp[0]); 00180 min[1] = MIN2(min[1], tmp[1]); 00181 min[2] = MIN2(min[2], tmp[2]); 00182 00183 // max BB 00184 max[0] = MAX2(max[0], tmp[0]); 00185 max[1] = MAX2(max[1], tmp[1]); 00186 max[2] = MAX2(max[2], tmp[2]); 00187 } 00188 00189 copy_v3_v3(smd->domain->p0, min); 00190 copy_v3_v3(smd->domain->p1, max); 00191 00192 // calc other res with max_res provided 00193 sub_v3_v3v3(size, max, min); 00194 00195 // printf("size: %f, %f, %f\n", size[0], size[1], size[2]); 00196 00197 // prevent crash when initializing a plane as domain 00198 if((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON)) 00199 return 0; 00200 00201 if(size[0] > size[1]) 00202 { 00203 if(size[0] > size[2]) 00204 { 00205 scale = res / size[0]; 00206 smd->domain->dx = size[0] / res; 00207 smd->domain->res[0] = res; 00208 smd->domain->res[1] = (int)(size[1] * scale + 0.5); 00209 smd->domain->res[2] = (int)(size[2] * scale + 0.5); 00210 } 00211 else 00212 { 00213 scale = res / size[2]; 00214 smd->domain->dx = size[2] / res; 00215 smd->domain->res[2] = res; 00216 smd->domain->res[0] = (int)(size[0] * scale + 0.5); 00217 smd->domain->res[1] = (int)(size[1] * scale + 0.5); 00218 } 00219 } 00220 else 00221 { 00222 if(size[1] > size[2]) 00223 { 00224 scale = res / size[1]; 00225 smd->domain->dx = size[1] / res; 00226 smd->domain->res[1] = res; 00227 smd->domain->res[0] = (int)(size[0] * scale + 0.5); 00228 smd->domain->res[2] = (int)(size[2] * scale + 0.5); 00229 } 00230 else 00231 { 00232 scale = res / size[2]; 00233 smd->domain->dx = size[2] / res; 00234 smd->domain->res[2] = res; 00235 smd->domain->res[0] = (int)(size[0] * scale + 0.5); 00236 smd->domain->res[1] = (int)(size[1] * scale + 0.5); 00237 } 00238 } 00239 00240 // printf("smd->domain->dx: %f\n", smd->domain->dx); 00241 00242 // TODO: put in failsafe if res<=0 - dg 00243 00244 // printf("res[0]: %d, res[1]: %d, res[2]: %d\n", smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]); 00245 // dt max is 0.1 00246 smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0); 00247 smd->time = scene->r.cfra; 00248 00249 if(smd->domain->flags & MOD_SMOKE_HIGHRES) 00250 { 00251 smd->domain->wt = smoke_turbulence_init(smd->domain->res, smd->domain->amplify + 1, smd->domain->noise); 00252 smd->domain->res_wt[0] = smd->domain->res[0] * (smd->domain->amplify + 1); 00253 smd->domain->res_wt[1] = smd->domain->res[1] * (smd->domain->amplify + 1); 00254 smd->domain->res_wt[2] = smd->domain->res[2] * (smd->domain->amplify + 1); 00255 smd->domain->dx_wt = smd->domain->dx / (smd->domain->amplify + 1); 00256 // printf("smd->domain->amplify: %d\n", smd->domain->amplify); 00257 // printf("(smd->domain->flags & MOD_SMOKE_HIGHRES)\n"); 00258 } 00259 00260 if(!smd->domain->shadow) 00261 smd->domain->shadow = MEM_callocN(sizeof(float) * smd->domain->res[0] * smd->domain->res[1] * smd->domain->res[2], "SmokeDomainShadow"); 00262 00263 smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta), &(smd->domain->time_scale), &(smd->domain->vorticity), &(smd->domain->border_collisions)); 00264 00265 if(smd->domain->wt) 00266 { 00267 smoke_initWaveletBlenderRNA(smd->domain->wt, &(smd->domain->strength)); 00268 // printf("smoke_initWaveletBlenderRNA\n"); 00269 } 00270 return 1; 00271 } 00272 else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) 00273 { 00274 // handle flow object here 00275 // XXX TODO 00276 00277 smd->time = scene->r.cfra; 00278 00279 // update particle lifetime to be one frame 00280 // smd->flow->psys->part->lifetime = scene->r.efra + 1; 00281 /* 00282 if(!smd->flow->bvh) 00283 { 00284 // smd->flow->bvh = MEM_callocN(sizeof(BVHTreeFromMesh), "smoke_bvhfromfaces"); 00285 // bvhtree_from_mesh_faces(smd->flow->bvh, dm, 0.0, 2, 6); 00286 00287 // copy obmat 00288 // copy_m4_m4(smd->flow->mat, ob->obmat); 00289 // copy_m4_m4(smd->flow->mat_old, ob->obmat); 00290 } 00291 */ 00292 00293 return 1; 00294 } 00295 else if((smd->type & MOD_SMOKE_TYPE_COLL)) 00296 { 00297 smd->time = scene->r.cfra; 00298 00299 // todo: delete this when loading colls work -dg 00300 if(!smd->coll) 00301 smokeModifier_createType(smd); 00302 00303 if(!smd->coll->points) 00304 { 00305 // init collision points 00306 SmokeCollSettings *scs = smd->coll; 00307 00308 // copy obmat 00309 copy_m4_m4(scs->mat, ob->obmat); 00310 copy_m4_m4(scs->mat_old, ob->obmat); 00311 00312 fill_scs_points(ob, dm, scs); 00313 } 00314 00315 if(!smd->coll->bvhtree) 00316 { 00317 smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 ); 00318 } 00319 return 1; 00320 } 00321 00322 return 2; 00323 } 00324 00325 static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs) 00326 { 00327 MVert *mvert = dm->getVertArray(dm); 00328 MFace *mface = dm->getFaceArray(dm); 00329 int i = 0, divs = 0; 00330 int *tridivs = NULL; 00331 float cell_len = 1.0 / 50.0; // for res = 50 00332 int newdivs = 0; 00333 int quads = 0, facecounter = 0; 00334 00335 // count quads 00336 for(i = 0; i < dm->getNumFaces(dm); i++) 00337 { 00338 if(mface[i].v4) 00339 quads++; 00340 } 00341 00342 calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len); 00343 00344 // count triangle divisions 00345 for(i = 0; i < dm->getNumFaces(dm) + quads; i++) 00346 { 00347 divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1); 00348 } 00349 00350 // printf("divs: %d\n", divs); 00351 00352 scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints"); 00353 00354 for(i = 0; i < dm->getNumVerts(dm); i++) 00355 { 00356 float tmpvec[3]; 00357 copy_v3_v3(tmpvec, mvert[i].co); 00358 mul_m4_v3(ob->obmat, tmpvec); 00359 copy_v3_v3(&scs->points[i * 3], tmpvec); 00360 } 00361 00362 for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++) 00363 { 00364 int again = 0; 00365 do 00366 { 00367 int j, k; 00368 int divs1 = tridivs[3 * facecounter + 0]; 00369 int divs2 = tridivs[3 * facecounter + 1]; 00370 //int divs3 = tridivs[3 * facecounter + 2]; 00371 float side1[3], side2[3], trinormorg[3], trinorm[3]; 00372 00373 if(again == 1 && mface[i].v4) 00374 { 00375 sub_v3_v3v3(side1, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co); 00376 sub_v3_v3v3(side2, mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co); 00377 } 00378 else 00379 { 00380 sub_v3_v3v3(side1, mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co); 00381 sub_v3_v3v3(side2, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co); 00382 } 00383 00384 cross_v3_v3v3(trinormorg, side1, side2); 00385 normalize_v3(trinormorg); 00386 copy_v3_v3(trinorm, trinormorg); 00387 mul_v3_fl(trinorm, 0.25 * cell_len); 00388 00389 for(j = 0; j <= divs1; j++) 00390 { 00391 for(k = 0; k <= divs2; k++) 00392 { 00393 float p1[3], p2[3], p3[3], p[3]={0,0,0}; 00394 const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0); 00395 const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0); 00396 float tmpvec[3]; 00397 00398 if(uf+vf > 1.0) 00399 { 00400 // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2); 00401 continue; 00402 } 00403 00404 copy_v3_v3(p1, mvert[ mface[i].v1 ].co); 00405 if(again == 1 && mface[i].v4) 00406 { 00407 copy_v3_v3(p2, mvert[ mface[i].v3 ].co); 00408 copy_v3_v3(p3, mvert[ mface[i].v4 ].co); 00409 } 00410 else 00411 { 00412 copy_v3_v3(p2, mvert[ mface[i].v2 ].co); 00413 copy_v3_v3(p3, mvert[ mface[i].v3 ].co); 00414 } 00415 00416 mul_v3_fl(p1, (1.0-uf-vf)); 00417 mul_v3_fl(p2, uf); 00418 mul_v3_fl(p3, vf); 00419 00420 add_v3_v3v3(p, p1, p2); 00421 add_v3_v3(p, p3); 00422 00423 if(newdivs > divs) 00424 printf("mem problem\n"); 00425 00426 // mMovPoints.push_back(p + trinorm); 00427 add_v3_v3v3(tmpvec, p, trinorm); 00428 mul_m4_v3(ob->obmat, tmpvec); 00429 copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec); 00430 newdivs++; 00431 00432 if(newdivs > divs) 00433 printf("mem problem\n"); 00434 00435 // mMovPoints.push_back(p - trinorm); 00436 copy_v3_v3(tmpvec, p); 00437 sub_v3_v3(tmpvec, trinorm); 00438 mul_m4_v3(ob->obmat, tmpvec); 00439 copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec); 00440 newdivs++; 00441 } 00442 } 00443 00444 if(again == 0 && mface[i].v4) 00445 again++; 00446 else 00447 again = 0; 00448 00449 facecounter++; 00450 00451 } while(again!=0); 00452 } 00453 00454 scs->numpoints = dm->getNumVerts(dm) + newdivs; 00455 00456 MEM_freeN(tridivs); 00457 } 00458 00460 static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len) 00461 { 00462 // mTriangleDivs1.resize( faces.size() ); 00463 // mTriangleDivs2.resize( faces.size() ); 00464 // mTriangleDivs3.resize( faces.size() ); 00465 00466 size_t i = 0, facecounter = 0; 00467 float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale); 00468 float maxpart = ABS(maxscale[0]); 00469 float scaleFac = 0; 00470 float fsTri = 0; 00471 if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]); 00472 if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]); 00473 scaleFac = 1.0 / maxpart; 00474 // featureSize = mLevel[mMaxRefine].nodeSize 00475 fsTri = cell_len * 0.5 * scaleFac; 00476 00477 if(*tridivs) 00478 MEM_freeN(*tridivs); 00479 00480 *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs"); 00481 00482 for(i = 0, facecounter = 0; i < numfaces; i++) 00483 { 00484 float p0[3], p1[3], p2[3]; 00485 float side1[3]; 00486 float side2[3]; 00487 float side3[3]; 00488 int divs1=0, divs2=0, divs3=0; 00489 00490 copy_v3_v3(p0, verts[faces[i].v1].co); 00491 mul_m4_v3(ob->obmat, p0); 00492 copy_v3_v3(p1, verts[faces[i].v2].co); 00493 mul_m4_v3(ob->obmat, p1); 00494 copy_v3_v3(p2, verts[faces[i].v3].co); 00495 mul_m4_v3(ob->obmat, p2); 00496 00497 sub_v3_v3v3(side1, p1, p0); 00498 sub_v3_v3v3(side2, p2, p0); 00499 sub_v3_v3v3(side3, p1, p2); 00500 00501 if(dot_v3v3(side1, side1) > fsTri*fsTri) 00502 { 00503 float tmp = normalize_v3(side1); 00504 divs1 = (int)ceil(tmp/fsTri); 00505 } 00506 if(dot_v3v3(side2, side2) > fsTri*fsTri) 00507 { 00508 float tmp = normalize_v3(side2); 00509 divs2 = (int)ceil(tmp/fsTri); 00510 00511 /* 00512 // debug 00513 if(i==0) 00514 printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2); 00515 */ 00516 } 00517 00518 (*tridivs)[3 * facecounter + 0] = divs1; 00519 (*tridivs)[3 * facecounter + 1] = divs2; 00520 (*tridivs)[3 * facecounter + 2] = divs3; 00521 00522 // TODO quad case 00523 if(faces[i].v4) 00524 { 00525 divs1=0, divs2=0, divs3=0; 00526 00527 facecounter++; 00528 00529 copy_v3_v3(p0, verts[faces[i].v3].co); 00530 mul_m4_v3(ob->obmat, p0); 00531 copy_v3_v3(p1, verts[faces[i].v4].co); 00532 mul_m4_v3(ob->obmat, p1); 00533 copy_v3_v3(p2, verts[faces[i].v1].co); 00534 mul_m4_v3(ob->obmat, p2); 00535 00536 sub_v3_v3v3(side1, p1, p0); 00537 sub_v3_v3v3(side2, p2, p0); 00538 sub_v3_v3v3(side3, p1, p2); 00539 00540 if(dot_v3v3(side1, side1) > fsTri*fsTri) 00541 { 00542 float tmp = normalize_v3(side1); 00543 divs1 = (int)ceil(tmp/fsTri); 00544 } 00545 if(dot_v3v3(side2, side2) > fsTri*fsTri) 00546 { 00547 float tmp = normalize_v3(side2); 00548 divs2 = (int)ceil(tmp/fsTri); 00549 } 00550 00551 (*tridivs)[3 * facecounter + 0] = divs1; 00552 (*tridivs)[3 * facecounter + 1] = divs2; 00553 (*tridivs)[3 * facecounter + 2] = divs3; 00554 } 00555 facecounter++; 00556 } 00557 } 00558 00559 #endif /* WITH_SMOKE */ 00560 00561 static void smokeModifier_freeDomain(SmokeModifierData *smd) 00562 { 00563 if(smd->domain) 00564 { 00565 if(smd->domain->shadow) 00566 MEM_freeN(smd->domain->shadow); 00567 smd->domain->shadow = NULL; 00568 00569 if(smd->domain->fluid) 00570 smoke_free(smd->domain->fluid); 00571 00572 if(smd->domain->wt) 00573 smoke_turbulence_free(smd->domain->wt); 00574 00575 if(smd->domain->effector_weights) 00576 MEM_freeN(smd->domain->effector_weights); 00577 smd->domain->effector_weights = NULL; 00578 00579 BKE_ptcache_free_list(&(smd->domain->ptcaches[0])); 00580 smd->domain->point_cache[0] = NULL; 00581 00582 MEM_freeN(smd->domain); 00583 smd->domain = NULL; 00584 } 00585 } 00586 00587 static void smokeModifier_freeFlow(SmokeModifierData *smd) 00588 { 00589 if(smd->flow) 00590 { 00591 /* 00592 if(smd->flow->bvh) 00593 { 00594 free_bvhtree_from_mesh(smd->flow->bvh); 00595 MEM_freeN(smd->flow->bvh); 00596 } 00597 smd->flow->bvh = NULL; 00598 */ 00599 MEM_freeN(smd->flow); 00600 smd->flow = NULL; 00601 } 00602 } 00603 00604 static void smokeModifier_freeCollision(SmokeModifierData *smd) 00605 { 00606 if(smd->coll) 00607 { 00608 if(smd->coll->points) 00609 { 00610 MEM_freeN(smd->coll->points); 00611 smd->coll->points = NULL; 00612 } 00613 00614 if(smd->coll->bvhtree) 00615 { 00616 BLI_bvhtree_free(smd->coll->bvhtree); 00617 smd->coll->bvhtree = NULL; 00618 } 00619 00620 if(smd->coll->dm) 00621 smd->coll->dm->release(smd->coll->dm); 00622 smd->coll->dm = NULL; 00623 00624 MEM_freeN(smd->coll); 00625 smd->coll = NULL; 00626 } 00627 } 00628 00629 void smokeModifier_reset_turbulence(struct SmokeModifierData *smd) 00630 { 00631 if(smd && smd->domain && smd->domain->wt) 00632 { 00633 smoke_turbulence_free(smd->domain->wt); 00634 smd->domain->wt = NULL; 00635 } 00636 } 00637 00638 void smokeModifier_reset(struct SmokeModifierData *smd) 00639 { 00640 if(smd) 00641 { 00642 if(smd->domain) 00643 { 00644 if(smd->domain->shadow) 00645 MEM_freeN(smd->domain->shadow); 00646 smd->domain->shadow = NULL; 00647 00648 if(smd->domain->fluid) 00649 { 00650 smoke_free(smd->domain->fluid); 00651 smd->domain->fluid = NULL; 00652 } 00653 00654 smokeModifier_reset_turbulence(smd); 00655 00656 smd->time = -1; 00657 00658 // printf("reset domain end\n"); 00659 } 00660 else if(smd->flow) 00661 { 00662 /* 00663 if(smd->flow->bvh) 00664 { 00665 free_bvhtree_from_mesh(smd->flow->bvh); 00666 MEM_freeN(smd->flow->bvh); 00667 } 00668 smd->flow->bvh = NULL; 00669 */ 00670 } 00671 else if(smd->coll) 00672 { 00673 if(smd->coll->points) 00674 { 00675 MEM_freeN(smd->coll->points); 00676 smd->coll->points = NULL; 00677 } 00678 00679 if(smd->coll->bvhtree) 00680 { 00681 BLI_bvhtree_free(smd->coll->bvhtree); 00682 smd->coll->bvhtree = NULL; 00683 } 00684 00685 if(smd->coll->dm) 00686 smd->coll->dm->release(smd->coll->dm); 00687 smd->coll->dm = NULL; 00688 00689 } 00690 } 00691 } 00692 00693 void smokeModifier_free (SmokeModifierData *smd) 00694 { 00695 if(smd) 00696 { 00697 smokeModifier_freeDomain(smd); 00698 smokeModifier_freeFlow(smd); 00699 smokeModifier_freeCollision(smd); 00700 } 00701 } 00702 00703 void smokeModifier_createType(struct SmokeModifierData *smd) 00704 { 00705 if(smd) 00706 { 00707 if(smd->type & MOD_SMOKE_TYPE_DOMAIN) 00708 { 00709 if(smd->domain) 00710 smokeModifier_freeDomain(smd); 00711 00712 smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain"); 00713 00714 smd->domain->smd = smd; 00715 00716 smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0])); 00717 smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE; 00718 smd->domain->point_cache[0]->step = 1; 00719 00720 /* Deprecated */ 00721 smd->domain->point_cache[1] = NULL; 00722 smd->domain->ptcaches[1].first = smd->domain->ptcaches[1].last = NULL; 00723 /* set some standard values */ 00724 smd->domain->fluid = NULL; 00725 smd->domain->wt = NULL; 00726 smd->domain->eff_group = NULL; 00727 smd->domain->fluid_group = NULL; 00728 smd->domain->coll_group = NULL; 00729 smd->domain->maxres = 32; 00730 smd->domain->amplify = 1; 00731 smd->domain->omega = 1.0; 00732 smd->domain->alpha = -0.001; 00733 smd->domain->beta = 0.1; 00734 smd->domain->time_scale = 1.0; 00735 smd->domain->vorticity = 2.0; 00736 smd->domain->border_collisions = 1; // vertically non-colliding 00737 smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG | MOD_SMOKE_HIGH_SMOOTH; 00738 smd->domain->strength = 2.0; 00739 smd->domain->noise = MOD_SMOKE_NOISEWAVE; 00740 smd->domain->diss_speed = 5; 00741 // init 3dview buffer 00742 00743 smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG; 00744 smd->domain->effector_weights = BKE_add_effector_weights(NULL); 00745 } 00746 else if(smd->type & MOD_SMOKE_TYPE_FLOW) 00747 { 00748 if(smd->flow) 00749 smokeModifier_freeFlow(smd); 00750 00751 smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow"); 00752 00753 smd->flow->smd = smd; 00754 00755 /* set some standard values */ 00756 smd->flow->density = 1.0; 00757 smd->flow->temp = 1.0; 00758 smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE; 00759 smd->flow->vel_multi = 1.0; 00760 00761 smd->flow->psys = NULL; 00762 00763 } 00764 else if(smd->type & MOD_SMOKE_TYPE_COLL) 00765 { 00766 if(smd->coll) 00767 smokeModifier_freeCollision(smd); 00768 00769 smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl"); 00770 00771 smd->coll->smd = smd; 00772 smd->coll->points = NULL; 00773 smd->coll->numpoints = 0; 00774 smd->coll->bvhtree = NULL; 00775 smd->coll->dm = NULL; 00776 } 00777 } 00778 } 00779 00780 void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData *tsmd) 00781 { 00782 tsmd->type = smd->type; 00783 tsmd->time = smd->time; 00784 00785 smokeModifier_createType(tsmd); 00786 00787 if (tsmd->domain) { 00788 tsmd->domain->maxres = smd->domain->maxres; 00789 tsmd->domain->amplify = smd->domain->amplify; 00790 tsmd->domain->omega = smd->domain->omega; 00791 tsmd->domain->alpha = smd->domain->alpha; 00792 tsmd->domain->beta = smd->domain->beta; 00793 tsmd->domain->flags = smd->domain->flags; 00794 tsmd->domain->strength = smd->domain->strength; 00795 tsmd->domain->noise = smd->domain->noise; 00796 tsmd->domain->diss_speed = smd->domain->diss_speed; 00797 tsmd->domain->viewsettings = smd->domain->viewsettings; 00798 tsmd->domain->fluid_group = smd->domain->fluid_group; 00799 tsmd->domain->coll_group = smd->domain->coll_group; 00800 tsmd->domain->vorticity = smd->domain->vorticity; 00801 tsmd->domain->time_scale = smd->domain->time_scale; 00802 tsmd->domain->border_collisions = smd->domain->border_collisions; 00803 00804 MEM_freeN(tsmd->domain->effector_weights); 00805 tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights); 00806 } else if (tsmd->flow) { 00807 tsmd->flow->density = smd->flow->density; 00808 tsmd->flow->temp = smd->flow->temp; 00809 tsmd->flow->psys = smd->flow->psys; 00810 tsmd->flow->type = smd->flow->type; 00811 tsmd->flow->flags = smd->flow->flags; 00812 tsmd->flow->vel_multi = smd->flow->vel_multi; 00813 } else if (tsmd->coll) { 00814 ; 00815 /* leave it as initialised, collision settings is mostly caches */ 00816 } 00817 } 00818 00819 #ifdef WITH_SMOKE 00820 00821 // forward decleration 00822 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); 00823 static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct); 00824 00825 static int get_lamp(Scene *scene, float *light) 00826 { 00827 Base *base_tmp = NULL; 00828 int found_lamp = 0; 00829 00830 // try to find a lamp, preferably local 00831 for(base_tmp = scene->base.first; base_tmp; base_tmp= base_tmp->next) { 00832 if(base_tmp->object->type == OB_LAMP) { 00833 Lamp *la = base_tmp->object->data; 00834 00835 if(la->type == LA_LOCAL) { 00836 copy_v3_v3(light, base_tmp->object->obmat[3]); 00837 return 1; 00838 } 00839 else if(!found_lamp) { 00840 copy_v3_v3(light, base_tmp->object->obmat[3]); 00841 found_lamp = 1; 00842 } 00843 } 00844 } 00845 00846 return found_lamp; 00847 } 00848 00849 static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd) 00850 { 00851 SmokeDomainSettings *sds = smd->domain; 00852 GroupObject *go = NULL; 00853 Base *base = NULL; 00854 00855 // do collisions, needs to be done before emission, so that smoke isn't emitted inside collision cells 00856 if(1) 00857 { 00858 Object *otherobj = NULL; 00859 ModifierData *md = NULL; 00860 00861 if(sds->coll_group) // we use groups since we have 2 domains 00862 go = sds->coll_group->gobject.first; 00863 else 00864 base = scene->base.first; 00865 00866 while(base || go) 00867 { 00868 otherobj = NULL; 00869 if(sds->coll_group) 00870 { 00871 if(go->ob) 00872 otherobj = go->ob; 00873 } 00874 else 00875 otherobj = base->object; 00876 if(!otherobj) 00877 { 00878 if(sds->coll_group) 00879 go = go->next; 00880 else 00881 base= base->next; 00882 continue; 00883 } 00884 md = modifiers_findByType(otherobj, eModifierType_Smoke); 00885 00886 // check for active smoke modifier 00887 if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) 00888 { 00889 SmokeModifierData *smd2 = (SmokeModifierData *)md; 00890 00891 if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points) 00892 { 00893 // we got nice collision object 00894 SmokeCollSettings *scs = smd2->coll; 00895 size_t i, j; 00896 unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid); 00897 00898 for(i = 0; i < scs->numpoints; i++) 00899 { 00900 int badcell = 0; 00901 size_t index = 0; 00902 int cell[3]; 00903 00904 // 1. get corresponding cell 00905 get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, &scs->points[3 * i], cell, 0); 00906 00907 // check if cell is valid (in the domain boundary) 00908 for(j = 0; j < 3; j++) 00909 if((cell[j] > sds->res[j] - 1) || (cell[j] < 0)) 00910 { 00911 badcell = 1; 00912 break; 00913 } 00914 00915 if(badcell) 00916 continue; 00917 // 2. set cell values (heat, density and velocity) 00918 index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]); 00919 00920 // printf("cell[0]: %d, cell[1]: %d, cell[2]: %d\n", cell[0], cell[1], cell[2]); 00921 // printf("res[0]: %d, res[1]: %d, res[2]: %d, index: %d\n\n", sds->res[0], sds->res[1], sds->res[2], index); 00922 obstacles[index] = 1; 00923 // for moving gobstacles 00924 /* 00925 const LbmFloat maxVelVal = 0.1666; 00926 const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5; 00927 00928 LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); 00929 { 00930 const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; 00931 USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); 00932 if(usqr>maxusqr) { 00933 // cutoff at maxVelVal 00934 for(int jj=0; jj<3; jj++) { 00935 if(objvel[jj]>0.) objvel[jj] = maxVelVal; 00936 if(objvel[jj]<0.) objvel[jj] = -maxVelVal; 00937 } 00938 } 00939 } 00940 const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); 00941 const LbmVec oldov=objvel; // debug 00942 objvel = vec2L((*pNormals)[n]) *dp; 00943 */ 00944 } 00945 } 00946 } 00947 00948 if(sds->coll_group) 00949 go = go->next; 00950 else 00951 base= base->next; 00952 } 00953 } 00954 00955 // do flows and fluids 00956 if(1) 00957 { 00958 Object *otherobj = NULL; 00959 ModifierData *md = NULL; 00960 if(sds->fluid_group) // we use groups since we have 2 domains 00961 go = sds->fluid_group->gobject.first; 00962 else 00963 base = scene->base.first; 00964 while(base || go) 00965 { 00966 otherobj = NULL; 00967 if(sds->fluid_group) 00968 { 00969 if(go->ob) 00970 otherobj = go->ob; 00971 } 00972 else 00973 otherobj = base->object; 00974 if(!otherobj) 00975 { 00976 if(sds->fluid_group) 00977 go = go->next; 00978 else 00979 base= base->next; 00980 00981 continue; 00982 } 00983 00984 md = modifiers_findByType(otherobj, eModifierType_Smoke); 00985 00986 // check for active smoke modifier 00987 if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) 00988 { 00989 SmokeModifierData *smd2 = (SmokeModifierData *)md; 00990 00991 // check for initialized smoke object 00992 if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) 00993 { 00994 // we got nice flow object 00995 SmokeFlowSettings *sfs = smd2->flow; 00996 00997 if(sfs && sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected 00998 { 00999 ParticleSimulationData sim; 01000 ParticleSystem *psys = sfs->psys; 01001 int p = 0; 01002 float *density = smoke_get_density(sds->fluid); 01003 float *bigdensity = smoke_turbulence_get_density(sds->wt); 01004 float *heat = smoke_get_heat(sds->fluid); 01005 float *velocity_x = smoke_get_velocity_x(sds->fluid); 01006 float *velocity_y = smoke_get_velocity_y(sds->fluid); 01007 float *velocity_z = smoke_get_velocity_z(sds->fluid); 01008 unsigned char *obstacle = smoke_get_obstacle(sds->fluid); 01009 int bigres[3]; 01010 short absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE); 01011 short high_emission_smoothing = bigdensity ? (smd->domain->flags & MOD_SMOKE_HIGH_SMOOTH) : 0; 01012 01013 /* 01014 * A temporary volume map used to store whole emissive 01015 * area to be added to smoke density and interpolated 01016 * for high resolution smoke. 01017 */ 01018 float *temp_emission_map = NULL; 01019 01020 sim.scene = scene; 01021 sim.ob = otherobj; 01022 sim.psys = psys; 01023 01024 // initialize temp emission map 01025 if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) 01026 { 01027 int i; 01028 temp_emission_map = MEM_callocN(sizeof(float) * sds->res[0]*sds->res[1]*sds->res[2], "SmokeTempEmission"); 01029 // set whole volume to 0.0f 01030 for (i=0; i<sds->res[0]*sds->res[1]*sds->res[2]; i++) { 01031 temp_emission_map[i] = 0.0f; 01032 } 01033 } 01034 01035 // mostly copied from particle code 01036 for(p=0; p<psys->totpart; p++) 01037 { 01038 int cell[3]; 01039 size_t i = 0; 01040 size_t index = 0; 01041 int badcell = 0; 01042 ParticleKey state; 01043 01044 if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST)) 01045 continue; 01046 01047 state.time = smd->time; 01048 01049 if(psys_get_particle_state(&sim, p, &state, 0) == 0) 01050 continue; 01051 01052 // copy_v3_v3(pos, pa->state.co); 01053 // mul_m4_v3(ob->imat, pos); 01054 // 1. get corresponding cell 01055 get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, state.co, cell, 0); 01056 // check if cell is valid (in the domain boundary) 01057 for(i = 0; i < 3; i++) 01058 { 01059 if((cell[i] > sds->res[i] - 1) || (cell[i] < 0)) 01060 { 01061 badcell = 1; 01062 break; 01063 } 01064 } 01065 if(badcell) 01066 continue; 01067 // 2. set cell values (heat, density and velocity) 01068 index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]); 01069 if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) && !(obstacle[index])) // this is inflow 01070 { 01071 // heat[index] += sfs->temp * 0.1; 01072 // density[index] += sfs->density * 0.1; 01073 heat[index] = sfs->temp; 01074 01075 // Add emitter density to temp emission map 01076 temp_emission_map[index] = sfs->density; 01077 01078 // Uses particle velocity as initial velocity for smoke 01079 if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) 01080 { 01081 velocity_x[index] = state.vel[0]*sfs->vel_multi; 01082 velocity_y[index] = state.vel[1]*sfs->vel_multi; 01083 velocity_z[index] = state.vel[2]*sfs->vel_multi; 01084 } 01085 } 01086 else if(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) // outflow 01087 { 01088 heat[index] = 0.f; 01089 density[index] = 0.f; 01090 velocity_x[index] = 0.f; 01091 velocity_y[index] = 0.f; 01092 velocity_z[index] = 0.f; 01093 // we need different handling for the high-res feature 01094 if(bigdensity) 01095 { 01096 // init all surrounding cells according to amplification, too 01097 int i, j, k; 01098 smoke_turbulence_get_res(smd->domain->wt, bigres); 01099 01100 for(i = 0; i < smd->domain->amplify + 1; i++) 01101 for(j = 0; j < smd->domain->amplify + 1; j++) 01102 for(k = 0; k < smd->domain->amplify + 1; k++) 01103 { 01104 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); 01105 bigdensity[index] = 0.f; 01106 } 01107 } 01108 } 01109 } // particles loop 01110 01111 01112 // apply emission values 01113 if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) { 01114 01115 // initialize variables 01116 int ii, jj, kk, x, y, z, block_size; 01117 size_t index, index_big; 01118 01119 smoke_turbulence_get_res(smd->domain->wt, bigres); 01120 block_size = smd->domain->amplify + 1; // high res block size 01121 01122 01123 // loop through every low res cell 01124 for(x = 0; x < sds->res[0]; x++) 01125 for(y = 0; y < sds->res[1]; y++) 01126 for(z = 0; z < sds->res[2]; z++) 01127 { 01128 01129 // neighbour cell emission densities (for high resolution smoke smooth interpolation) 01130 float c000, c001, c010, c011, c100, c101, c110, c111; 01131 01132 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; 01133 c001 = (x>0 && y>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y-1, sds->res[1], z)] : 0; 01134 c010 = (x>0 && z>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y, sds->res[1], z-1)] : 0; 01135 c011 = (x>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y, sds->res[1], z)] : 0; 01136 01137 c100 = (y>0 && z>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y-1, sds->res[1], z-1)] : 0; 01138 c101 = (y>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y-1, sds->res[1], z)] : 0; 01139 c110 = (z>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y, sds->res[1], z-1)] : 0; 01140 c111 = temp_emission_map[smoke_get_index(x, sds->res[0], y, sds->res[1], z)]; // this cell 01141 01142 01143 01144 // get cell index 01145 index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); 01146 01147 // add emission to low resolution density 01148 if (absolute_flow) {if (temp_emission_map[index]>0) density[index] = temp_emission_map[index];} 01149 else { 01150 density[index] += temp_emission_map[index]; 01151 if (density[index]>1) density[index]=1.0f; 01152 } 01153 01154 smoke_turbulence_get_res(smd->domain->wt, bigres); 01155 01156 01157 01158 /* 01159 loop through high res blocks if high res enabled 01160 */ 01161 if (bigdensity) 01162 for(ii = 0; ii < block_size; ii++) 01163 for(jj = 0; jj < block_size; jj++) 01164 for(kk = 0; kk < block_size; kk++) 01165 { 01166 01167 float fx,fy,fz, interpolated_value; 01168 int shift_x, shift_y, shift_z; 01169 01170 01171 /* 01172 * Do volume interpolation if emitter smoothing 01173 * is enabled 01174 */ 01175 if (high_emission_smoothing) { 01176 // convert block position to relative 01177 // for interpolation smoothing 01178 fx = (float)ii/block_size + 0.5f/block_size; 01179 fy = (float)jj/block_size + 0.5f/block_size; 01180 fz = (float)kk/block_size + 0.5f/block_size; 01181 01182 // calculate trilinear interpolation 01183 interpolated_value = c000 * (1-fx) * (1-fy) * (1-fz) + 01184 c100 * fx * (1-fy) * (1-fz) + 01185 c010 * (1-fx) * fy * (1-fz) + 01186 c001 * (1-fx) * (1-fy) * fz + 01187 c101 * fx * (1-fy) * fz + 01188 c011 * (1-fx) * fy * fz + 01189 c110 * fx * fy * (1-fz) + 01190 c111 * fx * fy * fz; 01191 01192 01193 // add some contrast / sharpness 01194 // depending on hi-res block size 01195 01196 interpolated_value = (interpolated_value-0.4f*sfs->density)*(block_size/2) + 0.4f*sfs->density; 01197 if (interpolated_value<0.0f) interpolated_value = 0.0f; 01198 if (interpolated_value>1.0f) interpolated_value = 1.0f; 01199 01200 // shift smoke block index 01201 // (because pixel center is actually 01202 // in halfway of the low res block) 01203 shift_x = (x < 1) ? 0 : block_size/2; 01204 shift_y = (y < 1) ? 0 : block_size/2; 01205 shift_z = (z < 1) ? 0 : block_size/2; 01206 } 01207 else { 01208 // without interpolation use same low resolution 01209 // block value for all hi-res blocks 01210 interpolated_value = c111; 01211 shift_x = 0; 01212 shift_y = 0; 01213 shift_z = 0; 01214 } 01215 01216 // get shifted index for current high resolution block 01217 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); 01218 01219 // add emission data to high resolution density 01220 if (absolute_flow) {if (interpolated_value > 0) bigdensity[index_big] = interpolated_value;} 01221 else { 01222 bigdensity[index_big] += interpolated_value; 01223 if (bigdensity[index_big]>1) bigdensity[index_big]=1.0f; 01224 } 01225 01226 } // end of hires loop 01227 01228 } // end of low res loop 01229 01230 // free temporary emission map 01231 if (temp_emission_map) MEM_freeN(temp_emission_map); 01232 01233 } // end emission 01234 01235 01236 01237 } 01238 else 01239 { 01240 /* 01241 for() 01242 { 01243 // no psys 01244 BVHTreeNearest nearest; 01245 nearest.index = -1; 01246 nearest.dist = FLT_MAX; 01247 01248 BLI_bvhtree_find_nearest(sfs->bvh->tree, pco, &nearest, sfs->bvh->nearest_callback, sfs->bvh); 01249 }*/ 01250 } 01251 } 01252 } 01253 if(sds->fluid_group) 01254 go = go->next; 01255 else 01256 base= base->next; 01257 } 01258 } 01259 01260 // do effectors 01261 { 01262 ListBase *effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights); 01263 01264 if(effectors) 01265 { 01266 float *density = smoke_get_density(sds->fluid); 01267 float *force_x = smoke_get_force_x(sds->fluid); 01268 float *force_y = smoke_get_force_y(sds->fluid); 01269 float *force_z = smoke_get_force_z(sds->fluid); 01270 float *velocity_x = smoke_get_velocity_x(sds->fluid); 01271 float *velocity_y = smoke_get_velocity_y(sds->fluid); 01272 float *velocity_z = smoke_get_velocity_z(sds->fluid); 01273 int x, y, z; 01274 01275 // precalculate wind forces 01276 for(x = 0; x < sds->res[0]; x++) 01277 for(y = 0; y < sds->res[1]; y++) 01278 for(z = 0; z < sds->res[2]; z++) 01279 { 01280 EffectedPoint epoint; 01281 float voxelCenter[3] = {0,0,0} , vel[3] = {0,0,0} , retvel[3] = {0,0,0}; 01282 unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); 01283 01284 if(density[index] < FLT_EPSILON) 01285 continue; 01286 01287 vel[0] = velocity_x[index]; 01288 vel[1] = velocity_y[index]; 01289 vel[2] = velocity_z[index]; 01290 01291 voxelCenter[0] = sds->p0[0] + sds->dx * x + sds->dx * 0.5; 01292 voxelCenter[1] = sds->p0[1] + sds->dx * y + sds->dx * 0.5; 01293 voxelCenter[2] = sds->p0[2] + sds->dx * z + sds->dx * 0.5; 01294 01295 pd_point_from_loc(scene, voxelCenter, vel, index, &epoint); 01296 pdDoEffectors(effectors, NULL, sds->effector_weights, &epoint, retvel, NULL); 01297 01298 // TODO dg - do in force! 01299 force_x[index] = MIN2(MAX2(-1.0, retvel[0] * 0.2), 1.0); 01300 force_y[index] = MIN2(MAX2(-1.0, retvel[1] * 0.2), 1.0); 01301 force_z[index] = MIN2(MAX2(-1.0, retvel[2] * 0.2), 1.0); 01302 } 01303 } 01304 01305 pdEndEffectors(&effectors); 01306 } 01307 01308 } 01309 void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm) 01310 { 01311 if((smd->type & MOD_SMOKE_TYPE_FLOW)) 01312 { 01313 if(scene->r.cfra >= smd->time) 01314 smokeModifier_init(smd, ob, scene, dm); 01315 01316 if(scene->r.cfra > smd->time) 01317 { 01318 // XXX TODO 01319 smd->time = scene->r.cfra; 01320 01321 // rigid movement support 01322 /* 01323 copy_m4_m4(smd->flow->mat_old, smd->flow->mat); 01324 copy_m4_m4(smd->flow->mat, ob->obmat); 01325 */ 01326 } 01327 else if(scene->r.cfra < smd->time) 01328 { 01329 smd->time = scene->r.cfra; 01330 smokeModifier_reset(smd); 01331 } 01332 } 01333 else if(smd->type & MOD_SMOKE_TYPE_COLL) 01334 { 01335 if(scene->r.cfra >= smd->time) 01336 smokeModifier_init(smd, ob, scene, dm); 01337 01338 if(scene->r.cfra > smd->time) 01339 { 01340 // XXX TODO 01341 smd->time = scene->r.cfra; 01342 01343 if(smd->coll->dm) 01344 smd->coll->dm->release(smd->coll->dm); 01345 01346 smd->coll->dm = CDDM_copy(dm); 01347 01348 // rigid movement support 01349 copy_m4_m4(smd->coll->mat_old, smd->coll->mat); 01350 copy_m4_m4(smd->coll->mat, ob->obmat); 01351 } 01352 else if(scene->r.cfra < smd->time) 01353 { 01354 smd->time = scene->r.cfra; 01355 smokeModifier_reset(smd); 01356 } 01357 } 01358 else if(smd->type & MOD_SMOKE_TYPE_DOMAIN) 01359 { 01360 SmokeDomainSettings *sds = smd->domain; 01361 float light[3]; 01362 PointCache *cache = NULL; 01363 PTCacheID pid; 01364 int startframe, endframe, framenr; 01365 float timescale; 01366 01367 framenr = scene->r.cfra; 01368 01369 //printf("time: %d\n", scene->r.cfra); 01370 01371 cache = sds->point_cache[0]; 01372 BKE_ptcache_id_from_smoke(&pid, ob, smd); 01373 BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); 01374 01375 if(!smd->domain->fluid || framenr == startframe) 01376 { 01377 BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); 01378 BKE_ptcache_validate(cache, framenr); 01379 cache->flag &= ~PTCACHE_REDO_NEEDED; 01380 } 01381 01382 if(!smd->domain->fluid && (framenr != startframe) && (smd->domain->flags & MOD_SMOKE_FILE_LOAD)==0 && (cache->flag & PTCACHE_BAKED)==0) 01383 return; 01384 01385 smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD; 01386 01387 CLAMP(framenr, startframe, endframe); 01388 01389 /* If already viewing a pre/after frame, no need to reload */ 01390 if ((smd->time == framenr) && (framenr != scene->r.cfra)) 01391 return; 01392 01393 // printf("startframe: %d, framenr: %d\n", startframe, framenr); 01394 01395 if(smokeModifier_init(smd, ob, scene, dm)==0) 01396 { 01397 printf("bad smokeModifier_init\n"); 01398 return; 01399 } 01400 01401 /* try to read from cache */ 01402 if(BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT) { 01403 BKE_ptcache_validate(cache, framenr); 01404 smd->time = framenr; 01405 return; 01406 } 01407 01408 /* only calculate something when we advanced a single frame */ 01409 if(framenr != (int)smd->time+1) 01410 return; 01411 01412 /* don't simulate if viewing start frame, but scene frame is not real start frame */ 01413 if (framenr != scene->r.cfra) 01414 return; 01415 01416 tstart(); 01417 01418 smoke_calc_domain(scene, ob, smd); 01419 01420 /* if on second frame, write cache for first frame */ 01421 if((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) { 01422 // create shadows straight after domain initialization so we get nice shadows for startframe, too 01423 if(get_lamp(scene, light)) 01424 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); 01425 01426 if(sds->wt) 01427 { 01428 if(sds->flags & MOD_SMOKE_DISSOLVE) 01429 smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); 01430 smoke_turbulence_step(sds->wt, sds->fluid); 01431 } 01432 01433 BKE_ptcache_write(&pid, startframe); 01434 } 01435 01436 // set new time 01437 smd->time = scene->r.cfra; 01438 01439 /* do simulation */ 01440 01441 // low res 01442 01443 // simulate the actual smoke (c++ code in intern/smoke) 01444 // DG: interesting commenting this line + deactivating loading of noise files 01445 if(framenr!=startframe) 01446 { 01447 if(sds->flags & MOD_SMOKE_DISSOLVE) 01448 smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); 01449 smoke_step(sds->fluid, smd->time, scene->r.frs_sec / scene->r.frs_sec_base); 01450 } 01451 01452 // create shadows before writing cache so they get stored 01453 if(get_lamp(scene, light)) 01454 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); 01455 01456 if(sds->wt) 01457 { 01458 if(sds->flags & MOD_SMOKE_DISSOLVE) 01459 smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); 01460 smoke_turbulence_step(sds->wt, sds->fluid); 01461 } 01462 01463 BKE_ptcache_validate(cache, framenr); 01464 if(framenr != startframe) 01465 BKE_ptcache_write(&pid, framenr); 01466 01467 tend(); 01468 //printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() ); 01469 } 01470 } 01471 01472 static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct) 01473 { 01474 const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]); 01475 01476 // T_ray *= T_vox 01477 *tRay *= exp(input[index]*correct); 01478 01479 if(result[index] < 0.0f) 01480 { 01481 #pragma omp critical 01482 result[index] = *tRay; 01483 } 01484 01485 return *tRay; 01486 } 01487 01488 long long smoke_get_mem_req(int xres, int yres, int zres, int amplify) 01489 { 01490 int totalCells = xres * yres * zres; 01491 int amplifiedCells = totalCells * amplify * amplify * amplify; 01492 01493 // print out memory requirements 01494 long long int coarseSize = sizeof(float) * totalCells * 22 + 01495 sizeof(unsigned char) * totalCells; 01496 01497 long long int fineSize = sizeof(float) * amplifiedCells * 7 + // big grids 01498 sizeof(float) * totalCells * 8 + // small grids 01499 sizeof(float) * 128 * 128 * 128; // noise tile 01500 01501 long long int totalMB = (coarseSize + fineSize) / (1024 * 1024); 01502 01503 return totalMB; 01504 } 01505 01506 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) 01507 { 01508 int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2; 01509 int pixel[3]; 01510 01511 pixel[0] = x1; 01512 pixel[1] = y1; 01513 pixel[2] = z1; 01514 01515 dx = x2 - x1; 01516 dy = y2 - y1; 01517 dz = z2 - z1; 01518 01519 x_inc = (dx < 0) ? -1 : 1; 01520 l = abs(dx); 01521 y_inc = (dy < 0) ? -1 : 1; 01522 m = abs(dy); 01523 z_inc = (dz < 0) ? -1 : 1; 01524 n = abs(dz); 01525 dx2 = l << 1; 01526 dy2 = m << 1; 01527 dz2 = n << 1; 01528 01529 if ((l >= m) && (l >= n)) { 01530 err_1 = dy2 - l; 01531 err_2 = dz2 - l; 01532 for (i = 0; i < l; i++) { 01533 if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) 01534 break; 01535 if (err_1 > 0) { 01536 pixel[1] += y_inc; 01537 err_1 -= dx2; 01538 } 01539 if (err_2 > 0) { 01540 pixel[2] += z_inc; 01541 err_2 -= dx2; 01542 } 01543 err_1 += dy2; 01544 err_2 += dz2; 01545 pixel[0] += x_inc; 01546 } 01547 } else if ((m >= l) && (m >= n)) { 01548 err_1 = dx2 - m; 01549 err_2 = dz2 - m; 01550 for (i = 0; i < m; i++) { 01551 if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) 01552 break; 01553 if (err_1 > 0) { 01554 pixel[0] += x_inc; 01555 err_1 -= dy2; 01556 } 01557 if (err_2 > 0) { 01558 pixel[2] += z_inc; 01559 err_2 -= dy2; 01560 } 01561 err_1 += dx2; 01562 err_2 += dz2; 01563 pixel[1] += y_inc; 01564 } 01565 } else { 01566 err_1 = dy2 - n; 01567 err_2 = dx2 - n; 01568 for (i = 0; i < n; i++) { 01569 if(cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) 01570 break; 01571 if (err_1 > 0) { 01572 pixel[1] += y_inc; 01573 err_1 -= dz2; 01574 } 01575 if (err_2 > 0) { 01576 pixel[0] += x_inc; 01577 err_2 -= dz2; 01578 } 01579 err_1 += dy2; 01580 err_2 += dx2; 01581 pixel[2] += z_inc; 01582 } 01583 } 01584 cb(result, input, res, pixel, tRay, correct); 01585 } 01586 01587 static void get_cell(float *p0, int res[3], float dx, float *pos, int *cell, int correct) 01588 { 01589 float tmp[3]; 01590 01591 sub_v3_v3v3(tmp, pos, p0); 01592 mul_v3_fl(tmp, 1.0 / dx); 01593 01594 if(correct) 01595 { 01596 cell[0] = MIN2(res[0] - 1, MAX2(0, (int)floor(tmp[0]))); 01597 cell[1] = MIN2(res[1] - 1, MAX2(0, (int)floor(tmp[1]))); 01598 cell[2] = MIN2(res[2] - 1, MAX2(0, (int)floor(tmp[2]))); 01599 } 01600 else 01601 { 01602 cell[0] = (int)floor(tmp[0]); 01603 cell[1] = (int)floor(tmp[1]); 01604 cell[2] = (int)floor(tmp[2]); 01605 } 01606 } 01607 01608 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) 01609 { 01610 float bv[6]; 01611 int a, z, slabsize=res[0]*res[1], size= res[0]*res[1]*res[2]; 01612 01613 for(a=0; a<size; a++) 01614 result[a]= -1.0f; 01615 01616 bv[0] = p0[0]; 01617 bv[1] = p1[0]; 01618 // y 01619 bv[2] = p0[1]; 01620 bv[3] = p1[1]; 01621 // z 01622 bv[4] = p0[2]; 01623 bv[5] = p1[2]; 01624 01625 #pragma omp parallel for schedule(static,1) 01626 for(z = 0; z < res[2]; z++) 01627 { 01628 size_t index = z*slabsize; 01629 int x,y; 01630 01631 for(y = 0; y < res[1]; y++) 01632 for(x = 0; x < res[0]; x++, index++) 01633 { 01634 float voxelCenter[3]; 01635 float pos[3]; 01636 int cell[3]; 01637 float tRay = 1.0; 01638 01639 if(result[index] >= 0.0f) 01640 continue; 01641 voxelCenter[0] = p0[0] + dx * x + dx * 0.5; 01642 voxelCenter[1] = p0[1] + dx * y + dx * 0.5; 01643 voxelCenter[2] = p0[2] + dx * z + dx * 0.5; 01644 01645 // get starting position (in voxel coords) 01646 if(BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) 01647 { 01648 // we're ouside 01649 get_cell(p0, res, dx, pos, cell, 1); 01650 } 01651 else 01652 { 01653 // we're inside 01654 get_cell(p0, res, dx, light, cell, 1); 01655 } 01656 01657 bresenham_linie_3D(cell[0], cell[1], cell[2], x, y, z, &tRay, cb, result, input, res, correct); 01658 01659 // convention -> from a RGBA float array, use G value for tRay 01660 // #pragma omp critical 01661 result[index] = tRay; 01662 } 01663 } 01664 } 01665 01666 #endif /* WITH_SMOKE */