Index: intern/smoke/extern/smoke_API.h =================================================================== --- intern/smoke/extern/smoke_API.h (revision 30053) +++ intern/smoke/extern/smoke_API.h (working copy) @@ -38,10 +38,10 @@ void smoke_export(struct FLUID_3D *fluid, float *dt, float *dx, float **dens, float **densold, float **heat, float **heatold, float **vx, float **vy, float **vz, float **vxold, float **vyold, float **vzold, unsigned char **obstacles); // low res -struct FLUID_3D *smoke_init(int *res, float *p0, float dt); +struct FLUID_3D *smoke_init(int *res, float *p0); void smoke_free(struct FLUID_3D *fluid); -void smoke_initBlenderRNA(struct FLUID_3D *fluid, float *alpha, float *beta); +void smoke_initBlenderRNA(struct FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli); void smoke_step(struct FLUID_3D *fluid, size_t framenr); float *smoke_get_density(struct FLUID_3D *fluid); Index: intern/smoke/intern/FLUID_3D.cpp =================================================================== --- intern/smoke/intern/FLUID_3D.cpp (revision 30053) +++ intern/smoke/intern/FLUID_3D.cpp (working copy) @@ -35,23 +35,17 @@ #include #endif // PARALLEL -// boundary conditions of the fluid domain -#define DOMAIN_BC_FRONT 0 // z -#define DOMAIN_BC_TOP 1 // y -#define DOMAIN_BC_LEFT 1 // x -#define DOMAIN_BC_BACK DOMAIN_BC_FRONT -#define DOMAIN_BC_BOTTOM DOMAIN_BC_TOP -#define DOMAIN_BC_RIGHT DOMAIN_BC_LEFT +#define DT_DEFAULT 0.1f; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// -FLUID_3D::FLUID_3D(int *res, float *p0, float dt) : - _xRes(res[0]), _yRes(res[1]), _zRes(res[2]), _res(0.0f), _dt(dt) +FLUID_3D::FLUID_3D(int *res, float *p0) : + _xRes(res[0]), _yRes(res[1]), _zRes(res[2]), _res(0.0f) { // set simulation consts - // _dt = dt; // 0.10 + _dt = DT_DEFAULT; // just in case. set in step from a RNA factor // start point of array _p0[0] = p0[0]; @@ -61,7 +55,6 @@ _iterations = 100; _tempAmb = 0; _heatDiffusion = 1e-3; - _vorticityEps = 2.0; _totalTime = 0.0f; _totalSteps = 0; _res = Vec3Int(_xRes,_yRes,_zRes); @@ -77,9 +70,9 @@ // scale the constants according to the refinement of the grid _dx = 1.0f / (float)_maxRes; - float scaling = 64.0f / _maxRes; - scaling = (scaling < 1.0f) ? 1.0f : scaling; - _vorticityEps /= scaling; + _constant_scaling = 64.0f / _maxRes; + _constant_scaling = (_constant_scaling < 1.0f) ? 1.0f : _constant_scaling; + _vorticityEps = 2.0f / _constant_scaling; // Just in case set a default value // allocate arrays _totalCells = _xRes * _yRes * _zRes; @@ -126,30 +119,42 @@ _obstacles[x] = false; } + // boundary conditions of the fluid domain + // set default values -> vertically non-colliding + DOMAIN_BC_FRONT = true; + DOMAIN_BC_TOP = false; + DOMAIN_BC_LEFT = true; + DOMAIN_BC_BACK = DOMAIN_BC_FRONT; + DOMAIN_BC_BOTTOM = DOMAIN_BC_TOP; + DOMAIN_BC_RIGHT = DOMAIN_BC_LEFT; + + colloPrev = 1; // default value + + // set side obstacles int index; for (int y = 0; y < _yRes; y++) for (int x = 0; x < _xRes; x++) { - // front slab + // bottom slab index = x + y * _xRes; - if(DOMAIN_BC_FRONT==1) _obstacles[index] = 1; + if(DOMAIN_BC_BOTTOM==1) _obstacles[index] = 1; - // back slab + // top slab index += _totalCells - _slabSize; - if(DOMAIN_BC_BACK==1) _obstacles[index] = 1; + if(DOMAIN_BC_TOP==1) _obstacles[index] = 1; } for (int z = 0; z < _zRes; z++) for (int x = 0; x < _xRes; x++) { - // bottom slab + // front slab index = x + z * _slabSize; - if(DOMAIN_BC_BOTTOM==1) _obstacles[index] = 1; + if(DOMAIN_BC_FRONT==1) _obstacles[index] = 1; - // top slab + // back slab index += _slabSize - _xRes; - if(DOMAIN_BC_TOP==1) _obstacles[index] = 1; + if(DOMAIN_BC_BACK==1) _obstacles[index] = 1; } for (int z = 0; z < _zRes; z++) @@ -163,6 +168,7 @@ index += _xRes - 1; if(DOMAIN_BC_RIGHT==1) _obstacles[index] = 1; } + } FLUID_3D::~FLUID_3D() @@ -193,10 +199,13 @@ } // init direct access functions from blender -void FLUID_3D::initBlenderRNA(float *alpha, float *beta) +void FLUID_3D::initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli) { _alpha = alpha; _beta = beta; + _dt_factor = dt_factor; + _vorticityRNA = vorticity; + _border_colli = border_colli; } ////////////////////////////////////////////////////////////////////// @@ -204,6 +213,18 @@ ////////////////////////////////////////////////////////////////////// void FLUID_3D::step() { + // If border rules have been changed + if (colloPrev != *_border_colli) { + setBorderCollisions(); + } + + + // set delta time by dt_factor + _dt = (*_dt_factor) * DT_DEFAULT; + // set vorticity from RNA value + _vorticityEps = (*_vorticityRNA)/_constant_scaling; + + #if PARALLEL==1 int threadval = 1; threadval = omp_get_max_threads(); @@ -246,6 +267,13 @@ #pragma omp single { #endif + /* + * addForce() changed Temp values to preserve thread safety + * (previous functions in per thread loop still needed + * original velocity data) + * + * So swap temp values to velocity + */ SWAP_POINTERS(_xVelocity, _xVelocityTemp); SWAP_POINTERS(_yVelocity, _yVelocityTemp); SWAP_POINTERS(_zVelocity, _zVelocityTemp); @@ -276,6 +304,10 @@ #pragma omp single { #endif + /* + * For thread safety use "Old" to read + * "current" values but still allow changing values. + */ SWAP_POINTERS(_xVelocity, _xVelocityOld); SWAP_POINTERS(_yVelocity, _yVelocityOld); SWAP_POINTERS(_zVelocity, _zVelocityOld); @@ -334,6 +366,10 @@ } #endif + /* + * swap final velocity back to Velocity array + * from temp xForce storage + */ SWAP_POINTERS(_xVelocity, _xForce); SWAP_POINTERS(_yVelocity, _yForce); SWAP_POINTERS(_zVelocity, _zForce); @@ -351,6 +387,83 @@ } + +// Set border collision model from RNA setting + +void FLUID_3D::setBorderCollisions() { + + + colloPrev = *_border_colli; // saving the current value + + // boundary conditions of the fluid domain + + if (colloPrev == 0) { // No collisions + DOMAIN_BC_FRONT = false; + DOMAIN_BC_TOP = false; + DOMAIN_BC_LEFT = false; + } + else if (colloPrev == 2) { // Collide with all sides + DOMAIN_BC_FRONT = true; + DOMAIN_BC_TOP = true; + DOMAIN_BC_LEFT = true; + } + else { // Default values: Collide with "walls", but not top and bottom + DOMAIN_BC_FRONT = true; + DOMAIN_BC_TOP = false; + DOMAIN_BC_LEFT = true; + } + + DOMAIN_BC_BACK = DOMAIN_BC_FRONT; + DOMAIN_BC_BOTTOM = DOMAIN_BC_TOP; + DOMAIN_BC_RIGHT = DOMAIN_BC_LEFT; + + + + // set side obstacles + int index; + for (int y = 0; y < _yRes; y++) + for (int x = 0; x < _xRes; x++) + { + // front slab + index = x + y * _xRes; + if(DOMAIN_BC_BOTTOM==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + + // back slab + index += _totalCells - _slabSize; + if(DOMAIN_BC_TOP==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + } + + for (int z = 0; z < _zRes; z++) + for (int x = 0; x < _xRes; x++) + { + // bottom slab + index = x + z * _slabSize; + if(DOMAIN_BC_FRONT==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + + // top slab + index += _slabSize - _xRes; + if(DOMAIN_BC_BACK==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + } + + for (int z = 0; z < _zRes; z++) + for (int y = 0; y < _yRes; y++) + { + // left slab + index = y * _xRes + z * _slabSize; + if(DOMAIN_BC_LEFT==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + + // right slab + index += _xRes - 1; + if(DOMAIN_BC_RIGHT==1) _obstacles[index] = 1; + else _obstacles[index] = 0; + } +} + ////////////////////////////////////////////////////////////////////// // helper function to dampen co-located grid artifacts of given arrays in intervals // (only needed for velocity, strength (w) depends on testcase... @@ -428,6 +541,10 @@ for (y = 1; y < _res[1]-1; y++) for (x = 1+(y+z)%2; x < _res[0]-1; x+=2) { index = x + y*_res[0] + posslab; + /* + * Uses xForce as temporary storage to allow other threads to read + * old values from xVelocityTemp + */ _xForce[index] = (1-w)*_xVelocityTemp[index] + 1./6. * w*( _xVelocityTemp[index+1] + _xVelocityTemp[index-1] + _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] + @@ -450,6 +567,11 @@ for (y = 1; y < _res[1]-1; y++) for (x = 1+(y+z+1)%2; x < _res[0]-1; x+=2) { index = x + y*_res[0] + posslab; + + /* + * Uses xForce as temporary storage to allow other threads to read + * old values from xVelocityTemp + */ _xForce[index] = (1-w)*_xVelocityTemp[index] + 1./6. * w*( _xVelocityTemp[index+1] + _xVelocityTemp[index-1] + _xVelocityTemp[index+_res[0]] + _xVelocityTemp[index-_res[0]] + @@ -664,10 +786,10 @@ if(DOMAIN_BC_LEFT == 0) setNeumannX(_xVelocity, _res, 0, _zRes); else setZeroX(_xVelocity, _res, 0, _zRes); - if(DOMAIN_BC_TOP == 0) setNeumannY(_yVelocity, _res, 0, _zRes); + if(DOMAIN_BC_FRONT == 0) setNeumannY(_yVelocity, _res, 0, _zRes); else setZeroY(_yVelocity, _res, 0, _zRes); - if(DOMAIN_BC_FRONT == 0) setNeumannZ(_zVelocity, _res, 0, _zRes); + if(DOMAIN_BC_TOP == 0) setNeumannZ(_zVelocity, _res, 0, _zRes); else setZeroZ(_zVelocity, _res, 0, _zRes); // calculate divergence @@ -1063,10 +1185,10 @@ if(DOMAIN_BC_LEFT == 0) copyBorderX(_xVelocityOld, res, zBegin, zEnd); else setZeroX(_xVelocityOld, res, zBegin, zEnd); - if(DOMAIN_BC_TOP == 0) copyBorderY(_yVelocityOld, res, zBegin, zEnd); + if(DOMAIN_BC_FRONT == 0) copyBorderY(_yVelocityOld, res, zBegin, zEnd); else setZeroY(_yVelocityOld, res, zBegin, zEnd); - if(DOMAIN_BC_FRONT == 0) copyBorderZ(_zVelocityOld, res, zBegin, zEnd); + if(DOMAIN_BC_TOP == 0) copyBorderZ(_zVelocityOld, res, zBegin, zEnd); else setZeroZ(_zVelocityOld, res, zBegin, zEnd); } @@ -1117,10 +1239,10 @@ if(DOMAIN_BC_LEFT == 0) copyBorderX(_xVelocityTemp, res, zBegin, zEnd); else setZeroX(_xVelocityTemp, res, zBegin, zEnd); - if(DOMAIN_BC_TOP == 0) copyBorderY(_yVelocityTemp, res, zBegin, zEnd); + if(DOMAIN_BC_FRONT == 0) copyBorderY(_yVelocityTemp, res, zBegin, zEnd); else setZeroY(_yVelocityTemp, res, zBegin, zEnd); - if(DOMAIN_BC_FRONT == 0) copyBorderZ(_zVelocityTemp, res, zBegin, zEnd); + if(DOMAIN_BC_TOP == 0) copyBorderZ(_zVelocityTemp, res, zBegin, zEnd); else setZeroZ(_zVelocityTemp, res, zBegin, zEnd); setZeroBorder(_density, res, zBegin, zEnd); Index: intern/smoke/intern/FLUID_3D.h =================================================================== --- intern/smoke/intern/FLUID_3D.h (revision 30053) +++ intern/smoke/intern/FLUID_3D.h (working copy) @@ -42,11 +42,11 @@ class FLUID_3D { public: - FLUID_3D(int *res, /* int amplify, */ float *p0, float dt); + FLUID_3D(int *res, /* int amplify, */ float *p0); FLUID_3D() {}; virtual ~FLUID_3D(); - void initBlenderRNA(float *alpha, float *beta); + void initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli); // create & allocate vector noise advection void initVectorNoise(int amplify); @@ -110,12 +110,26 @@ // simulation constants float _dt; + float *_dt_factor; float _vorticityEps; float _heatDiffusion; + float *_vorticityRNA; // RNA-pointer. float *_alpha; // for the buoyancy density term <-- as pointer to get blender RNA in here float *_beta; // was _buoyancy <-- as pointer to get blender RNA in here float _tempAmb; /* ambient temperature */ + float _constant_scaling; + bool DOMAIN_BC_FRONT; // z + bool DOMAIN_BC_TOP; // y + bool DOMAIN_BC_LEFT; // x + bool DOMAIN_BC_BACK; // DOMAIN_BC_FRONT + bool DOMAIN_BC_BOTTOM; // DOMAIN_BC_TOP + bool DOMAIN_BC_RIGHT; // DOMAIN_BC_LEFT + int *_border_colli; // border collision rules <-- as pointer to get blender RNA in here + int colloPrev; // To track whether value has been changed (to not + // have to recalibrate borders if nothing has changed + void setBorderCollisions(); + // WTURBULENCE object, if active // WTURBULENCE* _wTurbulence; Index: intern/smoke/intern/smoke_API.cpp =================================================================== --- intern/smoke/intern/smoke_API.cpp (revision 30053) +++ intern/smoke/intern/smoke_API.cpp (working copy) @@ -33,10 +33,10 @@ #include // y in smoke is z in blender -extern "C" FLUID_3D *smoke_init(int *res, float *p0, float dt) +extern "C" FLUID_3D *smoke_init(int *res, float *p0) { // smoke lib uses y as top-bottom/vertical axis where blender uses z - FLUID_3D *fluid = new FLUID_3D(res, p0, dt); + FLUID_3D *fluid = new FLUID_3D(res, p0); // printf("xres: %d, yres: %d, zres: %d\n", res[0], res[1], res[2]); @@ -85,9 +85,9 @@ wt->stepTurbulenceFull(fluid->_dt/fluid->_dx, fluid->_xVelocity, fluid->_yVelocity, fluid->_zVelocity, fluid->_obstacles); } -extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta) +extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli) { - fluid->initBlenderRNA(alpha, beta); + fluid->initBlenderRNA(alpha, beta, dt_factor, vorticity, border_colli); } extern "C" void smoke_dissolve(FLUID_3D *fluid, int speed, int log) Index: release/scripts/ui/properties_physics_smoke.py =================================================================== --- release/scripts/ui/properties_physics_smoke.py (revision 30053) +++ release/scripts/ui/properties_physics_smoke.py (working copy) @@ -80,19 +80,28 @@ col.prop(domain, "maxres", text="Divisions") col.label(text="Particle:") col.prop(domain, "initial_velocity", text="Initial Velocity") + sub = col.column() + sub.active = domain.initial_velocity + sub.prop(domain, "velocity_multiplier", text="Multiplier") if wide_ui: col = split.column() col.label(text="Behavior:") col.prop(domain, "alpha") col.prop(domain, "beta") + col.prop(domain, "vorticity") + col.prop(domain, "time_scale") col.prop(domain, "dissolve_smoke", text="Dissolve") sub = col.column() sub.active = domain.dissolve_smoke sub.prop(domain, "dissolve_speed", text="Time") sub.prop(domain, "dissolve_smoke_log", text="Slow") + layout.label(text="Domain Border Collisions:") + layout.prop(domain, "smoke_domain_colli", expand=True) + elif md.smoke_type == 'FLOW': + flow = md.flow_settings split = layout.split() @@ -111,6 +120,7 @@ col.label(text="Behavior:") col.prop(flow, "temperature") col.prop(flow, "density") + col.prop(flow, "absolute") #elif md.smoke_type == 'COLLISION': # layout.separator() @@ -191,6 +201,7 @@ col = split.column() col.label(text="Resolution:") col.prop(md, "amplify", text="Divisions") + col.prop(md, "smoothemitter") col.prop(md, "viewhighres") if wide_ui: Index: source/blender/blenkernel/intern/smoke.c =================================================================== --- source/blender/blenkernel/intern/smoke.c (revision 30053) +++ source/blender/blenkernel/intern/smoke.c (working copy) @@ -220,7 +220,7 @@ // 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, 0.1); + smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0); smd->time = scene->r.cfra; if(smd->domain->flags & MOD_SMOKE_HIGHRES) @@ -237,7 +237,7 @@ 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)); + 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) { @@ -713,11 +713,16 @@ smd->domain->omega = 1.0; smd->domain->alpha = -0.001; 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->flags = MOD_SMOKE_DISSOLVE_LOG; smd->domain->strength = 2.0; smd->domain->noise = MOD_SMOKE_NOISEWAVE; smd->domain->diss_speed = 5; - // init view3d buffer + smd->domain->vel_multi = 1.0; + // init 3dview buffer + smd->domain->viewsettings = 0; smd->domain->effector_weights = BKE_add_effector_weights(NULL); } @@ -733,6 +738,7 @@ /* set some standard values */ smd->flow->density = 1.0; smd->flow->temp = 1.0; + smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE; smd->flow->psys = NULL; @@ -862,7 +868,7 @@ { ParticleSystem *psys = sfs->psys; ParticleSettings *part=psys->part; - ParticleData *pa = NULL; + ParticleData *pa = NULL; int p = 0; float *density = smoke_get_density(sds->fluid); float *bigdensity = smoke_turbulence_get_density(sds->wt); @@ -871,7 +877,27 @@ 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]; + int bigres[3]; + short absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE); + short high_emission_smoothing = (smd->domain->flags & MOD_SMOKE_HIGH_SMOOTH); + + /* + * 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; + + // initialize temp emission map + if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) + { + int i; + temp_emission_map = MEM_callocN(sizeof(float) * sds->res[0]*sds->res[1]*sds->res[2], "SmokeTempEmission"); + // set whole volume to 0.0f + for (i=0; ires[0]*sds->res[1]*sds->res[2]; i++) { + temp_emission_map[i] = 0.0f; + } + } // mostly copied from particle code for(p=0, pa=psys->particles; ptotpart; p++, pa++) @@ -905,33 +931,21 @@ // heat[index] += sfs->temp * 0.1; // density[index] += sfs->density * 0.1; heat[index] = sfs->temp; - density[index] = sfs->density; + + // Add emitter density to temp emission map + temp_emission_map[index] = sfs->density; // Uses particle velocity as initial velocity for smoke if(smd->domain->flags & MOD_SMOKE_INITVELOCITY) { - velocity_x[index] = pa->state.vel[0]; - velocity_y[index] = pa->state.vel[1]; - velocity_z[index] = pa->state.vel[2]; + + velocity_x[index] = pa->state.vel[0]*smd->domain->vel_multi; + velocity_y[index] = pa->state.vel[1]*smd->domain->vel_multi; + velocity_z[index] = pa->state.vel[2]*smd->domain->vel_multi; + } - - // 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 { @@ -954,9 +968,136 @@ 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 - } + } + } + } // particles loop + + + // apply emission values + if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) { + + // initialize variables + int ii, jj, kk, x, y, z, block_size; + size_t index, index_big; + + smoke_turbulence_get_res(smd->domain->wt, bigres); + block_size = smd->domain->amplify + 1; // high res block size + + + // loop through every low res cell + for(x = 0; x < sds->res[0]; x++) + for(y = 0; y < sds->res[1]; y++) + for(z = 0; z < sds->res[2]; z++) + { + + // neighbour cell emission densities (for high resolution smoke smooth interpolation) + float c000, c001, c010, c011, c100, c101, c110, c111; + + c000 = (x>0 && y>0 && z>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y-1, sds->res[1], z-1)] : 0; + c001 = (x>0 && y>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y-1, sds->res[1], z)] : 0; + c010 = (x>0 && z>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y, sds->res[1], z-1)] : 0; + c011 = (x>0) ? temp_emission_map[smoke_get_index(x-1, sds->res[0], y, sds->res[1], z)] : 0; + + c100 = (y>0 && z>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y-1, sds->res[1], z-1)] : 0; + c101 = (y>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y-1, sds->res[1], z)] : 0; + c110 = (z>0) ? temp_emission_map[smoke_get_index(x, sds->res[0], y, sds->res[1], z-1)] : 0; + c111 = temp_emission_map[smoke_get_index(x, sds->res[0], y, sds->res[1], z)]; // this cell + + + + // get cell index + index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); + + // add emission to low resolution density + if (absolute_flow) {if (temp_emission_map[index]>0) density[index] = temp_emission_map[index];} + else { + density[index] += temp_emission_map[index]; + if (density[index]>1) density[index]=1.0f; + } + + smoke_turbulence_get_res(smd->domain->wt, bigres); + + + + /* + loop through high res blocks if high res enabled + */ + if (bigdensity) + for(ii = 0; ii < block_size; ii++) + for(jj = 0; jj < block_size; jj++) + for(kk = 0; kk < block_size; kk++) + { + + float fx,fy,fz, interpolated_value; + int shift_x, shift_y, shift_z; + + + /* + * Do volume interpolation if emitter smoothing + * is enabled + */ + if (high_emission_smoothing) { + // convert block position to relative + // for interpolation smoothing + fx = (float)ii/block_size + 0.5f/block_size; + fy = (float)jj/block_size + 0.5f/block_size; + fz = (float)kk/block_size + 0.5f/block_size; + + // calculate trilinear interpolation + interpolated_value = c000 * (1-fx) * (1-fy) * (1-fz) + + c100 * fx * (1-fy) * (1-fz) + + c010 * (1-fx) * fy * (1-fz) + + c001 * (1-fx) * (1-fy) * fz + + c101 * fx * (1-fy) * fz + + c011 * (1-fx) * fy * fz + + c110 * fx * fy * (1-fz) + + c111 * fx * fy * fz; + + + // add some contrast / sharpness + // depending on hi-res block size + + interpolated_value = (interpolated_value-0.4f*sfs->density)*(block_size/2) + 0.4f*sfs->density; + if (interpolated_value<0.0f) interpolated_value = 0.0f; + if (interpolated_value>1.0f) interpolated_value = 1.0f; + + // shift smoke block index + // (because pixel center is actually + // in halfway of the low res block) + shift_x = (x < 1) ? 0 : block_size/2; + shift_y = (y < 1) ? 0 : block_size/2; + shift_z = (z < 1) ? 0 : block_size/2; + } + else { + // without interpolation use same low resolution + // block value for all hi-res blocks + interpolated_value = c111; + shift_x = 0; + shift_y = 0; + shift_z = 0; + } + + // get shifted index for current high resolution block + index_big = smoke_get_index(block_size * x + ii - shift_x, bigres[0], block_size * y + jj - shift_y, bigres[1], block_size * z + kk - shift_z); + + // add emission data to high resolution density + if (absolute_flow) {if (interpolated_value > 0) bigdensity[index_big] = interpolated_value;} + else { + bigdensity[index_big] += interpolated_value; + if (bigdensity[index_big]>1) bigdensity[index_big]=1.0f; + } + + } // end of hires loop + + } // end of low res loop + + // free temporary emission map + if (temp_emission_map) MEM_freeN(temp_emission_map); + + } // end emission + + + } else { @@ -970,7 +1111,7 @@ BLI_bvhtree_find_nearest(sfs->bvh->tree, pco, &nearest, sfs->bvh->nearest_callback, sfs->bvh); }*/ - } + } } } if(sds->fluid_group) Index: source/blender/makesdna/DNA_smoke_types.h =================================================================== --- source/blender/makesdna/DNA_smoke_types.h (revision 30053) +++ source/blender/makesdna/DNA_smoke_types.h (working copy) @@ -35,6 +35,7 @@ #define MOD_SMOKE_DISSOLVE_LOG (1<<3) /* using 1/x for dissolve */ #define MOD_SMOKE_INITVELOCITY (1<<4) /* passes particles speed to the smoke*/ +#define MOD_SMOKE_HIGH_SMOOTH (1<<5) /* smoothens high res emission*/ /* noise */ #define MOD_SMOKE_NOISEWAVE (1<<0) @@ -47,6 +48,11 @@ #define SM_CACHE_LIGHT 0 #define SM_CACHE_HEAVY 1 +/* domain border collision */ +#define SM_BORDER_OPEN 0 +#define SM_BORDER_VERTICAL 1 +#define SM_BORDER_CLOSED 2 + typedef struct SmokeDomainSettings { struct SmokeModifierData *smd; /* for fast RNA access */ struct FLUID_3D *fluid; @@ -84,6 +90,11 @@ struct PointCache *point_cache[2]; /* definition is in DNA_object_force.h */ struct ListBase ptcaches[2]; struct EffectorWeights *effector_weights; + int border_collisions; /* How domain border collisions are handled */ + float vel_multi; // Multiplier for particle velocity + float time_scale; + float vorticity; + } SmokeDomainSettings; @@ -91,7 +102,10 @@ /* type */ #define MOD_SMOKE_FLOW_TYPE_OUTFLOW (1<<1) +#define MOD_SMOKE_FLOW_ABSOLUTE (1<<1) /*old style emission*/ + + typedef struct SmokeFlowSettings { struct SmokeModifierData *smd; /* for fast RNA access */ struct ParticleSystem *psys; @@ -103,7 +117,7 @@ short vgroup_density; short vgroup_heat; short type; /* inflow =0 or outflow = 1 */ - int pad; + int flags; /* absolute emission etc*/ } SmokeFlowSettings; /* Index: source/blender/makesrna/intern/rna_smoke.c =================================================================== --- source/blender/makesrna/intern/rna_smoke.c (revision 30053) +++ source/blender/makesrna/intern/rna_smoke.c (working copy) @@ -120,6 +120,12 @@ {SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"}, {0, NULL, 0, NULL, NULL}}; + static EnumPropertyItem smoke_domain_colli_items[] = { + {SM_BORDER_OPEN, "BORDEROPEN", 0, "Open", "Smoke doesn't collide with any border"}, + {SM_BORDER_VERTICAL, "BORDERVERTICAL", 0, "Vertically Open", "Smoke doesn't collide with top and bottom sides"}, + {SM_BORDER_CLOSED, "BORDERCLOSED", 0, "Collide All", "Smoke collides with every side"}, + {0, NULL, 0, NULL, NULL}}; + srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL); RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings"); RNA_def_struct_sdna(srna, "SmokeDomainSettings"); @@ -192,8 +198,8 @@ prop= RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "strength"); - RNA_def_property_range(prop, 1.0, 10.0); - RNA_def_property_ui_range(prop, 1.0, 10.0, 1, 2); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_range(prop, 0.0, 10.0, 1, 2); RNA_def_property_ui_text(prop, "Strength", "Strength of wavelet noise"); RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset"); @@ -209,6 +215,13 @@ RNA_def_property_ui_text(prop, "Initial Velocity", "Smoke inherits it's velocity from the emitter particle"); RNA_def_property_update(prop, 0, NULL); + prop= RNA_def_property(srna, "velocity_multiplier", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vel_multi"); + RNA_def_property_range(prop, -2.0, 2.0); + RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5); + RNA_def_property_ui_text(prop, "Multiplier", "Multiplier to adjust velocity passed to smoke"); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset"); + prop= RNA_def_property(srna, "dissolve_smoke", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE); RNA_def_property_ui_text(prop, "Dissolve Smoke", "Enable smoke to disappear over time"); @@ -241,12 +254,37 @@ RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used"); RNA_def_property_update(prop, 0, NULL); + prop= RNA_def_property(srna, "smoke_domain_colli", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "border_collisions"); + RNA_def_property_enum_items(prop, smoke_domain_colli_items); + RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used"); + RNA_def_property_update(prop, 0, NULL); + prop= RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "EffectorWeights"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Effector Weights", ""); + prop= RNA_def_property(srna, "smoothemitter", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGH_SMOOTH); + RNA_def_property_ui_text(prop, "Smooth Emitter", "Smoothens emitted smoke to avoid blockiness."); + RNA_def_property_update(prop, 0, NULL); + + prop= RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "time_scale"); + RNA_def_property_range(prop, 0.2, 1.5); + RNA_def_property_ui_range(prop, 0.2, 1.5, 0.02, 5); + RNA_def_property_ui_text(prop, "Time Scale", "Adjust simulation speed."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset"); + + prop= RNA_def_property(srna, "vorticity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vorticity"); + RNA_def_property_range(prop, 0.01, 4.0); + RNA_def_property_ui_range(prop, 0.01, 4.0, 0.02, 5); + RNA_def_property_ui_text(prop, "Vorticity", "Amount of turbulence/rotation in fluid."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset"); + } static void rna_def_smoke_flow_settings(BlenderRNA *brna) @@ -284,6 +322,11 @@ RNA_def_property_boolean_sdna(prop, NULL, "type", MOD_SMOKE_FLOW_TYPE_OUTFLOW); RNA_def_property_ui_text(prop, "Outflow", "Deletes smoke from simulation"); RNA_def_property_update(prop, 0, NULL); + + prop= RNA_def_property(srna, "absolute", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_ABSOLUTE); + RNA_def_property_ui_text(prop, "Absolute Density", "Only allows given density value in emitter area."); + RNA_def_property_update(prop, 0, NULL); } static void rna_def_smoke_coll_settings(BlenderRNA *brna)