Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Genrich <daniel.genrich@gmx.net>2012-10-10 17:18:07 +0400
committerDaniel Genrich <daniel.genrich@gmx.net>2012-10-10 17:18:07 +0400
commitcb634b910010c04543cb3361f7a16a261e5b9f89 (patch)
tree348403dcbd33baf2e6e9a7a5ef0bb57dd2e1b09d /source/blender
parentf0a9b664694dacb0388a8e078d46753dc6a36352 (diff)
Google Summer of Code project: "Smoke Simulator Improvements & Fire".
Documentation & Test blend files: ------------------ http://wiki.blender.org/index.php/User:MiikaH/GSoC-2012-Smoke-Simulator-Improvements Credits: ------------------ Miika Hamalainen (MiikaH): Student / Main programmer Daniel Genrich (Genscher): Mentor / Programmer of merged patches from Smoke2 branch Google: For Google Summer of Code 2012
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_smoke.h6
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c17
-rw-r--r--source/blender/blenkernel/intern/effect.c21
-rw-r--r--source/blender/blenkernel/intern/pointcache.c162
-rw-r--r--source/blender/blenkernel/intern/smoke.c2818
-rw-r--r--source/blender/blenkernel/intern/texture.c2
-rw-r--r--source/blender/blenlib/BLI_math_vector.h1
-rw-r--r--source/blender/blenlib/BLI_utildefines.h5
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c7
-rw-r--r--source/blender/blenloader/intern/readfile.c51
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/object/object_add.c3
-rw-r--r--source/blender/editors/space_view3d/drawobject.c128
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c263
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h11
-rw-r--r--source/blender/gpu/GPU_extensions.h2
-rw-r--r--source/blender/gpu/intern/gpu_draw.c42
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c14
-rw-r--r--source/blender/makesdna/DNA_object_force.h7
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h111
-rw-r--r--source/blender/makesdna/DNA_texture_types.h9
-rw-r--r--source/blender/makesrna/intern/rna_material.c6
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c25
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c19
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c250
-rw-r--r--source/blender/makesrna/intern/rna_texture.c3
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c59
-rw-r--r--source/blender/render/intern/source/render_texture.c20
-rw-r--r--source/blender/render/intern/source/voxeldata.c167
29 files changed, 2752 insertions, 1479 deletions
diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h
index 1f824ccbafc..3a9d2b86b41 100644
--- a/source/blender/blenkernel/BKE_smoke.h
+++ b/source/blender/blenkernel/BKE_smoke.h
@@ -35,8 +35,10 @@
typedef float (*bresenham_callback)(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
-void smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
+struct DerivedMesh *smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
+void smoke_reallocate_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
+void smoke_reallocate_highres_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
void smokeModifier_free(struct SmokeModifierData *smd);
void smokeModifier_reset(struct SmokeModifierData *smd);
void smokeModifier_reset_turbulence(struct SmokeModifierData *smd);
@@ -44,5 +46,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd);
void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData *tsmd);
long long smoke_get_mem_req(int xres, int yres, int zres, int amplify);
+float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
+int smoke_get_data_flags(struct SmokeDomainSettings *sds);
#endif /* __BKE_SMOKE_H__ */
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 31a6f768f89..9b52fbae626 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -400,8 +400,7 @@ static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Mat
}
}
-static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Object *ob, DagNode *node)
-{
+static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Object *ob, DagNode *node, int skip_forcefield){
Base *base;
DagNode *node2;
@@ -411,6 +410,8 @@ static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Objec
if ((base->lay & ob->lay) && base->object->pd) {
Object *ob1 = base->object;
if ((ob1->pd->deflect || ob1->pd->forcefield) && (ob1 != ob)) {
+ if (skip_forcefield && ob1->pd->forcefield == skip_forcefield)
+ continue;
node2 = dag_get_node(dag, ob1);
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Collision");
}
@@ -570,12 +571,14 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
/* softbody collision */
if ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_LATTICE)) {
if (ob->particlesystem.first ||
- modifiers_isModifierEnabled(ob, eModifierType_Softbody) ||
- modifiers_isModifierEnabled(ob, eModifierType_Cloth) ||
- modifiers_isModifierEnabled(ob, eModifierType_Smoke) ||
- modifiers_isModifierEnabled(ob, eModifierType_DynamicPaint))
+ modifiers_isModifierEnabled(ob, eModifierType_Softbody) ||
+ modifiers_isModifierEnabled(ob, eModifierType_Cloth) ||
+ modifiers_isModifierEnabled(ob, eModifierType_DynamicPaint))
{
- dag_add_collision_field_relation(dag, scene, ob, node); /* TODO: use effectorweight->group */
+ dag_add_collision_field_relation(dag, scene, ob, node, 0); /* TODO: use effectorweight->group */
+ }
+ else if (modifiers_isModifierEnabled(ob, eModifierType_Smoke)) {
+ dag_add_collision_field_relation(dag, scene, ob, node, PFIELD_SMOKEFLOW);
}
}
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 4f4bafd00b4..495814acbee 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -84,6 +84,7 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
+#include "BKE_smoke.h"
#include "RE_render_ext.h"
@@ -137,6 +138,9 @@ PartDeflect *object_add_collision_fields(int type)
case PFIELD_TEXTURE:
pd->f_size = 1.0f;
break;
+ case PFIELD_SMOKEFLOW:
+ pd->f_flow = 1.0f;
+ break;
}
pd->flag = PFIELD_DO_LOCATION|PFIELD_DO_ROTATION;
@@ -922,12 +926,27 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp));
break;
+ case PFIELD_SMOKEFLOW:
+ zero_v3(force);
+ if (pd->f_source) {
+ float density;
+ if ((density = smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) {
+ float influence = strength * efd->falloff;
+ if (pd->flag & PFIELD_SMOKE_DENSITY)
+ influence *= density;
+ mul_v3_fl(force, influence);
+ /* apply flow */
+ madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence);
+ }
+ }
+ break;
+
}
if (pd->flag & PFIELD_DO_LOCATION) {
madd_v3_v3fl(total_force, force, 1.0f/point->vel_to_sec);
- if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG)==0 && pd->f_flow != 0.0f) {
+ if (ELEM3(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) {
madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff);
}
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 8c0d19ba1fd..6b90ec88362 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -532,20 +532,31 @@ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
SmokeDomainSettings *sds = smd->domain;
if (sds->fluid) {
- return sds->res[0]*sds->res[1]*sds->res[2];
+ return sds->base_res[0]*sds->base_res[1]*sds->base_res[2];
}
else
return 0;
}
+
+#define SMOKE_CACHE_VERSION "1.04"
+
static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
{
SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
SmokeDomainSettings *sds = smd->domain;
int ret = 0;
+ int fluid_fields = smoke_get_data_flags(sds);
+
+ /* version header */
+ ptcache_file_write(pf, SMOKE_CACHE_VERSION, 4, sizeof(char));
+ ptcache_file_write(pf, &fluid_fields, 1, sizeof(int));
+ ptcache_file_write(pf, &sds->active_fields, 1, sizeof(int));
+ ptcache_file_write(pf, &sds->res, 3, sizeof(int));
+ ptcache_file_write(pf, &sds->dx, 1, sizeof(float));
if (sds->fluid) {
size_t res = sds->res[0]*sds->res[1]*sds->res[2];
- float dt, dx, *dens, *densold, *heat, *heatold, *vx, *vy, *vz, *vxold, *vyold, *vzold;
+ float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
unsigned int in_len = sizeof(float)*(unsigned int)res;
unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len)*4, "pointcache_lzo_buffer");
@@ -553,22 +564,40 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
int mode=1; // light
if (sds->cache_comp == SM_CACHE_HEAVY) mode=2; // heavy
- smoke_export(sds->fluid, &dt, &dx, &dens, &densold, &heat, &heatold, &vx, &vy, &vz, &vxold, &vyold, &vzold, &obstacles);
+ smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
ptcache_file_compressed_write(pf, (unsigned char *)sds->shadow, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)densold, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)heat, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)heatold, in_len, out, mode);
+ if (fluid_fields & SM_ACTIVE_HEAT) {
+ ptcache_file_compressed_write(pf, (unsigned char *)heat, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)heatold, in_len, out, mode);
+ }
+ if (fluid_fields & SM_ACTIVE_FIRE) {
+ ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)react, in_len, out, mode);
+ }
+ if (fluid_fields & SM_ACTIVE_COLORS) {
+ ptcache_file_compressed_write(pf, (unsigned char *)r, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)g, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)b, in_len, out, mode);
+ }
ptcache_file_compressed_write(pf, (unsigned char *)vx, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)vy, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)vz, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)vxold, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)vyold, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)vzold, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)obstacles, (unsigned int)res, out, mode);
ptcache_file_write(pf, &dt, 1, sizeof(float));
ptcache_file_write(pf, &dx, 1, sizeof(float));
+ ptcache_file_write(pf, &sds->p0, 3, sizeof(float));
+ ptcache_file_write(pf, &sds->p1, 3, sizeof(float));
+ ptcache_file_write(pf, &sds->dp0, 3, sizeof(float));
+ ptcache_file_write(pf, &sds->shift, 3, sizeof(int));
+ ptcache_file_write(pf, &sds->obj_shift_f, 3, sizeof(float));
+ ptcache_file_write(pf, &sds->obmat, 16, sizeof(float));
+ ptcache_file_write(pf, &sds->base_res, 3, sizeof(int));
+ ptcache_file_write(pf, &sds->res_min, 3, sizeof(int));
+ ptcache_file_write(pf, &sds->res_max, 3, sizeof(int));
+ ptcache_file_write(pf, &sds->active_color, 3, sizeof(float));
MEM_freeN(out);
@@ -579,7 +608,7 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
int res_big_array[3];
int res_big;
int res = sds->res[0]*sds->res[1]*sds->res[2];
- float *dens, *densold, *tcu, *tcv, *tcw;
+ float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
unsigned int in_len = sizeof(float)*(unsigned int)res;
unsigned int in_len_big;
unsigned char *out;
@@ -593,11 +622,20 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
in_len_big = sizeof(float) * (unsigned int)res_big;
- smoke_turbulence_export(sds->wt, &dens, &densold, &tcu, &tcv, &tcw);
+ smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len_big), "pointcache_lzo_buffer");
ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len_big, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)densold, in_len_big, out, mode);
+ if (fluid_fields & SM_ACTIVE_FIRE) {
+ ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len_big, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len_big, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)react, in_len_big, out, mode);
+ }
+ if (fluid_fields & SM_ACTIVE_COLORS) {
+ ptcache_file_compressed_write(pf, (unsigned char *)r, in_len_big, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)g, in_len_big, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)b, in_len_big, out, mode);
+ }
MEM_freeN(out);
out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
@@ -615,34 +653,95 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
{
SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
SmokeDomainSettings *sds = smd->domain;
+ char version[4];
+ int ch_res[3];
+ float ch_dx;
+ int fluid_fields = smoke_get_data_flags(sds);
+ int cache_fields = 0;
+ int active_fields = 0;
+ int reallocate = 0;
+
+ /* version header */
+ ptcache_file_read(pf, version, 4, sizeof(char));
+ if (strncmp(version, SMOKE_CACHE_VERSION, 4)) return 0;
+ /* fluid info */
+ ptcache_file_read(pf, &cache_fields, 1, sizeof(int));
+ ptcache_file_read(pf, &active_fields, 1, sizeof(int));
+ ptcache_file_read(pf, &ch_res, 3, sizeof(int));
+ ptcache_file_read(pf, &ch_dx, 1, sizeof(float));
+
+ /* check if resolution has changed */
+ if (sds->res[0] != ch_res[0] ||
+ sds->res[1] != ch_res[1] ||
+ sds->res[2] != ch_res[2]) {
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN)
+ reallocate = 1;
+ else
+ return 0;
+ }
+ /* check if active fields have changed */
+ if (fluid_fields != cache_fields ||
+ active_fields != sds->active_fields)
+ reallocate = 1;
+
+ /* reallocate fluid if needed*/
+ if (reallocate) {
+ sds->active_fields = active_fields;
+ smoke_reallocate_fluid(sds, ch_dx, ch_res, 1);
+ sds->dx = ch_dx;
+ VECCOPY(sds->res, ch_res);
+ sds->total_cells = ch_res[0]*ch_res[1]*ch_res[2];
+ if(sds->flags & MOD_SMOKE_HIGHRES) {
+ smoke_reallocate_highres_fluid(sds, ch_dx, ch_res, 1);
+ }
+ }
if (sds->fluid) {
size_t res = sds->res[0]*sds->res[1]*sds->res[2];
- float dt, dx, *dens, *densold, *heat, *heatold, *vx, *vy, *vz, *vxold, *vyold, *vzold;
+ float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
unsigned int out_len = (unsigned int)res * sizeof(float);
- smoke_export(sds->fluid, &dt, &dx, &dens, &densold, &heat, &heatold, &vx, &vy, &vz, &vxold, &vyold, &vzold, &obstacles);
+ smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)dens, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)densold, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)heat, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)heatold, out_len);
+ if (cache_fields & SM_ACTIVE_HEAT) {
+ ptcache_file_compressed_read(pf, (unsigned char*)heat, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char*)heatold, out_len);
+ }
+ if (cache_fields & SM_ACTIVE_FIRE) {
+ ptcache_file_compressed_read(pf, (unsigned char*)flame, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char*)fuel, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char*)react, out_len);
+ }
+ if (cache_fields & SM_ACTIVE_COLORS) {
+ ptcache_file_compressed_read(pf, (unsigned char*)r, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char*)g, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char*)b, out_len);
+ }
ptcache_file_compressed_read(pf, (unsigned char*)vx, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)vy, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)vz, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)vxold, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)vyold, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)vzold, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)obstacles, (unsigned int)res);
ptcache_file_read(pf, &dt, 1, sizeof(float));
ptcache_file_read(pf, &dx, 1, sizeof(float));
-
- if (pf->data_types & (1<<BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
+ ptcache_file_read(pf, &sds->p0, 3, sizeof(float));
+ ptcache_file_read(pf, &sds->p1, 3, sizeof(float));
+ ptcache_file_read(pf, &sds->dp0, 3, sizeof(float));
+ ptcache_file_read(pf, &sds->shift, 3, sizeof(int));
+ ptcache_file_read(pf, &sds->obj_shift_f, 3, sizeof(float));
+ ptcache_file_read(pf, &sds->obmat, 16, sizeof(float));
+ ptcache_file_read(pf, &sds->base_res, 3, sizeof(int));
+ ptcache_file_read(pf, &sds->res_min, 3, sizeof(int));
+ ptcache_file_read(pf, &sds->res_max, 3, sizeof(int));
+ ptcache_file_read(pf, &sds->active_color, 3, sizeof(float));
+ }
+
+ if (pf->data_types & (1<<BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
int res = sds->res[0]*sds->res[1]*sds->res[2];
int res_big, res_big_array[3];
- float *dens, *densold, *tcu, *tcv, *tcw;
+ float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
unsigned int out_len = sizeof(float)*(unsigned int)res;
unsigned int out_len_big;
@@ -650,16 +749,23 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
res_big = res_big_array[0]*res_big_array[1]*res_big_array[2];
out_len_big = sizeof(float) * (unsigned int)res_big;
- smoke_turbulence_export(sds->wt, &dens, &densold, &tcu, &tcv, &tcw);
+ smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
ptcache_file_compressed_read(pf, (unsigned char*)dens, out_len_big);
- ptcache_file_compressed_read(pf, (unsigned char*)densold, out_len_big);
+ if (cache_fields & SM_ACTIVE_FIRE) {
+ ptcache_file_compressed_read(pf, (unsigned char*)flame, out_len_big);
+ ptcache_file_compressed_read(pf, (unsigned char*)fuel, out_len_big);
+ }
+ if (cache_fields & SM_ACTIVE_COLORS) {
+ ptcache_file_compressed_read(pf, (unsigned char*)r, out_len_big);
+ ptcache_file_compressed_read(pf, (unsigned char*)g, out_len_big);
+ ptcache_file_compressed_read(pf, (unsigned char*)b, out_len_big);
+ }
ptcache_file_compressed_read(pf, (unsigned char*)tcu, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)tcv, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)tcw, out_len);
}
- }
return 1;
}
@@ -2466,10 +2572,10 @@ int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
sbFreeSimulation(pid->calldata);
else if (pid->type == PTCACHE_TYPE_PARTICLES)
psys_reset(pid->calldata, PSYS_RESET_DEPSGRAPH);
- else if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
+ /*else if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
smokeModifier_reset(pid->calldata);
else if (pid->type == PTCACHE_TYPE_SMOKE_HIGHRES)
- smokeModifier_reset_turbulence(pid->calldata);
+ smokeModifier_reset_turbulence(pid->calldata);*/
else if (pid->type == PTCACHE_TYPE_DYNAMICPAINT)
dynamicPaint_clearSurface((DynamicPaintSurface*)pid->calldata);
}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 5e67e094e43..a07c58746df 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -51,18 +51,7 @@
#include "BLI_kdtree.h"
#include "BLI_kdopbvh.h"
#include "BLI_utildefines.h"
-
-#include "BKE_bvhutils.h"
-#include "BKE_cdderivedmesh.h"
-#include "BKE_collision.h"
-#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_effect.h"
-#include "BKE_modifier.h"
-#include "BKE_particle.h"
-#include "BKE_pointcache.h"
-#include "BKE_smoke.h"
-
+#include "BLI_voxel.h"
#include "DNA_customdata_types.h"
#include "DNA_group_types.h"
@@ -75,8 +64,20 @@
#include "DNA_scene_types.h"
#include "DNA_smoke_types.h"
+#include "BKE_bvhutils.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_collision.h"
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_effect.h"
+#include "BKE_modifier.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
#include "BKE_smoke.h"
+#include "RE_shader_ext.h"
+
/* UNUSED so far, may be enabled later */
/* #define USE_SMOKE_COLLISION_DM */
@@ -103,7 +104,7 @@ static void tend ( void )
{
QueryPerformanceCounter ( &liCurrentTime );
}
-static double UNUSED_FUNCTION(tval)( void )
+static double tval( void )
{
return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart ));
}
@@ -134,590 +135,220 @@ struct Scene;
struct DerivedMesh;
struct SmokeModifierData;
-#define TRI_UVOFFSET (1./4.)
-
// timestep default value for nice appearance 0.1f
#define DT_DEFAULT 0.1f
-/* forward declerations */
-static void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int numfaces, int numtris, int **tridivs, float cell_len);
-static void get_cell(const float p0[3], const int res[3], float dx, const float pos[3], int cell[3], int correct);
-static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs);
+#define ADD_IF_LOWER_POS(a,b) (MIN2((a)+(b), MAX2((a),(b))))
+#define ADD_IF_LOWER_NEG(a,b) (MAX2((a)+(b), MIN2((a),(b))))
+#define ADD_IF_LOWER(a,b) (((b)>0)?ADD_IF_LOWER_POS((a),(b)):ADD_IF_LOWER_NEG((a),(b)))
#else /* WITH_SMOKE */
/* Stubs to use when smoke is disabled */
-struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype)) { return NULL; }
-// struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(p0)) { return NULL; }
+struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; }
+//struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(dx), float *UNUSED(dtdef), int UNUSED(use_heat), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; }
void smoke_free(struct FLUID_3D *UNUSED(fluid)) {}
float *smoke_get_density(struct FLUID_3D *UNUSED(fluid)) { return NULL; }
void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) {}
void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) {}
-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)) {}
-long long smoke_get_mem_req(int UNUSED(xres), int UNUSED(yres), int UNUSED(zres), int UNUSED(amplify)) { return 0; }
-void smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) {}
+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), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color),
+ float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {}
+struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { return NULL; }
+float smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; }
+void flame_get_spectrum(unsigned char *UNUSED(spec), int UNUSED(width), float UNUSED(t1), float UNUSED(t2)) {}
#endif /* WITH_SMOKE */
#ifdef WITH_SMOKE
-static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
+void smoke_reallocate_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old)
{
- if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
- {
- size_t i;
- float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- float size[3];
- MVert *verts = dm->getVertArray(dm);
- float scale = 0.0;
- int res;
+ int use_heat = (sds->active_fields & SM_ACTIVE_HEAT);
+ int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT|SM_ACTIVE_FIRE));
+ int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
+
+ if (free_old && sds->fluid)
+ smoke_free(sds->fluid);
+ if (!MIN3(res[0],res[1],res[2])) {
+ sds->fluid = NULL;
+ return;
+ }
+ sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors);
+ smoke_initBlenderRNA(sds->fluid, &(sds->alpha), &(sds->beta), &(sds->time_scale), &(sds->vorticity), &(sds->border_collisions),
+ &(sds->burning_rate), &(sds->flame_smoke), sds->flame_smoke_color, &(sds->flame_vorticity), &(sds->flame_ignition), &(sds->flame_max_temp));
+
+ /* reallocate shadow buffer */
+ if (sds->shadow)
+ MEM_freeN(sds->shadow);
+ sds->shadow = MEM_callocN(sizeof(float) * res[0] * res[1] * res[2], "SmokeDomainShadow");
+}
- res = smd->domain->maxres;
+void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old)
+{
+ int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT|SM_ACTIVE_FIRE));
+ int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
- // get BB of domain
- for(i = 0; i < dm->getNumVerts(dm); i++)
- {
- float tmp[3];
+ if (free_old && sds->wt)
+ smoke_turbulence_free(sds->wt);
+ if (!MIN3(res[0],res[1],res[2])) {
+ sds->wt = NULL;
+ return;
+ }
+ sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, use_fire, use_colors);
+ sds->res_wt[0] = res[0] * (sds->amplify + 1);
+ sds->res_wt[1] = res[1] * (sds->amplify + 1);
+ sds->res_wt[2] = res[2] * (sds->amplify + 1);
+ sds->dx_wt = dx / (sds->amplify + 1);
+ smoke_initWaveletBlenderRNA(sds->wt, &(sds->strength));
+}
- copy_v3_v3(tmp, verts[i].co);
- mul_m4_v3(ob->obmat, tmp);
+/* convert global position to domain cell space */
+static void smoke_pos_to_cell(SmokeDomainSettings *sds, float pos[3])
+{
+ mul_m4_v3(sds->imat, pos);
+ sub_v3_v3(pos, sds->p0);
+ pos[0] *= 1.0f/sds->cell_size[0];
+ pos[1] *= 1.0f/sds->cell_size[1];
+ pos[2] *= 1.0f/sds->cell_size[2];
+}
- // min BB
- min[0] = MIN2(min[0], tmp[0]);
- min[1] = MIN2(min[1], tmp[1]);
- min[2] = MIN2(min[2], tmp[2]);
+/* set domain resolution and dimensions from object derivedmesh */
+static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object *ob, DerivedMesh *dm)
+{
+ size_t i;
+ float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+ float size[3];
+ MVert *verts = dm->getVertArray(dm);
+ float scale = 0.0;
+ int res;
- // max BB
- max[0] = MAX2(max[0], tmp[0]);
- max[1] = MAX2(max[1], tmp[1]);
- max[2] = MAX2(max[2], tmp[2]);
- }
+ res = sds->maxres;
- copy_v3_v3(smd->domain->p0, min);
- copy_v3_v3(smd->domain->p1, max);
+ // get BB of domain
+ for(i = 0; i < dm->getNumVerts(dm); i++)
+ {
+ // min BB
+ min[0] = MIN2(min[0], verts[i].co[0]);
+ min[1] = MIN2(min[1], verts[i].co[1]);
+ min[2] = MIN2(min[2], verts[i].co[2]);
+
+ // max BB
+ max[0] = MAX2(max[0], verts[i].co[0]);
+ max[1] = MAX2(max[1], verts[i].co[1]);
+ max[2] = MAX2(max[2], verts[i].co[2]);
+ }
- // calc other res with max_res provided
- sub_v3_v3v3(size, max, min);
+ /* set domain bounds */
+ copy_v3_v3(sds->p0, min);
+ copy_v3_v3(sds->p1, max);
+ sds->dx = 1.0f / res;
- // prevent crash when initializing a plane as domain
- if((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON))
- return 0;
+ /* calculate domain dimensions */
+ sub_v3_v3v3(size, max, min);
+ copy_v3_v3(sds->cell_size, size);
+ mul_v3_v3(size, ob->size);
+ copy_v3_v3(sds->global_size, size);
+ copy_v3_v3(sds->dp0, min);
- if(size[0] > size[1])
- {
- if(size[0] > size[2])
- {
- scale = res / size[0];
- smd->domain->scale = size[0];
- smd->domain->dx = 1.0f / res;
- smd->domain->res[0] = res;
- smd->domain->res[1] = (int)(size[1] * scale + 0.5);
- smd->domain->res[2] = (int)(size[2] * scale + 0.5);
- }
- else {
- scale = res / size[2];
- smd->domain->scale = size[2];
- smd->domain->dx = 1.0f / res;
- smd->domain->res[2] = res;
- smd->domain->res[0] = (int)(size[0] * scale + 0.5);
- smd->domain->res[1] = (int)(size[1] * scale + 0.5);
- }
+ invert_m4_m4(sds->imat, ob->obmat);
+
+ // prevent crash when initializing a plane as domain
+ if((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON))
+ return;
+
+ /* define grid resolutions from longest domain side */
+ if (size[0] > MAX2(size[1], size[2])) {
+ scale = res / size[0];
+ sds->scale = size[0] / ob->size[0];
+ sds->base_res[0] = res;
+ sds->base_res[1] = (int)(size[1] * scale + 0.5);
+ sds->base_res[2] = (int)(size[2] * scale + 0.5);
+ }
+ else if (size[1] > MAX2(size[0], size[2])) {
+ scale = res / size[1];
+ sds->scale = size[1] / ob->size[1];
+ sds->base_res[0] = (int)(size[0] * scale + 0.5);
+ sds->base_res[1] = res;
+ sds->base_res[2] = (int)(size[2] * scale + 0.5);
+ }
+ else {
+ scale = res / size[2];
+ sds->scale = size[2] / ob->size[2];
+ sds->base_res[0] = (int)(size[0] * scale + 0.5);
+ sds->base_res[1] = (int)(size[1] * scale + 0.5);
+ sds->base_res[2] = res;
+ }
+
+ /* set cell size */
+ sds->cell_size[0] /= (float)sds->base_res[0];
+ sds->cell_size[1] /= (float)sds->base_res[1];
+ sds->cell_size[2] /= (float)sds->base_res[2];
+}
+
+static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
+{
+ if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
+ {
+ SmokeDomainSettings *sds = smd->domain;
+ int res[3];
+ /* set domain dimensions from derivedmesh */
+ smoke_set_domain_from_derivedmesh(sds, ob, dm);
+ /* reset domain values */
+ zero_v3_int(sds->shift);
+ zero_v3(sds->shift_f);
+ add_v3_fl(sds->shift_f, 0.5f);
+ zero_v3(sds->prev_loc);
+ mul_m4_v3(ob->obmat, sds->prev_loc);
+
+ /* set resolutions */
+ if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */
}
else {
- if(size[1] > size[2])
- {
- scale = res / size[1];
- smd->domain->scale = size[1];
- smd->domain->dx = 1.0f / res;
- smd->domain->res[1] = res;
- smd->domain->res[0] = (int)(size[0] * scale + 0.5);
- smd->domain->res[2] = (int)(size[2] * scale + 0.5);
- }
- else {
- scale = res / size[2];
- smd->domain->scale = size[2];
- smd->domain->dx = 1.0f / res;
- smd->domain->res[2] = res;
- smd->domain->res[0] = (int)(size[0] * scale + 0.5);
- smd->domain->res[1] = (int)(size[1] * scale + 0.5);
- }
+ VECCOPY(res, sds->base_res);
}
+ VECCOPY(sds->res, res);
+ sds->total_cells = sds->res[0]*sds->res[1]*sds->res[2];
+ sds->res_min[0] = sds->res_min[1] = sds->res_min[2] = 0;
+ VECCOPY(sds->res_max, res);
- // TODO: put in failsafe if res<=0 - dg
+ /* allocate fluid */
+ smoke_reallocate_fluid(sds, sds->dx, sds->res, 0);
- // dt max is 0.1
- smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0, DT_DEFAULT);
smd->time = scene->r.cfra;
- if(smd->domain->flags & MOD_SMOKE_HIGHRES)
- {
- smd->domain->wt = smoke_turbulence_init(smd->domain->res, smd->domain->amplify + 1, smd->domain->noise);
- smd->domain->res_wt[0] = smd->domain->res[0] * (smd->domain->amplify + 1);
- smd->domain->res_wt[1] = smd->domain->res[1] * (smd->domain->amplify + 1);
- smd->domain->res_wt[2] = smd->domain->res[2] * (smd->domain->amplify + 1);
- smd->domain->dx_wt = smd->domain->dx / (smd->domain->amplify + 1);
+ /* allocate highres fluid */
+ if(sds->flags & MOD_SMOKE_HIGHRES) {
+ smoke_reallocate_highres_fluid(sds, sds->dx, sds->res, 0);
}
+ /* allocate shadow buffer */
+ if(!sds->shadow)
+ sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2], "SmokeDomainShadow");
- 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), &(smd->domain->time_scale), &(smd->domain->vorticity), &(smd->domain->border_collisions));
-
- if(smd->domain->wt)
- {
- smoke_initWaveletBlenderRNA(smd->domain->wt, &(smd->domain->strength));
- }
return 1;
}
else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
{
- // handle flow object here
- // XXX TODO
-
smd->time = scene->r.cfra;
return 1;
}
else if((smd->type & MOD_SMOKE_TYPE_COLL))
{
- // todo: delete this when loading colls work -dg
-
if(!smd->coll)
{
smokeModifier_createType(smd);
}
- if(!smd->coll->points)
- {
- // init collision points
- SmokeCollSettings *scs = smd->coll;
-
- smd->time = scene->r.cfra;
-
- // copy obmat
- copy_m4_m4(scs->mat, ob->obmat);
- copy_m4_m4(scs->mat_old, ob->obmat);
-
- DM_ensure_tessface(dm);
- fill_scs_points(ob, dm, scs);
- }
+ smd->time = scene->r.cfra;
- if(!smd->coll->bvhtree)
- {
- smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getTessFaceArray(dm), dm->getNumTessFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
- }
return 1;
}
return 2;
}
-static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
-{
- MVert *mvert = dm->getVertArray(dm);
- MFace *mface = dm->getTessFaceArray(dm);
- int i = 0, divs = 0;
-
- // DG TODO: need to do this dynamically according to the domain object!
- float cell_len = scs->dx;
- int newdivs = 0;
- int quads = 0, facecounter = 0;
-
- // count quads
- for(i = 0; i < dm->getNumTessFaces(dm); i++)
- {
- if(mface[i].v4)
- quads++;
- }
-
- scs->numtris = dm->getNumTessFaces(dm) + quads;
- scs->tridivs = NULL;
- calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumTessFaces(dm), scs->numtris, &(scs->tridivs), cell_len);
-
- // count triangle divisions
- for(i = 0; i < dm->getNumTessFaces(dm) + quads; i++)
- {
- divs += (scs->tridivs[3 * i] + 1) * (scs->tridivs[3 * i + 1] + 1) * (scs->tridivs[3 * i + 2] + 1);
- }
-
- scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints");
- scs->points_old = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPointsOld");
-
- for(i = 0; i < dm->getNumVerts(dm); i++)
- {
- float tmpvec[3];
- copy_v3_v3(tmpvec, mvert[i].co);
- // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
- copy_v3_v3(&scs->points[i * 3], tmpvec);
- }
-
- for(i = 0, facecounter = 0; i < dm->getNumTessFaces(dm); i++)
- {
- int again = 0;
- do
- {
- int j, k;
- int divs1 = scs->tridivs[3 * facecounter + 0];
- int divs2 = scs->tridivs[3 * facecounter + 1];
- //int divs3 = scs->tridivs[3 * facecounter + 2];
- float side1[3], side2[3], trinormorg[3], trinorm[3];
-
- if(again == 1 && mface[i].v4)
- {
- sub_v3_v3v3(side1, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
- sub_v3_v3v3(side2, mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co);
- }
- else {
- sub_v3_v3v3(side1, mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co);
- sub_v3_v3v3(side2, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
- }
-
- cross_v3_v3v3(trinormorg, side1, side2);
- normalize_v3(trinormorg);
- copy_v3_v3(trinorm, trinormorg);
- mul_v3_fl(trinorm, 0.25 * cell_len);
-
- for(j = 0; j <= divs1; j++)
- {
- for(k = 0; k <= divs2; k++)
- {
- float p1[3], p2[3], p3[3], p[3]={0,0,0};
- const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0);
- const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0);
- float tmpvec[3];
-
- if(uf+vf > 1.0)
- {
- // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2);
- continue;
- }
-
- copy_v3_v3(p1, mvert[ mface[i].v1 ].co);
- if(again == 1 && mface[i].v4)
- {
- copy_v3_v3(p2, mvert[ mface[i].v3 ].co);
- copy_v3_v3(p3, mvert[ mface[i].v4 ].co);
- }
- else {
- copy_v3_v3(p2, mvert[ mface[i].v2 ].co);
- copy_v3_v3(p3, mvert[ mface[i].v3 ].co);
- }
-
- mul_v3_fl(p1, (1.0-uf-vf));
- mul_v3_fl(p2, uf);
- mul_v3_fl(p3, vf);
-
- add_v3_v3v3(p, p1, p2);
- add_v3_v3(p, p3);
-
- if(newdivs > divs)
- printf("mem problem\n");
-
- // mMovPoints.push_back(p + trinorm);
- add_v3_v3v3(tmpvec, p, trinorm);
- // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
- copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
- newdivs++;
-
- if(newdivs > divs)
- printf("mem problem\n");
-
- // mMovPoints.push_back(p - trinorm);
- copy_v3_v3(tmpvec, p);
- sub_v3_v3(tmpvec, trinorm);
- // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
- copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
- newdivs++;
- }
- }
-
- if(again == 0 && mface[i].v4)
- again++;
- else
- again = 0;
-
- facecounter++;
-
- } while(again!=0);
- }
-
- scs->numverts = dm->getNumVerts(dm);
- // DG TODO: also save triangle count?
-
- scs->numpoints = dm->getNumVerts(dm) + newdivs;
-
- for(i = 0; i < scs->numpoints * 3; i++)
- {
- scs->points_old[i] = scs->points[i];
- }
-}
-
-
-static void fill_scs_points_anim(Object *UNUSED(ob), DerivedMesh *dm, SmokeCollSettings *scs)
-{
- MVert *mvert = dm->getVertArray(dm);
- MFace *mface = dm->getTessFaceArray(dm);
- int quads = 0, numtris = 0, facecounter = 0;
- unsigned int i = 0;
- int divs = 0, newdivs = 0;
-
- // DG TODO: need to do this dynamically according to the domain object!
- float cell_len = scs->dx;
-
- // count quads
- for(i = 0; i < dm->getNumTessFaces(dm); i++)
- {
- if(mface[i].v4)
- quads++;
- }
-
- numtris = dm->getNumTessFaces(dm) + quads;
-
- // check if mesh changed topology
- if(scs->numtris != numtris)
- return;
- if(scs->numverts != dm->getNumVerts(dm))
- return;
-
- // update new positions
- for(i = 0; i < dm->getNumVerts(dm); i++)
- {
- float tmpvec[3];
- copy_v3_v3(tmpvec, mvert[i].co);
- copy_v3_v3(&scs->points[i * 3], tmpvec);
- }
-
- // for every triangle // update div points
- for(i = 0, facecounter = 0; i < dm->getNumTessFaces(dm); i++)
- {
- int again = 0;
- do
- {
- int j, k;
- int divs1 = scs->tridivs[3 * facecounter + 0];
- int divs2 = scs->tridivs[3 * facecounter + 1];
- float srcside1[3], srcside2[3], destside1[3], destside2[3], src_trinormorg[3], dest_trinormorg[3], src_trinorm[3], dest_trinorm[3];
-
- if(again == 1 && mface[i].v4)
- {
- sub_v3_v3v3(srcside1, &scs->points_old[mface[i].v3 * 3], &scs->points_old[mface[i].v1 * 3]);
- sub_v3_v3v3(destside1, &scs->points[mface[i].v3 * 3], &scs->points[mface[i].v1 * 3]);
-
- sub_v3_v3v3(srcside2, &scs->points_old[mface[i].v4 * 3], &scs->points_old[mface[i].v1 * 3]);
- sub_v3_v3v3(destside2, &scs->points[mface[i].v4 * 3], &scs->points[mface[i].v1 * 3]);
- }
- else {
- sub_v3_v3v3(srcside1, &scs->points_old[mface[i].v2 * 3], &scs->points_old[mface[i].v1 * 3]);
- sub_v3_v3v3(destside1, &scs->points[mface[i].v2 * 3], &scs->points[mface[i].v1 * 3]);
-
- sub_v3_v3v3(srcside2, &scs->points_old[mface[i].v3 * 3], &scs->points_old[mface[i].v1 * 3]);
- sub_v3_v3v3(destside2, &scs->points[mface[i].v3 * 3], &scs->points[mface[i].v1 * 3]);
- }
-
- cross_v3_v3v3(src_trinormorg, srcside1, srcside2);
- cross_v3_v3v3(dest_trinormorg, destside1, destside2);
-
- normalize_v3(src_trinormorg);
- normalize_v3(dest_trinormorg);
-
- copy_v3_v3(src_trinorm, src_trinormorg);
- copy_v3_v3(dest_trinorm, dest_trinormorg);
-
- mul_v3_fl(src_trinorm, 0.25 * cell_len);
- mul_v3_fl(dest_trinorm, 0.25 * cell_len);
-
- for(j = 0; j <= divs1; j++)
- {
- for(k = 0; k <= divs2; k++)
- {
- float src_p1[3], src_p2[3], src_p3[3], src_p[3]={0,0,0};
- float dest_p1[3], dest_p2[3], dest_p3[3], dest_p[3]={0,0,0};
- const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0);
- const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0);
- float src_tmpvec[3], dest_tmpvec[3];
-
- if(uf+vf > 1.0)
- {
- // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2);
- continue;
- }
-
- copy_v3_v3(src_p1, &scs->points_old[mface[i].v1 * 3]);
- copy_v3_v3(dest_p1, &scs->points[mface[i].v1 * 3]);
- if(again == 1 && mface[i].v4)
- {
- copy_v3_v3(src_p2, &scs->points_old[mface[i].v3 * 3]);
- copy_v3_v3(dest_p2, &scs->points[mface[i].v3 * 3]);
-
- copy_v3_v3(src_p3,&scs->points_old[mface[i].v4 * 3]);
- copy_v3_v3(dest_p3, &scs->points[mface[i].v4 * 3]);
- }
- else {
- copy_v3_v3(src_p2, &scs->points_old[mface[i].v2 * 3]);
- copy_v3_v3(dest_p2, &scs->points[mface[i].v2 * 3]);
- copy_v3_v3(src_p3, &scs->points_old[mface[i].v3 * 3]);
- copy_v3_v3(dest_p3, &scs->points[mface[i].v3 * 3]);
- }
-
- mul_v3_fl(src_p1, (1.0-uf-vf));
- mul_v3_fl(dest_p1, (1.0-uf-vf));
-
- mul_v3_fl(src_p2, uf);
- mul_v3_fl(dest_p2, uf);
-
- mul_v3_fl(src_p3, vf);
- mul_v3_fl(dest_p3, vf);
-
- add_v3_v3v3(src_p, src_p1, src_p2);
- add_v3_v3v3(dest_p, dest_p1, dest_p2);
-
- add_v3_v3(src_p, src_p3);
- add_v3_v3(dest_p, dest_p3);
-
- if(newdivs > divs)
- printf("mem problem\n");
-
- // mMovPoints.push_back(p + trinorm);
- add_v3_v3v3(src_tmpvec, src_p, src_trinorm);
- add_v3_v3v3(dest_tmpvec, dest_p, dest_trinorm);
-
- // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
- copy_v3_v3(&scs->points_old[3 * (dm->getNumVerts(dm) + newdivs)], src_tmpvec);
- copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], dest_tmpvec);
- newdivs++;
-
- if(newdivs > divs)
- printf("mem problem\n");
-
- // mMovPoints.push_back(p - trinorm);
- copy_v3_v3(src_tmpvec, src_p);
- copy_v3_v3(dest_tmpvec, dest_p);
-
- sub_v3_v3(src_tmpvec, src_trinorm);
- sub_v3_v3(dest_tmpvec, dest_trinorm);
-
- // mul_m4_v3(ob->obmat, tmpvec); // DG: use local coordinates, we save MAT anyway
- copy_v3_v3(&scs->points_old[3 * (dm->getNumVerts(dm) + newdivs)], src_tmpvec);
- copy_v3_v3(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], dest_tmpvec);
- newdivs++;
- }
- }
-
- if(again == 0 && mface[i].v4)
- again++;
- else
- again = 0;
-
- facecounter++;
-
- } while(again!=0);
- }
-
- // scs->numpoints = dm->getNumVerts(dm) + newdivs;
-
-}
-
-/*! init triangle divisions */
-static void calcTriangleDivs(Object *ob, MVert *verts, int UNUSED(numverts), MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len)
-{
- // mTriangleDivs1.resize( faces.size() );
- // mTriangleDivs2.resize( faces.size() );
- // mTriangleDivs3.resize( faces.size() );
-
- size_t i = 0, facecounter = 0;
- float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale); get max scale value
- float maxpart = ABS(maxscale[0]);
- float scaleFac = 0;
- float fsTri = 0;
- if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
- if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
- scaleFac = 1.0 / maxpart;
- // featureSize = mLevel[mMaxRefine].nodeSize
- fsTri = cell_len * 0.75 * scaleFac; // fsTri = cell_len * 0.9;
-
- if(*tridivs)
- MEM_freeN(*tridivs);
-
- *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs");
-
- for(i = 0, facecounter = 0; i < numfaces; i++)
- {
- float p0[3], p1[3], p2[3];
- float side1[3];
- float side2[3];
- float side3[3];
- int divs1=0, divs2=0, divs3=0;
-
- copy_v3_v3(p0, verts[faces[i].v1].co);
- mul_m4_v3(ob->obmat, p0);
- copy_v3_v3(p1, verts[faces[i].v2].co);
- mul_m4_v3(ob->obmat, p1);
- copy_v3_v3(p2, verts[faces[i].v3].co);
- mul_m4_v3(ob->obmat, p2);
-
- sub_v3_v3v3(side1, p1, p0);
- sub_v3_v3v3(side2, p2, p0);
- sub_v3_v3v3(side3, p1, p2);
-
- if(dot_v3v3(side1, side1) > fsTri*fsTri)
- {
- float tmp = normalize_v3(side1);
- divs1 = (int)ceil(tmp/fsTri);
- }
- if(dot_v3v3(side2, side2) > fsTri*fsTri)
- {
- float tmp = normalize_v3(side2);
- divs2 = (int)ceil(tmp/fsTri);
-
- /*
- // debug
- if(i==0)
- printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2);
- */
-
- }
-
- (*tridivs)[3 * facecounter + 0] = divs1;
- (*tridivs)[3 * facecounter + 1] = divs2;
- (*tridivs)[3 * facecounter + 2] = divs3;
-
- // TODO quad case
- if(faces[i].v4)
- {
- divs1=0, divs2=0, divs3=0;
-
- facecounter++;
-
- copy_v3_v3(p0, verts[faces[i].v3].co);
- mul_m4_v3(ob->obmat, p0);
- copy_v3_v3(p1, verts[faces[i].v4].co);
- mul_m4_v3(ob->obmat, p1);
- copy_v3_v3(p2, verts[faces[i].v1].co);
- mul_m4_v3(ob->obmat, p2);
-
- sub_v3_v3v3(side1, p1, p0);
- sub_v3_v3v3(side2, p2, p0);
- sub_v3_v3v3(side3, p1, p2);
-
- if(dot_v3v3(side1, side1) > fsTri*fsTri)
- {
- float tmp = normalize_v3(side1);
- divs1 = (int)ceil(tmp/fsTri);
- }
- if(dot_v3v3(side2, side2) > fsTri*fsTri)
- {
- float tmp = normalize_v3(side2);
- divs2 = (int)ceil(tmp/fsTri);
- }
-
- (*tridivs)[3 * facecounter + 0] = divs1;
- (*tridivs)[3 * facecounter + 1] = divs2;
- (*tridivs)[3 * facecounter + 2] = divs3;
- }
- facecounter++;
- }
-}
-
#endif /* WITH_SMOKE */
static void smokeModifier_freeDomain(SmokeModifierData *smd)
@@ -750,14 +381,8 @@ static 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;
-*/
+ if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm);
+ if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old);
MEM_freeN(smd->flow);
smd->flow = NULL;
}
@@ -769,36 +394,18 @@ static void smokeModifier_freeCollision(SmokeModifierData *smd)
{
SmokeCollSettings *scs = smd->coll;
- if(scs->numpoints)
+ if(scs->numverts)
{
- if(scs->points)
- {
- MEM_freeN(scs->points);
- scs->points = NULL;
- }
- if(scs->points_old)
- {
- MEM_freeN(scs->points_old);
- scs->points_old = NULL;
- }
- if(scs->tridivs)
+ if(scs->verts_old)
{
- MEM_freeN(scs->tridivs);
- scs->tridivs = NULL;
+ MEM_freeN(scs->verts_old);
+ scs->verts_old = NULL;
}
}
- if(scs->bvhtree)
- {
- BLI_bvhtree_free(scs->bvhtree);
- scs->bvhtree = NULL;
- }
-
-#ifdef USE_SMOKE_COLLISION_DM
if(smd->coll->dm)
smd->coll->dm->release(smd->coll->dm);
smd->coll->dm = NULL;
-#endif
MEM_freeN(smd->coll);
smd->coll = NULL;
@@ -833,39 +440,23 @@ void smokeModifier_reset(struct SmokeModifierData *smd)
smokeModifier_reset_turbulence(smd);
smd->time = -1;
-
- // printf("reset domain end\n");
+ smd->domain->total_cells = 0;
+ smd->domain->active_fields = 0;
}
else if(smd->flow)
{
- /*
- if(smd->flow->bvh)
- {
- free_bvhtree_from_mesh(smd->flow->bvh);
- MEM_freeN(smd->flow->bvh);
- }
- smd->flow->bvh = NULL;
- */
+ if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old);
+ smd->flow->verts_old = NULL;
+ smd->flow->numverts = 0;
}
else if(smd->coll)
{
SmokeCollSettings *scs = smd->coll;
- if(scs->numpoints && scs->points)
+ if(scs->numverts && scs->verts_old)
{
- MEM_freeN(scs->points);
- scs->points = NULL;
-
- if(scs->points_old)
- {
- MEM_freeN(scs->points_old);
- scs->points_old = NULL;
- }
- if(scs->tridivs)
- {
- MEM_freeN(scs->tridivs);
- scs->tridivs = NULL;
- }
+ MEM_freeN(scs->verts_old);
+ scs->verts_old = NULL;
}
}
}
@@ -908,8 +499,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->fluid_group = NULL;
smd->domain->coll_group = NULL;
smd->domain->maxres = 32;
- smd->domain->amplify = 1;
- smd->domain->omega = 1.0;
+ smd->domain->amplify = 1;
smd->domain->alpha = -0.001;
smd->domain->beta = 0.1;
smd->domain->time_scale = 1.0;
@@ -919,7 +509,21 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->strength = 2.0;
smd->domain->noise = MOD_SMOKE_NOISEWAVE;
smd->domain->diss_speed = 5;
- // init 3dview buffer
+ smd->domain->active_fields = 0;
+
+ smd->domain->adapt_margin = 4;
+ smd->domain->adapt_res = 0;
+ smd->domain->adapt_threshold = 0.02f;
+
+ smd->domain->burning_rate = 0.75f;
+ smd->domain->flame_smoke = 1.0f;
+ smd->domain->flame_vorticity = 0.5f;
+ smd->domain->flame_ignition = 1.25f;
+ smd->domain->flame_max_temp = 1.75f;
+ /* color */
+ smd->domain->flame_smoke_color[0] = 0.7f;
+ smd->domain->flame_smoke_color[1] = 0.7f;
+ smd->domain->flame_smoke_color[2] = 0.7f;
smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG;
smd->domain->effector_weights = BKE_add_effector_weights(NULL);
@@ -934,11 +538,20 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->flow->smd = smd;
/* set some standard values */
- smd->flow->density = 1.0;
- smd->flow->temp = 1.0;
+ smd->flow->density = 1.0f;
+ smd->flow->fuel_amount = 1.0f;
+ smd->flow->temp = 1.0f;
smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE;
- smd->flow->vel_multi = 1.0;
+ smd->flow->vel_multi = 1.0f;
+ smd->flow->surface_distance = 1.5f;
+ smd->flow->source = MOD_SMOKE_FLOW_SOURCE_MESH;
+ smd->flow->texture_size = 1.0f;
+
+ smd->flow->color[0] = 0.7f;
+ smd->flow->color[1] = 0.7f;
+ smd->flow->color[2] = 0.7f;
+ smd->flow->dm = NULL;
smd->flow->psys = NULL;
}
@@ -950,15 +563,10 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
smd->coll->smd = smd;
- smd->coll->points = NULL;
- smd->coll->points_old = NULL;
- smd->coll->tridivs = NULL;
- smd->coll->vel = NULL;
- smd->coll->numpoints = 0;
- smd->coll->numtris = 0;
- smd->coll->bvhtree = NULL;
+ smd->coll->verts_old = NULL;
+ smd->coll->numverts = 0;
smd->coll->type = 0; // static obstacle
- smd->coll->dx = 1.0f / 50.0f;
+ smd->coll->dm = NULL;
#ifdef USE_SMOKE_COLLISION_DM
smd->coll->dm = NULL;
@@ -975,32 +583,61 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
smokeModifier_createType(tsmd);
if (tsmd->domain) {
- tsmd->domain->maxres = smd->domain->maxres;
- tsmd->domain->amplify = smd->domain->amplify;
- tsmd->domain->omega = smd->domain->omega;
+ tsmd->domain->fluid_group = smd->domain->fluid_group;
+ tsmd->domain->coll_group = smd->domain->coll_group;
+
+ tsmd->domain->adapt_margin = smd->domain->adapt_margin;
+ tsmd->domain->adapt_res = smd->domain->adapt_res;
+ tsmd->domain->adapt_threshold = smd->domain->adapt_threshold;
+
tsmd->domain->alpha = smd->domain->alpha;
tsmd->domain->beta = smd->domain->beta;
+ tsmd->domain->amplify = smd->domain->amplify;
+ tsmd->domain->maxres = smd->domain->maxres;
tsmd->domain->flags = smd->domain->flags;
- tsmd->domain->strength = smd->domain->strength;
+ tsmd->domain->viewsettings = smd->domain->viewsettings;
tsmd->domain->noise = smd->domain->noise;
tsmd->domain->diss_speed = smd->domain->diss_speed;
- tsmd->domain->viewsettings = smd->domain->viewsettings;
- tsmd->domain->fluid_group = smd->domain->fluid_group;
- tsmd->domain->coll_group = smd->domain->coll_group;
+ tsmd->domain->strength = smd->domain->strength;
+
+ tsmd->domain->border_collisions = smd->domain->border_collisions;
tsmd->domain->vorticity = smd->domain->vorticity;
tsmd->domain->time_scale = smd->domain->time_scale;
- tsmd->domain->border_collisions = smd->domain->border_collisions;
+
+ tsmd->domain->burning_rate = smd->domain->burning_rate;
+ tsmd->domain->flame_smoke = smd->domain->flame_smoke;
+ tsmd->domain->flame_vorticity = smd->domain->flame_vorticity;
+ tsmd->domain->flame_ignition = smd->domain->flame_ignition;
+ tsmd->domain->flame_max_temp = smd->domain->flame_max_temp;
+ copy_v3_v3(tsmd->domain->flame_smoke_color, smd->domain->flame_smoke_color);
MEM_freeN(tsmd->domain->effector_weights);
tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights);
}
else if (tsmd->flow) {
+ tsmd->flow->psys = smd->flow->psys;
+ tsmd->flow->noise_texture = smd->flow->noise_texture;
+
+ tsmd->flow->vel_multi = smd->flow->vel_multi;
+ tsmd->flow->vel_normal = smd->flow->vel_normal;
+ tsmd->flow->vel_random = smd->flow->vel_random;
+
tsmd->flow->density = smd->flow->density;
+ copy_v3_v3(tsmd->flow->color, smd->flow->color);
+ tsmd->flow->fuel_amount = smd->flow->fuel_amount;
tsmd->flow->temp = smd->flow->temp;
- tsmd->flow->psys = smd->flow->psys;
+ tsmd->flow->volume_density = smd->flow->volume_density;
+ tsmd->flow->surface_distance = smd->flow->surface_distance;
+
+ tsmd->flow->texture_size = smd->flow->texture_size;
+ tsmd->flow->texture_offset = smd->flow->texture_offset;
+ BLI_strncpy(tsmd->flow->uvlayer_name, tsmd->flow->uvlayer_name, sizeof(tsmd->flow->uvlayer_name));
+ tsmd->flow->vgroup_density = smd->flow->vgroup_density;
+
tsmd->flow->type = smd->flow->type;
+ tsmd->flow->source = smd->flow->source;
+ tsmd->flow->texture_type = smd->flow->texture_type;
tsmd->flow->flags = smd->flow->flags;
- tsmd->flow->vel_multi = smd->flow->vel_multi;
}
else if (tsmd->coll) {
;
@@ -1011,7 +648,7 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
#ifdef WITH_SMOKE
// forward decleration
-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);
+static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene);
static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
static int get_lamp(Scene *scene, float *light)
@@ -1038,44 +675,127 @@ static int get_lamp(Scene *scene, float *light)
return found_lamp;
}
-static void smoke_calc_domain(Scene *UNUSED(scene), Object *UNUSED(ob), SmokeModifierData *UNUSED(smd))
+static void obstacles_from_derivedmesh(Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs, unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, float dt)
{
-#if 0
- SmokeDomainSettings *sds = smd->domain;
- GroupObject *go = NULL;
- Base *base = NULL;
-
- /* do collisions, needs to be done before emission, so that smoke isn't emitted inside collision cells */
- if(1)
+ if (!scs->dm) return;
{
- unsigned int i;
- Object **collobjs = NULL;
- unsigned int numcollobj = 0;
- collobjs = get_collisionobjects(scene, ob, sds->coll_group, &numcollobj);
+ DerivedMesh *dm = NULL;
+ MVert *mvert = NULL;
+ MFace *mface = NULL;
+ BVHTreeFromMesh treeData = {0};
+ int numverts, i, z;
+ int *res = sds->res;
+
+ float surface_distance = 0.6;
+
+ float *vert_vel = NULL;
+ int has_velocity = 0;
+
+ tstart();
+
+ dm = CDDM_copy(scs->dm);
+ CDDM_calc_normals(dm);
+ mvert = dm->getVertArray(dm);
+ mface = dm->getTessFaceArray(dm);
+ numverts = dm->getNumVerts(dm);
+
+ // DG TODO
+ // if(scs->type > SM_COLL_STATIC)
+ // if line above is used, the code is in trouble if the object moves but is declared as "does not move"
- for(i = 0; i < numcollobj; i++)
{
- Object *collob= collobjs[i];
- SmokeModifierData *smd2 = (SmokeModifierData*)modifiers_findByType(collob, eModifierType_Smoke);
-
- // check for active smoke modifier
- // if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
- // SmokeModifierData *smd2 = (SmokeModifierData *)md;
+ vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_velocity");
+
+ if (scs->numverts != numverts || !scs->verts_old) {
+ if (scs->verts_old) MEM_freeN(scs->verts_old);
+
+ scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_verts_old");
+ scs->numverts = numverts;
+ }
+ else {
+ has_velocity = 1;
+ }
+ }
- if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points && smd2->coll->points_old)
+ /* Transform collider vertices to
+ * domain grid space for fast lookups */
+ for (i = 0; i < numverts; i++) {
+ float n[3];
+ float co[3];
+
+ /* vert pos */
+ mul_m4_v3(coll_ob->obmat, mvert[i].co);
+ smoke_pos_to_cell(sds, mvert[i].co);
+
+ /* vert normal */
+ normal_short_to_float_v3(n, mvert[i].no);
+ mul_mat3_m4_v3(coll_ob->obmat, n);
+ mul_mat3_m4_v3(sds->imat, n);
+ normalize_v3(n);
+ normal_float_to_short_v3(mvert[i].no, n);
+
+ /* vert velocity */
+ VECADD(co, mvert[i].co, sds->shift);
+ if (has_velocity)
{
- // ??? anything to do here?
+ sub_v3_v3v3(&vert_vel[i*3], co, &scs->verts_old[i*3]);
+ mul_v3_fl(&vert_vel[i*3], sds->dx/dt);
+ }
+ copy_v3_v3(&scs->verts_old[i*3], co);
+ }
+
+ if (bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 6)) {
+ #pragma omp parallel for schedule(static)
+ for (z = sds->res_min[2]; z < sds->res_max[2]; z++) {
+ int x,y;
+ for (x = sds->res_min[0]; x < sds->res_max[0]; x++)
+ for (y = sds->res_min[1]; y < sds->res_max[1]; y++) {
+ int index = smoke_get_index(x-sds->res_min[0], sds->res[0], y-sds->res_min[1], sds->res[1], z-sds->res_min[2]);
+
+ float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
+ BVHTreeNearest nearest = {0};
+ nearest.index = -1;
+ nearest.dist = surface_distance * surface_distance; /* find_nearest uses squared distance */
+
+ /* find the nearest point on the mesh */
+ if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, treeData.nearest_callback, &treeData) != -1) {
+ float weights[4];
+ int v1, v2, v3, f_index = nearest.index;
+
+ /* calculate barycentric weights for nearest point */
+ v1 = mface[f_index].v1;
+ v2 = (nearest.flags & BVH_ONQUAD) ? mface[f_index].v3 : mface[f_index].v2;
+ v3 = (nearest.flags & BVH_ONQUAD) ? mface[f_index].v4 : mface[f_index].v3;
+ interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, nearest.co);
+
+ // DG TODO
+ if(has_velocity)
+ {
+ /* apply object velocity */
+ {
+ float hit_vel[3];
+ interp_v3_v3v3v3(hit_vel, &vert_vel[v1*3], &vert_vel[v2*3], &vert_vel[v3*3], weights);
+ velocityX[index] += hit_vel[0];
+ velocityY[index] += hit_vel[1];
+ velocityZ[index] += hit_vel[2];
+ }
+ }
- // TODO: only something to do for ANIMATED obstacles: need to update positions
+ /* tag obstacle cells */
+ obstacle_map[index] = 1;
+ if(has_velocity)
+ obstacle_map[index] |= 8;
+ }
+ }
}
}
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+ dm->release(dm);
- if(collobjs)
- MEM_freeN(collobjs);
+ if (vert_vel) MEM_freeN(vert_vel);
}
-
-#endif
}
/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */
@@ -1092,7 +812,12 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
float *velxOrig = smoke_get_velocity_x(sds->fluid);
float *velyOrig = smoke_get_velocity_y(sds->fluid);
float *velzOrig = smoke_get_velocity_z(sds->fluid);
- // float *density = smoke_get_density(sds->fluid);
+ float *density = smoke_get_density(sds->fluid);
+ float *fuel = smoke_get_fuel(sds->fluid);
+ float *flame = smoke_get_flame(sds->fluid);
+ float *r = smoke_get_color_r(sds->fluid);
+ float *g = smoke_get_color_g(sds->fluid);
+ float *b = smoke_get_color_b(sds->fluid);
unsigned int z;
smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
@@ -1100,15 +825,6 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
// TODO: delete old obstacle flags
for(z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
{
- if(obstacles[z])
- {
- // density[z] = 0;
-
- velxOrig[z] = 0;
- velyOrig[z] = 0;
- velzOrig[z] = 0;
- }
-
if(obstacles[z] & 8) // Do not delete static obstacles
{
obstacles[z] = 0;
@@ -1119,6 +835,7 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
velz[z] = 0;
}
+
collobjs = get_collisionobjects(scene, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
// update obstacle tags in cells
@@ -1129,105 +846,799 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
// DG TODO: check if modifier is active?
- if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points && smd2->coll->points_old)
+ if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
{
SmokeCollSettings *scs = smd2->coll;
- unsigned int i;
+ obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, dt);
+ }
+ }
+
+ if(collobjs)
+ MEM_freeN(collobjs);
+
+ /* obstacle cells should not contain any velocity from the smoke simulation */
+ for(z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
+ {
+ if(obstacles[z])
+ {
+ velxOrig[z] = 0;
+ velyOrig[z] = 0;
+ velzOrig[z] = 0;
+ density[z] = 0;
+ if (fuel) {
+ fuel[z] = 0;
+ flame[z] = 0;
+ }
+ if (r) {
+ r[z] = 0;
+ g[z] = 0;
+ b[z] = 0;
+ }
+ }
+ }
+}
+
- /*
- // DG TODO: support static cobstacles, but basicly we could even support static + rigid with one set of code
- if(scs->type > SM_COLL_STATIC)
- */
+typedef struct EmissionMap {
+ float *influence;
+ float *velocity;
+ int min[3], max[3], res[3];
+ int total_cells, valid;
+} EmissionMap;
- /* Handle collisions */
- for(i = 0; i < scs->numpoints; i++)
+static void em_boundInsert(EmissionMap *em, float point[3])
+{
+ int i = 0;
+ if (!em->valid) {
+ VECCOPY(em->min, point);
+ VECCOPY(em->max, point);
+ em->valid = 1;
+ }
+ else {
+ for (; i < 3; i++) {
+ if (point[i] < em->min[i]) em->min[i] = (int)floor(point[i]);
+ if (point[i] > em->max[i]) em->max[i] = (int)ceil(point[i]);
+ }
+ }
+}
+
+static void clampBoundsInDomain(SmokeDomainSettings *sds, int min[3], int max[3], float *min_vel, float *max_vel, int margin, float dt)
+{
+ int i;
+ for (i=0; i<3; i++) {
+ int adapt = (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) ? sds->adapt_res : 0;
+ /* add margin */
+ min[i] -= margin;
+ max[i] += margin;
+
+ /* adapt to velocity */
+ if (min_vel && min_vel[i]<0.0f) {
+ min[i] += (int)ceil(min_vel[i] * dt);
+ }
+ if (max_vel && max_vel[i]>0.0f) {
+ max[i] += (int)ceil(max_vel[i] * dt);
+ }
+
+ /* clamp within domain max size */
+ CLAMP(min[i], -adapt, sds->base_res[i]+adapt);
+ CLAMP(max[i], -adapt, sds->base_res[i]+adapt);
+ }
+}
+
+static void em_allocateData(EmissionMap *em, int use_velocity) {
+ int i, res[3];
+
+ for (i=0; i<3; i++) {
+ res[i] = em->max[i] - em->min[i];
+ if (res[i] <= 0)
+ return;
+ }
+ em->total_cells = res[0]*res[1]*res[2];
+ copy_v3_v3_int(em->res, res);
+
+
+ em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence");
+ if (use_velocity)
+ em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity");
+}
+
+static void em_freeData(EmissionMap *em) {
+ if (em->influence)
+ MEM_freeN(em->influence);
+ if (em->velocity)
+ MEM_freeN(em->velocity);
+}
+
+
+static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Scene *scene, float time, float dt)
+{
+ if(sfs && sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
+ {
+ ParticleSimulationData sim;
+ ParticleSystem *psys = sfs->psys;
+ float *particle_pos;
+ float *particle_vel;
+ int totpart=psys->totpart, totchild;
+ int p = 0;
+ int valid_particles = 0;
+
+ sim.scene = scene;
+ sim.ob = flow_ob;
+ sim.psys = psys;
+
+ if(psys->part->type==PART_HAIR)
+ {
+ // TODO: PART_HAIR not supported whatsoever
+ totchild=0;
+ }
+ else
+ totchild=psys->totchild*psys->part->disp/100;
+
+ particle_pos = MEM_callocN(sizeof(float) * (totpart+totchild) * 3, "smoke_flow_particles");
+ particle_vel = MEM_callocN(sizeof(float) * (totpart+totchild) * 3, "smoke_flow_particles");
+
+ /* calculate local position for each particle */
+ for(p=0; p<totpart+totchild; p++)
+ {
+ ParticleKey state;
+ float *pos;
+ if(p < totpart) {
+ if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
+ continue;
+ }
+ else {
+ /* handle child particle */
+ ChildParticle *cpa = &psys->child[p - totpart];
+ if(psys->particles[cpa->parent].flag & (PARS_NO_DISP|PARS_UNEXIST))
+ continue;
+ }
+
+ state.time = time;
+ if(psys_get_particle_state(&sim, p, &state, 0) == 0)
+ continue;
+
+ /* location */
+ pos = &particle_pos[valid_particles*3];
+ copy_v3_v3(pos, state.co);
+ smoke_pos_to_cell(sds, pos);
+
+ /* velocity */
+ copy_v3_v3(&particle_vel[valid_particles*3], state.vel);
+ mul_mat3_m4_v3(sds->imat, &particle_vel[valid_particles*3]);
+
+ /* calculate emission map bounds */
+ em_boundInsert(em, pos);
+ valid_particles++;
+ }
+
+ /* set emission map */
+ clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, 1, dt);
+ em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY);
+
+ for(p=0; p<valid_particles; p++)
+ {
+ int cell[3];
+ size_t i = 0;
+ size_t index = 0;
+ int badcell = 0;
+
+ /* 1. get corresponding cell */
+ cell[0] = floor(particle_pos[p*3]) - em->min[0];
+ cell[1] = floor(particle_pos[p*3+1]) - em->min[1];
+ cell[2] = floor(particle_pos[p*3+2]) - em->min[2];
+ /* check if cell is valid (in the domain boundary) */
+ for(i = 0; i < 3; i++) {
+ if((cell[i] > em->res[i] - 1) || (cell[i] < 0)) {
+ badcell = 1;
+ break;
+ }
+ }
+ if(badcell)
+ continue;
+ /* get cell index */
+ index = smoke_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]);
+ /* Add influence to emission map */
+ em->influence[index] = 1.0f;
+ /* Uses particle velocity as initial velocity for smoke */
+ if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO))
{
- // 1. get corresponding cell
- int cell[3];
- float pos[3], oldpos[3], vel[3];
- float cPos[3], cOldpos[3]; /* current position in substeps */
- int badcell = 0;
- size_t index;
- int j;
-
- // translate local points into global positions
- copy_v3_v3(cPos, &scs->points[3 * i]);
- mul_m4_v3(scs->mat, cPos);
- copy_v3_v3(pos, cPos);
-
- copy_v3_v3(cOldpos, &scs->points_old[3 * i]);
- mul_m4_v3(scs->mat_old, cOldpos);
- copy_v3_v3(oldpos, cOldpos);
-
- /* support for rigid bodies, armatures etc */
- {
- float tmp[3];
+ VECADDFAC(&em->velocity[index*3], &em->velocity[index*3], &particle_vel[p*3], sfs->vel_multi);
+ }
+ } // particles loop
+
+ /* free data */
+ if (particle_pos)
+ MEM_freeN(particle_pos);
+ if (particle_vel)
+ MEM_freeN(particle_vel);
+ }
+}
+
+static void get_texture_value(Tex *texture, float *tex_co, TexResult *texres)
+{
+ int result_type;
+
+ /* no node textures for now */
+ result_type = multitex_ext_safe(texture, tex_co, texres);
+
+ /* if the texture gave an RGB value, we assume it didn't give a valid
+ * intensity, since this is in the context of modifiers don't use perceptual color conversion.
+ * if the texture didn't give an RGB value, copy the intensity across
+ */
+ if (result_type & TEX_RGB) {
+ texres->tin = (1.0f / 3.0f) * (texres->tr + texres->tg + texres->tb);
+ }
+ else {
+ copy_v3_fl(&texres->tr, texres->tin);
+ }
+}
- /* x_current = x_old + (x_new - x_old) * step_current / steps_total */
- float mulStep = (float)(((float)substep) / ((float)totalsteps));
+static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
+{
+ if (!sfs->dm) return;
+ {
+ DerivedMesh *dm = sfs->dm;
+ int defgrp_index = sfs->vgroup_density-1;
+ MDeformVert *dvert = NULL;
+ MVert *mvert = NULL;
+ MVert *mvert_orig = NULL;
+ MFace *mface = NULL;
+ MTFace *tface = NULL;
+ BVHTreeFromMesh treeData = {0};
+ int numOfVerts, i, z;
+ float flow_center[3] = {0};
+
+ float *vert_vel = NULL;
+ int has_velocity = 0;
+
+ CDDM_calc_normals(dm);
+ mvert = dm->getVertArray(dm);
+ mvert_orig = dm->dupVertArray(dm); /* copy original mvert and restore when done */
+ mface = dm->getTessFaceArray(dm);
+ numOfVerts = dm->getNumVerts(dm);
+ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, sfs->uvlayer_name);
+
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+ vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity");
+
+ if (sfs->numverts != numOfVerts || !sfs->verts_old) {
+ if (sfs->verts_old) MEM_freeN(sfs->verts_old);
+ sfs->verts_old = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_verts_old");
+ sfs->numverts = numOfVerts;
+ }
+ else {
+ has_velocity = 1;
+ }
+ }
- sub_v3_v3v3(tmp, cPos, cOldpos);
- mul_v3_fl(tmp, mulStep);
- add_v3_v3(cOldpos, tmp);
+ /* Transform dm vertices to
+ * domain grid space for fast lookups */
+ for (i = 0; i < numOfVerts; i++) {
+ float n[3];
+ /* vert pos */
+ mul_m4_v3(flow_ob->obmat, mvert[i].co);
+ smoke_pos_to_cell(sds, mvert[i].co);
+ /* vert normal */
+ normal_short_to_float_v3(n, mvert[i].no);
+ mul_mat3_m4_v3(flow_ob->obmat, n);
+ mul_mat3_m4_v3(sds->imat, n);
+ normalize_v3(n);
+ normal_float_to_short_v3(mvert[i].no, n);
+ /* vert velocity */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+ float co[3];
+ VECADD(co, mvert[i].co, sds->shift);
+ if (has_velocity) {
+ sub_v3_v3v3(&vert_vel[i*3], co, &sfs->verts_old[i*3]);
+ mul_v3_fl(&vert_vel[i*3], sds->dx/dt);
}
+ copy_v3_v3(&sfs->verts_old[i*3], co);
+ }
- sub_v3_v3v3(vel, pos, oldpos);
- /* Scale velocity to incorperate the object movement during this step */
- mul_v3_fl(vel, 1.0 / (totalsteps * dt * sds->scale));
- // mul_v3_fl(vel, 1.0 / dt);
+ /* calculate emission map bounds */
+ em_boundInsert(em, mvert[i].co);
+ }
+ mul_m4_v3(flow_ob->obmat, flow_center);
+ smoke_pos_to_cell(sds, flow_center);
+
+ /* set emission map */
+ clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, sfs->surface_distance, dt);
+ em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY);
+
+ if (bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 6)) {
+ #pragma omp parallel for schedule(static)
+ for (z = em->min[2]; z < em->max[2]; z++) {
+ int x,y;
+ for (x = em->min[0]; x < em->max[0]; x++)
+ for (y = em->min[1]; y < em->max[1]; y++) {
+ int index = smoke_get_index(x-em->min[0], em->res[0], y-em->min[1], em->res[1], z-em->min[2]);
+
+ float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
+ float ray_dir[3] = {1.0f, 0.0f, 0.0f};
+
+ BVHTreeRayHit hit = {0};
+ BVHTreeNearest nearest = {0};
+
+ float volume_factor = 0.0f;
+ float sample_str = 0.0f;
+
+ hit.index = -1;
+ hit.dist = 9999;
+ nearest.index = -1;
+ nearest.dist = sfs->surface_distance * sfs->surface_distance; /* find_nearest uses squared distance */
+
+ /* Check volume collision */
+ if (sfs->volume_density) {
+ if (BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) {
+ float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
+ /* If ray and hit face normal are facing same direction
+ * hit point is inside a closed mesh. */
+ if (dot >= 0) {
+ /* Also cast a ray in opposite direction to make sure
+ * point is at least surrounded by two faces */
+ negate_v3(ray_dir);
+ hit.index = -1;
+ hit.dist = 9999;
+
+ BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, treeData.raycast_callback, &treeData);
+ if (hit.index != -1) {
+ volume_factor = sfs->volume_density;
+ nearest.dist = hit.dist*hit.dist;
+ }
+ }
+ }
+ }
- // DG TODO: cap velocity to maxVelMag (or maxvel)
+ /* find the nearest point on the mesh */
+ if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, treeData.nearest_callback, &treeData) != -1) {
+ float weights[4];
+ int v1, v2, v3, f_index = nearest.index;
+ float n1[3], n2[3], n3[3], hit_normal[3];
+
+ /* emit from surface based on distance */
+ if (sfs->surface_distance) {
+ sample_str = sqrtf(nearest.dist) / sfs->surface_distance;
+ CLAMP(sample_str, 0.0f, 1.0f);
+ sample_str = pow(1.0f - sample_str, 0.5f);
+ }
+ else
+ sample_str = 0.0f;
+
+ /* calculate barycentric weights for nearest point */
+ v1 = mface[f_index].v1;
+ v2 = (nearest.flags & BVH_ONQUAD) ? mface[f_index].v3 : mface[f_index].v2;
+ v3 = (nearest.flags & BVH_ONQUAD) ? mface[f_index].v4 : mface[f_index].v3;
+ interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, nearest.co);
+
+ if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+ /* apply normal directional velocity */
+ if (sfs->vel_normal) {
+ /* interpolate vertex normal vectors to get nearest point normal */
+ normal_short_to_float_v3(n1, mvert[v1].no);
+ normal_short_to_float_v3(n2, mvert[v2].no);
+ normal_short_to_float_v3(n3, mvert[v3].no);
+ interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
+ normalize_v3(hit_normal);
+ /* apply normal directional and random velocity
+ * - TODO: random disabled for now since it doesnt really work well as pressure calc smoothens it out... */
+ em->velocity[index*3] += hit_normal[0]*sfs->vel_normal * 0.25f;
+ em->velocity[index*3+1] += hit_normal[1]*sfs->vel_normal * 0.25f;
+ em->velocity[index*3+2] += hit_normal[2]*sfs->vel_normal * 0.25f;
+ /* TODO: for fire emitted from mesh surface we can use
+ * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */
+ }
+ /* apply object velocity */
+ if (has_velocity && sfs->vel_multi) {
+ float hit_vel[3];
+ interp_v3_v3v3v3(hit_vel, &vert_vel[v1*3], &vert_vel[v2*3], &vert_vel[v3*3], weights);
+ em->velocity[index*3] += hit_vel[0] * sfs->vel_multi;
+ em->velocity[index*3+1] += hit_vel[1] * sfs->vel_multi;
+ em->velocity[index*3+2] += hit_vel[2] * sfs->vel_multi;
+ }
+ }
- // oldpos + velocity * dt = newpos
- get_cell(sds->p0, sds->res, sds->dx*sds->scale, cOldpos /* use current position here instead of "pos" */, cell, 0);
+ /* apply vertex group influence if used */
+ if (defgrp_index >= 0 && dvert) {
+ float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
+ defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
+ defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
+ sample_str *= weight_mask;
+ }
- // 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;
+ /* apply emission texture */
+ if ((sfs->flags & MOD_SMOKE_FLOW_TEXTUREEMIT) && sfs->noise_texture) {
+ float tex_co[3] = {0};
+ TexResult texres;
+
+ if (sfs->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO) {
+ tex_co[0] = ((float)(x - flow_center[0]) / sds->base_res[0]) / sfs->texture_size;
+ tex_co[1] = ((float)(y - flow_center[1]) / sds->base_res[1]) / sfs->texture_size;
+ tex_co[2] = ((float)(z - flow_center[2]) / sds->base_res[2] - sfs->texture_offset) / sfs->texture_size;
+ }
+ else if (tface) {
+ interp_v2_v2v2v2(tex_co, tface[f_index].uv[0], tface[f_index].uv[(nearest.flags & BVH_ONQUAD) ? 2 : 1],
+ tface[f_index].uv[(nearest.flags & BVH_ONQUAD) ? 3 : 2], weights);
+ /* map between -1.0f and 1.0f */
+ tex_co[0] = tex_co[0] * 2.0f - 1.0f;
+ tex_co[1] = tex_co[1] * 2.0f - 1.0f;
+ tex_co[2] = sfs->texture_offset;
+ }
+ texres.nor = NULL;
+ get_texture_value(sfs->noise_texture, tex_co, &texres);
+ sample_str *= texres.tin;
+ }
}
-
- 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]);
+ /* multiply initial velocity by emitter influence */
+ if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+ mul_v3_fl(&em->velocity[index*3], sample_str);
+ }
- // Don't overwrite existing obstacles
- if(obstacles[index])
- continue;
-
- // 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 | 8 /* ANIMATED */;
+ /* apply final influence based on volume factor */
+ em->influence[index] = MAX2(volume_factor, sample_str);
+ }
+ }
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+ /* restore original mverts */
+ CustomData_set_layer(&dm->vertData, CD_MVERT, mvert_orig);
+ if (mvert)
+ MEM_freeN(mvert);
+
+ if (vert_vel) MEM_freeN(vert_vel);
+ }
+}
- if(len_v3(vel) > FLT_EPSILON)
- {
- // Collision object is moving
+static void adjustDomainResolution(SmokeDomainSettings *sds, int new_shift[3], EmissionMap *emaps, unsigned int numflowobj, float dt)
+{
+ int min[3]={32767,32767,32767}, max[3]={-32767,-32767,-32767}, res[3];
+ int total_cells = 1, res_changed = 0, shift_changed = 0;
+ float min_vel[3], max_vel[3];
+ int x,y,z, i;
+ float *density = smoke_get_density(sds->fluid);
+ float *fuel = smoke_get_fuel(sds->fluid);
+ float *vx = smoke_get_velocity_x(sds->fluid);
+ float *vy = smoke_get_velocity_y(sds->fluid);
+ float *vz = smoke_get_velocity_z(sds->fluid);
+
+ INIT_MINMAX(min_vel, max_vel);
+
+ /* Calculate bounds for current domain content */
+ for(x = sds->res_min[0]; x < sds->res_max[0]; x++)
+ for(y = sds->res_min[1]; y < sds->res_max[1]; y++)
+ for(z = sds->res_min[2]; z < sds->res_max[2]; z++)
+ {
+ int xn = x-new_shift[0];
+ int yn = y-new_shift[1];
+ int zn = z-new_shift[2];
+ int index = smoke_get_index(x-sds->res_min[0], sds->res[0], y-sds->res_min[1], sds->res[1], z-sds->res_min[2]);
+ float max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
+
+ /* content bounds (use shifted coordinates) */
+ if (max_den >= sds->adapt_threshold) {
+ if (min[0] > xn) min[0] = xn;
+ if (min[1] > yn) min[1] = yn;
+ if (min[2] > zn) min[2] = zn;
+ if (max[0] < xn) max[0] = xn;
+ if (max[1] < yn) max[1] = yn;
+ if (max[2] < zn) max[2] = zn;
+ }
+ /* velocity bounds */
+ if (min_vel[0] > vx[index]) min_vel[0] = vx[index];
+ if (min_vel[1] > vy[index]) min_vel[1] = vy[index];
+ if (min_vel[2] > vz[index]) min_vel[2] = vz[index];
+ if (max_vel[0] < vx[index]) max_vel[0] = vx[index];
+ if (max_vel[1] < vy[index]) max_vel[1] = vy[index];
+ if (max_vel[2] < vz[index]) max_vel[2] = vz[index];
+ }
- velx[index] = vel[0]; // use "+="?
- vely[index] = vel[1];
- velz[index] = vel[2];
+ /* also apply emission maps */
+ for(i = 0; i < numflowobj; i++)
+ {
+ EmissionMap *em = &emaps[i];
+
+ for(x = em->min[0]; x < em->max[0]; x++)
+ for(y = em->min[1]; y < em->max[1]; y++)
+ for(z = em->min[2]; z < em->max[2]; z++)
+ {
+ int index = smoke_get_index(x-em->min[0], em->res[0], y-em->min[1], em->res[1], z-em->min[2]);
+ float max_den = em->influence[index];
+
+ /* density bounds */
+ if (max_den >= sds->adapt_threshold) {
+ if (min[0] > x) min[0] = x;
+ if (min[1] > y) min[1] = y;
+ if (min[2] > z) min[2] = z;
+ if (max[0] < x) max[0] = x;
+ if (max[1] < y) max[1] = y;
+ if (max[2] < z) max[2] = z;
+ }
+ /* velocity bounds */
+ if (em->velocity) {
+ if (min_vel[0] > em->velocity[index*3]) min_vel[0] = em->velocity[index*3];
+ if (min_vel[1] > em->velocity[index*3+1]) min_vel[1] = em->velocity[index*3+1];
+ if (min_vel[2] > em->velocity[index*3+2]) min_vel[2] = em->velocity[index*3+2];
+ if (max_vel[0] < em->velocity[index*3]) max_vel[0] = em->velocity[index*3];
+ if (max_vel[1] < em->velocity[index*3+1]) max_vel[1] = em->velocity[index*3+1];
+ if (max_vel[2] < em->velocity[index*3+2]) max_vel[2] = em->velocity[index*3+2];
+ }
}
+ }
+
+ /* calculate new bounds based on these values */
+ clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin+1, dt);
+
+ for (i=0; i<3; i++) {
+ /* calculate new resolution */
+ res[i] = max[i] - min[i];
+ total_cells *= res[i];
+
+ if (new_shift[i])
+ shift_changed = 1;
+
+ /* if no content set minimum dimensions */
+ if (res[i] <= 0) {
+ int j;
+ for (j=0; j<3; j++) {
+ min[j] = 0;
+ max[j] = 1;
+ res[j] = 1;
}
+ res_changed = 1;
+ total_cells = 1;
+ break;
}
+ if (min[i] != sds->res_min[i] || max[i] != sds->res_max[i])
+ res_changed = 1;
}
- if(collobjs)
- MEM_freeN(collobjs);
+ if (res_changed || shift_changed) {
+ struct FLUID_3D *fluid_old = sds->fluid;
+ struct WTURBULENCE *turb_old = sds->wt;
+ /* allocate new fluid data */
+ smoke_reallocate_fluid(sds, sds->dx, res, 0);
+ if(sds->flags & MOD_SMOKE_HIGHRES) {
+ smoke_reallocate_highres_fluid(sds, sds->dx, res, 0);
+ }
+
+ /* copy values from old fluid to new */
+ if (sds->total_cells>1 && total_cells>1) {
+ /* low res smoke */
+ float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_heatold, *o_vx, *o_vy, *o_vz, *o_r, *o_g, *o_b;
+ float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_heatold, *n_vx, *n_vy, *n_vz, *n_r, *n_g, *n_b;
+ float dummy;
+ unsigned char *dummy_p;
+ /* high res smoke */
+ int wt_res_old[3];
+ float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw, *o_wt_r, *o_wt_g, *o_wt_b;
+ float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw, *n_wt_r, *n_wt_g, *n_wt_b;
+
+ smoke_export(fluid_old, &dummy, &dummy, &o_dens, &o_react, &o_flame, &o_fuel, &o_heat, &o_heatold, &o_vx, &o_vy, &o_vz, &o_r, &o_g, &o_b, &dummy_p);
+ smoke_export(sds->fluid, &dummy, &dummy, &n_dens, &n_react, &n_flame, &n_fuel, &n_heat, &n_heatold, &n_vx, &n_vy, &n_vz, &n_r, &n_g, &n_b, &dummy_p);
+
+ if(sds->flags & MOD_SMOKE_HIGHRES) {
+ smoke_turbulence_export(turb_old, &o_wt_dens, &o_wt_react, &o_wt_flame, &o_wt_fuel, &o_wt_r, &o_wt_g, &o_wt_b, &o_wt_tcu, &o_wt_tcv, &o_wt_tcw);
+ smoke_turbulence_get_res(turb_old, wt_res_old);
+ smoke_turbulence_export(sds->wt, &n_wt_dens, &n_wt_react, &n_wt_flame, &n_wt_fuel, &n_wt_r, &n_wt_g, &n_wt_b, &n_wt_tcu, &n_wt_tcv, &n_wt_tcw);
+ }
+
+
+ for(x = sds->res_min[0]; x < sds->res_max[0]; x++)
+ for(y = sds->res_min[1]; y < sds->res_max[1]; y++)
+ for(z = sds->res_min[2]; z < sds->res_max[2]; z++)
+ {
+ /* old grid index */
+ int xo = x-sds->res_min[0];
+ int yo = y-sds->res_min[1];
+ int zo = z-sds->res_min[2];
+ int index_old = smoke_get_index(xo, sds->res[0], yo, sds->res[1], zo);
+ /* new grid index */
+ int xn = x-min[0]-new_shift[0];
+ int yn = y-min[1]-new_shift[1];
+ int zn = z-min[2]-new_shift[2];
+ int index_new = smoke_get_index(xn, res[0], yn, res[1], zn);
+
+ /* skip if outside new domain */
+ if (xn<0 || xn>=res[0] ||
+ yn<0 || yn>=res[1] ||
+ zn<0 || zn>=res[2])
+ continue;
+
+ /* copy data */
+ n_dens[index_new] = o_dens[index_old];
+ /* heat */
+ if (n_heat && o_heat) {
+ n_heat[index_new] = o_heat[index_old];
+ n_heatold[index_new] = o_heatold[index_old];
+ }
+ /* fuel */
+ if (n_fuel && o_fuel) {
+ n_flame[index_new] = o_flame[index_old];
+ n_fuel[index_new] = o_fuel[index_old];
+ n_react[index_new] = o_react[index_old];
+ }
+ /* color */
+ if (o_r && n_r) {
+ n_r[index_new] = o_r[index_old];
+ n_g[index_new] = o_g[index_old];
+ n_b[index_new] = o_b[index_old];
+ }
+ n_vx[index_new] = o_vx[index_old];
+ n_vy[index_new] = o_vy[index_old];
+ n_vz[index_new] = o_vz[index_old];
+
+ if(sds->flags & MOD_SMOKE_HIGHRES && turb_old) {
+ int block_size = sds->amplify + 1;
+ int i,j,k;
+ /* old grid index */
+ int xx_o = xo*block_size;
+ int yy_o = yo*block_size;
+ int zz_o = zo*block_size;
+ /* new grid index */
+ int xx_n = xn*block_size;
+ int yy_n = yn*block_size;
+ int zz_n = zn*block_size;
+
+ n_wt_tcu[index_new] = o_wt_tcu[index_old];
+ n_wt_tcv[index_new] = o_wt_tcv[index_old];
+ n_wt_tcw[index_new] = o_wt_tcw[index_old];
+
+ for(i = 0; i < block_size; i++)
+ for(j = 0; j < block_size; j++)
+ for(k = 0; k < block_size; k++)
+ {
+ int big_index_old = smoke_get_index(xx_o+i, wt_res_old[0], yy_o+j, wt_res_old[1], zz_o+k);
+ int big_index_new = smoke_get_index(xx_n+i, sds->res_wt[0], yy_n+j, sds->res_wt[1], zz_n+k);
+ /* copy data */
+ n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
+ if (n_wt_flame && o_wt_flame) {
+ n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
+ n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
+ n_wt_react[big_index_new] = o_wt_react[big_index_old];
+ }
+ if (n_wt_r && o_wt_r) {
+ n_wt_r[big_index_new] = o_wt_r[big_index_old];
+ n_wt_g[big_index_new] = o_wt_g[big_index_old];
+ n_wt_b[big_index_new] = o_wt_b[big_index_old];
+ }
+ }
+ }
+ }
+ }
+ smoke_free(fluid_old);
+ if (turb_old)
+ smoke_turbulence_free(turb_old);
+
+ /* set new domain dimensions */
+ VECCOPY(sds->res_min, min);
+ VECCOPY(sds->res_max, max);
+ VECCOPY(sds->res, res);
+ sds->total_cells = total_cells;
+ }
+}
+
+BLI_INLINE void apply_outflow_fields(int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b)
+{
+ density[index] = 0.f;
+ if (heat) {
+ heat[index] = 0.f;
+ }
+ if (fuel) {
+ fuel[index] = 0.f;
+ react[index] = 0.f;
+ }
+ if (color_r) {
+ color_r[index] = 0.f;
+ color_g[index] = 0.f;
+ color_b[index] = 0.f;
+ }
+}
+
+BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value, int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b)
+{
+ int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
+ float dens_old = density[index];
+ float fuel_old = (fuel) ? fuel[index] : 0.0f;
+ float dens_flow = (sfs->type == MOD_SMOKE_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density;
+ float fuel_flow = emission_value * sfs->fuel_amount;
+ /* add heat */
+ if (heat) {
+ heat[index] = MAX2(emission_value*sfs->temp, heat[index]);
+ }
+ /* absolute */
+ if (absolute_flow) {
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
+ if (dens_flow > density[index])
+ density[index] = dens_flow;
+ }
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && fuel_flow) {
+ if (fuel_flow > fuel[index])
+ fuel[index] = fuel_flow;
+ }
+ }
+ /* additive */
+ else {
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
+ density[index] += dens_flow;
+ CLAMP(density[index], 0.0f, 1.0f);
+ }
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && sfs->fuel_amount) {
+ fuel[index] += fuel_flow;
+ CLAMP(fuel[index], 0.0f, 10.0f);
+ }
+ }
+
+ /* set color */
+ if (color_r && dens_flow) {
+ float total_dens = density[index]/(dens_old+dens_flow);
+ color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens;
+ color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens;
+ color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens;
+ }
+
+ /* set fire reaction coordinate */
+ if (fuel && fuel[index]) {
+ /* instead of using 1.0 for all new fuel add slight falloff
+ * to reduce flow blockiness */
+ float value = 1.0f - pow(1.0f - emission_value, 2.0f);
+
+ if (value > react[index]) {
+ float f = fuel_flow / fuel[index];
+ react[index] = value*f + (1.0f - f)*react[index];
+ }
+ }
}
-static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sds, float time)
+static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sds, float time, float dt)
{
Object **flowobjs = NULL;
+ EmissionMap *emaps = NULL;
unsigned int numflowobj = 0;
unsigned int flowIndex;
+ int new_shift[3] = {0};
+ int active_fields = sds->active_fields;
+
+ /* calculate domain shift for current frame if using adaptive domain */
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ int total_shift[3];
+ float frame_shift_f[3];
+ float ob_loc[3] = {0};
+
+ mul_m4_v3(ob->obmat, ob_loc);
+
+ VECSUB(frame_shift_f, ob_loc, sds->prev_loc);
+ copy_v3_v3(sds->prev_loc, ob_loc);
+ /* convert global space shift to local "cell" space */
+ mul_mat3_m4_v3(sds->imat, frame_shift_f);
+ frame_shift_f[0] = frame_shift_f[0]/sds->cell_size[0];
+ frame_shift_f[1] = frame_shift_f[1]/sds->cell_size[1];
+ frame_shift_f[2] = frame_shift_f[2]/sds->cell_size[2];
+ /* add to total shift */
+ VECADD(sds->shift_f, sds->shift_f, frame_shift_f);
+ /* convert to integer */
+ total_shift[0] = floor(sds->shift_f[0]);
+ total_shift[1] = floor(sds->shift_f[1]);
+ total_shift[2] = floor(sds->shift_f[2]);
+ VECSUB(new_shift, total_shift, sds->shift);
+ copy_v3_v3_int(sds->shift, total_shift);
+
+ /* calculate new domain boundary points so that smoke doesnt slide on sub-cell movement */
+ sds->p0[0] = sds->dp0[0] - sds->cell_size[0]*(sds->shift_f[0]-total_shift[0] - 0.5f);
+ sds->p0[1] = sds->dp0[1] - sds->cell_size[1]*(sds->shift_f[1]-total_shift[1] - 0.5f);
+ sds->p0[2] = sds->dp0[2] - sds->cell_size[2]*(sds->shift_f[2]-total_shift[2] - 0.5f);
+ sds->p1[0] = sds->p0[0] + sds->cell_size[0]*sds->base_res[0];
+ sds->p1[1] = sds->p0[1] + sds->cell_size[1]*sds->base_res[1];
+ sds->p1[2] = sds->p0[2] + sds->cell_size[2]*sds->base_res[2];
+ }
flowobjs = get_collisionobjects(scene, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
- // update obstacle tags in cells
+ /* init emission maps for each flow */
+ emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps");
+
+ /* Prepare flow emission maps */
for(flowIndex = 0; flowIndex < numflowobj; flowIndex++)
{
Object *collob= flowobjs[flowIndex];
@@ -1238,289 +1649,249 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
{
// we got nice flow object
SmokeFlowSettings *sfs = smd2->flow;
+ EmissionMap *em = &emaps[flowIndex];
- if(sfs && sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
- {
- ParticleSimulationData sim;
- ParticleSystem *psys = sfs->psys;
- int totpart=psys->totpart, totchild;
- 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);
- // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid);
- int bigres[3];
- short absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
- short high_emission_smoothing = bigdensity ? (sds->flags & MOD_SMOKE_HIGH_SMOOTH) : 0;
-
- /*
- * 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;
-
- sim.scene = scene;
- sim.ob = collob;
- sim.psys = psys;
-
- // 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; i<sds->res[0]*sds->res[1]*sds->res[2]; i++) {
- temp_emission_map[i] = 0.0f;
- }
- }
-
- // mostly copied from particle code
- if(psys->part->type==PART_HAIR)
- {
- /*
- if(psys->childcache)
- {
- totchild = psys->totchildcache;
- }
- else
- */
+ if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
+ emit_from_particles(collob, sds, sfs, em, scene, time, dt);
+ }
+ else {
+ emit_from_derivedmesh(collob, sds, sfs, em, dt);
+ }
- // TODO: PART_HAIR not supported whatsoever
- totchild=0;
+ /* update required data fields */
+ if (em->total_cells && sfs->type != MOD_SMOKE_FLOW_TYPE_OUTFLOW) {
+ /* activate heat field if flow produces any heat */
+ if (sfs->temp) {
+ active_fields |= SM_ACTIVE_HEAT;
}
- else
- totchild=psys->totchild*psys->part->disp/100;
-
- for(p=0; p<totpart+totchild; p++)
- {
- int cell[3];
- size_t i = 0;
- size_t index = 0;
- int badcell = 0;
- ParticleKey state;
-
- if(p < totpart)
- {
- if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
- continue;
- }
- else {
- /* handle child particle */
- ChildParticle *cpa = &psys->child[p - totpart];
-
- if(psys->particles[cpa->parent].flag & (PARS_NO_DISP|PARS_UNEXIST))
- continue;
+ /* activate fuel field if flow adds any fuel */
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && sfs->fuel_amount) {
+ active_fields |= SM_ACTIVE_FIRE;
+ }
+ /* activate color field if flows add smoke with varying colors */
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) {
+ if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
+ copy_v3_v3(sds->active_color, sfs->color);
+ active_fields |= SM_ACTIVE_COLOR_SET;
}
-
- state.time = time;
- if(psys_get_particle_state(&sim, p, &state, 0) == 0)
- continue;
-
- // copy_v3_v3(pos, pa->state.co);
- // mul_m4_v3(ob->imat, pos);
- // 1. get corresponding cell
- get_cell(sds->p0, sds->res, sds->dx*sds->scale, 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])) // this is inflow
- {
- // heat[index] += sfs->temp * 0.1;
- // density[index] += sfs->density * 0.1;
- heat[index] = sfs->temp;
-
- // Add emitter density to temp emission map
- temp_emission_map[index] = sfs->density;
-
- // Uses particle velocity as initial velocity for smoke
- if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO))
- {
- velocity_x[index] = state.vel[0]*sfs->vel_multi;
- velocity_y[index] = state.vel[1]*sfs->vel_multi;
- velocity_z[index] = state.vel[2]*sfs->vel_multi;
- }
- }
- 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(sds->wt, bigres);
-
- for(i = 0; i < sds->amplify + 1; i++)
- for(j = 0; j < sds->amplify + 1; j++)
- for(k = 0; k < sds->amplify + 1; k++)
- {
- index = smoke_get_index((sds->amplify + 1)* cell[0] + i, bigres[0], (sds->amplify + 1)* cell[1] + j, bigres[1], (sds->amplify + 1)* cell[2] + k);
- bigdensity[index] = 0.f;
- }
- }
+ else if (!equals_v3v3(sds->active_color, sfs->color)) {
+ active_fields |= SM_ACTIVE_COLORS;
}
- } // 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;
+ /* monitor active fields based on domain settings */
+ /* if domain has fire, activate new fields if required */
+ if (active_fields & SM_ACTIVE_FIRE) {
+ /* heat is always needed for fire */
+ active_fields |= SM_ACTIVE_HEAT;
+ /* also activate colors if domain smoke color differs from active color */
+ if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
+ copy_v3_v3(sds->active_color, sds->flame_smoke_color);
+ active_fields |= SM_ACTIVE_COLOR_SET;
+ }
+ else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) {
+ active_fields |= SM_ACTIVE_COLORS;
+ }
+ }
- smoke_turbulence_get_res(sds->wt, bigres);
- block_size = sds->amplify + 1; // high res block size
+ /* Adjust domain size if needed */
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ adjustDomainResolution(sds, new_shift, emaps, numflowobj, dt);
+ }
- // 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++)
- {
- // neighbor cell emission densities (for high resolution smoke smooth interpolation)
- float c000, c001, c010, c011, c100, c101, c110, c111;
+ /* Initialize new data fields if any */
+ if (active_fields & SM_ACTIVE_HEAT) {
+ smoke_ensure_heat(sds->fluid);
+ }
+ if (active_fields & SM_ACTIVE_FIRE) {
+ smoke_ensure_fire(sds->fluid, sds->wt);
+ }
+ if (active_fields & SM_ACTIVE_COLORS) {
+ /* initialize all smoke with "active_color" */
+ smoke_ensure_colors(sds->fluid, sds->wt, sds->active_color[0], sds->active_color[1], sds->active_color[2]);
+ }
+ sds->active_fields = active_fields;
- 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;
+ /* Apply emission data */
+ if (sds->fluid) {
+ for(flowIndex = 0; flowIndex < numflowobj; flowIndex++)
+ {
+ Object *collob= flowobjs[flowIndex];
+ SmokeModifierData *smd2 = (SmokeModifierData*)modifiers_findByType(collob, eModifierType_Smoke);
- 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
+ // check for initialized smoke object
+ if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
+ {
+ // we got nice flow object
+ SmokeFlowSettings *sfs = smd2->flow;
+ EmissionMap *em = &emaps[flowIndex];
+
+ float *density = smoke_get_density(sds->fluid);
+ float *color_r = smoke_get_color_r(sds->fluid);
+ float *color_g = smoke_get_color_g(sds->fluid);
+ float *color_b = smoke_get_color_b(sds->fluid);
+ float *fuel = smoke_get_fuel(sds->fluid);
+ float *react = smoke_get_react(sds->fluid);
+ float *bigdensity = smoke_turbulence_get_density(sds->wt);
+ float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
+ float *bigreact = smoke_turbulence_get_react(sds->wt);
+ float *bigcolor_r = smoke_turbulence_get_color_r(sds->wt);
+ float *bigcolor_g = smoke_turbulence_get_color_g(sds->wt);
+ float *bigcolor_b = smoke_turbulence_get_color_b(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);
+ // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid);
+ int bigres[3];
+ short high_emission_smoothing = (sds->flags & MOD_SMOKE_HIGH_SMOOTH);
+ float *velocity_map = em->velocity;
+ float *emission_map = em->influence;
- // get cell index
- index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
+ int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size;
+ size_t e_index, d_index, index_big;
- // add emission to low resolution density
- if (absolute_flow)
- {
- if (temp_emission_map[index]>0)
- density[index] = temp_emission_map[index];
+ // loop through every emission map cell
+ for(gx = em->min[0]; gx < em->max[0]; gx++)
+ for(gy = em->min[1]; gy < em->max[1]; gy++)
+ for(gz = em->min[2]; gz < em->max[2]; gz++)
+ {
+ /* get emission map index */
+ ex = gx-em->min[0];
+ ey = gy-em->min[1];
+ ez = gz-em->min[2];
+ e_index = smoke_get_index(ex, em->res[0], ey, em->res[1], ez);
+ if (!emission_map[e_index]) continue;
+ /* get domain index */
+ dx = gx-sds->res_min[0];
+ dy = gy-sds->res_min[1];
+ dz = gz-sds->res_min[2];
+ d_index = smoke_get_index(dx, sds->res[0], dy, sds->res[1], dz);
+
+ if(sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
+ apply_outflow_fields(d_index, density, heat, fuel, react, color_r, color_g, color_b);
+ }
+ else { // inflow
+ apply_inflow_fields(sfs, emission_map[e_index], d_index, density, heat, fuel, react, color_r, color_g, color_b);
+
+ /* initial velocity */
+ if(sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+ velocity_x[d_index] = ADD_IF_LOWER(velocity_x[d_index], velocity_map[e_index*3]);
+ velocity_y[d_index] = ADD_IF_LOWER(velocity_y[d_index], velocity_map[e_index*3+1]);
+ velocity_z[d_index] = ADD_IF_LOWER(velocity_z[d_index], velocity_map[e_index*3+2]);
}
- else
- {
- density[index] += temp_emission_map[index];
+ }
- if (density[index]>1)
- density[index]=1.0f;
- }
+ /* loop through high res blocks if high res enabled */
+ if (bigdensity) {
+ // neighbor cell emission densities (for high resolution smoke smooth interpolation)
+ float c000, c001, c010, c011, c100, c101, c110, c111;
smoke_turbulence_get_res(sds->wt, bigres);
+ block_size = sds->amplify + 1; // high res block size
- /* 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++)
- {
+ c000 = (ex>0 && ey>0 && ez>0) ? emission_map[smoke_get_index(ex-1, em->res[0], ey-1, em->res[1], ez-1)] : 0;
+ c001 = (ex>0 && ey>0) ? emission_map[smoke_get_index(ex-1, em->res[0], ey-1, em->res[1], ez)] : 0;
+ c010 = (ex>0 && ez>0) ? emission_map[smoke_get_index(ex-1, em->res[0], ey, em->res[1], ez-1)] : 0;
+ c011 = (ex>0) ? emission_map[smoke_get_index(ex-1, em->res[0], ey, em->res[1], ez)] : 0;
- 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;
+ c100 = (ey>0 && ez>0) ? emission_map[smoke_get_index(ex, em->res[0], ey-1, em->res[1], ez-1)] : 0;
+ c101 = (ey>0) ? emission_map[smoke_get_index(ex, em->res[0], ey-1, em->res[1], ez)] : 0;
+ c110 = (ez>0) ? emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez-1)] : 0;
+ c111 = emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez)]; // this cell
- if (bigdensity[index_big]>1)
- bigdensity[index_big]=1.0f;
- }
- } // end of hires loop
+ for(ii = 0; ii < block_size; ii++)
+ for(jj = 0; jj < block_size; jj++)
+ for(kk = 0; kk < block_size; kk++)
+ {
- } // end of low res loop
+ float fx,fy,fz, interpolated_value;
+ int shift_x, shift_y, shift_z;
- // free temporary emission map
- if (temp_emission_map)
- MEM_freeN(temp_emission_map);
- } // end emission
- }
+ /*
+ * Do volume interpolation if emitter smoothing
+ * is enabled
+ */
+ if (high_emission_smoothing)
+ {
+ /* get relative block position
+ * 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)*(block_size/2) + 0.4f;
+ CLAMP(interpolated_value, 0.0f, 1.0f);
+
+ /* shift smoke block index
+ * (because pixel center is actually
+ * in halfway of the low res block) */
+ shift_x = (dx < 1) ? 0 : block_size/2;
+ shift_y = (dy < 1) ? 0 : block_size/2;
+ shift_z = (dz < 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 * dx + ii - shift_x, bigres[0], block_size * dy + jj - shift_y, bigres[1], block_size * dz + kk - shift_z);
+
+ if(sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
+ if (interpolated_value) {
+ apply_outflow_fields(index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b);
+ }
+ }
+ else { // inflow
+ apply_inflow_fields(sfs, interpolated_value, index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b);
+ }
+ } // hires loop
+ } // bigdensity
+ } // low res loop
+
+ // free emission maps
+ em_freeData(em);
+
+ } // end emission
}
}
if(flowobjs)
MEM_freeN(flowobjs);
+ if(emaps)
+ MEM_freeN(emaps);
}
static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
{
- ListBase *effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights);
+ ListBase *effectors;
+ /* make sure smoke flow influence is 0.0f */
+ sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
+ effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights);
if(effectors)
{
@@ -1532,76 +1903,110 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds,
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 x, y, z;
+ int x;
// precalculate wind forces
+ #pragma omp parallel for schedule(static)
for(x = 0; x < sds->res[0]; x++)
+ {
+ int y, z;
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) || obstacle[index])
- continue;
-
- vel[0] = velocity_x[index];
- vel[1] = velocity_y[index];
- vel[2] = velocity_z[index];
-
- voxelCenter[0] = sds->p0[0] + sds->dx * sds->scale * x + sds->dx * sds->scale * 0.5;
- voxelCenter[1] = sds->p0[1] + sds->dx * sds->scale * y + sds->dx * sds->scale * 0.5;
- voxelCenter[2] = sds->p0[2] + sds->dx * sds->scale * z + sds->dx * sds->scale * 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);
+ {
+ EffectedPoint epoint;
+ float mag;
+ 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) || obstacle[index])
+ continue;
+
+ vel[0] = velocity_x[index];
+ vel[1] = velocity_y[index];
+ vel[2] = velocity_z[index];
+
+ /* convert vel to global space */
+ mag = len_v3(vel);
+ mul_mat3_m4_v3(sds->obmat, vel);
+ normalize_v3(vel);
+ mul_v3_fl(vel, mag);
+
+ voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x+sds->res_min[0]) + 0.5f);
+ voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y+sds->res_min[1]) + 0.5f);
+ voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z+sds->res_min[2]) + 0.5f);
+ mul_m4_v3(sds->obmat, voxelCenter);
+
+ pd_point_from_loc(scene, voxelCenter, vel, index, &epoint);
+ pdDoEffectors(effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
+
+ /* convert retvel to local space */
+ mag = len_v3(retvel);
+ mul_mat3_m4_v3(sds->imat, retvel);
+ normalize_v3(retvel);
+ mul_v3_fl(retvel, mag);
+
+ // 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);
}
-static void step(Scene *scene, Object *ob, SmokeModifierData *smd, float fps)
+static void step(Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *domain_dm, float fps)
{
+ SmokeDomainSettings *sds = smd->domain;
/* stability values copied from wturbulence.cpp */
const int maxSubSteps = 25;
float maxVel;
// maxVel should be 1.5 (1.5 cell max movement) * dx (cell size)
- float dt = DT_DEFAULT;
+ float dt;
float maxVelMag = 0.0f;
int totalSubsteps;
int substep = 0;
float dtSubdiv;
-
- SmokeDomainSettings *sds = smd->domain;
+ float gravity[3] = {0.0f, 0.0f, -1.0f};
+ float gravity_mag;
/* get max velocity and lower the dt value if it is too high */
- size_t size= sds->res[0] * sds->res[1] * sds->res[2];
-
+ size_t size = sds->res[0] * sds->res[1] * sds->res[2];
float *velX = smoke_get_velocity_x(sds->fluid);
float *velY = smoke_get_velocity_y(sds->fluid);
float *velZ = smoke_get_velocity_z(sds->fluid);
size_t i;
- /* adapt timestep for different framerates, dt = 0.1 is at 25fps */
- dt *= (25.0f / fps);
+ /* update object state */
+ invert_m4_m4(sds->imat, ob->obmat);
+ copy_m4_m4(sds->obmat, ob->obmat);
+ smoke_set_domain_from_derivedmesh(sds, ob, domain_dm);
+
+ /* use global gravity if enabled */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ copy_v3_v3(gravity, scene->physics_settings.gravity);
+ /* map default value to 1.0 */
+ mul_v3_fl(gravity, 1.0f/9.810f);
+ }
+ /* convert gravity to domain space */
+ gravity_mag = len_v3(gravity);
+ mul_mat3_m4_v3(sds->imat, gravity);
+ normalize_v3(gravity);
+ mul_v3_fl(gravity, gravity_mag);
+ /* adapt timestep for different framerates, dt = 0.1 is at 25fps */
+ dt = DT_DEFAULT * (25.0f / fps);
// maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel
maxVel = (sds->dx * 5.0);
- for(i = 0; i < size; i++)
+ /*for(i = 0; i < size; i++)
{
float vtemp = (velX[i]*velX[i]+velY[i]*velY[i]+velZ[i]*velZ[i]);
if(vtemp > maxVelMag)
maxVelMag = vtemp;
- }
+ }*/
maxVelMag = sqrt(maxVelMag) * dt * sds->time_scale;
totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */
@@ -1618,35 +2023,116 @@ static void step(Scene *scene, Object *ob, SmokeModifierData *smd, float fps)
for(substep = 0; substep < totalSubsteps; substep++)
{
// calc animated obstacle velocities
+ update_flowsfluids(scene, ob, sds, smd->time, dtSubdiv);
update_obstacles(scene, ob, sds, dtSubdiv, substep, totalSubsteps);
- update_flowsfluids(scene, ob, sds, smd->time);
- update_effectors(scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
-
- smoke_step(sds->fluid, dtSubdiv);
- // move animated obstacle: Done in update_obstacles() */
+ if (sds->total_cells > 1) {
+ update_effectors(scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
+ smoke_step(sds->fluid, gravity, dtSubdiv);
+ }
+ }
+}
- // where to delete old obstacles from array? Done in update_obstacles() */
+static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
+{
+ DerivedMesh *result;
+ MVert *mverts;
+ MPoly *mpolys;
+ MLoop *mloops;
+ float min[3];
+ float max[3];
+ float *co;
+ MPoly *mp;
+ MLoop *ml;
+
+ int num_verts = 8;
+ int num_faces = 6;
+ int i;
+ float ob_loc[3] = {0};
+ float ob_cache_loc[3] = {0};
+
+ /* dont generate any mesh if there isnt any content */
+ if (sds->total_cells <= 1) {
+ num_verts = 0;
+ num_faces = 0;
+ }
+
+ result = CDDM_new(num_verts, 0, 0, num_faces * 4, num_faces);
+ mverts = CDDM_get_verts(result);
+ mpolys = CDDM_get_polys(result);
+ mloops = CDDM_get_loops(result);
+
+
+ if (num_verts) {
+ /* volume bounds */
+ VECMADD(min, sds->p0, sds->cell_size, sds->res_min);
+ VECMADD(max, sds->p0, sds->cell_size, sds->res_max);
+
+ /* set vertices */
+ /* top slab */
+ co = mverts[0].co; co[0] = min[0]; co[1] = min[1]; co[2] = max[2];
+ co = mverts[1].co; co[0] = max[0]; co[1] = min[1]; co[2] = max[2];
+ co = mverts[2].co; co[0] = max[0]; co[1] = max[1]; co[2] = max[2];
+ co = mverts[3].co; co[0] = min[0]; co[1] = max[1]; co[2] = max[2];
+ /* bottom slab */
+ co = mverts[4].co; co[0] = min[0]; co[1] = min[1]; co[2] = min[2];
+ co = mverts[5].co; co[0] = max[0]; co[1] = min[1]; co[2] = min[2];
+ co = mverts[6].co; co[0] = max[0]; co[1] = max[1]; co[2] = min[2];
+ co = mverts[7].co; co[0] = min[0]; co[1] = max[1]; co[2] = min[2];
+
+ /* create faces */
+ /* top */
+ mp = &mpolys[0]; ml = &mloops[0 * 4]; mp->loopstart = 0 * 4; mp->totloop = 4;
+ ml[0].v = 0; ml[1].v = 1; ml[2].v = 2; ml[3].v = 3;
+ /* right */
+ mp = &mpolys[1]; ml = &mloops[1 * 4]; mp->loopstart = 1 * 4; mp->totloop = 4;
+ ml[0].v = 2; ml[1].v = 1; ml[2].v = 5; ml[3].v = 6;
+ /* bottom */
+ mp = &mpolys[2]; ml = &mloops[2 * 4]; mp->loopstart = 2 * 4; mp->totloop = 4;
+ ml[0].v = 7; ml[1].v = 6; ml[2].v = 5; ml[3].v = 4;
+ /* left */
+ mp = &mpolys[3]; ml = &mloops[3 * 4]; mp->loopstart = 3 * 4; mp->totloop = 4;
+ ml[0].v = 0; ml[1].v = 3; ml[2].v = 7; ml[3].v = 4;
+ /* front */
+ mp = &mpolys[4]; ml = &mloops[4 * 4]; mp->loopstart = 4 * 4; mp->totloop = 4;
+ ml[0].v = 3; ml[1].v = 2; ml[2].v = 6; ml[3].v = 7;
+ /* back */
+ mp = &mpolys[5]; ml = &mloops[5 * 4]; mp->loopstart = 5 * 4; mp->totloop = 4;
+ ml[0].v = 1; ml[1].v = 0; ml[2].v = 4; ml[3].v = 5;
+
+ /* calculate required shift to match domain's global position
+ * it was originally simulated at (if object moves without smoke step) */
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->obmat, ob_loc);
+ mul_m4_v3(sds->obmat, ob_cache_loc);
+ VECSUB(sds->obj_shift_f, ob_cache_loc, ob_loc);
+ /* convert shift to local space and apply to vertices */
+ mul_mat3_m4_v3(ob->imat, sds->obj_shift_f);
+ /* apply */
+ for (i=0; i<num_verts; i++) {
+ add_v3_v3(mverts[i].co, sds->obj_shift_f);
+ }
}
+
+
+ CDDM_calc_edges(result);
+ return result;
}
-void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
{
if((smd->type & MOD_SMOKE_TYPE_FLOW))
{
if(scene->r.cfra >= smd->time)
smokeModifier_init(smd, ob, scene, dm);
+ if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm);
+ smd->flow->dm = CDDM_copy(dm);
+ DM_ensure_tessface(smd->flow->dm);
+
if(scene->r.cfra > smd->time)
{
- // XXX TODO
smd->time = scene->r.cfra;
-
- // rigid movement support
- /*
- copy_m4_m4(smd->flow->mat_old, smd->flow->mat);
- copy_m4_m4(smd->flow->mat, ob->obmat);
- */
}
else if(scene->r.cfra < smd->time)
{
@@ -1656,99 +2142,27 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
}
else if(smd->type & MOD_SMOKE_TYPE_COLL)
{
- /* Check if domain resolution changed */
- /* DG TODO: can this be solved more elegant using dependancy graph? */
- {
- SmokeCollSettings *scs = smd->coll;
- Base *base = scene->base.first;
- int changed = 0;
- float dx = FLT_MAX;
- float scale = 1.0f;
- int haveDomain = 0;
-
- for ( ; base; base = base->next)
- {
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(base->object, eModifierType_Smoke);
-
- if (smd2 && (smd2->type & MOD_SMOKE_TYPE_DOMAIN) && smd2->domain)
- {
- SmokeDomainSettings *sds = smd2->domain;
-
- if(sds->dx * sds->scale < dx)
- {
- dx = sds->dx;
- scale = sds->scale;
- changed = 1;
- }
-
- haveDomain = 1;
- }
- }
-
- if(!haveDomain)
- return;
-
- if(changed)
- {
- if(dx*scale != scs->dx)
- {
- scs->dx = dx*scale;
- smokeModifier_reset(smd);
- }
- }
- }
-
if(scene->r.cfra >= smd->time)
smokeModifier_init(smd, ob, scene, dm);
- if(scene->r.cfra > smd->time)
+ if(smd->coll)
{
- unsigned int i;
- SmokeCollSettings *scs = smd->coll;
- float *points_old = scs->points_old;
- float *points = scs->points;
- unsigned int numpoints = scs->numpoints;
-
- // XXX TODO <-- DG: what is TODO here?
- smd->time = scene->r.cfra;
-
- // rigid movement support
- copy_m4_m4(scs->mat_old, scs->mat);
- copy_m4_m4(scs->mat, ob->obmat);
-
- if(scs->type != SM_COLL_ANIMATED) // if(not_animated)
- {
- // nothing to do, "mat" is already up to date
- }
- else
- {
- // XXX TODO: need to update positions + divs
+ if (smd->coll->dm)
+ smd->coll->dm->release(smd->coll->dm);
- if(scs->numverts != dm->getNumVerts(dm))
- {
- // DG TODO: reset modifier?
- return;
- }
-
- for(i = 0; i < numpoints * 3; i++)
- {
- points_old[i] = points[i];
- }
-
- DM_ensure_tessface(dm);
- fill_scs_points_anim(ob, dm, scs);
- }
+ smd->coll->dm = CDDM_copy(dm);
+ DM_ensure_tessface(smd->coll->dm);
}
- else if(scene->r.cfra < smd->time)
+
+ smd->time = scene->r.cfra;
+ 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;
int startframe, endframe, framenr;
@@ -1765,6 +2179,7 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
if(!smd->domain->fluid || framenr == startframe)
{
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+ smokeModifier_reset(smd);
BKE_ptcache_validate(cache, framenr);
cache->flag &= ~PTCACHE_REDO_NEEDED;
}
@@ -1773,15 +2188,12 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
return;
smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD;
-
CLAMP(framenr, startframe, endframe);
/* If already viewing a pre/after frame, no need to reload */
if ((smd->time == framenr) && (framenr != scene->r.cfra))
return;
- // printf("startframe: %d, framenr: %d\n", startframe, framenr);
-
if(smokeModifier_init(smd, ob, scene, dm)==0)
{
printf("bad smokeModifier_init\n");
@@ -1805,15 +2217,12 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
tstart();
- smoke_calc_domain(scene, ob, smd);
-
/* if on second frame, write cache for first frame */
if((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) {
// create shadows straight after domain initialization so we get nice shadows for startframe, 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);
+ smoke_calc_transparency(sds, scene);
- if(sds->wt)
+ if(sds->wt && sds->total_cells>1)
{
if(sds->flags & MOD_SMOKE_DISSOLVE)
smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
@@ -1828,8 +2237,6 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
/* do simulation */
- // low res
-
// simulate the actual smoke (c++ code in intern/smoke)
// DG: interesting commenting this line + deactivating loading of noise files
if(framenr!=startframe)
@@ -1837,12 +2244,11 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
if(sds->flags & MOD_SMOKE_DISSOLVE)
smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
- step(scene, ob, smd, scene->r.frs_sec / scene->r.frs_sec_base);
+ step(scene, ob, smd, dm, scene->r.frs_sec / scene->r.frs_sec_base);
}
// create shadows before writing cache so they get stored
- 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);
+ smoke_calc_transparency(sds, scene);
if(sds->wt)
{
@@ -1860,6 +2266,20 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
}
}
+struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+{
+ smokeModifier_process(smd, scene, ob, dm);
+
+ /* return generated geometry for adaptive domain */
+ if(smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
+ smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN &&
+ smd->domain->base_res[0])
+ {
+ return createDomainGeometry(smd->domain, ob);
+ }
+ else return CDDM_copy(dm);
+}
+
static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct)
{
const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
@@ -1876,24 +2296,6 @@ static float calc_voxel_transp(float *result, float *input, int res[3], int *pix
return *tRay;
}
-long long smoke_get_mem_req(int xres, int yres, int zres, int amplify)
-{
- int totalCells = xres * yres * zres;
- int amplifiedCells = totalCells * amplify * amplify * amplify;
-
- // print out memory requirements
- long long int coarseSize = sizeof(float) * totalCells * 22 +
- sizeof(unsigned char) * totalCells;
-
- long long int fineSize = sizeof(float) * amplifiedCells * 7 + // big grids
- sizeof(float) * totalCells * 8 + // small grids
- sizeof(float) * 128 * 128 * 128; // noise tile
-
- long long int totalMB = (coarseSize + fineSize) / (1024 * 1024);
-
- return totalMB;
-}
-
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)
{
int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
@@ -1977,80 +2379,142 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f
cb(result, input, res, pixel, tRay, correct);
}
-static void get_cell(const float p0[3], const int res[3], float dx, const float pos[3], int cell[3], int correct)
+static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene)
{
- float tmp[3];
-
- sub_v3_v3v3(tmp, pos, p0);
- mul_v3_fl(tmp, 1.0 / dx);
+ float bv[6] = {0};
+ float light[3];
+ int a, z, slabsize=sds->res[0]*sds->res[1], size= sds->res[0]*sds->res[1]*sds->res[2];
+ float *density = smoke_get_density(sds->fluid);
+ float correct = -7.0*sds->dx;
- if (correct) {
- cell[0] = MIN2(res[0] - 1, MAX2(0, (int)floor(tmp[0])));
- cell[1] = MIN2(res[1] - 1, MAX2(0, (int)floor(tmp[1])));
- cell[2] = MIN2(res[2] - 1, MAX2(0, (int)floor(tmp[2])));
- }
- else {
- cell[0] = (int)floor(tmp[0]);
- cell[1] = (int)floor(tmp[1]);
- cell[2] = (int)floor(tmp[2]);
- }
-}
+ if (!get_lamp(scene, light)) return;
-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)
-{
- float bv[6];
- int a, z, slabsize=res[0]*res[1], size= res[0]*res[1]*res[2];
+ /* convert light pos to sim cell space */
+ mul_m4_v3(sds->imat, light);
+ light[0] = (light[0] - sds->p0[0]) / sds->cell_size[0] - 0.5f;
+ light[1] = (light[1] - sds->p0[1]) / sds->cell_size[1] - 0.5f;
+ light[2] = (light[2] - sds->p0[2]) / sds->cell_size[2] - 0.5f;
for(a=0; a<size; a++)
- result[a]= -1.0f;
+ sds->shadow[a]= -1.0f;
- bv[0] = p0[0];
- bv[1] = p1[0];
- // y
- bv[2] = p0[1];
- bv[3] = p1[1];
- // z
- bv[4] = p0[2];
- bv[5] = p1[2];
+ /* calculate domain bounds in sim cell space */
+ // 0,2,4 = 0.0f
+ bv[1] = (float)sds->res[0]; // x
+ bv[3] = (float)sds->res[1]; // y
+ bv[5] = (float)sds->res[2]; // z
// #pragma omp parallel for schedule(static,1)
- for(z = 0; z < res[2]; z++)
+ for(z = 0; z < sds->res[2]; z++)
{
size_t index = z*slabsize;
int x,y;
- for(y = 0; y < res[1]; y++)
- for(x = 0; x < res[0]; x++, index++)
+ for(y = 0; y < sds->res[1]; y++)
+ for(x = 0; x < sds->res[0]; x++, index++)
{
float voxelCenter[3];
float pos[3];
int cell[3];
float tRay = 1.0;
- if(result[index] >= 0.0f)
+ if(sds->shadow[index] >= 0.0f)
continue;
- voxelCenter[0] = p0[0] + dx * x + dx * 0.5;
- voxelCenter[1] = p0[1] + dx * y + dx * 0.5;
- voxelCenter[2] = p0[2] + dx * z + dx * 0.5;
+ voxelCenter[0] = (float)x;
+ voxelCenter[1] = (float)y;
+ voxelCenter[2] = (float)z;
- // get starting position (in voxel coords)
+ // get starting cell (light pos)
if(BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON)
{
- // we're ouside
- get_cell(p0, res, dx, pos, cell, 1);
+ // we're ouside -> use point on side of domain
+ cell[0] = (int)floor(pos[0]);
+ cell[1] = (int)floor(pos[1]);
+ cell[2] = (int)floor(pos[2]);
}
else {
- // we're inside
- get_cell(p0, res, dx, light, cell, 1);
+ // we're inside -> use light itself
+ cell[0] = (int)floor(light[0]);
+ cell[1] = (int)floor(light[1]);
+ cell[2] = (int)floor(light[2]);
}
+ /* clamp within grid bounds */
+ CLAMP(cell[0], 0, sds->res[0]-1);
+ CLAMP(cell[1], 0, sds->res[1]-1);
+ CLAMP(cell[2], 0, sds->res[2]-1);
- bresenham_linie_3D(cell[0], cell[1], cell[2], x, y, z, &tRay, cb, result, input, res, correct);
+ bresenham_linie_3D(cell[0], cell[1], cell[2], x, y, z, &tRay, calc_voxel_transp, sds->shadow, density, sds->res, correct);
// convention -> from a RGBA float array, use G value for tRay
// #pragma omp critical
- result[index] = tRay;
+ sds->shadow[index] = tRay;
}
}
}
+/* get smoke velocity and density at given coordinates
+* returns fluid density or -1.0f if outside domain*/
+float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
+{
+ SmokeModifierData *smd = (SmokeModifierData*)modifiers_findByType(ob, eModifierType_Smoke);
+ zero_v3(velocity);
+
+ if(smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && smd->domain->fluid) {
+ SmokeDomainSettings *sds = smd->domain;
+ float time_mult = 25.f * DT_DEFAULT;
+ float vel_mag;
+ float *velX = smoke_get_velocity_x(sds->fluid);
+ float *velY = smoke_get_velocity_y(sds->fluid);
+ float *velZ = smoke_get_velocity_z(sds->fluid);
+ float density = 0.0f, fuel = 0.0f;
+ float pos[3];
+ copy_v3_v3(pos, position);
+ smoke_pos_to_cell(sds, pos);
+
+ /* check if point is outside domain max bounds */
+ if (pos[0] < sds->res_min[0] || pos[1] < sds->res_min[1] || pos[2] < sds->res_min[2]) return -1.0f;
+ if (pos[0] > sds->res_max[0] || pos[1] > sds->res_max[1] || pos[2] > sds->res_max[2]) return -1.0f;
+
+ /* map pos between 0.0 - 1.0 */
+ pos[0] = (pos[0] - sds->res_min[0]) / ((float)sds->res[0]);
+ pos[1] = (pos[1] - sds->res_min[1]) / ((float)sds->res[1]);
+ pos[2] = (pos[2] - sds->res_min[2]) / ((float)sds->res[2]);
+
+
+ /* check if point is outside active area */
+ if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) return 0.0f;
+ if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) return 0.0f;
+ }
+
+ /* get interpolated velocity */
+ velocity[0] = BLI_voxel_sample_trilinear(velX, sds->res, pos) * sds->global_size[0] * time_mult;
+ velocity[1] = BLI_voxel_sample_trilinear(velY, sds->res, pos) * sds->global_size[1] * time_mult;
+ velocity[2] = BLI_voxel_sample_trilinear(velZ, sds->res, pos) * sds->global_size[2] * time_mult;
+
+ /* convert velocity direction to global space */
+ vel_mag = len_v3(velocity);
+ mul_mat3_m4_v3(sds->obmat, velocity);
+ normalize_v3(velocity);
+ mul_v3_fl(velocity, vel_mag);
+
+ /* use max value of fuel or smoke density */
+ density = BLI_voxel_sample_trilinear(smoke_get_density(sds->fluid), sds->res, pos);
+ if (smoke_has_fuel(sds->fluid)) {
+ fuel = BLI_voxel_sample_trilinear(smoke_get_fuel(sds->fluid), sds->res, pos);
+ }
+ return MAX2(density, fuel);
+ }
+ return -1.0f;
+}
+
+int smoke_get_data_flags(SmokeDomainSettings *sds) {
+ int flags = 0;
+ if (smoke_has_heat(sds->fluid)) flags |= SM_ACTIVE_HEAT;
+ if (smoke_has_fuel(sds->fluid)) flags |= SM_ACTIVE_FIRE;
+ if (smoke_has_colors(sds->fluid)) flags |= SM_ACTIVE_COLORS;
+
+ return flags;
+}
+
#endif /* WITH_SMOKE */
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 9dd83181521..300d272b86b 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -571,7 +571,7 @@ void default_mtex(MTex *mtex)
mtex->size[1] = 1.0;
mtex->size[2] = 1.0;
mtex->tex = NULL;
- mtex->texflag = MTEX_3TAP_BUMP | MTEX_BUMP_OBJECTSPACE;
+ mtex->texflag = MTEX_3TAP_BUMP | MTEX_BUMP_OBJECTSPACE | MTEX_MAPTO_BOUNDS;
mtex->colormodel = 0;
mtex->r = 1.0;
mtex->g = 0.0;
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index a471f95d505..83b07bae53f 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -67,6 +67,7 @@ MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
MINLINE void copy_v4_v4_short(short r[4], const short a[4]);
/* int */
+MINLINE void zero_v3_int(int r[3]);
MINLINE void copy_v2_v2_int(int r[2], const int a[2]);
MINLINE void copy_v3_v3_int(int r[3], const int a[3]);
MINLINE void copy_v4_v4_int(int r[4], const int a[4]);
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index beb554042ea..47c2256c1e1 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -193,6 +193,11 @@
*(v1 + 1) = *(v2 + 1) + *(v3 + 1) * (fac); \
*(v1 + 2) = *(v2 + 2) + *(v3 + 2) * (fac); \
} (void)0
+#define VECMADD(v1, v2, v3, v4) { \
+ *(v1) = *(v2) + *(v3) * (*(v4)); \
+ *(v1 + 1) = *(v2 + 1) + *(v3 + 1) * (*(v4 + 1)); \
+ *(v1 + 2) = *(v2 + 2) + *(v3 + 2) * (*(v4 + 2)); \
+} (void)0
#define VECSUBFAC(v1, v2, v3, fac) { \
*(v1) = *(v2) - *(v3) * (fac); \
*(v1 + 1) = *(v2 + 1) - *(v3 + 1) * (fac); \
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index de1038724b0..191b0e16025 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -121,6 +121,13 @@ MINLINE void copy_v4_v4_char(char r[4], const char a[4])
}
/* short */
+MINLINE void zero_v3_int(int r[3])
+{
+ r[0] = 0;
+ r[1] = 0;
+ r[2] = 0;
+}
+
MINLINE void copy_v2_v2_short(short r[2], const short a[2])
{
r[0] = a[0];
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 606fd48dc2b..9171e78e7ad 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3335,6 +3335,8 @@ static void lib_link_partdeflect(FileData *fd, ID *id, PartDeflect *pd)
{
if (pd && pd->tex)
pd->tex = newlibadr_us(fd, id->lib, pd->tex);
+ if (pd && pd->f_source)
+ pd->f_source = newlibadr_us(fd, id->lib, pd->f_source);
}
static void lib_link_particlesettings(FileData *fd, Main *main)
@@ -4333,6 +4335,9 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
smd->coll = NULL;
smd->flow = newdataadr(fd, smd->flow);
smd->flow->smd = smd;
+ smd->flow->dm = NULL;
+ smd->flow->verts_old = NULL;
+ smd->flow->numverts = 0;
smd->flow->psys = newdataadr(fd, smd->flow->psys);
}
else if (smd->type == MOD_SMOKE_TYPE_COLL) {
@@ -4341,11 +4346,15 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
smd->coll = newdataadr(fd, smd->coll);
if (smd->coll) {
smd->coll->smd = smd;
- smd->coll->points = NULL;
- smd->coll->numpoints = 0;
+ smd->coll->verts_old = NULL;
+ smd->coll->numverts = 0;
+ smd->coll->dm = NULL;
}
else {
smd->type = 0;
+ smd->flow = NULL;
+ smd->domain = NULL;
+ smd->coll = NULL;
}
}
}
@@ -8038,6 +8047,44 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */
+ {
+ Object *ob;
+
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ ModifierData *md;
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
+ /* keep branch saves if possible */
+ if (!smd->domain->flame_max_temp) {
+ smd->domain->burning_rate = 0.75f;
+ smd->domain->flame_smoke = 1.0f;
+ smd->domain->flame_vorticity = 0.5f;
+ smd->domain->flame_ignition = 1.25f;
+ smd->domain->flame_max_temp = 1.75f;
+ smd->domain->adapt_threshold = 0.02f;
+ smd->domain->adapt_margin = 4;
+ smd->domain->flame_smoke_color[0] = 0.7f;
+ smd->domain->flame_smoke_color[1] = 0.7f;
+ smd->domain->flame_smoke_color[2] = 0.7f;
+ }
+ }
+ else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
+ if (!smd->flow->texture_size) {
+ smd->flow->fuel_amount = 1.0;
+ smd->flow->surface_distance = 1.5;
+ smd->flow->color[0] = 0.7f;
+ smd->flow->color[1] = 0.7f;
+ smd->flow->color[2] = 0.7f;
+ smd->flow->texture_size = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ }
+
/* don't forget to set version number in blender.c! */
}
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index ef7b8ed3a41..8f50edd1240 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -450,8 +450,8 @@ DEF_ICON(FORCE_CURVE)
DEF_ICON(FORCE_BOID)
DEF_ICON(FORCE_TURBULENCE)
DEF_ICON(FORCE_DRAG)
+DEF_ICON(FORCE_SMOKEFLOW)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK672)
DEF_ICON(BLANK673)
DEF_ICON(BLANK674)
DEF_ICON(BLANK675)
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 43a32cd662e..dc20e0d69cd 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -136,6 +136,7 @@ static EnumPropertyItem field_type_items[] = {
{PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""},
{PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", ""},
{PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", ""},
+ {PFIELD_SMOKEFLOW, "SMOKE", ICON_FORCE_SMOKEFLOW, "Smoke Flow", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -356,7 +357,7 @@ Object *ED_object_add_type(bContext *C, int type, const float loc[3], const floa
Scene *scene = CTX_data_scene(C);
Object *ob;
- /* For as long scene has editmode... */
+ /* for as long scene has editmode... */
if (CTX_data_edit_object(C))
ED_object_exit_editmode(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index eb17aa2b8ce..dd3c7408511 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -6625,72 +6625,74 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
/* only draw domains */
- 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 (!smd->domain->wt || !(smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
-// #if 0
- smd->domain->tex = NULL;
- GPU_create_smoke(smd, 0);
- draw_volume(ar, smd->domain->tex,
- smd->domain->p0, smd->domain->p1,
- smd->domain->res, smd->domain->dx,
- smd->domain->tex_shadow);
- GPU_free_smoke(smd);
-// #endif
-#if 0
- int x, y, z;
- float *density = smoke_get_density(smd->domain->fluid);
-
- glLoadMatrixf(rv3d->viewmat);
- // glMultMatrixf(ob->obmat);
+ if (smd->domain) {
+ SmokeDomainSettings *sds = smd->domain;
+ float p0[3], p1[3], viewnormal[3];
+ BoundBox bb;
- if (col || (ob->flag & SELECT)) cpack(0xFFFFFF);
- glDepthMask(GL_FALSE);
- glEnable(GL_BLEND);
-
-
- // glPointSize(3.0);
- bglBegin(GL_POINTS);
-
- for (x = 0; x < smd->domain->res[0]; x++) {
- for (y = 0; y < smd->domain->res[1]; y++) {
- for (z = 0; z < smd->domain->res[2]; z++) {
- float tmp[3];
- int index = smoke_get_index(x, smd->domain->res[0], y, smd->domain->res[1], z);
-
- if (density[index] > FLT_EPSILON) {
- float color[3];
- copy_v3_v3(tmp, smd->domain->p0);
- tmp[0] += smd->domain->dx * x + smd->domain->dx * 0.5;
- tmp[1] += smd->domain->dx * y + smd->domain->dx * 0.5;
- tmp[2] += smd->domain->dx * z + smd->domain->dx * 0.5;
- color[0] = color[1] = color[2] = density[index];
- glColor3fv(color);
- bglVertex3fv(tmp);
- }
- }
- }
+ glLoadMatrixf(rv3d->viewmat);
+ glMultMatrixf(ob->obmat);
+
+ /* draw adaptive domain bounds */
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ /* draw domain max bounds */
+ VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res);
+ VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res);
+ BKE_boundbox_init_from_minmax(&bb, p0, p1);
+ draw_box(bb.vec);
+
+ /* draw base resolution bounds */
+ /*BKE_boundbox_init_from_minmax(&bb, sds->p0, sds->p1);
+ draw_box(bb.vec);*/
+ }
+
+ /* don't show smoke before simulation starts, this could be made an option in the future */
+ if (smd->domain->fluid && CFRA >= smd->domain->point_cache[0]->startframe) {
+
+ // get view vector
+ copy_v3_v3(viewnormal, rv3d->viewinv[2]);
+ mul_mat3_m4_v3(ob->imat, viewnormal);
+ normalize_v3(viewnormal);
+
+ /* set dynamic boundaries to draw the volume */
+ p0[0] = sds->p0[0] + sds->cell_size[0]*sds->res_min[0] + sds->obj_shift_f[0];
+ p0[1] = sds->p0[1] + sds->cell_size[1]*sds->res_min[1] + sds->obj_shift_f[1];
+ p0[2] = sds->p0[2] + sds->cell_size[2]*sds->res_min[2] + sds->obj_shift_f[2];
+ p1[0] = sds->p0[0] + sds->cell_size[0]*sds->res_max[0] + sds->obj_shift_f[0];
+ p1[1] = sds->p0[1] + sds->cell_size[1]*sds->res_max[1] + sds->obj_shift_f[1];
+ p1[2] = sds->p0[2] + sds->cell_size[2]*sds->res_max[2] + sds->obj_shift_f[2];
+
+ /* scale cube to global space to equalize volume slicing on all axises
+ * (its scaled back before drawing) */
+ mul_v3_v3(p0, ob->size);
+ mul_v3_v3(p1, ob->size);
+
+ if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
+ smd->domain->tex = NULL;
+ GPU_create_smoke(smd, 0);
+ draw_smoke_volume(sds, ob, ar, sds->tex,
+ p0, p1,
+ sds->res, sds->dx, sds->scale*sds->maxres,
+ viewnormal, sds->tex_shadow, sds->tex_flame);
+ GPU_free_smoke(smd);
+ }
+ else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
+ sds->tex = NULL;
+ GPU_create_smoke(smd, 1);
+ draw_smoke_volume(sds, ob, ar, sds->tex,
+ p0, p1,
+ sds->res_wt, sds->dx, sds->scale*sds->maxres,
+ viewnormal, sds->tex_shadow, sds->tex_flame);
+ GPU_free_smoke(smd);
}
- bglEnd();
- glPointSize(1.0);
-
- glMultMatrixf(ob->obmat);
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
- if (col) cpack(col);
-#endif
- }
- else if (smd->domain->wt && (smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
- smd->domain->tex = NULL;
- GPU_create_smoke(smd, 1);
- draw_volume(ar, smd->domain->tex,
- smd->domain->p0, smd->domain->p1,
- smd->domain->res_wt, smd->domain->dx_wt,
- smd->domain->tex_shadow);
- GPU_free_smoke(smd);
+ /* smoke debug render */
+ #ifdef SMOKE_DEBUG_VELOCITY
+ draw_smoke_velocity(smd->domain, ob);
+ #endif
+ #ifdef SMOKE_DEBUG_HEAT
+ draw_smoke_heat(smd->domain, ob);
+ #endif
}
}
}
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 2c2d4039225..7215e8ec6b4 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -36,6 +36,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_smoke_types.h"
#include "DNA_view3d_types.h"
#include "BLI_utildefines.h"
@@ -156,12 +157,9 @@ static int convex(const float p0[3], const float up[3], const float a[3], const
return dot_v3v3(up, tmp) >= 0;
}
-void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int res[3], float dx, GPUTexture *tex_shadow)
+void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, ARegion *ar, GPUTexture *tex, float min[3], float max[3], int res[3], float dx, float base_scale, float viewnormal[3], GPUTexture *tex_shadow, GPUTexture *tex_flame)
{
- RegionView3D *rv3d = ar->regiondata;
-
- float viewnormal[3];
- int i, j, n, good_index;
+ int i, j, k, n, good_index;
float d /*, d0 */ /* UNUSED */, dd, ds;
float *points = NULL;
int numpoints = 0;
@@ -193,24 +191,72 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
{{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}
};
+ unsigned char *spec_data;
+ float *spec_pixels;
+ GPUTexture *tex_spec;
+
/* Fragment program to calculate the view3d of smoke */
- /* using 2 textures, density and shadow */
- const char *text = "!!ARBfp1.0\n"
+ /* using 4 textures, density, shadow, flame and flame spectrum */
+ const char *shader_basic = "!!ARBfp1.0\n"
"PARAM dx = program.local[0];\n"
"PARAM darkness = program.local[1];\n"
+ "PARAM render = program.local[2];\n"
"PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n"
- "TEMP temp, shadow, value;\n"
+ "TEMP temp, shadow, flame, spec, value;\n"
"TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
"TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
- "MUL value, temp, darkness;\n"
- "MUL value, value, dx;\n"
- "MUL value, value, f;\n"
+ "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
+ "TEX spec, flame.r, texture[3], 1D;\n"
+ /* calculate shading factor from density */
+ "MUL value.r, temp.a, darkness.a;\n"
+ "MUL value.r, value.r, dx.r;\n"
+ "MUL value.r, value.r, f.r;\n"
"EX2 temp, -value.r;\n"
- "SUB temp.a, 1.0, temp.r;\n"
+ /* alpha */
+ "SUB temp.a, 1.0, temp.r;\n"
+ /* shade colors */
+ "MUL temp.r, temp.r, shadow.r;\n"
+ "MUL temp.g, temp.g, shadow.r;\n"
+ "MUL temp.b, temp.b, shadow.r;\n"
+ "MUL temp.r, temp.r, darkness.r;\n"
+ "MUL temp.g, temp.g, darkness.g;\n"
+ "MUL temp.b, temp.b, darkness.b;\n"
+ /* for now this just replace smoke shading if rendering fire */
+ "CMP result.color, render.r, temp, spec;\n"
+ "END\n";
+
+ /* color shader */
+ const char *shader_color = "!!ARBfp1.0\n"
+ "PARAM dx = program.local[0];\n"
+ "PARAM darkness = program.local[1];\n"
+ "PARAM render = program.local[2];\n"
+ "PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n"
+ "TEMP temp, shadow, flame, spec, value;\n"
+ "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
+ "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
+ "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
+ "TEX spec, flame.r, texture[3], 1D;\n"
+ /* unpremultiply volume texture */
+ "RCP value.r, temp.a;\n"
+ "MUL temp.r, temp.r, value.r;\n"
+ "MUL temp.g, temp.g, value.r;\n"
+ "MUL temp.b, temp.b, value.r;\n"
+ /* calculate shading factor from density */
+ "MUL value.r, temp.a, darkness.a;\n"
+ "MUL value.r, value.r, dx.r;\n"
+ "MUL value.r, value.r, f.r;\n"
+ "EX2 value.r, -value.r;\n"
+ /* alpha */
+ "SUB temp.a, 1.0, value.r;\n"
+ /* shade colors */
"MUL temp.r, temp.r, shadow.r;\n"
"MUL temp.g, temp.g, shadow.r;\n"
"MUL temp.b, temp.b, shadow.r;\n"
- "MOV result.color, temp;\n"
+ "MUL temp.r, temp.r, value.r;\n"
+ "MUL temp.g, temp.g, value.r;\n"
+ "MUL temp.b, temp.b, value.r;\n"
+ /* for now this just replace smoke shading if rendering fire */
+ "CMP result.color, render.r, temp, spec;\n"
"END\n";
GLuint prog;
@@ -223,6 +269,32 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
}
tstart();
+ /* generate flame spectrum texture */
+ #define SPEC_WIDTH 256
+ #define FIRE_THRESH 7
+ #define MAX_FIRE_ALPHA 0.06f
+ #define FULL_ON_FIRE 100
+ spec_data = malloc(SPEC_WIDTH*4 * sizeof(unsigned char));
+ flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000);
+ spec_pixels = malloc(SPEC_WIDTH*4*16*16 * sizeof(float));
+ for (i=0;i<16;i++){
+ for (j=0;j<16;j++) {
+ for (k=0;k<SPEC_WIDTH;k++) {
+ int index = (j*SPEC_WIDTH*16+i*SPEC_WIDTH+k)*4;
+ if (k>=FIRE_THRESH) {
+ spec_pixels[index] = ((float)spec_data[k*4])/255.0f;
+ spec_pixels[index+1] = ((float)spec_data[k*4+1])/255.0f;
+ spec_pixels[index+2] = ((float)spec_data[k*4+2])/255.0f;
+ spec_pixels[index+3] = MAX_FIRE_ALPHA*(
+ (k>FULL_ON_FIRE) ? 1.0f : (k-FIRE_THRESH)/((float)FULL_ON_FIRE-FIRE_THRESH));
+ } else {
+ spec_pixels[index] = spec_pixels[index+1] = spec_pixels[index+2] = spec_pixels[index+3] = 0.0f;
+ }
+ }
+ }
+ }
+
+ tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL);
sub_v3_v3v3(size, max, min);
@@ -294,26 +366,11 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
edges[11][1][0] = size[0];
glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
- glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
-
- glLoadMatrixf(rv3d->viewmat);
- // glMultMatrixf(ob->obmat);
+ glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-#if 0
- printf("Viewinv:\n");
- printf("%f, %f, %f\n", rv3d->viewinv[0][0], rv3d->viewinv[0][1], rv3d->viewinv[0][2]);
- printf("%f, %f, %f\n", rv3d->viewinv[1][0], rv3d->viewinv[1][1], rv3d->viewinv[1][2]);
- printf("%f, %f, %f\n", rv3d->viewinv[2][0], rv3d->viewinv[2][1], rv3d->viewinv[2][2]);
-#endif
-
- /* get view vector */
- copy_v3_v3(viewnormal, rv3d->viewinv[2]);
- normalize_v3(viewnormal);
/* find cube vertex that is closest to the viewer */
for (i = 0; i < 8; i++) {
@@ -344,12 +401,19 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
glGenProgramsARB(1, &prog);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
- glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(text), text);
+ /* set shader */
+ if (sds->active_fields & SM_ACTIVE_COLORS)
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color);
+ else
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic);
/* cell spacing */
glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0);
/* custom parameter for smoke style (higher = thicker) */
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 7.0, 7.0, 7.0, 1.0);
+ if (sds->active_fields & SM_ACTIVE_COLORS)
+ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0);
+ else
+ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
}
else
printf("Your gfx card does not support 3D View smoke drawing.\n");
@@ -360,6 +424,11 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
else
printf("No volume shadow\n");
+ if (tex_flame) {
+ GPU_texture_bind(tex_flame, 2);
+ GPU_texture_bind(tex_spec, 3);
+ }
+
if (!GPU_non_power_of_two_support()) {
cor[0] = (float)res[0] / (float)power_of_2_max_i(res[0]);
cor[1] = (float)res[1] / (float)power_of_2_max_i(res[1]);
@@ -373,7 +442,7 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
/* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */
ds = (ABS(viewnormal[0]) * size[0] + ABS(viewnormal[1]) * size[1] + ABS(viewnormal[2]) * size[2]);
- dd = ds / 96.f;
+ dd = MAX3(sds->global_size[0],sds->global_size[1],sds->global_size[2])/128.f;
n = 0;
good_index = i;
@@ -416,14 +485,29 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
}
}
- // printf("numpoints: %d\n", numpoints);
+ /* render fire slice */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
for (i = 0; i < numpoints; i++) {
glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0],
(points[i * 3 + 1] - min[1]) * cor[1] / size[1],
(points[i * 3 + 2] - min[2]) * cor[2] / size[2]);
- glVertex3f(points[i * 3 + 0], points[i * 3 + 1], points[i * 3 + 2]);
+ glVertex3f(points[i * 3 + 0]/ob->size[0], points[i * 3 + 1]/ob->size[1], points[i * 3 + 2]/ob->size[2]);
+ }
+ glEnd();
+
+ /* render smoke slice */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0);
+ glBegin(GL_POLYGON);
+ glColor3f(1.0, 1.0, 1.0);
+ for (i = 0; i < numpoints; i++) {
+ glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0],
+ (points[i * 3 + 1] - min[1]) * cor[1] / size[1],
+ (points[i * 3 + 2] - min[2]) * cor[2] / size[2]);
+ glVertex3f(points[i * 3 + 0]/ob->size[0], points[i * 3 + 1]/ob->size[1], points[i * 3 + 2]/ob->size[2]);
}
glEnd();
}
@@ -436,6 +520,14 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
if (tex_shadow)
GPU_texture_unbind(tex_shadow);
GPU_texture_unbind(tex);
+ if (tex_flame) {
+ GPU_texture_unbind(tex_flame);
+ GPU_texture_unbind(tex_spec);
+ }
+ GPU_texture_free(tex_spec);
+
+ free(spec_data);
+ free(spec_pixels);
if (GLEW_ARB_fragment_program) {
glDisable(GL_FRAGMENT_PROGRAM_ARB);
@@ -454,3 +546,106 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
glDepthMask(GL_TRUE);
}
}
+
+#ifdef SMOKE_DEBUG_VELOCITY
+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)MAX3(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();
+ }
+ }
+}
+#endif
+
+#ifdef SMOKE_DEBUG_HEAT
+void draw_smoke_heat(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 *heat = smoke_get_heat(domain->fluid);
+
+ float min[3];
+ float *cell_size = domain->cell_size;
+ float step_size = ((float)MAX3(base_res[0], base_res[1], base_res[2]))/16.f;
+ float vf = domain->scale / 16.f * 2.f; /* velocity factor */
+
+ /* 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]};
+
+ /* draw heat as different sized points */
+ if (heat[index] >= 0.01f) {
+ float col_gb = 1.0f - heat[index];
+ CLAMP(col_gb, 0.0f, 1.0f);
+ glColor3f(1.0f, col_gb, col_gb);
+ glPointSize(24.0f * heat[index]);
+
+ glBegin(GL_POINTS);
+ glVertex3f(pos[0], pos[1], pos[2]);
+ glEnd();
+ }
+ }
+}
+#endif
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 5bfabf4fc4a..8d7a6421a34 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -212,7 +212,16 @@ ARegion *view3d_has_tools_region(ScrArea *sa);
extern const char *view3d_context_dir[]; /* doc access */
/* draw_volume.c */
-void draw_volume(struct ARegion *ar, struct GPUTexture *tex, float min[3], float max[3], int res[3], float dx, struct GPUTexture *tex_shadow);
+void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob, struct ARegion *ar, struct GPUTexture *tex, float min[3], float max[3], int res[3], float dx, float base_scale, float viewnormal[3], struct GPUTexture *tex_shadow, struct GPUTexture *tex_flame);
+//#define SMOKE_DEBUG_VELOCITY
+//#define SMOKE_DEBUG_HEAT
+
+#ifdef SMOKE_DEBUG_VELOCITY
+void draw_smoke_velocity(struct SmokeDomainSettings *domain, struct Object *ob);
+#endif
+#ifdef SMOKE_DEBUG_HEAT
+void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob);
+#endif
/* workaround for trivial but noticeable camera bug caused by imprecision
* between view border calculation in 2D/3D space, workaround for bug [#28037].
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 198d002ff0d..f4bb5da0495 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -107,7 +107,7 @@ int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver);
GPUTexture *GPU_texture_create_1D(int w, float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_2D(int w, int h, float *pixels, char err_out[256]);
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels);
+GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *fpixels);
GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]);
GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
GPUTexture *GPU_texture_from_blender(struct Image *ima,
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 956c76aec20..ac05f1e8309 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -1019,21 +1019,53 @@ void GPU_free_smoke(SmokeModifierData *smd)
if (smd->domain->tex_shadow)
GPU_texture_free(smd->domain->tex_shadow);
smd->domain->tex_shadow = NULL;
+
+ if (smd->domain->tex_flame)
+ GPU_texture_free(smd->domain->tex_flame);
+ smd->domain->tex_flame = NULL;
}
}
void GPU_create_smoke(SmokeModifierData *smd, int highres)
{
#ifdef WITH_SMOKE
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN && !smd->domain->tex && !highres)
- smd->domain->tex = GPU_texture_create_3D(smd->domain->res[0], smd->domain->res[1], smd->domain->res[2], smoke_get_density(smd->domain->fluid));
- else if (smd->type & MOD_SMOKE_TYPE_DOMAIN && !smd->domain->tex && highres)
- smd->domain->tex = GPU_texture_create_3D(smd->domain->res_wt[0], smd->domain->res_wt[1], smd->domain->res_wt[2], smoke_turbulence_get_density(smd->domain->wt));
+ if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
+ SmokeDomainSettings *sds = smd->domain;
+ if (!sds->tex && !highres) {
+ /* rgba texture for color + density */
+ if (smoke_has_colors(sds->fluid)) {
+ float *data = MEM_callocN(sizeof(float)*sds->total_cells*4, "smokeColorTexture");
+ smoke_get_rgba(sds->fluid, data, 0);
+ sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data);
+ MEM_freeN(data);
+ }
+ /* density only */
+ else {
+ sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_density(sds->fluid));
+ }
+ sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_flame(sds->fluid)) : NULL;
+ }
+ else if (!sds->tex && highres) {
+ /* rgba texture for color + density */
+ if (smoke_turbulence_has_colors(sds->wt)) {
+ float *data = MEM_callocN(sizeof(float)*smoke_turbulence_get_cells(sds->wt)*4, "smokeColorTexture");
+ smoke_turbulence_get_rgba(sds->wt, data, 0);
+ sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data);
+ MEM_freeN(data);
+ }
+ /* density only */
+ else {
+ sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_density(sds->wt));
+ }
+ sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_flame(sds->wt)) : NULL;
+ }
- smd->domain->tex_shadow = GPU_texture_create_3D(smd->domain->res[0], smd->domain->res[1], smd->domain->res[2], smd->domain->shadow);
+ sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, sds->shadow);
+ }
#else // WITH_SMOKE
(void)highres;
smd->domain->tex= NULL;
+ smd->domain->tex_flame= NULL;
smd->domain->tex_shadow= NULL;
#endif // WITH_SMOKE
}
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index c5f427fbcab..798868a5efe 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -442,7 +442,7 @@ static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, in
}
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels)
+GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *fpixels)
{
GPUTexture *tex;
GLenum type, format, internalformat;
@@ -480,9 +480,15 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels)
GPU_print_error("3D glBindTexture");
- type = GL_FLOAT; // GL_UNSIGNED_BYTE
- format = GL_RED;
- internalformat = GL_INTENSITY;
+ type = GL_FLOAT;
+ if (channels == 4) {
+ format = GL_RGBA;
+ internalformat = GL_RGBA;
+ }
+ else {
+ format = GL_RED;
+ internalformat = GL_INTENSITY;
+ }
//if (fpixels)
// pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h
index 1dd2aa6c59b..67d540db177 100644
--- a/source/blender/makesdna/DNA_object_force.h
+++ b/source/blender/makesdna/DNA_object_force.h
@@ -54,6 +54,7 @@ typedef enum PFieldType {
PFIELD_BOID = 10, /* Defines predator / goal for boids */
PFIELD_TURBULENCE = 11, /* Force defined by BLI_gTurbulence */
PFIELD_DRAG = 12, /* Linear & quadratic drag */
+ PFIELD_SMOKEFLOW = 13, /* Force based on smoke simulation air flow */
NUM_PFIELD_TYPES
} PFieldType;
@@ -110,14 +111,17 @@ typedef struct PartDeflect {
struct RNG *rng; /* random noise generator for e.g. wind */
float f_noise; /* noise of force */
int seed; /* noise random seed */
+
+ struct Object *f_source; /* force source object */
} PartDeflect;
typedef struct EffectorWeights {
struct Group *group; /* only use effectors from this group of objects */
- float weight[13]; /* effector type specific weights */
+ float weight[14]; /* effector type specific weights */
float global_gravity;
short flag, rt[3];
+ int pad;
} EffectorWeights;
/* EffectorWeights->flag */
@@ -365,6 +369,7 @@ typedef struct SoftBody {
#define PFIELD_DO_LOCATION (1<<14)
#define PFIELD_DO_ROTATION (1<<15)
#define PFIELD_GUIDE_PATH_WEIGHT (1<<16) /* apply curve weights */
+#define PFIELD_SMOKE_DENSITY (1<<17) /* multiply smoke force by density */
/* pd->falloff */
#define PFIELD_FALL_SPHERE 0
diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h
index cceb7333478..76ba3fcf7f8 100644
--- a/source/blender/makesdna/DNA_smoke_types.h
+++ b/source/blender/makesdna/DNA_smoke_types.h
@@ -39,6 +39,7 @@
#define MOD_SMOKE_HIGH_SMOOTH (1<<5) /* smoothens high res emission*/
#define MOD_SMOKE_FILE_LOAD (1<<6) /* flag for file load */
+#define MOD_SMOKE_ADAPTIVE_DOMAIN (1<<7)
/* noise */
#define MOD_SMOKE_NOISEWAVE (1<<0)
@@ -61,6 +62,12 @@
#define SM_COLL_RIGID 1
#define SM_COLL_ANIMATED 2
+/* smoke data fileds (active_fields) */
+#define SM_ACTIVE_HEAT (1<<0)
+#define SM_ACTIVE_FIRE (1<<1)
+#define SM_ACTIVE_COLORS (1<<2)
+#define SM_ACTIVE_COLOR_SET (1<<3)
+
typedef struct SmokeDomainSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
struct FLUID_3D *fluid;
@@ -71,17 +78,37 @@ typedef struct SmokeDomainSettings {
struct GPUTexture *tex;
struct GPUTexture *tex_wt;
struct GPUTexture *tex_shadow;
+ struct GPUTexture *tex_flame;
float *shadow;
- float p0[3]; /* start point of BB */
- float p1[3]; /* end point of BB */
- float dx; /* edge length of one cell */
- float omega; /* smoke color - from 0 to 1 */
- float temp; /* fluid temperature */
- float tempAmb; /* ambient temperature */
+
+ /* simulation data */
+ float p0[3]; /* start point of BB in local space (includes sub-cell shift for adaptive domain)*/
+ float p1[3]; /* end point of BB in local space */
+ float dp0[3]; /* difference from object center to grid start point */
+ float cell_size[3]; /* size of simulation cell in local space */
+ float global_size[3]; /* global size of domain axises */
+ float prev_loc[3];
+ int shift[3]; /* current domain shift in simulation cells */
+ float shift_f[3]; /* exact domain shift */
+ float obj_shift_f[3]; /* how much object has shifted since previous smoke frame (used to "lock" domain while drawing) */
+ float imat[4][4]; /* domain object imat */
+ float obmat[4][4]; /* domain obmat */
+
+ int base_res[3]; /* initial "non-adapted" resolution */
+ int res_min[3]; /* cell min */
+ int res_max[3]; /* cell max */
+ int res[3]; /* data resolution (res_max-res_min) */
+ int total_cells;
+ float dx; /* 1.0f / res */
+ float scale; /* largest domain size */
+
+ /* user settings */
+ int adapt_margin;
+ int adapt_res;
+ float adapt_threshold;
+
float alpha;
float beta;
- float scale; /* largest domain size */
- int res[3]; /* domain resolution */
int amplify; /* wavelet amplification */
int maxres; /* longest axis on the BB gets this resolution assigned */
int flags; /* show up-res or low res, etc */
@@ -92,7 +119,6 @@ typedef struct SmokeDomainSettings {
float strength;
int res_wt[3];
float dx_wt;
- int v3dnum;
int cache_comp;
int cache_high_comp;
@@ -103,31 +129,67 @@ typedef struct SmokeDomainSettings {
int border_collisions; /* How domain border collisions are handled */
float time_scale;
float vorticity;
- int pad2;
+ int active_fields;
+ float active_color[3]; /* monitor color situation of simulation */
+ int pad;
+
+ /* flame parameters */
+ float burning_rate, flame_smoke, flame_vorticity;
+ float flame_ignition, flame_max_temp;
+ float flame_smoke_color[3];
} SmokeDomainSettings;
/* inflow / outflow */
/* type */
-#define MOD_SMOKE_FLOW_TYPE_OUTFLOW (1<<1)
+#define MOD_SMOKE_FLOW_TYPE_SMOKE 0
+#define MOD_SMOKE_FLOW_TYPE_FIRE 1
+#define MOD_SMOKE_FLOW_TYPE_OUTFLOW 2
+#define MOD_SMOKE_FLOW_TYPE_SMOKEFIRE 3
+
+/* flow source */
+#define MOD_SMOKE_FLOW_SOURCE_PARTICLES 0
+#define MOD_SMOKE_FLOW_SOURCE_MESH 1
+
+/* flow texture type */
+#define MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO 0
+#define MOD_SMOKE_FLOW_TEXTURE_MAP_UV 1
/* flags */
#define MOD_SMOKE_FLOW_ABSOLUTE (1<<1) /*old style emission*/
#define MOD_SMOKE_FLOW_INITVELOCITY (1<<2) /* passes particles speed to the smoke */
+#define MOD_SMOKE_FLOW_TEXTUREEMIT (1<<3) /* use texture to control emission speed */
typedef struct SmokeFlowSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
+ struct DerivedMesh *dm;
struct ParticleSystem *psys;
+ struct Tex *noise_texture;
+
+ /* initial velocity */
+ float *verts_old; /* previous vertex positions in domain space */
+ int numverts;
+ float vel_multi; // Multiplier for inherited velocity
+ float vel_normal;
+ float vel_random;
+ /* emission */
float density;
+ float color[3];
+ float fuel_amount;
float temp; /* delta temperature (temp - ambient temp) */
- float velocity[2]; /* UNUSED, velocity taken from particles */
- float vel_multi; // Multiplier for particle velocity
- float vgrp_heat_scale[2]; /* min and max scaling for vgroup_heat */
- short vgroup_flow; /* where inflow/outflow happens - red=1=action */
+ float volume_density; /* density emitted within mesh volume */
+ float surface_distance; /* maximum emission distance from mesh surface */
+ /* texture control */
+ float texture_size;
+ float texture_offset;
+ int pad;
+ char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
short vgroup_density;
- short vgroup_heat;
- short type; /* inflow =0 or outflow = 1 */
+
+ short type; /* smoke, flames, both, outflow */
+ short source;
+ short texture_type;
int flags; /* absolute emission etc*/
} SmokeFlowSettings;
@@ -139,20 +201,11 @@ typedef struct SmokeFlowSettings {
/* collision objects (filled with smoke) */
typedef struct SmokeCollSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
- struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */
- float *points;
- float *points_old;
- float *vel; // UNUSED
- int *tridivs;
- float mat[4][4];
- float mat_old[4][4];
- int numpoints;
- int numverts; // check if mesh changed
- int numtris;
- float dx; /* global domain cell length taken from (scale / resolution) */
+ struct DerivedMesh *dm;
+ float *verts_old;
+ int numverts;
short type; // static = 0, rigid = 1, dynamic = 2
short pad;
- int pad2;
} SmokeCollSettings;
#endif
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index 9fdd9216549..ce94a229750 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -171,6 +171,9 @@ typedef struct VoxelData {
short flag;
short extend;
short smoked_type;
+ short data_type;
+ short pad;
+ int _pad;
struct Object *object; /* for rendering smoke sims */
float int_multiplier;
@@ -470,6 +473,7 @@ typedef struct ColorMapping {
#define MTEX_BUMP_TEXTURESPACE 2048
/* #define MTEX_BUMP_FLIPPED 4096 */ /* UNUSED */
#define MTEX_BICUBIC_BUMP 8192
+#define MTEX_MAPTO_BOUNDS 16384
/* blendtype */
#define MTEX_BLEND 0
@@ -577,6 +581,11 @@ typedef struct ColorMapping {
#define TEX_VD_SMOKEDENSITY 0
#define TEX_VD_SMOKEHEAT 1
#define TEX_VD_SMOKEVEL 2
+#define TEX_VD_SMOKEFLAME 3
+
+/* data_type */
+#define TEX_VD_INTENSITY 0
+#define TEX_VD_RGBA_PREMUL 1
/******************** Ocean *****************************/
/* output */
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 96529de074b..ed40f8cffb6 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -468,6 +468,12 @@ static void rna_def_material_mtex(BlenderRNA *brna)
"from their parent");
RNA_def_property_update(prop, 0, "rna_Material_update");
+ prop = RNA_def_property(srna, "use_map_to_bounds", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_MAPTO_BOUNDS);
+ RNA_def_property_ui_text(prop, "Map to Bounds",
+ "Map coordinates in object bounds");
+ RNA_def_property_update(prop, 0, "rna_Material_update");
+
prop = RNA_def_property(srna, "use_from_original", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_OB_DUPLI_ORIG);
RNA_def_property_ui_text(prop, "From Original",
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 1b26c0447ff..8a8bb2a2384 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -257,9 +257,6 @@ static void rna_Smoke_set_type(Main *bmain, Scene *scene, PointerRNA *ptr)
{
SmokeModifierData *smd = (SmokeModifierData *)ptr->data;
Object *ob = (Object *)ptr->id.data;
- ParticleSystemModifierData *psmd = NULL;
- ParticleSystem *psys = NULL;
- ParticleSettings *part = NULL;
/* nothing changed */
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
@@ -273,28 +270,6 @@ static void rna_Smoke_set_type(Main *bmain, Scene *scene, PointerRNA *ptr)
ob->dt = OB_WIRE;
break;
case MOD_SMOKE_TYPE_FLOW:
- for (psys = ob->particlesystem.first; psys; psys = psys->next)
- if (psys->part->type == PART_EMITTER)
- break;
- if (ob->type == OB_MESH && !psys) {
- /* add particle system */
- psmd = (ParticleSystemModifierData *)object_add_particle_system(scene, ob, NULL);
- if (psmd) {
- psys = psmd->psys;
- part = psys->part;
- part->lifetime = 1.0f;
- part->sta = 1.0f;
- part->end = 250.0f;
- part->ren_as = PART_DRAW_NOT;
- part->flag |= PART_UNBORN;
- part->draw_as = PART_DRAW_DOT;
- BLI_strncpy(psys->name, "SmokeParticles", sizeof(psys->name));
- psys->recalc |= (PSYS_RECALC_RESET | PSYS_RECALC_PHYS);
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
- }
- }
- if (smd->flow)
- smd->flow->psys = psys;
case MOD_SMOKE_TYPE_COLL:
case 0:
default:
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 39f85ebc742..940d59ec9b3 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -1056,6 +1056,13 @@ static void rna_def_effector_weight(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_ui_text(prop, "Drag", "Drag effector weight");
RNA_def_property_update(prop, 0, "rna_EffectorWeight_update");
+
+ prop = RNA_def_property(srna, "smokeflow", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "weight[13]");
+ RNA_def_property_range(prop, -200.0f, 200.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Smoke Flow", "Smoke Flow effector weight");
+ RNA_def_property_update(prop, 0, "rna_EffectorWeight_update");
}
static void rna_def_field(BlenderRNA *brna)
@@ -1082,6 +1089,7 @@ static void rna_def_field(BlenderRNA *brna)
{PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""},
{PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", "Create turbulence with a noise field"},
{PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", "Create a force that dampens motion"},
+ {PFIELD_SMOKEFLOW, "SMOKE_FLOW", ICON_FORCE_SMOKEFLOW, "Smoke Flow", "Create a force based on smoke simulation air flow"},
{0, NULL, 0, NULL, NULL}
};
@@ -1334,6 +1342,11 @@ static void rna_def_field(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_MULTIPLE_SPRINGS);
RNA_def_property_ui_text(prop, "Multiple Springs", "Every point is effected by multiple springs");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
+
+ prop = RNA_def_property(srna, "use_smoke_density", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_SMOKE_DENSITY);
+ RNA_def_property_ui_text(prop, "Apply Density", "Adjust force strength based on smoke density");
+ RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
/* Pointer */
@@ -1342,6 +1355,12 @@ static void rna_def_field(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Texture", "Texture to use as force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
+
+ prop = RNA_def_property(srna, "source_object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "f_source");
+ RNA_def_property_ui_text(prop, "Domain Object", "Select domain object of the smoke simulation");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
/********** Curve Guide Field Settings **********/
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index e8818248609..417530acc14 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -65,14 +65,20 @@ static void rna_Smoke_dependency_update(Main *bmain, Scene *scene, PointerRNA *p
DAG_scene_sort(bmain, scene);
}
+static void rna_Smoke_resetCache(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
+ if (settings->smd && settings->smd->domain)
+ settings->point_cache[0]->flag |= PTCACHE_OUTDATED;
+ DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+}
+
static void rna_Smoke_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
{
SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
smokeModifier_reset(settings->smd);
-
- if (settings->smd && settings->smd->domain)
- settings->point_cache[0]->flag |= PTCACHE_OUTDATED;
+ rna_Smoke_resetCache(bmain, scene, ptr);
rna_Smoke_update(bmain, scene, ptr);
}
@@ -142,6 +148,30 @@ static void rna_SmokeModifier_density_get(PointerRNA *ptr, float *values)
memcpy(values, density, size * sizeof(float));
}
+static void rna_SmokeFlow_density_vgroup_get(PointerRNA *ptr, char *value)
+{
+ SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
+ rna_object_vgroup_name_index_get(ptr, value, flow->vgroup_density);
+}
+
+static int rna_SmokeFlow_density_vgroup_length(PointerRNA *ptr)
+{
+ SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
+ return rna_object_vgroup_name_index_length(ptr, flow->vgroup_density);
+}
+
+static void rna_SmokeFlow_density_vgroup_set(PointerRNA *ptr, const char *value)
+{
+ SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
+ rna_object_vgroup_name_index_set(ptr, value, &flow->vgroup_density);
+}
+
+static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value)
+{
+ SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
+ rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name));
+}
+
#else
static void rna_def_smoke_domain_settings(BlenderRNA *brna)
@@ -217,7 +247,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
RNA_def_property_ui_text(prop, "Density",
"How much density affects smoke motion (higher value results in faster rising smoke)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "beta", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "beta");
@@ -225,7 +255,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
RNA_def_property_ui_text(prop, "Heat",
"How much heat affects smoke motion (higher value results in faster rising smoke)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "collision_group", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "coll_group");
@@ -253,24 +283,24 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
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 noise");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
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, 10000.0);
RNA_def_property_ui_range(prop, 1.0, 10000.0, 1, 0);
RNA_def_property_ui_text(prop, "Dissolve Speed", "Dissolve Speed");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "use_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, "rna_Smoke_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "use_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, "rna_Smoke_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -297,21 +327,21 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "smooth_emitter", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGH_SMOOTH);
RNA_def_property_ui_text(prop, "Smooth Emitter", "Smooth emitted smoke to avoid blockiness");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
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");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
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");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 32);
@@ -321,25 +351,80 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, "rna_SmokeModifier_density_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Density", "Smoke density");
- prop = RNA_def_property(srna, "cell_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "dx");
+ prop = RNA_def_property(srna, "cell_size", PROP_FLOAT, PROP_XYZ); /* can change each frame when using adaptive domain */
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "dx", "Cell Size");
+ RNA_def_property_ui_text(prop, "cell_size", "Cell Size");
- prop = RNA_def_property(srna, "start_point", PROP_FLOAT, PROP_XYZ);
+ prop = RNA_def_property(srna, "start_point", PROP_FLOAT, PROP_XYZ); /* can change each frame when using adaptive domain */
RNA_def_property_float_sdna(prop, NULL, "p0");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "p0", "Start point");
- prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "scale");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "scale", "Domain scale factor");
-
- prop = RNA_def_property(srna, "domain_resolution", PROP_INT, PROP_XYZ);
+ prop = RNA_def_property(srna, "domain_resolution", PROP_INT, PROP_XYZ); /* can change each frame when using adaptive domain */
RNA_def_property_int_sdna(prop, NULL, "res");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "res", "Smoke Grid Resolution");
+
+ prop = RNA_def_property(srna, "burning_rate", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.01, 4.0);
+ RNA_def_property_ui_range(prop, 0.01, 2.0, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Speed", "Speed of the burning reaction. Use larger values for smaller flame");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "flame_smoke", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 8.0);
+ RNA_def_property_ui_range(prop, 0.0, 4.0, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Smoke", "Amount of smoke created by burning fuel");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "flame_vorticity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Vorticity", "Additional vorticity for the flames");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "flame_ignition", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.5, 5.0);
+ RNA_def_property_ui_range(prop, 0.5, 2.5, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Ignition", "Minimum temperature of flames");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "flame_max_temp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 1.0, 10.0);
+ RNA_def_property_ui_range(prop, 1.0, 5.0, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Maximum", "Maximum temperature of flames");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "flame_smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke emitted from burning fuel");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "use_adaptive_domain", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_ADAPTIVE_DOMAIN);
+ RNA_def_property_ui_text(prop, "Adaptive Domain", "Adapt simulation resolution and size to fluid");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "additional_res", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "adapt_res");
+ RNA_def_property_range(prop, 0, 512);
+ RNA_def_property_ui_range(prop, 0, 512, 2, 0);
+ RNA_def_property_ui_text(prop, "Additional", "Maximum number of additional cells");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "adapt_margin", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "adapt_margin");
+ RNA_def_property_range(prop, 2, 24);
+ RNA_def_property_ui_range(prop, 2, 24, 2, 0);
+ RNA_def_property_ui_text(prop, "Margin", "Margin added around fluid to minimize boundary interference");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "adapt_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.01, 0.5);
+ RNA_def_property_ui_range(prop, 0.01, 0.5, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Threshold", "Maximum amount of fluid cell can contain before it's considered empty");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
}
static void rna_def_smoke_flow_settings(BlenderRNA *brna)
@@ -347,6 +432,26 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ static EnumPropertyItem smoke_flow_types[] = {
+ {MOD_SMOKE_FLOW_TYPE_OUTFLOW, "OUTFLOW", 0, "Outflow", "Delete smoke from simulation"},
+ {MOD_SMOKE_FLOW_TYPE_SMOKE, "SMOKE", 0, "Smoke", "Add smoke"},
+ {MOD_SMOKE_FLOW_TYPE_SMOKEFIRE, "BOTH", 0, "Fire + Smoke", "Add fire and smoke"},
+ {MOD_SMOKE_FLOW_TYPE_FIRE, "FIRE", 0, "Fire", "Add fire"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem smoke_flow_sources[] = {
+ {MOD_SMOKE_FLOW_SOURCE_PARTICLES, "PARTICLES", ICON_PARTICLES, "Particle System", "Emit smoke from particles"},
+ {MOD_SMOKE_FLOW_SOURCE_MESH, "MESH", ICON_META_CUBE, "Mesh", "Emit smoke from mesh surface or volume"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem smoke_flow_texture_types[] = {
+ {MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO, "AUTO", 0, "Generated", "Generated coordinates centered to flow object"},
+ {MOD_SMOKE_FLOW_TEXTURE_MAP_UV, "UV", 0, "UV", "Use UV layer for texture coordinates"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "SmokeFlowSettings", NULL);
RNA_def_struct_ui_text(srna, "Flow Settings", "Smoke flow settings");
RNA_def_struct_sdna(srna, "SmokeFlowSettings");
@@ -354,11 +459,23 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "density");
- RNA_def_property_range(prop, 0.001, 1);
- RNA_def_property_ui_range(prop, 0.001, 1.0, 1.0, 4);
+ RNA_def_property_range(prop, 0.0, 1);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 4);
RNA_def_property_ui_text(prop, "Density", "");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+ prop = RNA_def_property(srna, "smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "color");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "fuel_amount", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10);
+ RNA_def_property_ui_range(prop, 0.0, 5.0, 1.0, 4);
+ RNA_def_property_ui_text(prop, "Flame Rate", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
prop = RNA_def_property(srna, "temperature", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "temp");
RNA_def_property_range(prop, -10, 10);
@@ -373,9 +490,16 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Particle Systems", "Particle systems emitted from the object");
RNA_def_property_update(prop, 0, "rna_Smoke_reset_dependancy");
- prop = RNA_def_property(srna, "use_outflow", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "type", MOD_SMOKE_FLOW_TYPE_OUTFLOW);
- RNA_def_property_ui_text(prop, "Outflow", "Delete smoke from simulation");
+ prop = RNA_def_property(srna, "smoke_flow_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, smoke_flow_types);
+ RNA_def_property_ui_text(prop, "Flow Type", "Change how flow affects the simulation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "smoke_flow_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "source");
+ RNA_def_property_enum_items(prop, smoke_flow_sources);
+ RNA_def_property_ui_text(prop, "Source", "Change how smoke is emitted");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "use_absolute", PROP_BOOLEAN, PROP_NONE);
@@ -385,14 +509,82 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "initial_velocity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_INITVELOCITY);
- RNA_def_property_ui_text(prop, "Initial Velocity", "Smoke inherits its velocity from the emitter particle");
+ RNA_def_property_ui_text(prop, "Initial Velocity", "Smoke has some initial velocity when it is emitted");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "velocity_factor", 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_ui_text(prop, "Source", "Multiplier of source velocity passed to smoke");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "velocity_normal", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vel_normal");
+ 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, "Normal", "Amount of normal directional velocity");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "velocity_random", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vel_random");
+ RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_ui_range(prop, 0.0, 2.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Random", "Amount of random velocity");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "volume_density", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Volume", "Factor for smoke emitted from inside the mesh volume");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.5, 10.0);
+ RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Surface", "Maximum distance from mesh surface to emit smoke");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "density_vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_SmokeFlow_density_vgroup_get",
+ "rna_SmokeFlow_density_vgroup_length",
+ "rna_SmokeFlow_density_vgroup_set");
+ RNA_def_property_ui_text(prop, "Vertex Group",
+ "Name of Vertex Group which determines surface emission rate");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "use_texture", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_TEXTUREEMIT);
+ RNA_def_property_ui_text(prop, "Use Texture", "Use a texture to controll emission strength");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "texture_map_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "texture_type");
+ RNA_def_property_enum_items(prop, smoke_flow_texture_types);
+ RNA_def_property_ui_text(prop, "Mapping", "Texture mapping type");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "uvlayer_name");
+ RNA_def_property_ui_text(prop, "UV Map", "UV map name");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SmokeFlow_uvlayer_set");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "noise_texture", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Texture", "Texture that controls emission strength");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "texture_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.01, 10.0);
+ RNA_def_property_ui_range(prop, 0.1, 5.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Size", "Size of texture mapping");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 200.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 0.05, 5);
+ RNA_def_property_ui_text(prop, "Offset", "Z-offset of texture mapping");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
}
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 202c53cb75d..e77c5d13a6b 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -1800,7 +1800,8 @@ static void rna_def_texture_voxeldata(BlenderRNA *brna)
};
static EnumPropertyItem smoked_type_items[] = {
- {TEX_VD_SMOKEDENSITY, "SMOKEDENSITY", 0, "Density", "Use smoke density as texture data"},
+ {TEX_VD_SMOKEDENSITY, "SMOKEDENSITY", 0, "Smoke", "Use smoke density and color as texture data"},
+ {TEX_VD_SMOKEFLAME, "SMOKEFLAME", 0, "Flame", "Use flame temperature as texture data"},
{TEX_VD_SMOKEHEAT, "SMOKEHEAT", 0, "Heat", "Use smoke heat as texture data. Values from -2.0 to 2.0 are used"},
{TEX_VD_SMOKEVEL, "SMOKEVEL", 0, "Velocity", "Use smoke velocity as texture data"},
{0, NULL, 0, NULL, NULL}
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c
index b9b3b89e06d..4b2ce47b8d9 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -81,19 +81,31 @@ static void freeData(ModifierData *md)
smokeModifier_free(smd);
}
-static void deformVerts(ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- float (*vertexCos)[3],
- int UNUSED(numVerts),
- ModifierApplyFlag UNUSED(flag))
+static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
- SmokeModifierData *smd = (SmokeModifierData *) md;
- DerivedMesh *dm = get_cddm(ob, NULL, derivedData, vertexCos);
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ CustomDataMask dataMask = 0;
+
+ if (smd && (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
+ if (smd->flow->source == MOD_SMOKE_FLOW_SOURCE_MESH) {
+ /* vertex groups */
+ if (smd->flow->vgroup_density)
+ dataMask |= CD_MASK_MDEFORMVERT;
+ /* uv layer */
+ if (smd->flow->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_UV)
+ dataMask |= CD_MASK_MTFACE;
+ }
+ }
+ return dataMask;
+}
- smokeModifier_do(smd, md->scene, ob, dm);
+static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
+ DerivedMesh *dm,
+ ModifierApplyFlag UNUSED(flag))
+{
+ SmokeModifierData *smd = (SmokeModifierData *) md;
- if (dm != derivedData)
- dm->release(dm);
+ return smokeModifier_do(smd, md->scene, ob, dm);
}
static int dependsOnTime(ModifierData *UNUSED(md))
@@ -102,11 +114,11 @@ static int dependsOnTime(ModifierData *UNUSED(md))
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Scene *scene,
- Object *UNUSED(ob),
+ struct Scene *scene, struct Object *ob,
DagNode *obNode)
{
SmokeModifierData *smd = (SmokeModifierData *) md;
+ Base *base;
if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
if (smd->domain->fluid_group || smd->domain->coll_group) {
@@ -139,8 +151,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
else {
- Base *base = scene->base.first;
-
+ base = scene->base.first;
for (; base; base = base->next) {
SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(base->object, eModifierType_Smoke);
@@ -150,6 +161,14 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
}
+ /* add relation to all "smoke flow" force fields */
+ base = scene->base.first;
+ for (; base; base = base->next) {
+ if (base->object->pd && base->object->pd->forcefield == PFIELD_SMOKEFLOW && base->object->pd->f_source == ob) {
+ DagNode *node2 = dag_get_node(forest, base->object);
+ dag_add_relation(forest, obNode, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Source Object");
+ }
+ }
}
}
@@ -167,26 +186,30 @@ static void foreachIDLink(ModifierData *md, Object *ob,
walk(userData, ob, (ID **)&smd->domain->effector_weights->group);
}
}
+
+ if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) {
+ walk(userData, ob, (ID **)&smd->flow->noise_texture);
+ }
}
ModifierTypeInfo modifierType_Smoke = {
/* name */ "Smoke",
/* structName */ "SmokeModifierData",
/* structSize */ sizeof(SmokeModifierData),
- /* type */ eModifierTypeType_OnlyDeform,
+ /* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_UsesPointCache |
eModifierTypeFlag_Single,
/* copyData */ copyData,
- /* deformVerts */ deformVerts,
+ /* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* applyModifier */ applyModifier,
/* applyModifierEM */ NULL,
/* initData */ initData,
- /* requiredDataMask */ NULL,
+ /* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 3e2ce95af50..9bd2395ca79 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -2660,6 +2660,13 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
mul_m4_v3(shi->obi->duplitexmat, co);
}
mul_m4_v3(ob->imat_ren, co);
+
+ if (mtex->texflag & MTEX_MAPTO_BOUNDS && ob->bb) {
+ /* use bb vec[0] as min and bb vec[6] as max */
+ co[0] = (co[0] - ob->bb->vec[0][0]) / (ob->bb->vec[6][0]-ob->bb->vec[0][0]) * 2.0f - 1.0f;
+ co[1] = (co[1] - ob->bb->vec[0][1]) / (ob->bb->vec[6][1]-ob->bb->vec[0][1]) * 2.0f - 1.0f;
+ co[2] = (co[2] - ob->bb->vec[0][2]) / (ob->bb->vec[6][2]-ob->bb->vec[0][2]) * 2.0f - 1.0f;
+ }
}
}
/* not really orco, but 'local' */
@@ -2672,6 +2679,13 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
Object *ob= shi->obi->ob;
copy_v3_v3(co, xyz);
mul_m4_v3(ob->imat_ren, co);
+
+ if (mtex->texflag & MTEX_MAPTO_BOUNDS && ob->bb) {
+ /* use bb vec[0] as min and bb vec[6] as max */
+ co[0] = (co[0] - ob->bb->vec[0][0]) / (ob->bb->vec[6][0]-ob->bb->vec[0][0]) * 2.0f - 1.0f;
+ co[1] = (co[1] - ob->bb->vec[0][1]) / (ob->bb->vec[6][1]-ob->bb->vec[0][1]) * 2.0f - 1.0f;
+ co[2] = (co[2] - ob->bb->vec[0][2]) / (ob->bb->vec[6][2]-ob->bb->vec[0][2]) * 2.0f - 1.0f;
+ }
}
}
else if (mtex->texco==TEXCO_GLOB) {
@@ -2738,6 +2752,12 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
if ((rgbnor & TEX_RGB) == 0) {
copy_v3_v3(tcol, &mtex->r);
}
+ else if (mtex->mapto & MAP_DENSITY) {
+ copy_v3_v3(tcol, &texres.tr);
+ if (texres.talpha) {
+ texres.tin = stencilTin;
+ }
+ }
else {
copy_v3_v3(tcol, &texres.tr);
if (texres.talpha) {
diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c
index d73171648fb..7eccacb816d 100644
--- a/source/blender/render/intern/source/voxeldata.c
+++ b/source/blender/render/intern/source/voxeldata.c
@@ -227,69 +227,102 @@ static void init_frame_smoke(VoxelData *vd, float cfra)
/* draw code for smoke */
if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke))) {
SmokeModifierData *smd = (SmokeModifierData *)md;
-
+ SmokeDomainSettings *sds = smd->domain;
- if (smd->domain && smd->domain->fluid) {
- if (cfra < smd->domain->point_cache[0]->startframe)
+ if (sds && sds->fluid) {
+ 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;
- copy_v3_v3_int(vd->resol, smd->domain->res);
- totRes = vd_resol_size(vd);
+ if (!smoke_has_heat(sds->fluid)) return;
- /* scaling heat values from -2.0-2.0 to 0.0-1.0 */
+ 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);
-
- heat = smoke_get_heat(smd->domain->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;
}
-
- /* 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;
- copy_v3_v3_int(vd->resol, smd->domain->res);
+ copy_v3_v3_int(vd->resol, sds->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");
+ /* get velocity data */
+ xvel = smoke_get_velocity_x(sds->fluid);
+ yvel = smoke_get_velocity_y(sds->fluid);
+ zvel = smoke_get_velocity_z(sds->fluid);
- xvel = smoke_get_velocity_x(smd->domain->fluid);
- yvel = smoke_get_velocity_y(smd->domain->fluid);
- zvel = smoke_get_velocity_z(smd->domain->fluid);
-
+ /* map velocities between 0 and 0.3f */
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 {
+ else if (vd->smoked_type == TEX_VD_SMOKEFLAME) {
size_t totRes;
- float *density;
+ float *flame;
- if (smd->domain->flags & MOD_SMOKE_HIGHRES) {
- smoke_turbulence_get_res(smd->domain->wt, vd->resol);
- density = smoke_turbulence_get_density(smd->domain->wt);
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ if (!smoke_turbulence_has_fuel(sds->wt)) return;
+ smoke_turbulence_get_res(sds->wt, vd->resol);
+ flame = smoke_turbulence_get_flame(sds->wt);
}
else {
- copy_v3_v3_int(vd->resol, smd->domain->res);
- density = smoke_get_density(smd->domain->fluid);
+ if (!smoke_has_fuel(sds->fluid)) 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 */
- totRes = vd_resol_size(vd);
+ totCells = vd_resol_size(vd) * depth;
/* 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);
+ 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 */
}
}
@@ -320,6 +353,8 @@ void cache_voxeldata(Tex *tex, int scene_frame)
MEM_freeN(vd->dataset);
vd->dataset = NULL;
}
+ /* reset data_type */
+ vd->data_type = TEX_VD_INTENSITY;
if (vd->flag & TEX_VD_STILL)
curframe = vd->still_frame;
@@ -379,9 +414,11 @@ void make_voxeldata(struct Render *re)
int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres)
{
- int retval = TEX_INT;
VoxelData *vd = tex->vd;
- float co[3], offset[3] = {0.5, 0.5, 0.5};
+ float co[3], offset[3] = {0.5, 0.5, 0.5}, a;
+ int retval = (vd->data_type == TEX_VD_RGBA_PREMUL) ? TEX_RGB : TEX_INT;
+ int depth = (vd->data_type == TEX_VD_RGBA_PREMUL) ? 4 : 1;
+ int ch;
if (vd->dataset == NULL) {
texres->tin = 0.0f;
@@ -420,29 +457,61 @@ int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texre
break;
}
}
-
- switch (vd->interp_type) {
- case TEX_VD_NEARESTNEIGHBOR:
- texres->tin = BLI_voxel_sample_nearest(vd->dataset, vd->resol, co);
- break;
- case TEX_VD_LINEAR:
- texres->tin = BLI_voxel_sample_trilinear(vd->dataset, vd->resol, co);
- break;
- case TEX_VD_QUADRATIC:
- texres->tin = BLI_voxel_sample_triquadratic(vd->dataset, vd->resol, co);
- break;
- case TEX_VD_TRICUBIC_CATROM:
- case TEX_VD_TRICUBIC_BSPLINE:
- texres->tin = BLI_voxel_sample_tricubic(vd->dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE));
- break;
+
+ for (ch = 0; ch < depth; ch++) {
+ float *dataset = vd->dataset + ch*vd->resol[0]*vd->resol[1]*vd->resol[2];
+ float *result = &texres->tin;
+
+ if (vd->data_type == TEX_VD_RGBA_PREMUL) {
+ switch (ch) {
+ case 0:
+ result = &texres->tr;
+ break;
+ case 1:
+ result = &texres->tg;
+ break;
+ case 2:
+ result = &texres->tb;
+ break;
+ }
+ }
+
+ switch (vd->interp_type) {
+ case TEX_VD_NEARESTNEIGHBOR:
+ *result = BLI_voxel_sample_nearest(dataset, vd->resol, co);
+ break;
+ case TEX_VD_LINEAR:
+ *result = BLI_voxel_sample_trilinear(dataset, vd->resol, co);
+ break;
+ case TEX_VD_QUADRATIC:
+ *result = BLI_voxel_sample_triquadratic(dataset, vd->resol, co);
+ break;
+ case TEX_VD_TRICUBIC_CATROM:
+ case TEX_VD_TRICUBIC_BSPLINE:
+ *result = BLI_voxel_sample_tricubic(dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE));
+ break;
+ }
}
-
+
+ a = texres->tin;
texres->tin *= vd->int_multiplier;
BRICONT;
- texres->tr = texres->tin;
- texres->tg = texres->tin;
- texres->tb = texres->tin;
+ if (vd->data_type == TEX_VD_RGBA_PREMUL) {
+ /* unmultiply */
+ if (a>0.001f) {
+ texres->tr /= a;
+ texres->tg /= a;
+ texres->tb /= a;
+ }
+ texres->talpha = 1;
+ }
+ else {
+ texres->tr = texres->tin;
+ texres->tg = texres->tin;
+ texres->tb = texres->tin;
+ }
+
texres->ta = texres->tin;
BRICONTRGB;