Smoke:
authorDaniel Genrich <daniel.genrich@gmx.net>
Wed, 12 Aug 2009 17:32:02 +0000 (17:32 +0000)
committerDaniel Genrich <daniel.genrich@gmx.net>
Wed, 12 Aug 2009 17:32:02 +0000 (17:32 +0000)
* New feature: "Dissolve Smoke" - Idea by nudelZ

intern/smoke/extern/smoke_API.h
intern/smoke/intern/FLUID_3D.cpp
intern/smoke/intern/FLUID_3D.h
intern/smoke/intern/FLUID_3D_STATIC.cpp
intern/smoke/intern/smoke_API.cpp
release/ui/buttons_physics_smoke.py
source/blender/blenkernel/intern/smoke.c
source/blender/makesdna/DNA_smoke_types.h
source/blender/makesrna/intern/rna_smoke.c

index 52df3891ca003d1c4aaad4986681fd606554c754..f0dba3cc7a4618031e4ef59d7b1e4bd0c4eb74ce 100644 (file)
@@ -36,7 +36,7 @@ struct FLUID_3D *smoke_init(int *res, float *p0, float dt);
 void smoke_free(struct FLUID_3D *fluid);
 
 void smoke_initBlenderRNA(struct FLUID_3D *fluid, float *alpha, float *beta);
-void smoke_step(struct FLUID_3D *fluid);
+void smoke_step(struct FLUID_3D *fluid, size_t framenr);
 
 float *smoke_get_density(struct FLUID_3D *fluid);
 float *smoke_get_heat(struct FLUID_3D *fluid);
@@ -49,6 +49,8 @@ unsigned char *smoke_get_obstacle(struct FLUID_3D *fluid);
 size_t smoke_get_index(int x, int max_x, int y, int max_y, int z);
 size_t smoke_get_index2d(int x, int max_x, int y);
 
+void smoke_dissolve(struct FLUID_3D *fluid, int speed, int log);
+
 // wavelet turbulence functions
 struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype);
 void smoke_turbulence_free(struct WTURBULENCE *wt);
@@ -59,6 +61,8 @@ void smoke_turbulence_get_res(struct WTURBULENCE *wt, int *res);
 void smoke_turbulence_set_noise(struct WTURBULENCE *wt, int type);
 void smoke_initWaveletBlenderRNA(struct WTURBULENCE *wt, float *strength);
 
+void smoke_dissolve_wavelet(struct WTURBULENCE *wt, int speed, int log);
+
 #ifdef __cplusplus
 }
 #endif
index 0e1fe637bb8a11ad30a49dbb673dddc032da1ea3..8f72b1da536662902206bad30838506490af5e9e 100644 (file)
@@ -101,6 +101,11 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dt) :
        _h                        = new float[_totalCells];
        _Precond          = new float[_totalCells];
 
+       _spectrum = new unsigned char[256*4*16*16];
+
+
+       // DG TODO: check if alloc went fine
+
        for (int x = 0; x < _totalCells; x++)
        {
                _density[x]      = 0.0f;
@@ -202,6 +207,8 @@ FLUID_3D::~FLUID_3D()
        if (_obstacles) delete[] _obstacles;
     // if (_wTurbulence) delete _wTurbulence;
 
+       if(_spectrum) delete[] _spectrum;
+
     printf("deleted fluid\n");
 }
 
@@ -219,7 +226,10 @@ void FLUID_3D::step()
 {
        // wipe forces
        for (int i = 0; i < _totalCells; i++)
+       {
                _xForce[i] = _yForce[i] = _zForce[i] = 0.0f;
+               _obstacles[i] &= ~2;
+       }
 
        wipeBoundaries();
 
@@ -683,16 +693,17 @@ void FLUID_3D::advectMacCormack()
 
        const float dt0 = _dt / _dx;
        // use force arrays as temp arrays
-  for (int x = 0; x < _totalCells; x++)
-    _xForce[x] = _yForce[x] = 0.0;
+       for (int x = 0; x < _totalCells; x++)
+               _xForce[x] = _yForce[x] = 0.0;
+
        float* t1 = _xForce;
        float* t2 = _yForce;
 
-       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _density, t1,t2, res, NULL);
-       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heat, t1,t2, res, NULL);
-       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocity, t1,t2, res, NULL);
-       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocity, t1,t2, res, NULL);
-       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocity, t1,t2, res, NULL);
+       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _density, t1,t2, res, _obstacles);
+       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heat, t1,t2, res, _obstacles);
+       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocity, t1,t2, res, _obstacles);
+       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocity, t1,t2, res, _obstacles);
+       advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocity, t1,t2, res, _obstacles);
 
        if(DOMAIN_BC_LEFT == 0) copyBorderX(_xVelocity, res);
        else setZeroX(_xVelocity, res);
index 614ea4e46de0c68107fe41fbf4c3aaf80238bc48..f228abc05a99fd6cec6f60f0c47f7db27492d439 100644 (file)
@@ -99,6 +99,7 @@ class FLUID_3D
                float* _h;
                float* _Precond;
                unsigned char*  _obstacles;
+               unsigned char *_spectrum;
 
                // CG fields
                float* _residual;
@@ -161,13 +162,13 @@ class FLUID_3D
                static void advectFieldSemiLagrange(const float dt, const float* velx, const float* vely,  const float* velz,
                                float* oldField, float* newField, Vec3Int res);
                static void advectFieldMacCormack(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity, 
-                               float* oldField, float* newField, float* temp1, float* temp2, Vec3Int res, const float* obstacles);
+                               float* oldField, float* newField, float* temp1, float* temp2, Vec3Int res, const unsigned char* obstacles);
 
                // maccormack helper functions
                static void clampExtrema(const float dt, const float* xVelocity, const float* yVelocity,  const float* zVelocity,
                                float* oldField, float* newField, Vec3Int res);
                static void clampOutsideRays(const float dt, const float* xVelocity, const float* yVelocity,  const float* zVelocity,
-                               float* oldField, float* newField, Vec3Int res, const float* obstacles, const float *oldAdvection);
+                               float* oldField, float* newField, Vec3Int res, const unsigned char* obstacles, const float *oldAdvection);
 
                // output helper functions
                // static void writeImageSliceXY(const float *field, Vec3Int res, int slice, string prefix, int picCnt, float scale=1.);
index ebb351dc323921b28cae7c2b96b62f7ae7b5c742..4474129beea7a89f6e7f51572855ef9960fc42b6 100644 (file)
@@ -338,7 +338,7 @@ void FLUID_3D::advectFieldSemiLagrange(const float dt, const float* velx, const
 // comments are the pseudocode from selle's paper
 //////////////////////////////////////////////////////////////////////
 void FLUID_3D::advectFieldMacCormack(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity,
-               float* oldField, float* newField, float* temp1, float* temp2, Vec3Int res, const float* obstacles)
+               float* oldField, float* newField, float* temp1, float* temp2, Vec3Int res, const unsigned char* obstacles)
 {
        float* phiHatN  = temp1;
        float* phiHatN1 = temp2;
@@ -459,7 +459,7 @@ void FLUID_3D::clampExtrema(const float dt, const float* velx, const float* vely
 // incorrect
 //////////////////////////////////////////////////////////////////////
 void FLUID_3D::clampOutsideRays(const float dt, const float* velx, const float* vely, const float* velz,
-               float* oldField, float* newField, Vec3Int res, const float* obstacles, const float *oldAdvection)
+               float* oldField, float* newField, Vec3Int res, const unsigned char* obstacles, const float *oldAdvection)
 {
        const int sx= res[0];
        const int sy= res[1];
index c4dd23146c2e0f045eadf27ac73a249c350f9f7c..7f90971f14d476bbff6e3256042b452cdc0c8548 100644 (file)
@@ -63,7 +63,18 @@ extern "C" void smoke_turbulence_free(WTURBULENCE *wt)
         wt = NULL;
 }
 
-extern "C" void smoke_step(FLUID_3D *fluid)
+extern "C" size_t smoke_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */)
+{
+       // // const int index = x + y * smd->res[0] + z * smd->res[0]*smd->res[1];
+       return x + y * max_x + z * max_x*max_y;
+}
+
+extern "C" size_t smoke_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */)
+{
+       return x + y * max_x;
+}
+
+extern "C" void smoke_step(FLUID_3D *fluid, size_t framenr)
 {
        fluid->step();
 }
@@ -79,6 +90,84 @@ extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta)
        fluid->initBlenderRNA(alpha, beta);
 }
 
+extern "C" void smoke_dissolve(FLUID_3D *fluid, int speed, int log)
+{
+       float *density = fluid->_density;
+       float *densityOld = fluid->_densityOld;
+       float *heat = fluid->_heat;
+
+       if(log)
+       {
+               /* max density/speed = dydx */
+               float dydx = 1.0 / (float)speed;
+
+               for(size_t i = 0; i < fluid->_xRes * fluid->_yRes * fluid->_zRes; i++)
+               {
+                       density[i] *= (1.0 - dydx);
+
+                       if(density[i] < 0.0f)
+                               density[i] = 0.0f;
+
+                       heat[i] *= (1.0 - dydx);
+
+                       if(heat[i] < 0.0f)
+                               heat[i] = 0.0f;
+               }
+       }
+       else // linear falloff
+       {
+               /* max density/speed = dydx */
+               float dydx = 1.0 / (float)speed;
+
+               for(size_t i = 0; i < fluid->_xRes * fluid->_yRes * fluid->_zRes; i++)
+               {
+                       density[i] -= dydx;
+
+                       if(density[i] < 0.0f)
+                               density[i] = 0.0f;
+
+                       heat[i] -= dydx;
+
+                       if(heat[i] < 0.0f)
+                               heat[i] = 0.0f;
+                               
+               }
+       }
+}
+
+extern "C" void smoke_dissolve_wavelet(WTURBULENCE *wt, int speed, int log)
+{
+       float *density = wt->getDensityBig();
+       Vec3Int r = wt->getResBig();
+
+       if(log)
+       {
+               /* max density/speed = dydx */
+               float dydx = 1.0 / (float)speed;
+
+               for(size_t i = 0; i < r[0] * r[1] * r[2]; i++)
+               {
+                       density[i] *= (1.0 - dydx);
+
+                       if(density[i] < 0.0f)
+                               density[i] = 0.0f;
+               }
+       }
+       else // linear falloff
+       {
+               /* max density/speed = dydx */
+               float dydx = 1.0 / (float)speed;
+
+               for(size_t i = 0; i < r[0] * r[1] * r[2]; i++)
+               {
+                       density[i] -= dydx;
+
+                       if(density[i] < 0.0f)
+                               density[i] = 0.0f;                              
+               }
+       }
+}
+
 extern "C" void smoke_initWaveletBlenderRNA(WTURBULENCE *wt, float *strength)
 {
        wt->initBlenderRNA(strength);
@@ -134,17 +223,6 @@ extern "C" unsigned char *smoke_get_obstacle(FLUID_3D *fluid)
        return fluid->_obstacles;
 }
 
-extern "C" size_t smoke_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */)
-{
-       // // const int index = x + y * smd->res[0] + z * smd->res[0]*smd->res[1];
-       return x + y * max_x + z * max_x*max_y;
-}
-
-extern "C" size_t smoke_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */)
-{
-       return x + y * max_x;
-}
-
 extern "C" void smoke_turbulence_set_noise(WTURBULENCE *wt, int type)
 {
        wt->setNoise(type);
index caafb3d58f2a612075076546992fbeedd8decbff..5471030883e25054a3ed8a8c6dc9f4785500c63e 100644 (file)
@@ -71,6 +71,14 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel):
                                col.itemR(md.domain_settings, "strength")
                                sub = split.column()
                                
+                               split = layout.split()
+                               col = split.column()
+                               col.itemR(md.domain_settings, "dissolve_smoke")
+                               sub = col.column()
+                               sub.active = md.domain_settings.dissolve_smoke
+                               sub.itemR(md.domain_settings, "dissolve_speed")
+                               sub.itemR(md.domain_settings, "dissolve_smoke_log")
+                               
                                split = layout.split()
                                
                                col = split.column()
index 8224f0dd3f34880f142ffb6b8a0a8bd133ed0a22..9d4c75245cf15f8e3c66e517f997d548a1412c72 100644 (file)
@@ -207,7 +207,7 @@ int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, Derive
                // 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, 2.5 / FPS);
+               smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0, 0.1);
                smd->domain->wt = smoke_turbulence_init(smd->domain->res,  (smd->domain->flags & MOD_SMOKE_HIGHRES) ? (smd->domain->amplify + 1) : 0, smd->domain->noise);
                smd->time = scene->r.cfra;
                smd->domain->firstframe = smd->time;
@@ -228,6 +228,17 @@ int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, Derive
 
                // update particle lifetime to be one frame
                // smd->flow->psys->part->lifetime = scene->r.efra + 1;
+/*
+               if(!smd->flow->bvh)
+               {
+                       // smd->flow->bvh = MEM_callocN(sizeof(BVHTreeFromMesh), "smoke_bvhfromfaces");
+                       // bvhtree_from_mesh_faces(smd->flow->bvh, dm, 0.0, 2, 6);
+
+                       // copy obmat
+                       // Mat4CpyMat4(smd->flow->mat, ob->obmat);
+                       // Mat4CpyMat4(smd->flow->mat_old, ob->obmat);
+               }
+*/
 
                return 1;
        }
@@ -527,6 +538,14 @@ void smokeModifier_freeFlow(SmokeModifierData *smd)
 {
        if(smd->flow)
        {
+/*
+               if(smd->flow->bvh)
+               {
+                       free_bvhtree_from_mesh(smd->flow->bvh);
+                       MEM_freeN(smd->flow->bvh);
+               }
+               smd->flow->bvh = NULL;
+*/
                MEM_freeN(smd->flow);
                smd->flow = NULL;
        }
@@ -604,7 +623,14 @@ void smokeModifier_reset(struct SmokeModifierData *smd)
                }
                else if(smd->flow)
                {
-                                               
+                       /*
+                       if(smd->flow->bvh)
+                       {
+                               free_bvhtree_from_mesh(smd->flow->bvh);
+                               MEM_freeN(smd->flow->bvh);
+                       }
+                       smd->flow->bvh = NULL;
+                       */
                }
                else if(smd->coll)
                {
@@ -662,11 +688,11 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
                        smd->domain->omega = 1.0;
                        smd->domain->alpha = -0.001;
                        smd->domain->beta = 0.1;
-                       smd->domain->flags = 0; // MOD_SMOKE_DISSOLVE_INV;
+                       smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG;
                        smd->domain->strength = 2.0;
                        smd->domain->noise = MOD_SMOKE_NOISEWAVE;
                        smd->domain->visibility = 1;
-                       // smd->domain->diss_speed = 50;
+                       smd->domain->diss_speed = 5;
 
                        // init 3dview buffer
                        smd->domain->tvox = NULL;
@@ -723,6 +749,12 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                {
                        // 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)
                {
@@ -763,8 +795,13 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                        
                        tstart();
                        
-                       // if(sds->flags & MOD_SMOKE_DISSOLVE)
-                       //      smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG, sds->flags & MOD_SMOKE_DISSOLVE_INV);
+                       if(sds->flags & MOD_SMOKE_DISSOLVE)
+                       {
+                               smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
+                               
+                               if(sds->wt)
+                                       smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
+                       }
 
                        /* reset view for new frame */
                        if(sds->viewsettings < MOD_SMOKE_VIEW_USEBIG)
@@ -830,7 +867,10 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                                                                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 bigres[3];                                                          
+                                                               unsigned char *obstacle = smoke_get_obstacle(sds->fluid);
+                                                               int bigres[3];  
+
+                                                               printf("found flow psys\n");
                                                                
                                                                // mostly copied from particle code
                                                                for(p=0, pa=psys->particles; p<psys->totpart; p++, pa++)
@@ -867,15 +907,20 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                                                                        // 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)) // this is inflow
+                                                                       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)
@@ -894,7 +939,7 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                                                                                                        }
                                                                                }
                                                                        }
-                                                                       else // outflow
+                                                                       else if(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) // outflow
                                                                        {
                                                                                heat[index] = 0.f;
                                                                                density[index] = 0.f;
@@ -920,7 +965,21 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                                                                                }
                                                                        }
                                                                }
-                                                       }       
+                                                       }
+                                                       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);
+                                                               }*/
+                                                       }
                                                }       
                                        }
 
@@ -1058,7 +1117,7 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
                        smd->time = scene->r.cfra;
 
                        // simulate the actual smoke (c++ code in intern/smoke)
-                       smoke_step(sds->fluid);
+                       smoke_step(sds->fluid, smd->time);
                        if(sds->wt)
                                smoke_turbulence_step(sds->wt, sds->fluid);
 
index 7d64862ba32c84dc3d9416f098eabedb91ea4fc0..c7f49d3ddd2712851284a1c98d1bbc296229307e 100644 (file)
 #define DNA_SMOKE_TYPES_H
 
 /* flags */
-#define MOD_SMOKE_HIGHRES (1<<1)
+#define MOD_SMOKE_HIGHRES (1<<1) /* compute high resolution */
+#define MOD_SMOKE_DISSOLVE (1<<2) /* let smoke dissolve */
+#define MOD_SMOKE_DISSOLVE_LOG (1<<3) /* using 1/x for dissolve */
+
 /* noise */
 #define MOD_SMOKE_NOISEWAVE (1<<0)
 #define MOD_SMOKE_NOISEFFT (1<<1)
@@ -75,8 +78,8 @@ typedef struct SmokeDomainSettings {
        int viewsettings;
        int max_textures;
        short noise; /* noise type: wave, curl, anisotropic */
-       short pad2;
-       int pad;
+       short diss_percent; 
+       int diss_speed;/* in frames */
        float strength;
        struct WTURBULENCE *wt; // WTURBULENCE object, if active
 } SmokeDomainSettings;
@@ -101,6 +104,12 @@ typedef struct SmokeFlowSettings {
        int pad;
 } SmokeFlowSettings;
 
+/*
+       struct BVHTreeFromMesh *bvh;
+       float mat[4][4];
+       float mat_old[4][4];
+       */
+
 /* collision objects (filled with smoke) */
 typedef struct SmokeCollSettings {
        struct SmokeModifierData *smd; /* for fast RNA access */
index 1cd98ca3a9c2b9df8bc2d3cc8bbc07ceb726791f..6f1babb495a904074a77db171518166c0b13ed5b 100644 (file)
@@ -210,10 +210,27 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
 
        prop= RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
        RNA_def_property_float_sdna(prop, NULL, "strength");
-       RNA_def_property_range(prop, -5.0, 5.0);
+       RNA_def_property_range(prop, 1.0, 10.0);
        RNA_def_property_ui_range(prop, 1.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");
+
+       prop= RNA_def_property(srna, "dissolve_speed", PROP_INT, PROP_NONE);
+       RNA_def_property_int_sdna(prop, NULL, "diss_speed");
+       RNA_def_property_range(prop, 1.0, 100.0);
+       RNA_def_property_ui_range(prop, 1.0, 1000.0, 1, 0);
+       RNA_def_property_ui_text(prop, "Dissolve Speed", "Dissolve Speed");
+       RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, NULL);
+
+       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.");
+       RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, NULL);
+
+       prop= RNA_def_property(srna, "dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE_LOG);
+       RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x ");
+       RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, NULL);
 }
 
 static void rna_def_smoke_flow_settings(BlenderRNA *brna)