2011-02-23 10:52:22 +00:00
/*
2009-07-30 15:00:26 +00:00
* * * * * * BEGIN GPL LICENSE BLOCK * * * * *
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
2010-02-12 13:34:04 +00:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2009-07-30 15:00:26 +00:00
*
* The Original Code is Copyright ( C ) Blender Foundation .
* All rights reserved .
*
* The Original Code is : all of this file .
*
* Contributor ( s ) : Daniel Genrich
2012-04-28 21:46:43 +00:00
* Blender Foundation
2009-07-30 15:00:26 +00:00
*
* * * * * * END GPL LICENSE BLOCK * * * * *
*/
2011-02-27 20:40:57 +00:00
/** \file blender/blenkernel/intern/smoke.c
* \ ingroup bke
*/
2009-07-30 20:12:40 +00:00
/* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
2009-07-30 15:00:26 +00:00
# include <GL/glew.h>
# include "MEM_guardedalloc.h"
# include <float.h>
# include <math.h>
2010-08-13 15:26:37 +00:00
# include <stdio.h>
# include <string.h> /* memset */
2009-07-30 15:00:26 +00:00
# include "BLI_linklist.h"
# include "BLI_rand.h"
# include "BLI_jitter.h"
# include "BLI_blenlib.h"
2009-11-10 20:43:45 +00:00
# include "BLI_math.h"
2009-07-30 15:00:26 +00:00
# include "BLI_edgehash.h"
# include "BLI_kdtree.h"
# include "BLI_kdopbvh.h"
2012-02-17 21:22:18 +00:00
# include "BLI_utildefines.h"
2012-10-10 13:18:07 +00:00
# include "BLI_voxel.h"
2009-07-30 15:00:26 +00:00
# include "DNA_customdata_types.h"
# include "DNA_group_types.h"
2009-08-20 00:33:59 +00:00
# include "DNA_lamp_types.h"
2009-07-30 15:00:26 +00:00
# include "DNA_mesh_types.h"
# include "DNA_meshdata_types.h"
# include "DNA_modifier_types.h"
# include "DNA_object_types.h"
# include "DNA_particle_types.h"
# include "DNA_scene_types.h"
# include "DNA_smoke_types.h"
2012-10-10 13:18:07 +00:00
# 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"
2009-07-30 15:00:26 +00:00
# include "BKE_smoke.h"
2012-10-10 13:18:07 +00:00
# include "RE_shader_ext.h"
2012-01-24 01:21:43 +00:00
/* UNUSED so far, may be enabled later */
/* #define USE_SMOKE_COLLISION_DM */
2012-03-27 00:17:57 +00:00
# include "smoke_API.h"
2012-09-15 01:52:28 +00:00
# ifdef WITH_SMOKE
2009-07-30 15:00:26 +00:00
# ifdef _WIN32
# include <time.h>
# include <stdio.h>
# include <conio.h>
# include <windows.h>
static LARGE_INTEGER liFrequency ;
static LARGE_INTEGER liStartTime ;
static LARGE_INTEGER liCurrentTime ;
2012-10-10 23:44:07 +00:00
static void tstart ( void )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
QueryPerformanceFrequency ( & liFrequency ) ;
QueryPerformanceCounter ( & liStartTime ) ;
2009-07-30 15:00:26 +00:00
}
2012-10-10 23:44:07 +00:00
static void tend ( void )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
QueryPerformanceCounter ( & liCurrentTime ) ;
2009-07-30 15:00:26 +00:00
}
2012-10-10 23:44:07 +00:00
static double tval ( void )
2009-09-16 17:43:09 +00:00
{
2012-10-10 23:44:07 +00:00
return ( ( double ) ( ( liCurrentTime . QuadPart - liStartTime . QuadPart ) * ( double ) 1000.0 / ( double ) liFrequency . QuadPart ) ) ;
2009-09-16 17:43:09 +00:00
}
2009-07-30 15:00:26 +00:00
# else
# include <sys/time.h>
static struct timeval _tstart , _tend ;
static struct timezone tz ;
2012-10-10 23:44:07 +00:00
static void tstart ( void )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
gettimeofday ( & _tstart , & tz ) ;
2009-07-30 15:00:26 +00:00
}
2012-10-10 23:44:07 +00:00
static void tend ( void )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
gettimeofday ( & _tend , & tz ) ;
2009-07-30 15:00:26 +00:00
}
2010-12-03 01:52:28 +00:00
2012-10-10 23:44:07 +00:00
static double UNUSED_FUNCTION ( tval ) ( void )
2009-07-30 15:00:26 +00:00
{
double t1 , t2 ;
2012-10-10 23:44:07 +00:00
t1 = ( double ) _tstart . tv_sec * 1000 + ( double ) _tstart . tv_usec / ( 1000 ) ;
t2 = ( double ) _tend . tv_sec * 1000 + ( double ) _tend . tv_usec / ( 1000 ) ;
return t2 - t1 ;
2009-07-30 15:00:26 +00:00
}
# endif
struct Object ;
struct Scene ;
struct DerivedMesh ;
struct SmokeModifierData ;
2012-04-28 21:46:43 +00:00
// timestep default value for nice appearance 0.1f
# define DT_DEFAULT 0.1f
2009-07-30 15:00:26 +00:00
2012-10-10 23:44:07 +00:00
# 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)))
2011-11-01 22:51:10 +00:00
2011-10-21 00:48:02 +00:00
# else /* WITH_SMOKE */
2011-11-01 22:51:10 +00:00
2011-07-13 18:40:21 +00:00
/* Stubs to use when smoke is disabled */
2012-10-10 13:18:07 +00:00
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; }
2011-07-13 18:40:21 +00:00
void smoke_free ( struct FLUID_3D * UNUSED ( fluid ) ) { }
2012-06-06 05:37:38 +00:00
float * smoke_get_density ( struct FLUID_3D * UNUSED ( fluid ) ) { return NULL ; }
2011-07-13 18:40:21 +00:00
void smoke_turbulence_free ( struct WTURBULENCE * UNUSED ( wt ) ) { }
void smoke_initWaveletBlenderRNA ( struct WTURBULENCE * UNUSED ( wt ) , float * UNUSED ( strength ) ) { }
2012-10-10 13:18:07 +00:00
void smoke_initBlenderRNA ( struct FLUID_3D * UNUSED ( fluid ) , float * UNUSED ( alpha ) , float * UNUSED ( beta ) , float * UNUSED ( dt_factor ) , float * UNUSED ( vorticity ) ,
2012-10-10 23:44:07 +00:00
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 ) ) { }
2012-10-10 13:18:07 +00:00
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 ) ) { }
2011-11-01 22:51:10 +00:00
2011-10-21 00:48:02 +00:00
# endif /* WITH_SMOKE */
2011-07-13 18:40:21 +00:00
2011-10-21 00:48:02 +00:00
# ifdef WITH_SMOKE
2011-11-01 22:51:10 +00:00
2012-10-10 13:18:07 +00:00
void smoke_reallocate_fluid ( SmokeDomainSettings * sds , float dx , int res [ 3 ] , int free_old )
2009-07-30 15:00:26 +00:00
{
2012-10-10 13:18:07 +00:00
int use_heat = ( sds - > active_fields & SM_ACTIVE_HEAT ) ;
2012-11-30 11:01:14 +00:00
int use_fire = ( sds - > active_fields & SM_ACTIVE_FIRE ) ;
2012-10-10 13:18:07 +00:00
int use_colors = ( sds - > active_fields & SM_ACTIVE_COLORS ) ;
if ( free_old & & sds - > fluid )
smoke_free ( sds - > fluid ) ;
2012-12-21 05:07:26 +00:00
if ( ! min_iii ( res [ 0 ] , res [ 1 ] , res [ 2 ] ) ) {
2012-10-10 13:18:07 +00:00
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 ) ,
2012-10-10 23:44:07 +00:00
& ( sds - > burning_rate ) , & ( sds - > flame_smoke ) , sds - > flame_smoke_color , & ( sds - > flame_vorticity ) , & ( sds - > flame_ignition ) , & ( sds - > flame_max_temp ) ) ;
2012-10-10 13:18:07 +00:00
/* reallocate shadow buffer */
if ( sds - > shadow )
MEM_freeN ( sds - > shadow ) ;
sds - > shadow = MEM_callocN ( sizeof ( float ) * res [ 0 ] * res [ 1 ] * res [ 2 ] , " SmokeDomainShadow " ) ;
}
2009-08-03 16:39:12 +00:00
2012-10-10 13:18:07 +00:00
void smoke_reallocate_highres_fluid ( SmokeDomainSettings * sds , float dx , int res [ 3 ] , int free_old )
{
2012-10-10 23:44:07 +00:00
int use_fire = ( sds - > active_fields & ( SM_ACTIVE_HEAT | SM_ACTIVE_FIRE ) ) ;
2012-10-10 13:18:07 +00:00
int use_colors = ( sds - > active_fields & SM_ACTIVE_COLORS ) ;
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
if ( free_old & & sds - > wt )
smoke_turbulence_free ( sds - > wt ) ;
2012-12-21 05:07:26 +00:00
if ( ! min_iii ( res [ 0 ] , res [ 1 ] , res [ 2 ] ) ) {
2012-10-10 13:18:07 +00:00
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 ) ;
2012-10-10 23:44:07 +00:00
sds - > res_wt [ 1 ] = res [ 1 ] * ( sds - > amplify + 1 ) ;
sds - > res_wt [ 2 ] = res [ 2 ] * ( sds - > amplify + 1 ) ;
2012-10-10 13:18:07 +00:00
sds - > dx_wt = dx / ( sds - > amplify + 1 ) ;
smoke_initWaveletBlenderRNA ( sds - > wt , & ( sds - > strength ) ) ;
}
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
/* 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 ) ;
2012-10-10 23:44:07 +00:00
pos [ 0 ] * = 1.0f / sds - > cell_size [ 0 ] ;
pos [ 1 ] * = 1.0f / sds - > cell_size [ 1 ] ;
pos [ 2 ] * = 1.0f / sds - > cell_size [ 2 ] ;
2012-10-10 13:18:07 +00:00
}
2009-07-30 15:00:26 +00:00
2013-01-29 19:27:05 +00:00
/* set domain transformations and base resolution from object derivedmesh */
static void smoke_set_domain_from_derivedmesh ( SmokeDomainSettings * sds , Object * ob , DerivedMesh * dm , int init_resolution )
2012-10-10 13:18:07 +00:00
{
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 ;
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
res = sds - > maxres ;
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
// get BB of domain
2012-10-10 23:44:07 +00:00
for ( i = 0 ; i < dm - > getNumVerts ( dm ) ; i + + )
2012-10-10 13:18:07 +00:00
{
// 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 ] ) ;
}
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
/* set domain bounds */
copy_v3_v3 ( sds - > p0 , min ) ;
copy_v3_v3 ( sds - > p1 , max ) ;
sds - > dx = 1.0f / res ;
2009-08-25 23:39:49 +00:00
2012-10-10 13:18:07 +00:00
/* calculate domain dimensions */
sub_v3_v3v3 ( size , max , min ) ;
2013-01-29 19:27:05 +00:00
if ( init_resolution ) {
zero_v3_int ( sds - > base_res ) ;
copy_v3_v3 ( sds - > cell_size , size ) ;
}
2012-10-10 13:18:07 +00:00
mul_v3_v3 ( size , ob - > size ) ;
copy_v3_v3 ( sds - > global_size , size ) ;
copy_v3_v3 ( sds - > dp0 , min ) ;
2009-08-25 23:39:49 +00:00
2012-10-10 13:18:07 +00:00
invert_m4_m4 ( sds - > imat , ob - > obmat ) ;
// prevent crash when initializing a plane as domain
2013-01-29 19:27:05 +00:00
if ( ! init_resolution | | ( size [ 0 ] < FLT_EPSILON ) | | ( size [ 1 ] < FLT_EPSILON ) | | ( size [ 2 ] < FLT_EPSILON ) )
2012-10-10 13:18:07 +00:00
return ;
/* define grid resolutions from longest domain side */
2013-01-29 19:27:05 +00:00
if ( size [ 0 ] > = MAX2 ( size [ 1 ] , size [ 2 ] ) ) {
2012-10-10 13:18:07 +00:00
scale = res / size [ 0 ] ;
sds - > scale = size [ 0 ] / ob - > size [ 0 ] ;
sds - > base_res [ 0 ] = res ;
2012-11-09 16:15:00 +00:00
sds - > base_res [ 1 ] = ( int ) ( size [ 1 ] * scale + 0.5f ) ;
sds - > base_res [ 2 ] = ( int ) ( size [ 2 ] * scale + 0.5f ) ;
2012-10-10 13:18:07 +00:00
}
2013-01-29 19:27:05 +00:00
else if ( size [ 1 ] > = MAX2 ( size [ 0 ] , size [ 2 ] ) ) {
2012-10-10 13:18:07 +00:00
scale = res / size [ 1 ] ;
sds - > scale = size [ 1 ] / ob - > size [ 1 ] ;
2012-11-09 16:15:00 +00:00
sds - > base_res [ 0 ] = ( int ) ( size [ 0 ] * scale + 0.5f ) ;
2012-10-10 13:18:07 +00:00
sds - > base_res [ 1 ] = res ;
2012-11-09 16:15:00 +00:00
sds - > base_res [ 2 ] = ( int ) ( size [ 2 ] * scale + 0.5f ) ;
2012-10-10 13:18:07 +00:00
}
else {
scale = res / size [ 2 ] ;
sds - > scale = size [ 2 ] / ob - > size [ 2 ] ;
2012-11-09 16:15:00 +00:00
sds - > base_res [ 0 ] = ( int ) ( size [ 0 ] * scale + 0.5f ) ;
sds - > base_res [ 1 ] = ( int ) ( size [ 1 ] * scale + 0.5f ) ;
2012-10-10 13:18:07 +00:00
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 )
{
2012-10-10 23:44:07 +00:00
if ( ( smd - > type & MOD_SMOKE_TYPE_DOMAIN ) & & smd - > domain & & ! smd - > domain - > fluid )
2012-10-10 13:18:07 +00:00
{
SmokeDomainSettings * sds = smd - > domain ;
int res [ 3 ] ;
/* set domain dimensions from derivedmesh */
2013-01-29 19:27:05 +00:00
smoke_set_domain_from_derivedmesh ( sds , ob , dm , TRUE ) ;
2012-10-10 13:18:07 +00:00
/* 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 */
2009-07-30 15:00:26 +00:00
}
2012-03-06 18:40:15 +00:00
else {
2012-10-10 13:18:07 +00:00
VECCOPY ( res , sds - > base_res ) ;
2009-07-30 15:00:26 +00:00
}
2012-10-10 13:18:07 +00:00
VECCOPY ( sds - > res , res ) ;
2012-10-10 23:44:07 +00:00
sds - > total_cells = sds - > res [ 0 ] * sds - > res [ 1 ] * sds - > res [ 2 ] ;
2012-10-10 13:18:07 +00:00
sds - > res_min [ 0 ] = sds - > res_min [ 1 ] = sds - > res_min [ 2 ] = 0 ;
VECCOPY ( sds - > res_max , res ) ;
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
/* allocate fluid */
smoke_reallocate_fluid ( sds , sds - > dx , sds - > res , 0 ) ;
2009-08-02 23:30:44 +00:00
2009-07-30 15:00:26 +00:00
smd - > time = scene - > r . cfra ;
2009-08-25 21:53:52 +00:00
2012-10-10 13:18:07 +00:00
/* allocate highres fluid */
2012-10-10 23:44:07 +00:00
if ( sds - > flags & MOD_SMOKE_HIGHRES ) {
2012-10-10 13:18:07 +00:00
smoke_reallocate_highres_fluid ( sds , sds - > dx , sds - > res , 0 ) ;
2009-08-20 00:33:59 +00:00
}
2012-10-10 13:18:07 +00:00
/* allocate shadow buffer */
2012-10-10 23:44:07 +00:00
if ( ! sds - > shadow )
2012-10-10 13:18:07 +00:00
sds - > shadow = MEM_callocN ( sizeof ( float ) * sds - > res [ 0 ] * sds - > res [ 1 ] * sds - > res [ 2 ] , " SmokeDomainShadow " ) ;
2009-08-20 00:33:59 +00:00
2009-07-30 15:00:26 +00:00
return 1 ;
}
2012-10-10 23:44:07 +00:00
else if ( ( smd - > type & MOD_SMOKE_TYPE_FLOW ) & & smd - > flow )
2009-07-30 15:00:26 +00:00
{
smd - > time = scene - > r . cfra ;
return 1 ;
}
2012-10-10 23:44:07 +00:00
else if ( ( smd - > type & MOD_SMOKE_TYPE_COLL ) )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( ! smd - > coll )
2012-04-28 21:46:43 +00:00
{
2009-08-02 23:30:44 +00:00
smokeModifier_createType ( smd ) ;
2012-04-28 21:46:43 +00:00
}
2009-08-02 23:30:44 +00:00
2012-10-10 13:18:07 +00:00
smd - > time = scene - > r . cfra ;
2009-07-30 15:00:26 +00:00
2009-10-22 23:22:05 +00:00
return 1 ;
}
2009-07-30 15:00:26 +00:00
2010-08-01 15:00:53 +00:00
return 2 ;
2009-10-22 23:22:05 +00:00
}
2011-10-21 00:48:02 +00:00
# endif /* WITH_SMOKE */
2009-09-16 17:43:09 +00:00
static void smokeModifier_freeDomain ( SmokeModifierData * smd )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd - > domain )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd - > domain - > shadow )
MEM_freeN ( smd - > domain - > shadow ) ;
smd - > domain - > shadow = NULL ;
2009-07-30 15:00:26 +00:00
2012-10-10 23:44:07 +00:00
if ( smd - > domain - > fluid )
2009-07-30 15:00:26 +00:00
smoke_free ( smd - > domain - > fluid ) ;
2009-08-09 01:30:32 +00:00
2012-10-10 23:44:07 +00:00
if ( smd - > domain - > wt )
2009-08-25 21:53:52 +00:00
smoke_turbulence_free ( smd - > domain - > wt ) ;
2012-10-10 23:44:07 +00:00
if ( smd - > domain - > effector_weights )
MEM_freeN ( smd - > domain - > effector_weights ) ;
2009-10-22 23:22:05 +00:00
smd - > domain - > effector_weights = NULL ;
2009-08-25 23:39:49 +00:00
BKE_ptcache_free_list ( & ( smd - > domain - > ptcaches [ 0 ] ) ) ;
smd - > domain - > point_cache [ 0 ] = NULL ;
2009-08-09 01:30:32 +00:00
2009-07-30 15:00:26 +00:00
MEM_freeN ( smd - > domain ) ;
smd - > domain = NULL ;
}
}
2009-09-16 17:43:09 +00:00
static void smokeModifier_freeFlow ( SmokeModifierData * smd )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd - > flow )
2009-07-30 15:00:26 +00:00
{
2012-10-10 13:18:07 +00:00
if ( smd - > flow - > dm ) smd - > flow - > dm - > release ( smd - > flow - > dm ) ;
if ( smd - > flow - > verts_old ) MEM_freeN ( smd - > flow - > verts_old ) ;
2009-07-30 15:00:26 +00:00
MEM_freeN ( smd - > flow ) ;
smd - > flow = NULL ;
}
}
2009-09-16 17:43:09 +00:00
static void smokeModifier_freeCollision ( SmokeModifierData * smd )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd - > coll )
2009-07-30 15:00:26 +00:00
{
2012-04-28 21:46:43 +00:00
SmokeCollSettings * scs = smd - > coll ;
2012-10-10 23:44:07 +00:00
if ( scs - > numverts )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( scs - > verts_old )
2012-04-28 21:46:43 +00:00
{
2012-10-10 13:18:07 +00:00
MEM_freeN ( scs - > verts_old ) ;
scs - > verts_old = NULL ;
2012-04-28 21:46:43 +00:00
}
2009-07-30 15:00:26 +00:00
}
2012-10-10 23:44:07 +00:00
if ( smd - > coll - > dm )
2009-08-06 16:50:02 +00:00
smd - > coll - > dm - > release ( smd - > coll - > dm ) ;
smd - > coll - > dm = NULL ;
2009-07-30 15:00:26 +00:00
MEM_freeN ( smd - > coll ) ;
smd - > coll = NULL ;
}
}
2009-09-16 17:43:09 +00:00
void smokeModifier_reset_turbulence ( struct SmokeModifierData * smd )
{
2012-10-10 23:44:07 +00:00
if ( smd & & smd - > domain & & smd - > domain - > wt )
2009-09-16 17:43:09 +00:00
{
smoke_turbulence_free ( smd - > domain - > wt ) ;
smd - > domain - > wt = NULL ;
}
}
2009-07-30 15:00:26 +00:00
void smokeModifier_reset ( struct SmokeModifierData * smd )
{
2012-10-10 23:44:07 +00:00
if ( smd )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd - > domain )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd - > domain - > shadow )
2009-09-16 17:43:09 +00:00
MEM_freeN ( smd - > domain - > shadow ) ;
smd - > domain - > shadow = NULL ;
2009-07-30 15:00:26 +00:00
2012-10-10 23:44:07 +00:00
if ( smd - > domain - > fluid )
2009-07-30 15:00:26 +00:00
{
smoke_free ( smd - > domain - > fluid ) ;
smd - > domain - > fluid = NULL ;
}
2009-08-25 21:53:52 +00:00
2009-09-16 17:43:09 +00:00
smokeModifier_reset_turbulence ( smd ) ;
smd - > time = - 1 ;
2012-10-10 13:18:07 +00:00
smd - > domain - > total_cells = 0 ;
smd - > domain - > active_fields = 0 ;
2009-07-30 15:00:26 +00:00
}
2012-10-10 23:44:07 +00:00
else if ( smd - > flow )
2009-07-30 15:00:26 +00:00
{
2012-10-10 13:18:07 +00:00
if ( smd - > flow - > verts_old ) MEM_freeN ( smd - > flow - > verts_old ) ;
smd - > flow - > verts_old = NULL ;
smd - > flow - > numverts = 0 ;
2009-07-30 15:00:26 +00:00
}
2012-10-10 23:44:07 +00:00
else if ( smd - > coll )
2009-07-30 15:00:26 +00:00
{
2012-04-28 21:46:43 +00:00
SmokeCollSettings * scs = smd - > coll ;
2009-08-03 16:39:12 +00:00
2012-10-10 23:44:07 +00:00
if ( scs - > numverts & & scs - > verts_old )
2009-08-03 16:39:12 +00:00
{
2012-10-10 13:18:07 +00:00
MEM_freeN ( scs - > verts_old ) ;
scs - > verts_old = NULL ;
2009-08-03 16:39:12 +00:00
}
2009-07-30 15:00:26 +00:00
}
}
}
2012-04-29 17:11:40 +00:00
void smokeModifier_free ( SmokeModifierData * smd )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd )
2009-07-30 15:00:26 +00:00
{
smokeModifier_freeDomain ( smd ) ;
smokeModifier_freeFlow ( smd ) ;
smokeModifier_freeCollision ( smd ) ;
}
}
void smokeModifier_createType ( struct SmokeModifierData * smd )
{
2012-10-10 23:44:07 +00:00
if ( smd )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd - > type & MOD_SMOKE_TYPE_DOMAIN )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd - > domain )
2009-07-30 15:00:26 +00:00
smokeModifier_freeDomain ( smd ) ;
smd - > domain = MEM_callocN ( sizeof ( SmokeDomainSettings ) , " SmokeDomain " ) ;
smd - > domain - > smd = smd ;
2009-08-25 23:39:49 +00:00
smd - > domain - > point_cache [ 0 ] = BKE_ptcache_add ( & ( smd - > domain - > ptcaches [ 0 ] ) ) ;
smd - > domain - > point_cache [ 0 ] - > flag | = PTCACHE_DISK_CACHE ;
smd - > domain - > point_cache [ 0 ] - > step = 1 ;
2010-11-30 21:31:18 +00:00
/* Deprecated */
smd - > domain - > point_cache [ 1 ] = NULL ;
smd - > domain - > ptcaches [ 1 ] . first = smd - > domain - > ptcaches [ 1 ] . last = NULL ;
2009-07-30 15:00:26 +00:00
/* set some standard values */
smd - > domain - > fluid = NULL ;
2012-10-10 23:44:07 +00:00
smd - > domain - > wt = NULL ;
2009-07-30 15:00:26 +00:00
smd - > domain - > eff_group = NULL ;
smd - > domain - > fluid_group = NULL ;
smd - > domain - > coll_group = NULL ;
2009-08-02 23:30:44 +00:00
smd - > domain - > maxres = 32 ;
2012-10-10 23:44:07 +00:00
smd - > domain - > amplify = 1 ;
2009-07-30 15:00:26 +00:00
smd - > domain - > alpha = - 0.001 ;
smd - > domain - > beta = 0.1 ;
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
smd - > domain - > time_scale = 1.0 ;
smd - > domain - > vorticity = 2.0 ;
2012-04-28 21:46:43 +00:00
smd - > domain - > border_collisions = SM_BORDER_OPEN ; // open domain
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
smd - > domain - > flags = MOD_SMOKE_DISSOLVE_LOG | MOD_SMOKE_HIGH_SMOOTH ;
2009-09-16 17:43:09 +00:00
smd - > domain - > strength = 2.0 ;
2009-07-30 15:00:26 +00:00
smd - > domain - > noise = MOD_SMOKE_NOISEWAVE ;
2009-09-16 17:43:09 +00:00
smd - > domain - > diss_speed = 5 ;
2012-10-10 13:18:07 +00:00
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 ;
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
smd - > domain - > viewsettings = MOD_SMOKE_VIEW_SHOWBIG ;
2009-10-22 23:22:05 +00:00
smd - > domain - > effector_weights = BKE_add_effector_weights ( NULL ) ;
2009-07-30 15:00:26 +00:00
}
2012-10-10 23:44:07 +00:00
else if ( smd - > type & MOD_SMOKE_TYPE_FLOW )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd - > flow )
2009-07-30 15:00:26 +00:00
smokeModifier_freeFlow ( smd ) ;
smd - > flow = MEM_callocN ( sizeof ( SmokeFlowSettings ) , " SmokeFlow " ) ;
smd - > flow - > smd = smd ;
/* set some standard values */
2012-10-10 13:18:07 +00:00
smd - > flow - > density = 1.0f ;
smd - > flow - > fuel_amount = 1.0f ;
smd - > flow - > temp = 1.0f ;
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
smd - > flow - > flags = MOD_SMOKE_FLOW_ABSOLUTE ;
2012-10-10 13:18:07 +00:00
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 ;
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
smd - > flow - > color [ 0 ] = 0.7f ;
smd - > flow - > color [ 1 ] = 0.7f ;
smd - > flow - > color [ 2 ] = 0.7f ;
smd - > flow - > dm = NULL ;
2009-07-30 15:00:26 +00:00
smd - > flow - > psys = NULL ;
}
2012-10-10 23:44:07 +00:00
else if ( smd - > type & MOD_SMOKE_TYPE_COLL )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd - > coll )
2009-07-30 15:00:26 +00:00
smokeModifier_freeCollision ( smd ) ;
smd - > coll = MEM_callocN ( sizeof ( SmokeCollSettings ) , " SmokeColl " ) ;
smd - > coll - > smd = smd ;
2012-10-10 13:18:07 +00:00
smd - > coll - > verts_old = NULL ;
smd - > coll - > numverts = 0 ;
2012-04-28 21:46:43 +00:00
smd - > coll - > type = 0 ; // static obstacle
2012-10-10 13:18:07 +00:00
smd - > coll - > dm = NULL ;
2012-01-24 01:21:43 +00:00
# ifdef USE_SMOKE_COLLISION_DM
2009-08-06 16:50:02 +00:00
smd - > coll - > dm = NULL ;
2012-01-24 01:21:43 +00:00
# endif
2009-07-30 15:00:26 +00:00
}
}
}
2010-05-14 07:09:15 +00:00
void smokeModifier_copy ( struct SmokeModifierData * smd , struct SmokeModifierData * tsmd )
{
tsmd - > type = smd - > type ;
tsmd - > time = smd - > time ;
2012-10-10 23:44:07 +00:00
2010-05-14 07:09:15 +00:00
smokeModifier_createType ( tsmd ) ;
if ( tsmd - > domain ) {
2012-10-10 13:18:07 +00:00
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 ;
2010-05-14 07:09:15 +00:00
tsmd - > domain - > alpha = smd - > domain - > alpha ;
tsmd - > domain - > beta = smd - > domain - > beta ;
2012-10-10 13:18:07 +00:00
tsmd - > domain - > amplify = smd - > domain - > amplify ;
tsmd - > domain - > maxres = smd - > domain - > maxres ;
2010-05-14 07:09:15 +00:00
tsmd - > domain - > flags = smd - > domain - > flags ;
2012-10-10 13:18:07 +00:00
tsmd - > domain - > viewsettings = smd - > domain - > viewsettings ;
2010-05-14 07:09:15 +00:00
tsmd - > domain - > noise = smd - > domain - > noise ;
tsmd - > domain - > diss_speed = smd - > domain - > diss_speed ;
2012-10-10 13:18:07 +00:00
tsmd - > domain - > strength = smd - > domain - > strength ;
tsmd - > domain - > border_collisions = smd - > domain - > border_collisions ;
2010-12-01 02:28:08 +00:00
tsmd - > domain - > vorticity = smd - > domain - > vorticity ;
tsmd - > domain - > time_scale = smd - > domain - > time_scale ;
2012-10-10 13:18:07 +00:00
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 ) ;
2012-10-10 23:44:07 +00:00
2010-05-14 07:09:15 +00:00
MEM_freeN ( tsmd - > domain - > effector_weights ) ;
tsmd - > domain - > effector_weights = MEM_dupallocN ( smd - > domain - > effector_weights ) ;
2012-10-10 23:44:07 +00:00
}
2012-03-24 06:18:31 +00:00
else if ( tsmd - > flow ) {
2012-10-10 13:18:07 +00:00
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 ;
2010-05-14 07:09:15 +00:00
tsmd - > flow - > density = smd - > flow - > density ;
2012-10-10 13:18:07 +00:00
copy_v3_v3 ( tsmd - > flow - > color , smd - > flow - > color ) ;
tsmd - > flow - > fuel_amount = smd - > flow - > fuel_amount ;
2010-05-14 07:09:15 +00:00
tsmd - > flow - > temp = smd - > flow - > temp ;
2012-10-10 13:18:07 +00:00
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 ;
2010-05-14 07:09:15 +00:00
tsmd - > flow - > type = smd - > flow - > type ;
2012-10-10 13:18:07 +00:00
tsmd - > flow - > source = smd - > flow - > source ;
tsmd - > flow - > texture_type = smd - > flow - > texture_type ;
2010-12-01 02:28:08 +00:00
tsmd - > flow - > flags = smd - > flow - > flags ;
2012-03-24 06:18:31 +00:00
}
else if ( tsmd - > coll ) {
2012-03-18 07:38:51 +00:00
/* leave it as initialized, collision settings is mostly caches */
2010-05-14 07:09:15 +00:00
}
}
2011-10-20 09:47:05 +00:00
# ifdef WITH_SMOKE
2010-05-14 07:09:15 +00:00
2009-09-16 17:43:09 +00:00
// forward decleration
2012-10-10 13:18:07 +00:00
static void smoke_calc_transparency ( SmokeDomainSettings * sds , Scene * scene ) ;
2009-09-16 17:43:09 +00:00
static float calc_voxel_transp ( float * result , float * input , int res [ 3 ] , int * pixel , float * tRay , float correct ) ;
2011-07-13 18:40:21 +00:00
2009-09-16 17:43:09 +00:00
static int get_lamp ( Scene * scene , float * light )
2012-10-10 23:44:07 +00:00
{
Base * base_tmp = NULL ;
2010-09-30 20:19:54 +00:00
int found_lamp = 0 ;
// try to find a lamp, preferably local
2012-10-10 23:44:07 +00:00
for ( base_tmp = scene - > base . first ; base_tmp ; base_tmp = base_tmp - > next ) {
if ( base_tmp - > object - > type = = OB_LAMP ) {
2010-09-30 20:19:54 +00:00
Lamp * la = base_tmp - > object - > data ;
2012-10-10 23:44:07 +00:00
if ( la - > type = = LA_LOCAL ) {
2010-09-30 20:19:54 +00:00
copy_v3_v3 ( light , base_tmp - > object - > obmat [ 3 ] ) ;
return 1 ;
}
2012-10-10 23:44:07 +00:00
else if ( ! found_lamp ) {
2010-09-30 20:19:54 +00:00
copy_v3_v3 ( light , base_tmp - > object - > obmat [ 3 ] ) ;
found_lamp = 1 ;
}
}
}
return found_lamp ;
2009-09-16 17:43:09 +00:00
}
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
static void obstacles_from_derivedmesh ( Object * coll_ob , SmokeDomainSettings * sds , SmokeCollSettings * scs , unsigned char * obstacle_map , float * velocityX , float * velocityY , float * velocityZ , float dt )
2009-09-16 17:43:09 +00:00
{
2012-10-10 13:18:07 +00:00
if ( ! scs - > dm ) return ;
2010-11-23 14:40:27 +00:00
{
2012-10-10 13:18:07 +00:00
DerivedMesh * dm = NULL ;
MVert * mvert = NULL ;
MFace * mface = NULL ;
BVHTreeFromMesh treeData = { 0 } ;
int numverts , i , z ;
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
2012-10-21 07:58:38 +00:00
// if (scs->type > SM_COLL_STATIC)
2012-10-10 13:18:07 +00:00
// if line above is used, the code is in trouble if the object moves but is declared as "does not move"
2010-11-23 14:40:27 +00:00
{
2012-10-10 13:18:07 +00:00
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 ) ;
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
scs - > verts_old = MEM_callocN ( sizeof ( float ) * numverts * 3 , " smoke_obs_verts_old " ) ;
scs - > numverts = numverts ;
}
else {
has_velocity = 1 ;
}
}
/* Transform collider vertices to
2012-10-10 23:44:07 +00:00
* domain grid space for fast lookups */
2012-10-10 13:18:07 +00:00
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 ) ;
2012-10-10 23:44:07 +00:00
if ( has_velocity )
2010-11-23 14:40:27 +00:00
{
2012-10-10 23:44:07 +00:00
sub_v3_v3v3 ( & vert_vel [ i * 3 ] , co , & scs - > verts_old [ i * 3 ] ) ;
mul_v3_fl ( & vert_vel [ i * 3 ] , sds - > dx / dt ) ;
2012-10-10 13:18:07 +00:00
}
2012-10-10 23:44:07 +00:00
copy_v3_v3 ( & scs - > verts_old [ i * 3 ] , co ) ;
2012-10-10 13:18:07 +00:00
}
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 + + ) {
2012-10-10 23:44:07 +00:00
int x , y ;
2012-10-10 13:18:07 +00:00
for ( x = sds - > res_min [ 0 ] ; x < sds - > res_max [ 0 ] ; x + + )
2012-10-10 23:44:07 +00:00
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 )
2012-10-10 13:18:07 +00:00
{
2012-10-10 23:44:07 +00:00
/* 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 ] ;
}
2012-10-10 13:18:07 +00:00
}
2012-04-28 21:46:43 +00:00
2012-10-10 23:44:07 +00:00
/* tag obstacle cells */
obstacle_map [ index ] = 1 ;
2012-04-28 21:46:43 +00:00
2012-10-10 23:44:07 +00:00
if ( has_velocity )
obstacle_map [ index ] | = 8 ;
}
2012-10-10 13:18:07 +00:00
}
2012-04-28 21:46:43 +00:00
}
}
2012-10-10 13:18:07 +00:00
/* free bvh tree */
free_bvhtree_from_mesh ( & treeData ) ;
dm - > release ( dm ) ;
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
if ( vert_vel ) MEM_freeN ( vert_vel ) ;
2012-04-28 21:46:43 +00:00
}
}
2010-11-23 14:40:27 +00:00
2012-04-28 21:46:43 +00:00
/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */
2012-10-10 14:28:47 +00:00
static void update_obstacles ( Scene * scene , Object * ob , SmokeDomainSettings * sds , float dt ,
int UNUSED ( substep ) , int UNUSED ( totalsteps ) )
2012-04-28 21:46:43 +00:00
{
Object * * collobjs = NULL ;
unsigned int numcollobj = 0 ;
unsigned int collIndex ;
unsigned char * obstacles = smoke_get_obstacle ( sds - > fluid ) ;
float * velx = NULL ;
float * vely = NULL ;
float * velz = NULL ;
float * velxOrig = smoke_get_velocity_x ( sds - > fluid ) ;
float * velyOrig = smoke_get_velocity_y ( sds - > fluid ) ;
float * velzOrig = smoke_get_velocity_z ( sds - > fluid ) ;
2012-10-10 13:18:07 +00:00
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 ) ;
2012-04-28 21:46:43 +00:00
unsigned int z ;
2012-10-10 13:18:07 +00:00
smoke_get_ob_velocity ( sds - > fluid , & velx , & vely , & velz ) ;
// TODO: delete old obstacle flags
2012-10-10 23:44:07 +00:00
for ( z = 0 ; z < sds - > res [ 0 ] * sds - > res [ 1 ] * sds - > res [ 2 ] ; z + + )
2012-10-10 13:18:07 +00:00
{
2012-10-10 23:44:07 +00:00
if ( obstacles [ z ] & 8 ) // Do not delete static obstacles
2012-10-10 13:18:07 +00:00
{
obstacles [ z ] = 0 ;
}
velx [ z ] = 0 ;
vely [ z ] = 0 ;
velz [ z ] = 0 ;
}
collobjs = get_collisionobjects ( scene , ob , sds - > coll_group , & numcollobj , eModifierType_Smoke ) ;
// update obstacle tags in cells
2012-10-10 23:44:07 +00:00
for ( collIndex = 0 ; collIndex < numcollobj ; collIndex + + )
2012-10-10 13:18:07 +00:00
{
2012-10-10 23:44:07 +00:00
Object * collob = collobjs [ collIndex ] ;
SmokeModifierData * smd2 = ( SmokeModifierData * ) modifiers_findByType ( collob , eModifierType_Smoke ) ;
2012-10-10 13:18:07 +00:00
// DG TODO: check if modifier is active?
2012-10-10 23:44:07 +00:00
if ( ( smd2 - > type & MOD_SMOKE_TYPE_COLL ) & & smd2 - > coll )
2012-10-10 13:18:07 +00:00
{
SmokeCollSettings * scs = smd2 - > coll ;
obstacles_from_derivedmesh ( collob , sds , scs , obstacles , velx , vely , velz , dt ) ;
}
}
2012-10-10 23:44:07 +00:00
if ( collobjs )
2012-10-10 13:18:07 +00:00
MEM_freeN ( collobjs ) ;
/* obstacle cells should not contain any velocity from the smoke simulation */
2012-10-10 23:44:07 +00:00
for ( z = 0 ; z < sds - > res [ 0 ] * sds - > res [ 1 ] * sds - > res [ 2 ] ; z + + )
2012-10-10 13:18:07 +00:00
{
2012-10-10 23:44:07 +00:00
if ( obstacles [ z ] )
2012-10-10 13:18:07 +00:00
{
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 ;
}
}
}
}
typedef struct EmissionMap {
float * influence ;
float * velocity ;
int min [ 3 ] , max [ 3 ] , res [ 3 ] ;
int total_cells , valid ;
} EmissionMap ;
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 ;
2012-10-10 23:44:07 +00:00
for ( i = 0 ; i < 3 ; i + + ) {
2012-10-10 13:18:07 +00:00
int adapt = ( sds - > flags & MOD_SMOKE_ADAPTIVE_DOMAIN ) ? sds - > adapt_res : 0 ;
/* add margin */
min [ i ] - = margin ;
max [ i ] + = margin ;
/* adapt to velocity */
2012-10-10 23:44:07 +00:00
if ( min_vel & & min_vel [ i ] < 0.0f ) {
2012-10-10 13:18:07 +00:00
min [ i ] + = ( int ) ceil ( min_vel [ i ] * dt ) ;
}
2012-10-10 23:44:07 +00:00
if ( max_vel & & max_vel [ i ] > 0.0f ) {
2012-10-10 13:18:07 +00:00
max [ i ] + = ( int ) ceil ( max_vel [ i ] * dt ) ;
}
/* clamp within domain max size */
2012-10-10 23:44:07 +00:00
CLAMP ( min [ i ] , - adapt , sds - > base_res [ i ] + adapt ) ;
CLAMP ( max [ i ] , - adapt , sds - > base_res [ i ] + adapt ) ;
2012-10-10 13:18:07 +00:00
}
}
2012-12-18 01:52:18 +00:00
static void em_allocateData ( EmissionMap * em , int use_velocity )
{
2012-10-10 13:18:07 +00:00
int i , res [ 3 ] ;
2012-10-10 23:44:07 +00:00
for ( i = 0 ; i < 3 ; i + + ) {
2012-10-10 13:18:07 +00:00
res [ i ] = em - > max [ i ] - em - > min [ i ] ;
if ( res [ i ] < = 0 )
return ;
}
2012-10-10 23:44:07 +00:00
em - > total_cells = res [ 0 ] * res [ 1 ] * res [ 2 ] ;
2012-10-10 13:18:07 +00:00
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 " ) ;
}
2012-12-18 01:52:18 +00:00
static void em_freeData ( EmissionMap * em )
{
2012-10-10 13:18:07 +00:00
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 )
{
2012-10-27 17:19:55 +00:00
if ( sfs & & sfs - > psys & & sfs - > psys - > part & & ELEM ( sfs - > psys - > part - > type , PART_EMITTER , PART_FLUID ) ) // is particle system selected
2012-10-10 13:18:07 +00:00
{
ParticleSimulationData sim ;
ParticleSystem * psys = sfs - > psys ;
float * particle_pos ;
float * particle_vel ;
2012-10-10 23:44:07 +00:00
int totpart = psys - > totpart , totchild ;
2012-10-10 13:18:07 +00:00
int p = 0 ;
int valid_particles = 0 ;
sim . scene = scene ;
sim . ob = flow_ob ;
sim . psys = psys ;
2012-10-10 23:44:07 +00:00
if ( psys - > part - > type = = PART_HAIR )
2012-10-10 13:18:07 +00:00
{
// TODO: PART_HAIR not supported whatsoever
2012-10-10 23:44:07 +00:00
totchild = 0 ;
2012-10-10 13:18:07 +00:00
}
else
2012-10-10 23:44:07 +00:00
totchild = psys - > totchild * psys - > part - > disp / 100 ;
2012-10-10 13:18:07 +00:00
2012-10-10 23:44:07 +00:00
particle_pos = MEM_callocN ( sizeof ( float ) * ( totpart + totchild ) * 3 , " smoke_flow_particles " ) ;
particle_vel = MEM_callocN ( sizeof ( float ) * ( totpart + totchild ) * 3 , " smoke_flow_particles " ) ;
2012-10-10 13:18:07 +00:00
/* calculate local position for each particle */
2012-10-10 23:44:07 +00:00
for ( p = 0 ; p < totpart + totchild ; p + + )
2012-10-10 13:18:07 +00:00
{
ParticleKey state ;
float * pos ;
2012-10-10 23:44:07 +00:00
if ( p < totpart ) {
if ( psys - > particles [ p ] . flag & ( PARS_NO_DISP | PARS_UNEXIST ) )
2012-10-10 13:18:07 +00:00
continue ;
}
else {
/* handle child particle */
ChildParticle * cpa = & psys - > child [ p - totpart ] ;
2012-10-10 23:44:07 +00:00
if ( psys - > particles [ cpa - > parent ] . flag & ( PARS_NO_DISP | PARS_UNEXIST ) )
2012-10-10 13:18:07 +00:00
continue ;
}
state . time = time ;
2012-10-10 23:44:07 +00:00
if ( psys_get_particle_state ( & sim , p , & state , 0 ) = = 0 )
2012-10-10 13:18:07 +00:00
continue ;
/* location */
2012-10-10 23:44:07 +00:00
pos = & particle_pos [ valid_particles * 3 ] ;
2012-10-10 13:18:07 +00:00
copy_v3_v3 ( pos , state . co ) ;
smoke_pos_to_cell ( sds , pos ) ;
/* velocity */
2012-10-10 23:44:07 +00:00
copy_v3_v3 ( & particle_vel [ valid_particles * 3 ] , state . vel ) ;
mul_mat3_m4_v3 ( sds - > imat , & particle_vel [ valid_particles * 3 ] ) ;
2012-10-10 13:18:07 +00:00
/* 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 ) ;
2012-10-10 23:44:07 +00:00
for ( p = 0 ; p < valid_particles ; p + + )
2012-10-10 13:18:07 +00:00
{
int cell [ 3 ] ;
size_t i = 0 ;
size_t index = 0 ;
int badcell = 0 ;
/* 1. get corresponding cell */
2012-10-10 23:44:07 +00:00
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 ] ;
2012-10-10 13:18:07 +00:00
/* check if cell is valid (in the domain boundary) */
2012-10-10 23:44:07 +00:00
for ( i = 0 ; i < 3 ; i + + ) {
if ( ( cell [ i ] > em - > res [ i ] - 1 ) | | ( cell [ i ] < 0 ) ) {
2012-10-10 13:18:07 +00:00
badcell = 1 ;
break ;
}
}
2012-10-10 23:44:07 +00:00
if ( badcell )
2012-10-10 13:18:07 +00:00
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 */
2012-10-10 23:44:07 +00:00
if ( sfs - > flags & MOD_SMOKE_FLOW_INITVELOCITY & & ( psys - > part - > phystype ! = PART_PHYS_NO ) )
2012-10-10 13:18:07 +00:00
{
2012-10-10 23:44:07 +00:00
VECADDFAC ( & em - > velocity [ index * 3 ] , & em - > velocity [ index * 3 ] , & particle_vel [ p * 3 ] , sfs - > vel_multi ) ;
2012-10-10 13:18:07 +00:00
}
2012-10-10 23:44:07 +00:00
} // particles loop
2012-10-10 13:18:07 +00:00
/* free data */
if ( particle_pos )
MEM_freeN ( particle_pos ) ;
if ( particle_vel )
MEM_freeN ( particle_vel ) ;
}
}
2012-10-15 23:11:59 +00:00
static void get_texture_value ( Tex * texture , float tex_co [ 3 ] , TexResult * texres )
2012-10-10 13:18:07 +00:00
{
int result_type ;
/* no node textures for now */
2013-01-21 08:49:42 +00:00
result_type = multitex_ext_safe ( texture , tex_co , texres , NULL ) ;
2012-10-10 13:18:07 +00:00
/* 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 ) ;
}
}
static void emit_from_derivedmesh ( Object * flow_ob , SmokeDomainSettings * sds , SmokeFlowSettings * sfs , EmissionMap * em , float dt )
{
if ( ! sfs - > dm ) return ;
{
DerivedMesh * dm = sfs - > dm ;
2012-10-10 23:44:07 +00:00
int defgrp_index = sfs - > vgroup_density - 1 ;
2012-10-10 13:18:07 +00:00
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 ) ;
2012-10-10 23:44:07 +00:00
mvert_orig = dm - > dupVertArray ( dm ) ; /* copy original mvert and restore when done */
2012-10-10 13:18:07 +00:00
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 ;
}
}
/* Transform dm vertices to
2012-10-10 23:44:07 +00:00
* domain grid space for fast lookups */
2012-10-10 13:18:07 +00:00
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 ) {
2012-10-10 23:44:07 +00:00
sub_v3_v3v3 ( & vert_vel [ i * 3 ] , co , & sfs - > verts_old [ i * 3 ] ) ;
mul_v3_fl ( & vert_vel [ i * 3 ] , sds - > dx / dt ) ;
2012-10-10 13:18:07 +00:00
}
2012-10-10 23:44:07 +00:00
copy_v3_v3 ( & sfs - > verts_old [ i * 3 ] , co ) ;
2012-10-10 13:18:07 +00:00
}
/* 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 + + ) {
2012-10-10 23:44:07 +00:00
int x , y ;
2012-10-10 13:18:07 +00:00
for ( x = em - > min [ 0 ] ; x < em - > max [ 0 ] ; x + + )
2012-10-10 23:44:07 +00:00
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 ;
}
2012-10-10 13:18:07 +00:00
}
}
}
2012-10-10 23:44:07 +00:00
/* 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 ) ;
2012-10-10 13:18:07 +00:00
}
2012-10-10 23:44:07 +00:00
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 ;
}
2012-10-10 13:18:07 +00:00
}
2012-04-28 21:46:43 +00:00
2012-10-10 23:44:07 +00:00
/* apply vertex group influence if used */
2012-10-22 17:19:05 +00:00
if ( defgrp_index ! = - 1 & & dvert ) {
2012-10-10 23:44:07 +00:00
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 ;
}
2012-04-28 21:46:43 +00:00
2012-10-10 23:44:07 +00:00
/* apply emission texture */
if ( ( sfs - > flags & MOD_SMOKE_FLOW_TEXTUREEMIT ) & & sfs - > noise_texture ) {
float tex_co [ 3 ] = { 0 } ;
TexResult texres ;
2012-10-10 13:18:07 +00:00
2012-10-10 23:44:07 +00:00
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 ;
2012-10-10 13:18:07 +00:00
}
}
2012-04-28 21:46:43 +00:00
2012-10-10 23:44:07 +00:00
/* multiply initial velocity by emitter influence */
if ( sfs - > flags & MOD_SMOKE_FLOW_INITVELOCITY ) {
mul_v3_fl ( & em - > velocity [ index * 3 ] , sample_str ) ;
}
2012-04-28 21:46:43 +00:00
2012-10-10 23:44:07 +00:00
/* apply final influence based on volume factor */
em - > influence [ index ] = MAX2 ( volume_factor , sample_str ) ;
}
2012-10-10 13:18:07 +00:00
}
}
/* 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 ) ;
2012-04-28 21:46:43 +00:00
}
2012-10-10 13:18:07 +00:00
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
static void adjustDomainResolution ( SmokeDomainSettings * sds , int new_shift [ 3 ] , EmissionMap * emaps , unsigned int numflowobj , float dt )
{
2012-10-10 23:44:07 +00:00
int min [ 3 ] = { 32767 , 32767 , 32767 } , max [ 3 ] = { - 32767 , - 32767 , - 32767 } , res [ 3 ] ;
2012-10-10 13:18:07 +00:00
int total_cells = 1 , res_changed = 0 , shift_changed = 0 ;
float min_vel [ 3 ] , max_vel [ 3 ] ;
2012-10-10 23:44:07 +00:00
int x , y , z , i ;
2012-10-10 13:18:07 +00:00
float * density = smoke_get_density ( sds - > fluid ) ;
float * fuel = smoke_get_fuel ( sds - > fluid ) ;
2013-03-22 17:11:32 +00:00
float * bigdensity = smoke_turbulence_get_density ( sds - > wt ) ;
float * bigfuel = smoke_turbulence_get_fuel ( sds - > wt ) ;
2012-10-10 13:18:07 +00:00
float * vx = smoke_get_velocity_x ( sds - > fluid ) ;
float * vy = smoke_get_velocity_y ( sds - > fluid ) ;
float * vz = smoke_get_velocity_z ( sds - > fluid ) ;
2013-03-22 17:11:32 +00:00
int block_size = sds - > amplify + 1 ;
int wt_res [ 3 ] ;
if ( sds - > flags & MOD_SMOKE_HIGHRES & & sds - > wt ) {
smoke_turbulence_get_res ( sds - > wt , wt_res ) ;
}
2012-10-10 13:18:07 +00:00
INIT_MINMAX ( min_vel , max_vel ) ;
/* Calculate bounds for current domain content */
2012-10-10 23:44:07 +00:00
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 + + )
2012-10-10 13:18:07 +00:00
{
2012-10-10 23:44:07 +00:00
int xn = x - new_shift [ 0 ] ;
int yn = y - new_shift [ 1 ] ;
int zn = z - new_shift [ 2 ] ;
2013-03-22 17:11:32 +00:00
int index ;
float max_den ;
/* skip if cell already belongs to new area */
if ( xn > = min [ 0 ] & & xn < = max [ 0 ] & & yn > = min [ 1 ] & & yn < = max [ 1 ] & & zn > = min [ 2 ] & & zn < = max [ 2 ] )
continue ;
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 ] ) ;
max_den = ( fuel ) ? MAX2 ( density [ index ] , fuel [ index ] ) : density [ index ] ;
/* check high resolution bounds if max density isnt already high enough */
if ( max_den < sds - > adapt_threshold & & sds - > flags & MOD_SMOKE_HIGHRES & & sds - > wt ) {
int i , j , k ;
/* high res grid index */
int xx = ( x - sds - > res_min [ 0 ] ) * block_size ;
int yy = ( y - sds - > res_min [ 1 ] ) * block_size ;
int zz = ( z - sds - > res_min [ 2 ] ) * block_size ;
for ( i = 0 ; i < block_size ; i + + )
for ( j = 0 ; j < block_size ; j + + )
for ( k = 0 ; k < block_size ; k + + )
{
int big_index = smoke_get_index ( xx + i , wt_res [ 0 ] , yy + j , wt_res [ 1 ] , zz + k ) ;
float den = ( bigfuel ) ? MAX2 ( bigdensity [ big_index ] , bigfuel [ big_index ] ) : bigdensity [ big_index ] ;
if ( den > max_den ) {
max_den = den ;
}
}
}
2012-10-10 13:18:07 +00:00
/* 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 ;
}
2013-03-22 17:11:32 +00:00
2012-10-10 13:18:07 +00:00
/* 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 ] ;
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
/* also apply emission maps */
2012-10-10 23:44:07 +00:00
for ( i = 0 ; i < numflowobj ; i + + )
2012-04-28 21:46:43 +00:00
{
2012-10-10 13:18:07 +00:00
EmissionMap * em = & emaps [ i ] ;
2012-04-28 21:46:43 +00:00
2012-10-10 23:44:07 +00:00
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 + + )
2012-10-10 13:18:07 +00:00
{
2012-10-10 23:44:07 +00:00
int index = smoke_get_index ( x - em - > min [ 0 ] , em - > res [ 0 ] , y - em - > min [ 1 ] , em - > res [ 1 ] , z - em - > min [ 2 ] ) ;
2012-10-10 13:18:07 +00:00
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 ) {
2012-10-10 23:44:07 +00:00
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 ] ;
2012-10-10 13:18:07 +00:00
}
}
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
/* calculate new bounds based on these values */
2012-10-10 23:44:07 +00:00
clampBoundsInDomain ( sds , min , max , min_vel , max_vel , sds - > adapt_margin + 1 , dt ) ;
2012-04-28 21:46:43 +00:00
2012-10-10 23:44:07 +00:00
for ( i = 0 ; i < 3 ; i + + ) {
2012-10-10 13:18:07 +00:00
/* calculate new resolution */
res [ i ] = max [ i ] - min [ i ] ;
total_cells * = res [ i ] ;
2010-11-23 14:40:27 +00:00
2012-10-10 13:18:07 +00:00
if ( new_shift [ i ] )
shift_changed = 1 ;
2010-11-23 14:40:27 +00:00
2012-10-10 13:18:07 +00:00
/* if no content set minimum dimensions */
if ( res [ i ] < = 0 ) {
int j ;
2012-10-10 23:44:07 +00:00
for ( j = 0 ; j < 3 ; j + + ) {
2012-10-10 13:18:07 +00:00
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 ;
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
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 ) ;
2012-10-10 23:44:07 +00:00
if ( sds - > flags & MOD_SMOKE_HIGHRES ) {
2012-10-10 13:18:07 +00:00
smoke_reallocate_highres_fluid ( sds , sds - > dx , res , 0 ) ;
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
/* copy values from old fluid to new */
2012-10-10 23:44:07 +00:00
if ( sds - > total_cells > 1 & & total_cells > 1 ) {
2012-10-10 13:18:07 +00:00
/* 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 ) ;
2012-10-10 23:44:07 +00:00
if ( sds - > flags & MOD_SMOKE_HIGHRES ) {
2012-10-10 13:18:07 +00:00
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 ) ;
}
2012-04-28 21:46:43 +00:00
2012-10-10 23:44:07 +00:00
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 + + )
2012-04-28 21:46:43 +00:00
{
2012-10-10 13:18:07 +00:00
/* old grid index */
2012-10-10 23:44:07 +00:00
int xo = x - sds - > res_min [ 0 ] ;
int yo = y - sds - > res_min [ 1 ] ;
int zo = z - sds - > res_min [ 2 ] ;
2012-10-10 13:18:07 +00:00
int index_old = smoke_get_index ( xo , sds - > res [ 0 ] , yo , sds - > res [ 1 ] , zo ) ;
/* new grid index */
2012-10-10 23:44:07 +00:00
int xn = x - min [ 0 ] - new_shift [ 0 ] ;
int yn = y - min [ 1 ] - new_shift [ 1 ] ;
int zn = z - min [ 2 ] - new_shift [ 2 ] ;
2012-10-10 13:18:07 +00:00
int index_new = smoke_get_index ( xn , res [ 0 ] , yn , res [ 1 ] , zn ) ;
/* skip if outside new domain */
2012-10-10 23:44:07 +00:00
if ( xn < 0 | | xn > = res [ 0 ] | |
yn < 0 | | yn > = res [ 1 ] | |
zn < 0 | | zn > = res [ 2 ] )
2012-10-10 13:18:07 +00:00
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 ] ;
2012-10-10 23:44:07 +00:00
if ( sds - > flags & MOD_SMOKE_HIGHRES & & turb_old ) {
2012-10-10 13:18:07 +00:00
int block_size = sds - > amplify + 1 ;
2012-10-10 23:44:07 +00:00
int i , j , k ;
2012-10-10 13:18:07 +00:00
/* old grid index */
2012-10-10 23:44:07 +00:00
int xx_o = xo * block_size ;
int yy_o = yo * block_size ;
int zz_o = zo * block_size ;
2012-10-10 13:18:07 +00:00
/* new grid index */
2012-10-10 23:44:07 +00:00
int xx_n = xn * block_size ;
int yy_n = yn * block_size ;
int zz_n = zn * block_size ;
2012-10-10 13:18:07 +00:00
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 ] ;
2012-10-10 23:44:07 +00:00
for ( i = 0 ; i < block_size ; i + + )
for ( j = 0 ; j < block_size ; j + + )
for ( k = 0 ; k < block_size ; k + + )
2012-10-10 13:18:07 +00:00
{
2012-10-10 23:44:07 +00:00
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 ) ;
2012-10-10 13:18:07 +00:00
/* 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 ] ;
}
}
}
2010-11-23 14:40:27 +00:00
}
2012-10-10 13:18:07 +00:00
}
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 ;
}
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
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 ;
}
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
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 ] ;
2012-10-10 14:28:47 +00:00
// float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
2012-10-10 13:18:07 +00:00
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 ) {
2013-04-05 07:56:59 +00:00
heat [ index ] = ADD_IF_LOWER ( heat [ index ] , emission_value * sfs - > temp ) ;
2012-10-10 13:18:07 +00:00
}
/* 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 ) ;
}
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
/* set color */
if ( color_r & & dens_flow ) {
2012-10-10 23:44:07 +00:00
float total_dens = density [ index ] / ( dens_old + dens_flow ) ;
2012-10-10 13:18:07 +00:00
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 ;
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
/* set fire reaction coordinate */
2013-02-11 13:28:18 +00:00
if ( fuel & & fuel [ index ] > FLT_EPSILON ) {
2012-10-10 13:18:07 +00:00
/* instead of using 1.0 for all new fuel add slight falloff
* to reduce flow blockiness */
2012-11-09 16:15:00 +00:00
float value = 1.0f - powf ( 1.0f - emission_value , 2.0f ) ;
2012-10-10 13:18:07 +00:00
if ( value > react [ index ] ) {
float f = fuel_flow / fuel [ index ] ;
2012-10-10 23:44:07 +00:00
react [ index ] = value * f + ( 1.0f - f ) * react [ index ] ;
2013-02-11 15:03:22 +00:00
CLAMP ( react [ index ] , 0.0f , value ) ;
2010-11-23 14:40:27 +00:00
}
}
2012-04-28 21:46:43 +00:00
}
2012-10-10 13:18:07 +00:00
static void update_flowsfluids ( Scene * scene , Object * ob , SmokeDomainSettings * sds , float time , float dt )
2012-04-28 21:46:43 +00:00
{
Object * * flowobjs = NULL ;
2012-10-10 13:18:07 +00:00
EmissionMap * emaps = NULL ;
2012-04-28 21:46:43 +00:00
unsigned int numflowobj = 0 ;
unsigned int flowIndex ;
2012-10-10 13:18:07 +00:00
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 ) ;
2012-10-10 23:44:07 +00:00
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 ] ;
2012-10-10 13:18:07 +00:00
/* 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 */
2012-10-10 23:44:07 +00:00
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 ] ;
2012-10-10 13:18:07 +00:00
}
2012-04-28 21:46:43 +00:00
flowobjs = get_collisionobjects ( scene , ob , sds - > fluid_group , & numflowobj , eModifierType_Smoke ) ;
2012-10-10 13:18:07 +00:00
/* init emission maps for each flow */
emaps = MEM_callocN ( sizeof ( struct EmissionMap ) * numflowobj , " smoke_flow_maps " ) ;
/* Prepare flow emission maps */
2012-10-10 23:44:07 +00:00
for ( flowIndex = 0 ; flowIndex < numflowobj ; flowIndex + + )
2010-11-23 14:40:27 +00:00
{
2012-10-10 23:44:07 +00:00
Object * collob = flowobjs [ flowIndex ] ;
SmokeModifierData * smd2 = ( SmokeModifierData * ) modifiers_findByType ( collob , eModifierType_Smoke ) ;
2009-09-16 17:43:09 +00:00
2012-04-28 21:46:43 +00:00
// check for initialized smoke object
2012-10-10 23:44:07 +00:00
if ( ( smd2 - > type & MOD_SMOKE_TYPE_FLOW ) & & smd2 - > flow )
2012-04-28 21:46:43 +00:00
{
// we got nice flow object
SmokeFlowSettings * sfs = smd2 - > flow ;
2012-10-10 13:18:07 +00:00
EmissionMap * em = & emaps [ flowIndex ] ;
2009-09-16 17:43:09 +00:00
2012-10-10 13:18:07 +00:00
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 ) ;
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
/* 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 ;
2012-04-28 21:46:43 +00:00
}
2012-10-10 13:18:07 +00:00
/* 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 ;
2012-04-28 21:46:43 +00:00
}
2012-10-10 13:18:07 +00:00
else if ( ! equals_v3v3 ( sds - > active_color , sfs - > color ) ) {
active_fields | = SM_ACTIVE_COLORS ;
2012-04-28 21:46:43 +00:00
}
2012-10-10 13:18:07 +00:00
}
}
}
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
/* 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 ;
}
}
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
/* Adjust domain size if needed */
if ( sds - > flags & MOD_SMOKE_ADAPTIVE_DOMAIN ) {
adjustDomainResolution ( sds , new_shift , emaps , numflowobj , dt ) ;
}
2010-12-15 17:05:34 +00:00
2012-10-10 13:18:07 +00:00
/* 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 ;
2010-12-15 17:05:34 +00:00
2012-10-10 13:18:07 +00:00
/* Apply emission data */
if ( sds - > fluid ) {
2012-10-10 23:44:07 +00:00
for ( flowIndex = 0 ; flowIndex < numflowobj ; flowIndex + + )
2012-10-10 13:18:07 +00:00
{
2012-10-10 23:44:07 +00:00
Object * collob = flowobjs [ flowIndex ] ;
SmokeModifierData * smd2 = ( SmokeModifierData * ) modifiers_findByType ( collob , eModifierType_Smoke ) ;
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
// check for initialized smoke object
2012-10-10 23:44:07 +00:00
if ( ( smd2 - > type & MOD_SMOKE_TYPE_FLOW ) & & smd2 - > flow )
2012-10-10 13:18:07 +00:00
{
// we got nice flow object
SmokeFlowSettings * sfs = smd2 - > flow ;
EmissionMap * em = & emaps [ flowIndex ] ;
2012-10-10 23:44:07 +00:00
2012-10-10 13:18:07 +00:00
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 ) ;
2012-10-10 23:44:07 +00:00
//unsigned char *obstacle = smoke_get_obstacle(sds->fluid);
2012-10-10 13:18:07 +00:00
// 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 ;
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
int ii , jj , kk , gx , gy , gz , ex , ey , ez , dx , dy , dz , block_size ;
size_t e_index , d_index , index_big ;
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
// loop through every emission map cell
2012-10-10 23:44:07 +00:00
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 + + )
2012-10-10 13:18:07 +00:00
{
/* get emission map index */
2012-10-10 23:44:07 +00:00
ex = gx - em - > min [ 0 ] ;
ey = gy - em - > min [ 1 ] ;
ez = gz - em - > min [ 2 ] ;
2012-10-10 13:18:07 +00:00
e_index = smoke_get_index ( ex , em - > res [ 0 ] , ey , em - > res [ 1 ] , ez ) ;
if ( ! emission_map [ e_index ] ) continue ;
/* get domain index */
2012-10-10 23:44:07 +00:00
dx = gx - sds - > res_min [ 0 ] ;
dy = gy - sds - > res_min [ 1 ] ;
dz = gz - sds - > res_min [ 2 ] ;
2012-10-10 13:18:07 +00:00
d_index = smoke_get_index ( dx , sds - > res [ 0 ] , dy , sds - > res [ 1 ] , dz ) ;
2013-03-10 19:12:40 +00:00
/* make sure emission cell is inside the new domain boundary */
if ( dx < 0 | | dy < 0 | | dz < 0 | | dx > = sds - > res [ 0 ] | | dy > = sds - > res [ 1 ] | | dz > = sds - > res [ 2 ] ) continue ;
2012-10-10 13:18:07 +00:00
2012-10-10 23:44:07 +00:00
if ( sfs - > type = = MOD_SMOKE_FLOW_TYPE_OUTFLOW ) { // outflow
2012-10-10 13:18:07 +00:00
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 */
2012-10-10 23:44:07 +00:00
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 ] ) ;
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
}
2012-10-10 13:18:07 +00:00
}
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 13:18:07 +00:00
/* 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 Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-04-28 21:46:43 +00:00
smoke_turbulence_get_res ( sds - > wt , bigres ) ;
2012-10-10 23:44:07 +00:00
block_size = sds - > amplify + 1 ; // high res block size
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 23:44:07 +00:00
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 ;
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 23:44:07 +00:00
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 ;
2012-10-10 13:18:07 +00:00
c111 = emission_map [ smoke_get_index ( ex , em - > res [ 0 ] , ey , em - > res [ 1 ] , ez ) ] ; // this cell
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 23:44:07 +00:00
for ( ii = 0 ; ii < block_size ; ii + + )
for ( jj = 0 ; jj < block_size ; jj + + )
for ( kk = 0 ; kk < block_size ; kk + + )
2012-10-10 13:18:07 +00:00
{
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 23:44:07 +00:00
float fx , fy , fz , interpolated_value ;
2012-10-10 13:18:07 +00:00
int shift_x , shift_y , shift_z ;
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 13:18:07 +00:00
/*
2012-10-10 23:44:07 +00:00
* Do volume interpolation if emitter smoothing
* is enabled
*/
2012-10-10 13:18:07 +00:00
if ( high_emission_smoothing )
{
/* get relative block position
* for interpolation smoothing */
2012-10-10 23:44:07 +00:00
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 ;
2012-10-10 13:18:07 +00:00
/* calculate trilinear interpolation */
2012-10-10 23:44:07 +00:00
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 ;
2012-10-10 13:18:07 +00:00
/* add some contrast / sharpness
* depending on hi - res block size */
2012-10-10 23:44:07 +00:00
interpolated_value = ( interpolated_value - 0.4f ) * ( block_size / 2 ) + 0.4f ;
2012-10-10 13:18:07 +00:00
CLAMP ( interpolated_value , 0.0f , 1.0f ) ;
/* shift smoke block index
* ( because pixel center is actually
* in halfway of the low res block ) */
2012-10-10 23:44:07 +00:00
shift_x = ( dx < 1 ) ? 0 : block_size / 2 ;
shift_y = ( dy < 1 ) ? 0 : block_size / 2 ;
shift_z = ( dz < 1 ) ? 0 : block_size / 2 ;
2012-10-10 13:18:07 +00:00
}
2012-10-10 23:44:07 +00:00
else {
2012-10-10 13:18:07 +00:00
/* 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 */
2012-10-10 23:44:07 +00:00
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 ) ;
2012-10-10 13:18:07 +00:00
2012-10-10 23:44:07 +00:00
if ( sfs - > type = = MOD_SMOKE_FLOW_TYPE_OUTFLOW ) { // outflow
2012-10-10 13:18:07 +00:00
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
2012-04-28 21:46:43 +00:00
}
}
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 23:44:07 +00:00
if ( flowobjs )
2012-04-28 21:46:43 +00:00
MEM_freeN ( flowobjs ) ;
2012-10-10 23:44:07 +00:00
if ( emaps )
2012-10-10 13:18:07 +00:00
MEM_freeN ( emaps ) ;
2012-04-28 21:46:43 +00:00
}
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-04-29 09:34:51 +00:00
static void update_effectors ( Scene * scene , Object * ob , SmokeDomainSettings * sds , float UNUSED ( dt ) )
2012-04-28 21:46:43 +00:00
{
2012-10-10 13:18:07 +00:00
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 ) ;
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 23:44:07 +00:00
if ( effectors )
2012-04-28 21:46:43 +00:00
{
float * density = smoke_get_density ( sds - > fluid ) ;
float * force_x = smoke_get_force_x ( sds - > fluid ) ;
float * force_y = smoke_get_force_y ( sds - > fluid ) ;
float * force_z = smoke_get_force_z ( sds - > fluid ) ;
float * velocity_x = smoke_get_velocity_x ( sds - > fluid ) ;
float * velocity_y = smoke_get_velocity_y ( sds - > fluid ) ;
float * velocity_z = smoke_get_velocity_z ( sds - > fluid ) ;
unsigned char * obstacle = smoke_get_obstacle ( sds - > fluid ) ;
2012-10-10 13:18:07 +00:00
int x ;
2012-04-28 21:46:43 +00:00
// precalculate wind forces
2012-10-10 13:18:07 +00:00
# pragma omp parallel for schedule(static)
2012-10-10 23:44:07 +00:00
for ( x = 0 ; x < sds - > res [ 0 ] ; x + + )
2012-10-10 13:18:07 +00:00
{
int y , z ;
2012-10-10 23:44:07 +00:00
for ( y = 0 ; y < sds - > res [ 1 ] ; y + + )
for ( z = 0 ; z < sds - > res [ 2 ] ; z + + )
{
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!
2012-11-09 16:15:00 +00:00
force_x [ index ] = min_ff ( max_ff ( - 1.0f , retvel [ 0 ] * 0.2f ) , 1.0f ) ;
force_y [ index ] = min_ff ( max_ff ( - 1.0f , retvel [ 1 ] * 0.2f ) , 1.0f ) ;
force_z [ index ] = min_ff ( max_ff ( - 1.0f , retvel [ 2 ] * 0.2f ) , 1.0f ) ;
2012-10-10 23:44:07 +00:00
}
2012-04-28 21:46:43 +00:00
}
}
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-04-28 21:46:43 +00:00
pdEndEffectors ( & effectors ) ;
}
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 13:18:07 +00:00
static void step ( Scene * scene , Object * ob , SmokeModifierData * smd , DerivedMesh * domain_dm , float fps )
2012-04-28 21:46:43 +00:00
{
2012-10-10 13:18:07 +00:00
SmokeDomainSettings * sds = smd - > domain ;
2012-04-28 21:46:43 +00:00
/* 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)
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 13:18:07 +00:00
float dt ;
2012-04-28 21:46:43 +00:00
float maxVelMag = 0.0f ;
int totalSubsteps ;
int substep = 0 ;
float dtSubdiv ;
2012-10-10 13:18:07 +00:00
float gravity [ 3 ] = { 0.0f , 0.0f , - 1.0f } ;
float gravity_mag ;
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 14:28:47 +00:00
#if 0 /* UNUSED */
2012-10-10 23:44:07 +00:00
/* get max velocity and lower the dt value if it is too high */
2012-10-10 13:18:07 +00:00
size_t size = sds - > res [ 0 ] * sds - > res [ 1 ] * sds - > res [ 2 ] ;
2012-04-28 21:46:43 +00:00
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 ;
2012-10-10 14:28:47 +00:00
# endif
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 13:18:07 +00:00
/* update object state */
invert_m4_m4 ( sds - > imat , ob - > obmat ) ;
copy_m4_m4 ( sds - > obmat , ob - > obmat ) ;
2013-01-29 19:27:05 +00:00
smoke_set_domain_from_derivedmesh ( sds , ob , domain_dm , ( sds - > flags & MOD_SMOKE_ADAPTIVE_DOMAIN ) ) ;
Smoke Patch + additions: a) Applying patch #22765 by Miika Hämäläinen (domain border collision settings, vorticity settings, time scale, non absolute density, smooth high res emitter, initial velocity multiplier, high res strength available to be set to 0), b) Additions by me: --Initial velocity is now per flow object, not per domain; --Using boundingbox as standard display mode for domains (was wire before); --When adding a flow object, an initial nice SmokeParticle system is added too with nice initial settings (life=1, no_render, unborn, etc) fitting smoke simulation; --Adaptive timesteps introduced to the smoke sim (depending on the magnitude of the velocity) because it was quite unstable when used for fire simulations, still needs to be tested and will also slow down some simulations.
2010-07-27 14:53:20 +00:00
2012-10-10 13:18:07 +00:00
/* 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 */
2012-10-10 23:44:07 +00:00
mul_v3_fl ( gravity , 1.0f / 9.810f ) ;
2012-10-10 13:18:07 +00:00
}
/* 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 ) ;
2012-05-27 18:45:16 +00:00
// maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel
2012-11-09 16:15:00 +00:00
maxVel = ( sds - > dx * 5.0f ) ;
2009-09-16 17:43:09 +00:00
2012-10-10 14:28:47 +00:00
#if 0
for ( i = 0 ; i < size ; i + + ) {
2012-10-10 23:44:07 +00:00
float vtemp = ( velX [ i ] * velX [ i ] + velY [ i ] * velY [ i ] + velZ [ i ] * velZ [ i ] ) ;
if ( vtemp > maxVelMag )
2012-04-28 21:46:43 +00:00
maxVelMag = vtemp ;
2012-10-10 14:28:47 +00:00
}
# endif
2009-09-16 17:43:09 +00:00
2012-11-09 16:15:00 +00:00
maxVelMag = sqrtf ( maxVelMag ) * dt * sds - > time_scale ;
2012-04-28 21:46:43 +00:00
totalSubsteps = ( int ) ( ( maxVelMag / maxVel ) + 1.0f ) ; /* always round up */
totalSubsteps = ( totalSubsteps < 1 ) ? 1 : totalSubsteps ;
totalSubsteps = ( totalSubsteps > maxSubSteps ) ? maxSubSteps : totalSubsteps ;
2012-05-27 18:45:16 +00:00
/* Disable substeps for now, since it results in numerical instability */
2012-10-10 23:44:07 +00:00
totalSubsteps = 1.0f ;
2012-04-28 21:46:43 +00:00
dtSubdiv = ( float ) dt / ( float ) totalSubsteps ;
// printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt);
2012-10-10 23:44:07 +00:00
for ( substep = 0 ; substep < totalSubsteps ; substep + + )
2009-09-16 17:43:09 +00:00
{
2012-04-28 21:46:43 +00:00
// calc animated obstacle velocities
2012-10-10 13:18:07 +00:00
update_flowsfluids ( scene , ob , sds , smd - > time , dtSubdiv ) ;
2012-04-28 21:46:43 +00:00
update_obstacles ( scene , ob , sds , dtSubdiv , substep , totalSubsteps ) ;
2009-10-22 23:22:05 +00:00
2012-10-10 13:18:07 +00:00
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 ) ;
}
}
}
2009-09-16 17:43:09 +00:00
2012-10-10 13:18:07 +00:00
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 ;
}
2012-10-10 23:44:07 +00:00
2012-10-10 13:18:07 +00:00
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
2012-10-10 23:44:07 +00:00
* it was originally simulated at ( if object moves without smoke step ) */
2012-10-10 13:18:07 +00:00
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 */
2012-10-10 23:44:07 +00:00
for ( i = 0 ; i < num_verts ; i + + ) {
2012-10-10 13:18:07 +00:00
add_v3_v3 ( mverts [ i ] . co , sds - > obj_shift_f ) ;
}
2012-04-28 21:46:43 +00:00
}
2012-10-10 13:18:07 +00:00
CDDM_calc_edges ( result ) ;
return result ;
2009-09-16 17:43:09 +00:00
}
2012-04-28 21:46:43 +00:00
2012-10-10 14:28:47 +00:00
static void smokeModifier_process ( SmokeModifierData * smd , Scene * scene , Object * ob , DerivedMesh * dm )
2012-10-10 23:44:07 +00:00
{
if ( ( smd - > type & MOD_SMOKE_TYPE_FLOW ) )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
if ( scene - > r . cfra > = smd - > time )
2009-09-16 17:43:09 +00:00
smokeModifier_init ( smd , ob , scene , dm ) ;
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
if ( smd - > flow - > dm ) smd - > flow - > dm - > release ( smd - > flow - > dm ) ;
smd - > flow - > dm = CDDM_copy ( dm ) ;
DM_ensure_tessface ( smd - > flow - > dm ) ;
2012-10-10 23:44:07 +00:00
if ( scene - > r . cfra > smd - > time )
2009-07-30 15:00:26 +00:00
{
2009-08-03 16:39:12 +00:00
smd - > time = scene - > r . cfra ;
}
2012-10-10 23:44:07 +00:00
else if ( scene - > r . cfra < smd - > time )
2009-08-03 16:39:12 +00:00
{
smd - > time = scene - > r . cfra ;
smokeModifier_reset ( smd ) ;
}
}
2012-10-10 23:44:07 +00:00
else if ( smd - > type & MOD_SMOKE_TYPE_COLL )
2009-08-03 16:39:12 +00:00
{
2012-10-10 23:44:07 +00:00
if ( scene - > r . cfra > = smd - > time )
2009-08-20 00:33:59 +00:00
smokeModifier_init ( smd , ob , scene , dm ) ;
2012-10-10 23:44:07 +00:00
if ( smd - > coll )
2009-08-03 16:39:12 +00:00
{
2012-10-10 23:44:07 +00:00
if ( smd - > coll - > dm )
2012-10-10 13:18:07 +00:00
smd - > coll - > dm - > release ( smd - > coll - > dm ) ;
2012-04-28 21:46:43 +00:00
2012-10-10 13:18:07 +00:00
smd - > coll - > dm = CDDM_copy ( dm ) ;
DM_ensure_tessface ( smd - > coll - > dm ) ;
2009-07-30 15:00:26 +00:00
}
2012-10-10 13:18:07 +00:00
smd - > time = scene - > r . cfra ;
2012-10-10 23:44:07 +00:00
if ( scene - > r . cfra < smd - > time )
2009-07-30 15:00:26 +00:00
{
smokeModifier_reset ( smd ) ;
}
}
2012-10-10 23:44:07 +00:00
else if ( smd - > type & MOD_SMOKE_TYPE_DOMAIN )
2009-07-30 15:00:26 +00:00
{
2009-09-16 17:43:09 +00:00
SmokeDomainSettings * sds = smd - > domain ;
PointCache * cache = NULL ;
2009-08-20 00:33:59 +00:00
PTCacheID pid ;
int startframe , endframe , framenr ;
2009-09-16 17:43:09 +00:00
float timescale ;
2009-08-20 00:33:59 +00:00
framenr = scene - > r . cfra ;
2010-11-30 21:31:18 +00:00
//printf("time: %d\n", scene->r.cfra);
2009-09-16 17:43:09 +00:00
cache = sds - > point_cache [ 0 ] ;
2009-08-20 00:33:59 +00:00
BKE_ptcache_id_from_smoke ( & pid , ob , smd ) ;
BKE_ptcache_id_time ( & pid , scene , framenr , & startframe , & endframe , & timescale ) ;
2012-10-10 23:44:07 +00:00
if ( ! smd - > domain - > fluid | | framenr = = startframe )
2009-09-16 17:43:09 +00:00
{
BKE_ptcache_id_reset ( scene , & pid , PTCACHE_RESET_OUTDATED ) ;
2012-10-10 13:18:07 +00:00
smokeModifier_reset ( smd ) ;
2010-09-27 12:24:12 +00:00
BKE_ptcache_validate ( cache , framenr ) ;
cache - > flag & = ~ PTCACHE_REDO_NEEDED ;
2009-08-20 00:33:59 +00:00
}
2009-09-16 17:43:09 +00:00
2012-10-10 23:44:07 +00:00
if ( ! smd - > domain - > fluid & & ( framenr ! = startframe ) & & ( smd - > domain - > flags & MOD_SMOKE_FILE_LOAD ) = = 0 & & ( cache - > flag & PTCACHE_BAKED ) = = 0 )
2009-09-16 17:43:09 +00:00
return ;
2009-07-30 15:00:26 +00:00
2010-11-23 14:04:05 +00:00
smd - > domain - > flags & = ~ MOD_SMOKE_FILE_LOAD ;
2010-11-30 21:31:18 +00:00
CLAMP ( framenr , startframe , endframe ) ;
2009-07-30 15:00:26 +00:00
2010-11-11 17:59:52 +00:00
/* If already viewing a pre/after frame, no need to reload */
if ( ( smd - > time = = framenr ) & & ( framenr ! = scene - > r . cfra ) )
2009-08-20 00:33:59 +00:00
return ;
2009-07-30 15:00:26 +00:00
2012-10-10 23:44:07 +00:00
if ( smokeModifier_init ( smd , ob , scene , dm ) = = 0 )
2009-09-16 17:43:09 +00:00
{
printf ( " bad smokeModifier_init \n " ) ;
2009-08-25 23:39:49 +00:00
return ;
2009-09-16 17:43:09 +00:00
}
2009-07-30 15:00:26 +00:00
2009-08-20 00:33:59 +00:00
/* try to read from cache */
2012-10-10 23:44:07 +00:00
if ( BKE_ptcache_read ( & pid , ( float ) framenr ) = = PTCACHE_READ_EXACT ) {
2010-03-21 20:36:06 +00:00
BKE_ptcache_validate ( cache , framenr ) ;
2010-09-27 12:24:12 +00:00
smd - > time = framenr ;
2010-11-30 21:31:18 +00:00
return ;
2009-08-20 00:33:59 +00:00
}
2012-10-10 23:44:07 +00:00
2010-09-27 12:24:12 +00:00
/* only calculate something when we advanced a single frame */
2012-10-10 23:44:07 +00:00
if ( framenr ! = ( int ) smd - > time + 1 )
2010-04-01 14:44:31 +00:00
return ;
2009-08-20 00:33:59 +00:00
2010-11-11 17:59:52 +00:00
/* don't simulate if viewing start frame, but scene frame is not real start frame */
if ( framenr ! = scene - > r . cfra )
2010-04-01 14:44:31 +00:00
return ;
2009-09-16 17:43:09 +00:00
tstart ( ) ;
2010-09-27 12:24:12 +00:00
/* if on second frame, write cache for first frame */
2012-10-10 23:44:07 +00:00
if ( ( int ) smd - > time = = startframe & & ( cache - > flag & PTCACHE_OUTDATED | | cache - > last_exact = = 0 ) ) {
2010-10-30 08:51:50 +00:00
// create shadows straight after domain initialization so we get nice shadows for startframe, too
2012-10-10 13:18:07 +00:00
smoke_calc_transparency ( sds , scene ) ;
2010-10-30 08:51:50 +00:00
2012-10-10 23:44:07 +00:00
if ( sds - > wt & & sds - > total_cells > 1 )
2010-11-30 21:31:18 +00:00
{
2012-10-10 23:44:07 +00:00
if ( sds - > flags & MOD_SMOKE_DISSOLVE )
2010-11-30 21:31:18 +00:00
smoke_dissolve_wavelet ( sds - > wt , sds - > diss_speed , sds - > flags & MOD_SMOKE_DISSOLVE_LOG ) ;
smoke_turbulence_step ( sds - > wt , sds - > fluid ) ;
}
2010-12-18 15:03:31 +00:00
BKE_ptcache_write ( & pid , startframe ) ;
2010-09-27 12:24:12 +00:00
}
2012-10-10 23:44:07 +00:00
2009-09-16 17:43:09 +00:00
// set new time
smd - > time = scene - > r . cfra ;
2009-08-20 00:33:59 +00:00
/* do simulation */
2009-09-16 17:43:09 +00:00
// simulate the actual smoke (c++ code in intern/smoke)
// DG: interesting commenting this line + deactivating loading of noise files
2012-10-10 23:44:07 +00:00
if ( framenr ! = startframe )
2009-10-22 23:22:05 +00:00
{
2012-10-10 23:44:07 +00:00
if ( sds - > flags & MOD_SMOKE_DISSOLVE )
2009-10-22 23:22:05 +00:00
smoke_dissolve ( sds - > fluid , sds - > diss_speed , sds - > flags & MOD_SMOKE_DISSOLVE_LOG ) ;
2012-10-10 23:44:07 +00:00
2012-10-10 13:18:07 +00:00
step ( scene , ob , smd , dm , scene - > r . frs_sec / scene - > r . frs_sec_base ) ;
2009-10-02 11:09:05 +00:00
}
2009-08-20 00:33:59 +00:00
2010-10-30 08:51:50 +00:00
// create shadows before writing cache so they get stored
2012-10-10 13:18:07 +00:00
smoke_calc_transparency ( sds , scene ) ;
2009-08-25 23:39:49 +00:00
2012-10-10 23:44:07 +00:00
if ( sds - > wt )
2009-08-20 00:33:59 +00:00
{
2012-10-10 23:44:07 +00:00
if ( sds - > flags & MOD_SMOKE_DISSOLVE )
2010-11-30 21:31:18 +00:00
smoke_dissolve_wavelet ( sds - > wt , sds - > diss_speed , sds - > flags & MOD_SMOKE_DISSOLVE_LOG ) ;
smoke_turbulence_step ( sds - > wt , sds - > fluid ) ;
2009-08-20 00:33:59 +00:00
}
2012-10-10 23:44:07 +00:00
2010-11-30 21:31:18 +00:00
BKE_ptcache_validate ( cache , framenr ) ;
2012-10-10 23:44:07 +00:00
if ( framenr ! = startframe )
2010-12-18 15:03:31 +00:00
BKE_ptcache_write ( & pid , framenr ) ;
2009-07-30 15:00:26 +00:00
2009-08-20 00:33:59 +00:00
tend ( ) ;
2012-06-17 09:58:26 +00:00
// printf ( "Frame: %d, Time: %f\n\n", (int)smd->time, (float) tval() );
2009-08-20 00:33:59 +00:00
}
}
2012-11-07 01:02:28 +00:00
struct DerivedMesh * smokeModifier_do ( SmokeModifierData * smd , Scene * scene , Object * ob , DerivedMesh * dm )
{
2012-10-10 13:18:07 +00:00
smokeModifier_process ( smd , scene , ob , dm ) ;
/* return generated geometry for adaptive domain */
2012-10-10 23:44:07 +00:00
if ( smd - > type & MOD_SMOKE_TYPE_DOMAIN & & smd - > domain & &
smd - > domain - > flags & MOD_SMOKE_ADAPTIVE_DOMAIN & &
smd - > domain - > base_res [ 0 ] )
2012-10-10 13:18:07 +00:00
{
return createDomainGeometry ( smd - > domain , ob ) ;
}
2013-03-09 03:46:30 +00:00
else {
return CDDM_copy ( dm ) ;
}
2012-10-10 13:18:07 +00:00
}
2009-09-16 17:43:09 +00:00
static float calc_voxel_transp ( float * result , float * input , int res [ 3 ] , int * pixel , float * tRay , float correct )
2009-08-20 00:33:59 +00:00
{
const size_t index = smoke_get_index ( pixel [ 0 ] , res [ 0 ] , pixel [ 1 ] , res [ 1 ] , pixel [ 2 ] ) ;
// T_ray *= T_vox
2012-11-09 16:15:00 +00:00
* tRay * = expf ( input [ index ] * correct ) ;
2012-10-10 23:44:07 +00:00
if ( result [ index ] < 0.0f )
2009-07-30 15:00:26 +00:00
{
2012-10-10 23:44:07 +00:00
// #pragma omp critical
result [ index ] = * tRay ;
}
2009-07-30 15:00:26 +00:00
2009-09-16 17:43:09 +00:00
return * tRay ;
2009-07-30 15:00:26 +00:00
}
2009-09-16 17:43:09 +00:00
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 )
2009-07-30 15:00:26 +00:00
{
2010-03-22 09:30:00 +00:00
int dx , dy , dz , i , l , m , n , x_inc , y_inc , z_inc , err_1 , err_2 , dx2 , dy2 , dz2 ;
int pixel [ 3 ] ;
pixel [ 0 ] = x1 ;
pixel [ 1 ] = y1 ;
pixel [ 2 ] = z1 ;
dx = x2 - x1 ;
dy = y2 - y1 ;
dz = z2 - z1 ;
x_inc = ( dx < 0 ) ? - 1 : 1 ;
l = abs ( dx ) ;
y_inc = ( dy < 0 ) ? - 1 : 1 ;
m = abs ( dy ) ;
z_inc = ( dz < 0 ) ? - 1 : 1 ;
n = abs ( dz ) ;
dx2 = l < < 1 ;
dy2 = m < < 1 ;
dz2 = n < < 1 ;
if ( ( l > = m ) & & ( l > = n ) ) {
err_1 = dy2 - l ;
err_2 = dz2 - l ;
for ( i = 0 ; i < l ; i + + ) {
2012-10-10 23:44:07 +00:00
if ( cb ( result , input , res , pixel , tRay , correct ) < = FLT_EPSILON )
2010-03-22 09:30:00 +00:00
break ;
if ( err_1 > 0 ) {
pixel [ 1 ] + = y_inc ;
err_1 - = dx2 ;
}
if ( err_2 > 0 ) {
pixel [ 2 ] + = z_inc ;
err_2 - = dx2 ;
}
err_1 + = dy2 ;
err_2 + = dz2 ;
pixel [ 0 ] + = x_inc ;
}
2012-10-10 23:44:07 +00:00
}
2012-03-24 06:18:31 +00:00
else if ( ( m > = l ) & & ( m > = n ) ) {
2010-03-22 09:30:00 +00:00
err_1 = dx2 - m ;
err_2 = dz2 - m ;
for ( i = 0 ; i < m ; i + + ) {
2012-10-10 23:44:07 +00:00
if ( cb ( result , input , res , pixel , tRay , correct ) < = FLT_EPSILON )
2010-03-22 09:30:00 +00:00
break ;
if ( err_1 > 0 ) {
pixel [ 0 ] + = x_inc ;
err_1 - = dy2 ;
}
if ( err_2 > 0 ) {
pixel [ 2 ] + = z_inc ;
err_2 - = dy2 ;
}
err_1 + = dx2 ;
err_2 + = dz2 ;
pixel [ 1 ] + = y_inc ;
}
2012-10-10 23:44:07 +00:00
}
2012-03-24 06:18:31 +00:00
else {
2010-03-22 09:30:00 +00:00
err_1 = dy2 - n ;
err_2 = dx2 - n ;
for ( i = 0 ; i < n ; i + + ) {
2012-10-10 23:44:07 +00:00
if ( cb ( result , input , res , pixel , tRay , correct ) < = FLT_EPSILON )
2010-03-22 09:30:00 +00:00
break ;
if ( err_1 > 0 ) {
pixel [ 1 ] + = y_inc ;
err_1 - = dz2 ;
}
if ( err_2 > 0 ) {
pixel [ 0 ] + = x_inc ;
err_2 - = dz2 ;
}
err_1 + = dy2 ;
err_2 + = dx2 ;
pixel [ 2 ] + = z_inc ;
}
}
cb ( result , input , res , pixel , tRay , correct ) ;
2009-07-30 15:00:26 +00:00
}
2012-10-10 13:18:07 +00:00
static void smoke_calc_transparency ( SmokeDomainSettings * sds , Scene * scene )
2009-07-30 15:00:26 +00:00
{
2012-10-10 13:18:07 +00:00
float bv [ 6 ] = { 0 } ;
float light [ 3 ] ;
2012-10-10 23:44:07 +00:00
int a , z , slabsize = sds - > res [ 0 ] * sds - > res [ 1 ] , size = sds - > res [ 0 ] * sds - > res [ 1 ] * sds - > res [ 2 ] ;
2012-10-10 13:18:07 +00:00
float * density = smoke_get_density ( sds - > fluid ) ;
2012-11-09 16:15:00 +00:00
float correct = - 7.0f * sds - > dx ;
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
if ( ! get_lamp ( scene , light ) ) return ;
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
/* convert light pos to sim cell space */
mul_m4_v3 ( sds - > imat , light ) ;
2012-10-18 14:23:04 +00:00
light [ 0 ] = ( light [ 0 ] - sds - > p0 [ 0 ] ) / sds - > cell_size [ 0 ] - 0.5f - ( float ) sds - > res_min [ 0 ] ;
light [ 1 ] = ( light [ 1 ] - sds - > p0 [ 1 ] ) / sds - > cell_size [ 1 ] - 0.5f - ( float ) sds - > res_min [ 1 ] ;
light [ 2 ] = ( light [ 2 ] - sds - > p0 [ 2 ] ) / sds - > cell_size [ 2 ] - 0.5f - ( float ) sds - > res_min [ 2 ] ;
2010-03-12 14:42:03 +00:00
2012-10-10 23:44:07 +00:00
for ( a = 0 ; a < size ; a + + )
sds - > shadow [ a ] = - 1.0f ;
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
/* 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
2009-07-30 15:00:26 +00:00
2012-12-29 01:54:58 +00:00
// #pragma omp parallel for schedule(static, 1)
2012-10-10 23:44:07 +00:00
for ( z = 0 ; z < sds - > res [ 2 ] ; z + + )
2010-01-25 15:10:14 +00:00
{
2012-10-10 23:44:07 +00:00
size_t index = z * slabsize ;
int x , y ;
2010-01-25 15:10:14 +00:00
2012-10-10 23:44:07 +00:00
for ( y = 0 ; y < sds - > res [ 1 ] ; y + + )
for ( x = 0 ; x < sds - > res [ 0 ] ; x + + , index + + )
2009-07-30 15:00:26 +00:00
{
float voxelCenter [ 3 ] ;
float pos [ 3 ] ;
int cell [ 3 ] ;
float tRay = 1.0 ;
2012-10-10 23:44:07 +00:00
if ( sds - > shadow [ index ] > = 0.0f )
continue ;
2012-10-10 13:18:07 +00:00
voxelCenter [ 0 ] = ( float ) x ;
voxelCenter [ 1 ] = ( float ) y ;
voxelCenter [ 2 ] = ( float ) z ;
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
// get starting cell (light pos)
2012-10-10 23:44:07 +00:00
if ( BLI_bvhtree_bb_raycast ( bv , light , voxelCenter , pos ) > FLT_EPSILON )
2009-07-30 15:00:26 +00:00
{
2012-10-10 13:18:07 +00:00
// 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 ] ) ;
2009-07-30 15:00:26 +00:00
}
2012-03-06 18:40:15 +00:00
else {
2012-10-10 13:18:07 +00:00
// we're inside -> use light itself
cell [ 0 ] = ( int ) floor ( light [ 0 ] ) ;
cell [ 1 ] = ( int ) floor ( light [ 1 ] ) ;
cell [ 2 ] = ( int ) floor ( light [ 2 ] ) ;
2009-07-30 15:00:26 +00:00
}
2012-10-10 13:18:07 +00:00
/* clamp within grid bounds */
2012-10-10 23:44:07 +00:00
CLAMP ( cell [ 0 ] , 0 , sds - > res [ 0 ] - 1 ) ;
CLAMP ( cell [ 1 ] , 0 , sds - > res [ 1 ] - 1 ) ;
CLAMP ( cell [ 2 ] , 0 , sds - > res [ 2 ] - 1 ) ;
2009-07-30 15:00:26 +00:00
2012-10-10 13:18:07 +00:00
bresenham_linie_3D ( cell [ 0 ] , cell [ 1 ] , cell [ 2 ] , x , y , z , & tRay , calc_voxel_transp , sds - > shadow , density , sds - > res , correct ) ;
2009-07-30 15:00:26 +00:00
2009-08-20 00:33:59 +00:00
// convention -> from a RGBA float array, use G value for tRay
2009-09-16 17:43:09 +00:00
// #pragma omp critical
2012-10-10 23:44:07 +00:00
sds - > shadow [ index ] = tRay ;
2009-07-30 15:00:26 +00:00
}
2010-01-25 15:10:14 +00:00
}
2009-07-30 15:00:26 +00:00
}
2012-10-10 13:18:07 +00:00
/* get smoke velocity and density at given coordinates
2012-10-10 23:44:07 +00:00
* returns fluid density or - 1.0f if outside domain */
2012-10-10 13:18:07 +00:00
float smoke_get_velocity_at ( struct Object * ob , float position [ 3 ] , float velocity [ 3 ] )
{
2012-10-10 23:44:07 +00:00
SmokeModifierData * smd = ( SmokeModifierData * ) modifiers_findByType ( ob , eModifierType_Smoke ) ;
2012-10-10 13:18:07 +00:00
zero_v3 ( velocity ) ;
2012-10-10 23:44:07 +00:00
if ( smd & & ( smd - > type & MOD_SMOKE_TYPE_DOMAIN ) & & smd - > domain & & smd - > domain - > fluid ) {
2012-10-10 13:18:07 +00:00
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 ;
}
2012-12-18 01:52:18 +00:00
int smoke_get_data_flags ( SmokeDomainSettings * sds )
{
2012-10-10 13:18:07 +00:00
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 ;
}
2011-10-21 00:48:02 +00:00
# endif /* WITH_SMOKE */