static void rna_SmokeModifier_velocity_grid_get(PointerRNA *ptr, float *values) { #ifdef WITH_SMOKE SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; int length[RNA_MAX_ARRAY_DIMENSION]; int size = rna_SmokeModifier_velocity_grid_get_length(ptr, length); float *vx, *vy, *vz; int i; BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ); vx = smoke_get_velocity_x(sds->fluid); vy = smoke_get_velocity_y(sds->fluid); vz = smoke_get_velocity_z(sds->fluid); for (i = 0; i < size; i += 3) { *(values++) = *(vx++); *(values++) = *(vy++); *(values++) = *(vz++); } BLI_rw_mutex_unlock(sds->fluid_mutex); #else UNUSED_VARS(ptr, values); #endif }
void draw_smoke_velocity(SmokeDomainSettings *domain, Object *ob) { float x, y, z; float x0, y0, z0; int *base_res = domain->base_res; int *res = domain->res; int *res_min = domain->res_min; int *res_max = domain->res_max; float *vel_x = smoke_get_velocity_x(domain->fluid); float *vel_y = smoke_get_velocity_y(domain->fluid); float *vel_z = smoke_get_velocity_z(domain->fluid); float min[3]; float *cell_size = domain->cell_size; float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f; float vf = domain->scale / 16.f * 2.f; /* velocity factor */ glLineWidth(1.0f); /* set first position so that it doesn't jump when domain moves */ x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size); y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size); z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size); if (x0 < res_min[0]) x0 += step_size; if (y0 < res_min[1]) y0 += step_size; if (z0 < res_min[2]) z0 += step_size; add_v3_v3v3(min, domain->p0, domain->obj_shift_f); for (x = floor(x0); x < res_max[0]; x += step_size) for (y = floor(y0); y < res_max[1]; y += step_size) for (z = floor(z0); z < res_max[2]; z += step_size) { int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1]; float pos[3] = {min[0] + ((float)x + 0.5f) * cell_size[0], min[1] + ((float)y + 0.5f) * cell_size[1], min[2] + ((float)z + 0.5f) * cell_size[2]}; float vel = sqrtf(vel_x[index] * vel_x[index] + vel_y[index] * vel_y[index] + vel_z[index] * vel_z[index]); /* draw heat as scaled "arrows" */ if (vel >= 0.01f) { float col_g = 1.0f - vel; CLAMP(col_g, 0.0f, 1.0f); glColor3f(1.0f, col_g, 0.0f); glPointSize(10.0f * vel); glBegin(GL_LINES); glVertex3f(pos[0], pos[1], pos[2]); glVertex3f(pos[0] + vel_x[index] * vf, pos[1] + vel_y[index] * vf, pos[2] + vel_z[index] * vf); glEnd(); glBegin(GL_POINTS); glVertex3f(pos[0] + vel_x[index] * vf, pos[1] + vel_y[index] * vf, pos[2] + vel_z[index] * vf); glEnd(); } } }
static int rna_SmokeModifier_velocity_grid_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) { #ifdef WITH_SMOKE SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; float *vx = NULL; float *vy = NULL; float *vz = NULL; int size = 0; /* Velocity data is always low-resolution. */ if (sds->fluid) { size = 3 * sds->res[0] * sds->res[1] * sds->res[2]; vx = smoke_get_velocity_x(sds->fluid); vy = smoke_get_velocity_y(sds->fluid); vz = smoke_get_velocity_z(sds->fluid); } length[0] = (vx && vy && vz) ? size : 0; #else (void)ptr; length[0] = 0; #endif return length[0]; }
static void init_frame_smoke(VoxelData *vd, int 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; SmokeDomainSettings *sds = smd->domain; if (sds && sds->fluid) { BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ); if (!sds->fluid) { BLI_rw_mutex_unlock(sds->fluid_mutex); return; } if (cfra < sds->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; if (!smoke_has_heat(sds->fluid)) { BLI_rw_mutex_unlock(sds->fluid_mutex); return; } copy_v3_v3_int(vd->resol, sds->res); totRes = vd_resol_size(vd); vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data"); /* get heat data */ heat = smoke_get_heat(sds->fluid); /* scale heat values from -2.0-2.0 to 0.0-1.0 */ for (i = 0; i < totRes; i++) { vd->dataset[i] = (heat[i] + 2.0f) / 4.0f; } } else if (vd->smoked_type == TEX_VD_SMOKEVEL) { size_t totRes; size_t i; float *xvel, *yvel, *zvel; copy_v3_v3_int(vd->resol, sds->res); totRes = vd_resol_size(vd); vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data"); /* get velocity data */ xvel = smoke_get_velocity_x(sds->fluid); yvel = smoke_get_velocity_y(sds->fluid); zvel = smoke_get_velocity_z(sds->fluid); /* map velocities between 0 and 0.3f */ for (i = 0; i < totRes; i++) { vd->dataset[i] = sqrtf(xvel[i] * xvel[i] + yvel[i] * yvel[i] + zvel[i] * zvel[i]) * 3.0f; } } else if (vd->smoked_type == TEX_VD_SMOKEFLAME) { size_t totRes; float *flame; if (sds->flags & MOD_SMOKE_HIGHRES) { if (!smoke_turbulence_has_fuel(sds->wt)) { BLI_rw_mutex_unlock(sds->fluid_mutex); return; } smoke_turbulence_get_res(sds->wt, vd->resol); flame = smoke_turbulence_get_flame(sds->wt); } else { if (!smoke_has_fuel(sds->fluid)) { BLI_rw_mutex_unlock(sds->fluid_mutex); return; } copy_v3_v3_int(vd->resol, sds->res); flame = smoke_get_flame(sds->fluid); } /* always store copy, as smoke internal data can change */ totRes = vd_resol_size(vd); vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data"); memcpy(vd->dataset, flame, sizeof(float)*totRes); } else { size_t totCells; int depth = 4; vd->data_type = TEX_VD_RGBA_PREMUL; /* data resolution */ if (sds->flags & MOD_SMOKE_HIGHRES) { smoke_turbulence_get_res(sds->wt, vd->resol); } else { copy_v3_v3_int(vd->resol, sds->res); } /* TODO: is_vd_res_ok(rvd) doesnt check this resolution */ totCells = vd_resol_size(vd) * depth; /* always store copy, as smoke internal data can change */ vd->dataset = MEM_mapallocN(sizeof(float) * totCells, "smoke data"); if (sds->flags & MOD_SMOKE_HIGHRES) { if (smoke_turbulence_has_colors(sds->wt)) { smoke_turbulence_get_rgba(sds->wt, vd->dataset, 1); } else { smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, vd->dataset, 1); } } else { if (smoke_has_colors(sds->fluid)) { smoke_get_rgba(sds->fluid, vd->dataset, 1); } else { smoke_get_rgba_from_density(sds->fluid, sds->active_color, vd->dataset, 1); } } } /* end of fluid condition */ BLI_rw_mutex_unlock(sds->fluid_mutex); } } vd->ok = 1; #else // WITH_SMOKE (void)vd; (void)cfra; vd->dataset = NULL; #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; } } }