static int rna_SmokeModifier_grid_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) { #ifdef WITH_SMOKE SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; float *density = NULL; int size = 0; if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) { /* high resolution smoke */ int res[3]; smoke_turbulence_get_res(sds->wt, res); size = res[0] * res[1] * res[2]; density = smoke_turbulence_get_density(sds->wt); } else if (sds->fluid) { /* regular resolution */ size = sds->res[0] * sds->res[1] * sds->res[2]; density = smoke_get_density(sds->fluid); } length[0] = (density) ? size : 0; #else (void)ptr; length[0] = 0; #endif return length[0]; }
static void rna_SmokeModifier_density_get(PointerRNA *ptr, float *values) { SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data; float *density = smoke_get_density(settings->fluid); unsigned int size = settings->res[0] * settings->res[1] * settings->res[2]; memcpy(values, density, size * sizeof(float)); }
static int rna_SmokeModifier_density_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) { SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data; if (settings->fluid) { float *density = smoke_get_density(settings->fluid); unsigned int size = settings->res[0] * settings->res[1] * settings->res[2]; if (density) length[0] = size; else length[0] = 0; } else { length[0] = 0; /* No smoke domain created yet */ } return length[0]; }
static void rna_SmokeModifier_density_grid_get(PointerRNA *ptr, float *values) { #ifdef WITH_SMOKE SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; int length[RNA_MAX_ARRAY_DIMENSION]; int size = rna_SmokeModifier_grid_get_length(ptr, length); float *density; BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ); if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) density = smoke_turbulence_get_density(sds->wt); else density = smoke_get_density(sds->fluid); memcpy(values, density, size * sizeof(float)); BLI_rw_mutex_unlock(sds->fluid_mutex); #else UNUSED_VARS(ptr, values); #endif }
static void init_frame_smoke(VoxelData *vd, float cfra) { #ifdef WITH_SMOKE Object *ob; ModifierData *md; vd->dataset = NULL; if (vd->object == NULL) return; ob= vd->object; /* draw code for smoke */ if( (md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke)) ) { SmokeModifierData *smd = (SmokeModifierData *)md; if(smd->domain && smd->domain->fluid) { if(cfra < smd->domain->point_cache[0]->startframe) ; /* don't show smoke before simulation starts, this could be made an option in the future */ else if (vd->smoked_type == TEX_VD_SMOKEHEAT) { size_t totRes; size_t i; float *heat; VECCOPY(vd->resol, smd->domain->res); totRes= vd_resol_size(vd); // scaling heat values from -2.0-2.0 to 0.0-1.0 vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data"); heat = smoke_get_heat(smd->domain->fluid); for (i=0; i<totRes; i++) { vd->dataset[i] = (heat[i]+2.0f)/4.0f; } //vd->dataset = smoke_get_heat(smd->domain->fluid); } else if (vd->smoked_type == TEX_VD_SMOKEVEL) { size_t totRes; size_t i; float *xvel, *yvel, *zvel; VECCOPY(vd->resol, smd->domain->res); totRes= vd_resol_size(vd); // scaling heat values from -2.0-2.0 to 0.0-1.0 vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data"); xvel = smoke_get_velocity_x(smd->domain->fluid); yvel = smoke_get_velocity_y(smd->domain->fluid); zvel = smoke_get_velocity_z(smd->domain->fluid); for (i=0; i<totRes; i++) { vd->dataset[i] = sqrt(xvel[i]*xvel[i] + yvel[i]*yvel[i] + zvel[i]*zvel[i])*3.0f; } } else { size_t totRes; float *density; if (smd->domain->flags & MOD_SMOKE_HIGHRES) { smoke_turbulence_get_res(smd->domain->wt, vd->resol); density = smoke_turbulence_get_density(smd->domain->wt); } else { VECCOPY(vd->resol, smd->domain->res); density = smoke_get_density(smd->domain->fluid); } /* TODO: is_vd_res_ok(rvd) doesnt check this resolution */ totRes= vd_resol_size(vd); /* always store copy, as smoke internal data can change */ vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data"); memcpy(vd->dataset, density, sizeof(float)*totRes); } // end of fluid condition } } vd->ok = 1; #else // WITH_SMOKE (void)vd; (void)cfra; vd->dataset= NULL; #endif }
static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd) { SmokeDomainSettings *sds = smd->domain; GroupObject *go = NULL; Base *base = NULL; // do flows and fluids if(1) { Object *otherobj = NULL; ModifierData *md = NULL; if(sds->fluid_group) // we use groups since we have 2 domains go = sds->fluid_group->gobject.first; else base = scene->base.first; while(base || go) { otherobj = NULL; if(sds->fluid_group) { if(go->ob) otherobj = go->ob; } else otherobj = base->object; if(!otherobj) { if(sds->fluid_group) go = go->next; else base= base->next; continue; } md = modifiers_findByType(otherobj, eModifierType_Smoke); // check for active smoke modifier if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) { SmokeModifierData *smd2 = (SmokeModifierData *)md; // check for initialized smoke object if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) { // we got nice flow object SmokeFlowSettings *sfs = smd2->flow; if(sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected { ParticleSystem *psys = sfs->psys; ParticleSettings *part=psys->part; ParticleData *pa = NULL; int p = 0; float *density = smoke_get_density(sds->fluid); float *bigdensity = smoke_turbulence_get_density(sds->wt); float *heat = smoke_get_heat(sds->fluid); float *velocity_x = smoke_get_velocity_x(sds->fluid); float *velocity_y = smoke_get_velocity_y(sds->fluid); float *velocity_z = smoke_get_velocity_z(sds->fluid); unsigned char *obstacle = smoke_get_obstacle(sds->fluid); int bigres[3]; // mostly copied from particle code for(p=0, pa=psys->particles; p<psys->totpart; p++, pa++) { int cell[3]; size_t i = 0; size_t index = 0; int badcell = 0; if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue; else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0) continue; else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue; // VECCOPY(pos, pa->state.co); // Mat4MulVecfl (ob->imat, pos); // 1. get corresponding cell get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, pa->state.co, cell, 0); // check if cell is valid (in the domain boundary) for(i = 0; i < 3; i++) { if((cell[i] > sds->res[i] - 1) || (cell[i] < 0)) { badcell = 1; break; } } if(badcell) continue; // 2. set cell values (heat, density and velocity) index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]); if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) && !(obstacle[index] & 2)) // this is inflow { // heat[index] += sfs->temp * 0.1; // density[index] += sfs->density * 0.1; heat[index] = sfs->temp; density[index] = sfs->density; /* velocity_x[index] = pa->state.vel[0]; velocity_y[index] = pa->state.vel[1]; velocity_z[index] = pa->state.vel[2]; */ // obstacle[index] |= 2; // we need different handling for the high-res feature if(bigdensity) { // init all surrounding cells according to amplification, too int i, j, k; smoke_turbulence_get_res(smd->domain->wt, bigres); for(i = 0; i < smd->domain->amplify + 1; i++) for(j = 0; j < smd->domain->amplify + 1; j++) for(k = 0; k < smd->domain->amplify + 1; k++) { index = smoke_get_index((smd->domain->amplify + 1)* cell[0] + i, bigres[0], (smd->domain->amplify + 1)* cell[1] + j, bigres[1], (smd->domain->amplify + 1)* cell[2] + k); bigdensity[index] = sfs->density; } } } else if(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) // outflow { heat[index] = 0.f; density[index] = 0.f; velocity_x[index] = 0.f; velocity_y[index] = 0.f; velocity_z[index] = 0.f; // we need different handling for the high-res feature if(bigdensity) { // init all surrounding cells according to amplification, too int i, j, k; smoke_turbulence_get_res(smd->domain->wt, bigres); for(i = 0; i < smd->domain->amplify + 1; i++) for(j = 0; j < smd->domain->amplify + 1; j++) for(k = 0; k < smd->domain->amplify + 1; k++) { index = smoke_get_index((smd->domain->amplify + 1)* cell[0] + i, bigres[0], (smd->domain->amplify + 1)* cell[1] + j, bigres[1], (smd->domain->amplify + 1)* cell[2] + k); bigdensity[index] = 0.f; } } } // particles loop } } else { /* for() { // no psys BVHTreeNearest nearest; nearest.index = -1; nearest.dist = FLT_MAX; BLI_bvhtree_find_nearest(sfs->bvh->tree, pco, &nearest, sfs->bvh->nearest_callback, sfs->bvh); }*/ } } } if(sds->fluid_group) go = go->next; else base= base->next; } } // do effectors { 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); 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); } } pdEndEffectors(&effectors); } // do collisions if(1) { Object *otherobj = NULL; ModifierData *md = NULL; if(sds->coll_group) // we use groups since we have 2 domains go = sds->coll_group->gobject.first; else base = scene->base.first; while(base || go) { otherobj = NULL; if(sds->coll_group) { if(go->ob) otherobj = go->ob; } else otherobj = base->object; if(!otherobj) { if(sds->coll_group) go = go->next; else base= base->next; continue; } md = modifiers_findByType(otherobj, eModifierType_Smoke); // check for active smoke modifier if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) { SmokeModifierData *smd2 = (SmokeModifierData *)md; if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points) { // we got nice collision object SmokeCollSettings *scs = smd2->coll; size_t i, j; unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid); for(i = 0; i < scs->numpoints; i++) { int badcell = 0; size_t index = 0; int cell[3]; // 1. get corresponding cell get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, &scs->points[3 * i], cell, 0); // check if cell is valid (in the domain boundary) for(j = 0; j < 3; j++) if((cell[j] > sds->res[j] - 1) || (cell[j] < 0)) { badcell = 1; break; } if(badcell) continue; // 2. set cell values (heat, density and velocity) index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]); // printf("cell[0]: %d, cell[1]: %d, cell[2]: %d\n", cell[0], cell[1], cell[2]); // printf("res[0]: %d, res[1]: %d, res[2]: %d, index: %d\n\n", sds->res[0], sds->res[1], sds->res[2], index); obstacles[index] = 1; // for moving gobstacles /* const LbmFloat maxVelVal = 0.1666; const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5; LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); { const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); if(usqr>maxusqr) { // cutoff at maxVelVal for(int jj=0; jj<3; jj++) { if(objvel[jj]>0.) objvel[jj] = maxVelVal; if(objvel[jj]<0.) objvel[jj] = -maxVelVal; } } } const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); const LbmVec oldov=objvel; // debug objvel = vec2L((*pNormals)[n]) *dp; */ } } } if(sds->coll_group) go = go->next; else base= base->next; } } }
void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) { if((smd->type & MOD_SMOKE_TYPE_FLOW)) { if(scene->r.cfra >= smd->time) smokeModifier_init(smd, ob, scene, dm); if(scene->r.cfra > smd->time) { // XXX TODO smd->time = scene->r.cfra; // rigid movement support /* Mat4CpyMat4(smd->flow->mat_old, smd->flow->mat); Mat4CpyMat4(smd->flow->mat, ob->obmat); */ } else if(scene->r.cfra < smd->time) { smd->time = scene->r.cfra; smokeModifier_reset(smd); } } else if(smd->type & MOD_SMOKE_TYPE_COLL) { if(scene->r.cfra >= smd->time) smokeModifier_init(smd, ob, scene, dm); if(scene->r.cfra > smd->time) { // XXX TODO smd->time = scene->r.cfra; if(smd->coll->dm) smd->coll->dm->release(smd->coll->dm); smd->coll->dm = CDDM_copy(dm); // rigid movement support Mat4CpyMat4(smd->coll->mat_old, smd->coll->mat); Mat4CpyMat4(smd->coll->mat, ob->obmat); } else if(scene->r.cfra < smd->time) { smd->time = scene->r.cfra; smokeModifier_reset(smd); } } else if(smd->type & MOD_SMOKE_TYPE_DOMAIN) { SmokeDomainSettings *sds = smd->domain; float light[3]; PointCache *cache = NULL; PTCacheID pid; PointCache *cache_wt = NULL; PTCacheID pid_wt; int startframe, endframe, framenr; float timescale; int cache_result = 0, cache_result_wt = 0; framenr = scene->r.cfra; // printf("time: %d\n", scene->r.cfra); if(framenr == smd->time) return; cache = sds->point_cache[0]; BKE_ptcache_id_from_smoke(&pid, ob, smd); BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); cache_wt = sds->point_cache[1]; BKE_ptcache_id_from_smoke_turbulence(&pid_wt, ob, smd); if(!smd->domain->fluid) { BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); BKE_ptcache_id_reset(scene, &pid_wt, PTCACHE_RESET_OUTDATED); } if(framenr < startframe) return; if(framenr > endframe) return; if(!smd->domain->fluid && (framenr != startframe)) return; // printf("startframe: %d, framenr: %d\n", startframe, framenr); if(!smokeModifier_init(smd, ob, scene, dm)) { printf("bad smokeModifier_init\n"); return; } /* try to read from cache */ cache_result = BKE_ptcache_read_cache(&pid, (float)framenr, scene->r.frs_sec); // printf("cache_result: %d\n", cache_result); if(cache_result == PTCACHE_READ_EXACT) { cache->flag |= PTCACHE_SIMULATION_VALID; cache->simframe= framenr; if(sds->wt) { cache_result_wt = BKE_ptcache_read_cache(&pid_wt, (float)framenr, scene->r.frs_sec); if(cache_result_wt == PTCACHE_READ_EXACT) { cache_wt->flag |= PTCACHE_SIMULATION_VALID; cache_wt->simframe= framenr; } } return; } tstart(); smoke_calc_domain(scene, ob, smd); // set new time smd->time = scene->r.cfra; /* do simulation */ // low res cache->flag |= PTCACHE_SIMULATION_VALID; cache->simframe= framenr; // simulate the actual smoke (c++ code in intern/smoke) // DG: interesting commenting this line + deactivating loading of noise files if(framenr!=startframe) { 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); } // create shadows before writing cache so we get nice shadows for sstartframe, too if(get_lamp(scene, light)) smoke_calc_transparency(sds->shadow, smoke_get_density(sds->fluid), sds->p0, sds->p1, sds->res, sds->dx, light, calc_voxel_transp, -7.0*sds->dx); BKE_ptcache_write_cache(&pid, framenr); if(sds->wt) { if(framenr!=startframe) { 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); } cache_wt->flag |= PTCACHE_SIMULATION_VALID; cache_wt->simframe= framenr; BKE_ptcache_write_cache(&pid_wt, framenr); } tend(); printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() ); } }