Google Summer of Code project: "Smoke Simulator Improvements & Fire".

Documentation & Test blend files:
------------------
http://wiki.blender.org/index.php/User:MiikaH/GSoC-2012-Smoke-Simulator-Improvements

Credits:
------------------
Miika Hamalainen (MiikaH): Student / Main programmer

Daniel Genrich (Genscher): Mentor / Programmer of merged patches from Smoke2 branch
Google: For Google Summer of Code 2012
This commit is contained in:
2012-10-10 13:18:07 +00:00
parent f0a9b66469
commit cb634b9100
50 changed files with 4206 additions and 1836 deletions

View File

@@ -40,6 +40,7 @@ set(SRC
intern/FLUID_3D_SOLVERS.cpp
intern/FLUID_3D_STATIC.cpp
intern/LU_HELPER.cpp
intern/spectrum.cpp
intern/SPHERE.cpp
intern/WTURBULENCE.cpp
intern/smoke_API.cpp
@@ -53,6 +54,7 @@ set(SRC
intern/LU_HELPER.h
intern/MERSENNETWISTER.h
intern/OBSTACLE.h
intern/spectrum.h
intern/SPHERE.h
intern/VEC3.h
intern/WAVELET_NOISE.h

View File

@@ -37,17 +37,23 @@ extern "C" {
struct FLUID_3D;
// export
void smoke_export(struct FLUID_3D *fluid, float *dt, float *dx, float **dens, float **densold, float **heat, float **heatold, float **vx, float **vy, float **vz, float **vxold, float **vyold, float **vzold, unsigned char **obstacles);
// low res
struct FLUID_3D *smoke_init(int *res, float *p0, float dtdef);
struct FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, int use_fire, int use_colors);
void smoke_free(struct FLUID_3D *fluid);
void smoke_initBlenderRNA(struct FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli);
void smoke_step(struct FLUID_3D *fluid, float dtSubdiv);
void smoke_initBlenderRNA(struct FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp);
void smoke_step(struct FLUID_3D *fluid, float gravity[3], float dtSubdiv);
float *smoke_get_density(struct FLUID_3D *fluid);
float *smoke_get_flame(struct FLUID_3D *fluid);
float *smoke_get_fuel(struct FLUID_3D *fluid);
float *smoke_get_react(struct FLUID_3D *fluid);
float *smoke_get_color_r(struct FLUID_3D *fluid);
float *smoke_get_color_g(struct FLUID_3D *fluid);
float *smoke_get_color_b(struct FLUID_3D *fluid);
void smoke_get_rgba(struct FLUID_3D *fluid, float *data, int sequential);
void smoke_get_rgba_from_density(struct FLUID_3D *fluid, float color[3], float *data, int sequential);
float *smoke_get_heat(struct FLUID_3D *fluid);
float *smoke_get_velocity_x(struct FLUID_3D *fluid);
float *smoke_get_velocity_y(struct FLUID_3D *fluid);
@@ -68,19 +74,44 @@ size_t smoke_get_index2d(int x, int max_x, int y);
void smoke_dissolve(struct FLUID_3D *fluid, int speed, int log);
// wavelet turbulence functions
struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype);
struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, int use_fire, int use_colors);
void smoke_turbulence_free(struct WTURBULENCE *wt);
void smoke_turbulence_step(struct WTURBULENCE *wt, struct FLUID_3D *fluid);
float *smoke_turbulence_get_density(struct WTURBULENCE *wt);
float *smoke_turbulence_get_color_r(struct WTURBULENCE *wt);
float *smoke_turbulence_get_color_g(struct WTURBULENCE *wt);
float *smoke_turbulence_get_color_b(struct WTURBULENCE *wt);
void smoke_turbulence_get_rgba(struct WTURBULENCE *wt, float *data, int sequential);
void smoke_turbulence_get_rgba_from_density(struct WTURBULENCE *wt, float color[3], float *data, int sequential);
float *smoke_turbulence_get_flame(struct WTURBULENCE *wt);
float *smoke_turbulence_get_fuel(struct WTURBULENCE *wt);
float *smoke_turbulence_get_react(struct WTURBULENCE *wt);
void smoke_turbulence_get_res(struct WTURBULENCE *wt, int *res);
int smoke_turbulence_get_cells(struct WTURBULENCE *wt);
void smoke_turbulence_set_noise(struct WTURBULENCE *wt, int type);
void smoke_initWaveletBlenderRNA(struct WTURBULENCE *wt, float *strength);
void smoke_dissolve_wavelet(struct WTURBULENCE *wt, int speed, int log);
// export
void smoke_turbulence_export(struct WTURBULENCE *wt, float **dens, float **densold, float **tcu, float **tcv, float **tcw);
/* export */
void smoke_export(struct FLUID_3D *fluid, float *dt, float *dx, float **dens, float **react, float **flame, float **fuel, float **heat, float **heatold,
float **vx, float **vy, float **vz, float **r, float **g, float **b, unsigned char **obstacles);
void smoke_turbulence_export(struct WTURBULENCE *wt, float **dens, float **react, float **flame, float **fuel,
float **r, float **g, float **b, float **tcu, float **tcv, float **tcw);
/* flame spectrum */
void flame_get_spectrum(unsigned char *spec, int width, float t1, float t2);
/* data fields */
int smoke_has_heat(struct FLUID_3D *fluid);
int smoke_has_fuel(struct FLUID_3D *fluid);
int smoke_has_colors(struct FLUID_3D *fluid);
int smoke_turbulence_has_fuel(struct WTURBULENCE *wt);
int smoke_turbulence_has_colors(struct WTURBULENCE *wt);
void smoke_ensure_heat(struct FLUID_3D *fluid);
void smoke_ensure_fire(struct FLUID_3D *fluid, struct WTURBULENCE *wt);
void smoke_ensure_colors(struct FLUID_3D *fluid, struct WTURBULENCE *wt, float init_r, float init_g, float init_b);
#ifdef __cplusplus
}

View File

@@ -44,17 +44,12 @@
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
FLUID_3D::FLUID_3D(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors) :
_xRes(res[0]), _yRes(res[1]), _zRes(res[2]), _res(0.0f)
{
// set simulation consts
_dt = dtdef; // just in case. set in step from a RNA factor
// start point of array
_p0[0] = p0[0];
_p0[1] = p0[1];
_p0[2] = p0[2];
_iterations = 100;
_tempAmb = 0;
_heatDiffusion = 1e-3;
@@ -72,7 +67,10 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
*/
// scale the constants according to the refinement of the grid
if (!dx)
_dx = 1.0f / (float)_maxRes;
else
_dx = dx;
_constantScaling = 64.0f / _maxRes;
_constantScaling = (_constantScaling < 1.0f) ? 1.0f : _constantScaling;
_vorticityEps = 2.0f / _constantScaling; // Just in case set a default value
@@ -94,8 +92,6 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
_zForce = new float[_totalCells];
_density = new float[_totalCells];
_densityOld = new float[_totalCells];
_heat = new float[_totalCells];
_heatOld = new float[_totalCells];
_obstacles = new unsigned char[_totalCells]; // set 0 at end of step
// For threaded version:
@@ -103,7 +99,6 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
_yVelocityTemp = new float[_totalCells];
_zVelocityTemp = new float[_totalCells];
_densityTemp = new float[_totalCells];
_heatTemp = new float[_totalCells];
// DG TODO: check if alloc went fine
@@ -111,8 +106,6 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
{
_density[x] = 0.0f;
_densityOld[x] = 0.0f;
_heat[x] = 0.0f;
_heatOld[x] = 0.0f;
_xVelocity[x] = 0.0f;
_yVelocity[x] = 0.0f;
_zVelocity[x] = 0.0f;
@@ -128,6 +121,25 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
_obstacles[x] = false;
}
/* heat */
_heat = _heatOld = _heatTemp = NULL;
if (init_heat) {
initHeat();
}
// Fire simulation
_flame = _fuel = _fuelTemp = _fuelOld = NULL;
_react = _reactTemp = _reactOld = NULL;
if (init_fire) {
initFire();
}
// Smoke color
_color_r = _color_rOld = _color_rTemp = NULL;
_color_g = _color_gOld = _color_gTemp = NULL;
_color_b = _color_bOld = _color_bTemp = NULL;
if (init_colors) {
initColors(0.0f, 0.0f, 0.0f);
}
// boundary conditions of the fluid domain
// set default values -> vertically non-colliding
_domainBcFront = true;
@@ -138,9 +150,70 @@ FLUID_3D::FLUID_3D(int *res, float *p0, float dtdef) :
_domainBcRight = _domainBcLeft;
_colloPrev = 1; // default value
}
setBorderObstacles(); // walls
void FLUID_3D::initHeat()
{
if (!_heat) {
_heat = new float[_totalCells];
_heatOld = new float[_totalCells];
_heatTemp = new float[_totalCells];
for (int x = 0; x < _totalCells; x++)
{
_heat[x] = 0.0f;
_heatOld[x] = 0.0f;
}
}
}
void FLUID_3D::initFire()
{
if (!_flame) {
_flame = new float[_totalCells];
_fuel = new float[_totalCells];
_fuelTemp = new float[_totalCells];
_fuelOld = new float[_totalCells];
_react = new float[_totalCells];
_reactTemp = new float[_totalCells];
_reactOld = new float[_totalCells];
for (int x = 0; x < _totalCells; x++)
{
_flame[x] = 0.0f;
_fuel[x] = 0.0f;
_fuelTemp[x] = 0.0f;
_fuelOld[x] = 0.0f;
_react[x] = 0.0f;
_reactTemp[x] = 0.0f;
_reactOld[x] = 0.0f;
}
}
}
void FLUID_3D::initColors(float init_r, float init_g, float init_b)
{
if (!_color_r) {
_color_r = new float[_totalCells];
_color_rOld = new float[_totalCells];
_color_rTemp = new float[_totalCells];
_color_g = new float[_totalCells];
_color_gOld = new float[_totalCells];
_color_gTemp = new float[_totalCells];
_color_b = new float[_totalCells];
_color_bOld = new float[_totalCells];
_color_bTemp = new float[_totalCells];
for (int x = 0; x < _totalCells; x++)
{
_color_r[x] = _density[x] * init_r;
_color_rOld[x] = 0.0f;
_color_g[x] = _density[x] * init_g;
_color_gOld[x] = 0.0f;
_color_b[x] = _density[x] * init_b;
_color_bOld[x] = 0.0f;
}
}
}
void FLUID_3D::setBorderObstacles()
@@ -204,7 +277,6 @@ FLUID_3D::~FLUID_3D()
if (_heat) delete[] _heat;
if (_heatOld) delete[] _heatOld;
if (_obstacles) delete[] _obstacles;
// if (_wTurbulence) delete _wTurbulence;
if (_xVelocityTemp) delete[] _xVelocityTemp;
if (_yVelocityTemp) delete[] _yVelocityTemp;
@@ -212,23 +284,48 @@ FLUID_3D::~FLUID_3D()
if (_densityTemp) delete[] _densityTemp;
if (_heatTemp) delete[] _heatTemp;
if (_flame) delete[] _flame;
if (_fuel) delete[] _fuel;
if (_fuelTemp) delete[] _fuelTemp;
if (_fuelOld) delete[] _fuelOld;
if (_react) delete[] _react;
if (_reactTemp) delete[] _reactTemp;
if (_reactOld) delete[] _reactOld;
if (_color_r) delete[] _color_r;
if (_color_rOld) delete[] _color_rOld;
if (_color_rTemp) delete[] _color_rTemp;
if (_color_g) delete[] _color_g;
if (_color_gOld) delete[] _color_gOld;
if (_color_gTemp) delete[] _color_gTemp;
if (_color_b) delete[] _color_b;
if (_color_bOld) delete[] _color_bOld;
if (_color_bTemp) delete[] _color_bTemp;
// printf("deleted fluid\n");
}
// init direct access functions from blender
void FLUID_3D::initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *borderCollision)
void FLUID_3D::initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *borderCollision, float *burning_rate,
float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp)
{
_alpha = alpha;
_beta = beta;
_dtFactor = dt_factor;
_vorticityRNA = vorticity;
_borderColli = borderCollision;
_burning_rate = burning_rate;
_flame_smoke = flame_smoke;
_flame_smoke_color = flame_smoke_color;
_flame_vorticity = flame_vorticity;
_ignition_temp = flame_ignition_temp;
_max_temp = flame_max_temp;
}
//////////////////////////////////////////////////////////////////////
// step simulation once
//////////////////////////////////////////////////////////////////////
void FLUID_3D::step(float dt)
void FLUID_3D::step(float dt, float gravity[3])
{
#if 0
// If border rules have been changed
@@ -281,7 +378,7 @@ void FLUID_3D::step(float dt)
wipeBoundariesSL(zBegin, zEnd);
addVorticity(zBegin, zEnd);
addBuoyancy(_heat, _density, zBegin, zEnd);
addBuoyancy(_heat, _density, gravity, zBegin, zEnd);
addForce(zBegin, zEnd);
#if PARALLEL==1
@@ -315,10 +412,12 @@ void FLUID_3D::step(float dt)
project();
#if PARALLEL==1
}
else
else if (i==1)
{
#endif
if (_heat) {
diffuseHeat();
}
#if PARALLEL==1
}
}
@@ -338,6 +437,13 @@ void FLUID_3D::step(float dt)
SWAP_POINTERS(_density, _densityOld);
SWAP_POINTERS(_heat, _heatOld);
SWAP_POINTERS(_fuel, _fuelOld);
SWAP_POINTERS(_react, _reactOld);
SWAP_POINTERS(_color_r, _color_rOld);
SWAP_POINTERS(_color_g, _color_gOld);
SWAP_POINTERS(_color_b, _color_bOld);
advectMacCormackBegin(0, _zRes);
#if PARALLEL==1
@@ -398,9 +504,6 @@ void FLUID_3D::step(float dt)
SWAP_POINTERS(_yVelocity, _yForce);
SWAP_POINTERS(_zVelocity, _zForce);
_totalTime += _dt;
_totalSteps++;
@@ -643,6 +746,15 @@ void FLUID_3D::wipeBoundaries(int zBegin, int zEnd)
setZeroBorder(_yVelocity, _res, zBegin, zEnd);
setZeroBorder(_zVelocity, _res, zBegin, zEnd);
setZeroBorder(_density, _res, zBegin, zEnd);
if (_fuel) {
setZeroBorder(_fuel, _res, zBegin, zEnd);
setZeroBorder(_react, _res, zBegin, zEnd);
}
if (_color_r) {
setZeroBorder(_color_r, _res, zBegin, zEnd);
setZeroBorder(_color_g, _res, zBegin, zEnd);
setZeroBorder(_color_b, _res, zBegin, zEnd);
}
}
void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
@@ -668,6 +780,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
_yVelocity[index] = 0.0f;
_zVelocity[index] = 0.0f;
_density[index] = 0.0f;
if (_fuel) {
_fuel[index] = 0.0f;
_react[index] = 0.0f;
}
if (_color_r) {
_color_r[index] = 0.0f;
_color_g[index] = 0.0f;
_color_b[index] = 0.0f;
}
// right slab
index += _xRes - 1;
@@ -675,6 +796,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
_yVelocity[index] = 0.0f;
_zVelocity[index] = 0.0f;
_density[index] = 0.0f;
if (_fuel) {
_fuel[index] = 0.0f;
_react[index] = 0.0f;
}
if (_color_r) {
_color_r[index] = 0.0f;
_color_g[index] = 0.0f;
_color_b[index] = 0.0f;
}
}
/////////////////////////////////////
@@ -690,6 +820,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
_yVelocity[index] = 0.0f;
_zVelocity[index] = 0.0f;
_density[index] = 0.0f;
if (_fuel) {
_fuel[index] = 0.0f;
_react[index] = 0.0f;
}
if (_color_r) {
_color_r[index] = 0.0f;
_color_g[index] = 0.0f;
_color_b[index] = 0.0f;
}
// top slab
index += slabSize - _xRes;
@@ -697,6 +836,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
_yVelocity[index] = 0.0f;
_zVelocity[index] = 0.0f;
_density[index] = 0.0f;
if (_fuel) {
_fuel[index] = 0.0f;
_react[index] = 0.0f;
}
if (_color_r) {
_color_r[index] = 0.0f;
_color_g[index] = 0.0f;
_color_b[index] = 0.0f;
}
}
@@ -717,6 +865,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
_yVelocity[index] = 0.0f;
_zVelocity[index] = 0.0f;
_density[index] = 0.0f;
if (_fuel) {
_fuel[index] = 0.0f;
_react[index] = 0.0f;
}
if (_color_r) {
_color_r[index] = 0.0f;
_color_g[index] = 0.0f;
_color_b[index] = 0.0f;
}
}
if (zEnd == _zRes)
@@ -735,6 +892,15 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
_yVelocity[indexx] = 0.0f;
_zVelocity[indexx] = 0.0f;
_density[indexx] = 0.0f;
if (_fuel) {
_fuel[index] = 0.0f;
_react[index] = 0.0f;
}
if (_color_r) {
_color_r[index] = 0.0f;
_color_g[index] = 0.0f;
_color_b[index] = 0.0f;
}
}
}
@@ -781,35 +947,6 @@ void FLUID_3D::project()
if(!_domainBcTop) setNeumannZ(_zVelocity, _res, 0, _zRes);
else setZeroZ(_zVelocity, _res, 0, _zRes);
/*
{
float maxx = 0, maxy = 0, maxz = 0;
for(unsigned int i = 0; i < _xRes * _yRes * _zRes; i++)
{
if(_xVelocity[i] > maxx)
maxx = _xVelocity[i];
if(_yVelocity[i] > maxy)
maxy = _yVelocity[i];
if(_zVelocity[i] > maxz)
maxz = _zVelocity[i];
}
printf("Max velx: %f, vely: %f, velz: %f\n", maxx, maxy, maxz);
}
*/
/*
{
float maxvalue = 0;
for(unsigned int i = 0; i < _xRes * _yRes * _zRes; i++)
{
if(_heat[i] > maxvalue)
maxvalue = _heat[i];
}
printf("Max heat: %f\n", maxvalue);
}
*/
// calculate divergence
index = _slabSize + _xRes + 1;
for (z = 1; z < _zRes - 1; z++, index += 2 * _xRes)
@@ -1007,7 +1144,6 @@ void FLUID_3D::diffuseHeat()
for (int x = 0; x < _totalCells; x++)
if (_obstacles[x])
_heat[x] = 0.0f;
}
//////////////////////////////////////////////////////////////////////
@@ -1175,7 +1311,7 @@ void FLUID_3D::setObstacleBoundaries(float *_pressure, int zBegin, int zEnd)
//////////////////////////////////////////////////////////////////////
// add buoyancy forces
//////////////////////////////////////////////////////////////////////
void FLUID_3D::addBuoyancy(float *heat, float *density, int zBegin, int zEnd)
void FLUID_3D::addBuoyancy(float *heat, float *density, float gravity[3], int zBegin, int zEnd)
{
int index = zBegin*_slabSize;
@@ -1183,7 +1319,10 @@ void FLUID_3D::addBuoyancy(float *heat, float *density, int zBegin, int zEnd)
for (int y = 0; y < _yRes; y++)
for (int x = 0; x < _xRes; x++, index++)
{
_zForce[index] += *_alpha * density[index] + (*_beta * (heat[index] - _tempAmb)); // DG: was _yForce, changed for Blender
float buoyancy = *_alpha * density[index] + (*_beta * (((heat) ? heat[index] : 0.0f) - _tempAmb));
_xForce[index] -= gravity[0] * buoyancy;
_yForce[index] -= gravity[1] * buoyancy;
_zForce[index] -= gravity[2] * buoyancy;
}
}
@@ -1192,8 +1331,10 @@ void FLUID_3D::addBuoyancy(float *heat, float *density, int zBegin, int zEnd)
//////////////////////////////////////////////////////////////////////
void FLUID_3D::addVorticity(int zBegin, int zEnd)
{
// set flame vorticity from RNA value
float flame_vorticity = (*_flame_vorticity)/_constantScaling;
//int x,y,z,index;
if(_vorticityEps<=0.) return;
if(_vorticityEps+flame_vorticity<=0.) return;
int _blockSize=zEnd-zBegin;
int _blockTotalCells = _slabSize * (_blockSize+2);
@@ -1300,14 +1441,15 @@ void FLUID_3D::addVorticity(int zBegin, int zEnd)
float magnitude = sqrtf(N[0] * N[0] + N[1] * N[1] + N[2] * N[2]);
if (magnitude > FLT_EPSILON)
{
float flame_vort = (_fuel) ? _fuel[index]*flame_vorticity : 0.0f;
magnitude = 1.0f / magnitude;
N[0] *= magnitude;
N[1] *= magnitude;
N[2] *= magnitude;
_xForce[index] += (N[1] * _zVorticity[vIndex] - N[2] * _yVorticity[vIndex]) * _dx * eps;
_yForce[index] += (N[2] * _xVorticity[vIndex] - N[0] * _zVorticity[vIndex]) * _dx * eps;
_zForce[index] += (N[0] * _yVorticity[vIndex] - N[1] * _xVorticity[vIndex]) * _dx * eps;
_xForce[index] += (N[1] * _zVorticity[vIndex] - N[2] * _yVorticity[vIndex]) * _dx * (eps + flame_vort);
_yForce[index] += (N[2] * _xVorticity[vIndex] - N[0] * _zVorticity[vIndex]) * _dx * (eps + flame_vort);
_zForce[index] += (N[0] * _yVorticity[vIndex] - N[1] * _xVorticity[vIndex]) * _dx * (eps + flame_vort);
}
} // if
vIndex++;
@@ -1328,14 +1470,9 @@ void FLUID_3D::advectMacCormackBegin(int zBegin, int zEnd)
{
Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
if(!_domainBcLeft) copyBorderX(_xVelocityOld, res, zBegin, zEnd);
else setZeroX(_xVelocityOld, res, zBegin, zEnd);
if(!_domainBcFront) copyBorderY(_yVelocityOld, res, zBegin, zEnd);
else setZeroY(_yVelocityOld, res, zBegin, zEnd);
if(!_domainBcTop) copyBorderZ(_zVelocityOld, res, zBegin, zEnd);
else setZeroZ(_zVelocityOld, res, zBegin, zEnd);
setZeroX(_xVelocityOld, res, zBegin, zEnd);
setZeroY(_yVelocityOld, res, zBegin, zEnd);
setZeroZ(_zVelocityOld, res, zBegin, zEnd);
}
//////////////////////////////////////////////////////////////////////
@@ -1355,7 +1492,18 @@ void FLUID_3D::advectMacCormackEnd1(int zBegin, int zEnd)
// advectFieldMacCormack1(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res)
advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _densityTemp, res, zBegin, zEnd);
if (_heat) {
advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heatTemp, res, zBegin, zEnd);
}
if (_fuel) {
advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _fuelOld, _fuelTemp, res, zBegin, zEnd);
advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _reactOld, _reactTemp, res, zBegin, zEnd);
}
if (_color_r) {
advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_rOld, _color_rTemp, res, zBegin, zEnd);
advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_gOld, _color_gTemp, res, zBegin, zEnd);
advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_bOld, _color_bTemp, res, zBegin, zEnd);
}
advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocity, res, zBegin, zEnd);
advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocity, res, zBegin, zEnd);
advectFieldMacCormack1(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocity, res, zBegin, zEnd);
@@ -1371,17 +1519,30 @@ void FLUID_3D::advectMacCormackEnd2(int zBegin, int zEnd)
const float dt0 = _dt / _dx;
Vec3Int res = Vec3Int(_xRes,_yRes,_zRes);
// use force array as temp arrays
// use force array as temp array
float* t1 = _xForce;
// advectFieldMacCormack2(dt, xVelocity, yVelocity, zVelocity, oldField, newField, tempfield, temp, res, obstacles)
/* finish advection */
advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _density, _densityTemp, t1, res, _obstacles, zBegin, zEnd);
if (_heat) {
advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heat, _heatTemp, t1, res, _obstacles, zBegin, zEnd);
}
if (_fuel) {
advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _fuelOld, _fuel, _fuelTemp, t1, res, _obstacles, zBegin, zEnd);
advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _reactOld, _react, _reactTemp, t1, res, _obstacles, zBegin, zEnd);
}
if (_color_r) {
advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_rOld, _color_r, _color_rTemp, t1, res, _obstacles, zBegin, zEnd);
advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_gOld, _color_g, _color_gTemp, t1, res, _obstacles, zBegin, zEnd);
advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _color_bOld, _color_b, _color_bTemp, t1, res, _obstacles, zBegin, zEnd);
}
advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocityTemp, _xVelocity, t1, res, _obstacles, zBegin, zEnd);
advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocityTemp, _yVelocity, t1, res, _obstacles, zBegin, zEnd);
advectFieldMacCormack2(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocityTemp, _zVelocity, t1, res, _obstacles, zBegin, zEnd);
/* set boundary conditions for velocity */
if(!_domainBcLeft) copyBorderX(_xVelocityTemp, res, zBegin, zEnd);
else setZeroX(_xVelocityTemp, res, zBegin, zEnd);
@@ -1391,40 +1552,71 @@ void FLUID_3D::advectMacCormackEnd2(int zBegin, int zEnd)
if(!_domainBcTop) copyBorderZ(_zVelocityTemp, res, zBegin, zEnd);
else setZeroZ(_zVelocityTemp, res, zBegin, zEnd);
/* clear data boundaries */
setZeroBorder(_density, res, zBegin, zEnd);
setZeroBorder(_heat, res, zBegin, zEnd);
#if 0
{
const size_t index_ = _slabSize + _xRes + 1;
int bb=0;
int bt=0;
if (_fuel) {
setZeroBorder(_fuel, res, zBegin, zEnd);
setZeroBorder(_react, res, zBegin, zEnd);
}
if (_color_r) {
setZeroBorder(_color_r, res, zBegin, zEnd);
setZeroBorder(_color_g, res, zBegin, zEnd);
setZeroBorder(_color_b, res, zBegin, zEnd);
}
}
if (zBegin == 0) {bb = 1;}
if (zEnd == _zRes) {bt = 1;}
for (int z = zBegin + bb; z < zEnd - bt; z++)
void FLUID_3D::processBurn(float *fuel, float *smoke, float *react, float *flame, float *heat,
float *r, float *g, float *b, int total_cells, float dt)
{
size_t index = index_ +(z-1)*_slabSize;
float burning_rate = *_burning_rate;
float flame_smoke = *_flame_smoke;
float ignition_point = *_ignition_temp;
float temp_max = *_max_temp;
for (int y = 1; y < _yRes - 1; y++, index += 2)
for (int index = 0; index < total_cells; index++)
{
for (int x = 1; x < _xRes - 1; x++, index++)
{
// clean custom velocities from moving obstacles again
if (_obstacles[index])
{
_xVelocity[index] =
_yVelocity[index] =
_zVelocity[index] = 0.0f;
}
}
}
}
}
#endif
float orig_fuel = fuel[index];
float orig_smoke = smoke[index];
float smoke_emit = 0.0f;
float react_coord = 0.0f;
/*int begin=zBegin * _slabSize;
int end=begin + (zEnd - zBegin) * _slabSize;
for (int x = begin; x < end; x++)
_xForce[x] = _yForce[x] = 0.0f;*/
/* process fuel */
fuel[index] -= burning_rate * dt;
if (fuel[index] < 0.0f) fuel[index] = 0.0f;
/* process reaction coordinate */
if (orig_fuel) {
react[index] *= fuel[index]/orig_fuel;
react_coord = react[index];
}
else {
react[index] = 0.0f;
}
/* emit smoke based on fuel burn rate and "flame_smoke" factor */
smoke_emit = (orig_fuel < 1.0f) ? (1.0f - orig_fuel)*0.5f : 0.0f;
smoke_emit = (smoke_emit + 0.5f) * (orig_fuel-fuel[index]) * 0.1f * flame_smoke;
smoke[index] += smoke_emit;
CLAMP(smoke[index], 0.0f, 1.0f);
/* model flame temperature curve from the reaction coordinate (fuel) */
if (react_coord>0.0f) {
/* do a smooth falloff for rest of the values */
flame[index] = pow(react_coord, 0.5f);
}
else
flame[index] = 0.0f;
/* set fluid temperature from the flame temperature profile */
if (heat && flame[index])
heat[index] = (1.0f-flame[index])*ignition_point + flame[index]*temp_max;
/* mix new color */
if (r && smoke_emit) {
float smoke_factor = smoke[index]/(orig_smoke+smoke_emit);
r[index] = (r[index] + _flame_smoke_color[0] * smoke_emit) * smoke_factor;
g[index] = (g[index] + _flame_smoke_color[1] * smoke_emit) * smoke_factor;
b[index] = (b[index] + _flame_smoke_color[2] * smoke_emit) * smoke_factor;
}
}
}

View File

@@ -46,11 +46,16 @@ class WTURBULENCE;
class FLUID_3D
{
public:
FLUID_3D(int *res, /* int amplify, */ float *p0, float dtdef);
FLUID_3D(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors);
FLUID_3D() {};
virtual ~FLUID_3D();
void initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli);
void initHeat();
void initFire();
void initColors(float init_r, float init_g, float init_b);
void initBlenderRNA(float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *ignition_temp, float *max_temp);
// create & allocate vector noise advection
void initVectorNoise(int amplify);
@@ -58,7 +63,7 @@ class FLUID_3D
void addSmokeColumn();
static void addSmokeTestCase(float* field, Vec3Int res);
void step(float dt);
void step(float dt, float gravity[3]);
void addObstacle(OBSTACLE* obstacle);
const float* xVelocity() { return _xVelocity; };
@@ -115,6 +120,27 @@ class FLUID_3D
float* _heatTemp;
float* _densityTemp;
// fire simulation
float *_flame;
float *_fuel;
float *_fuelTemp;
float *_fuelOld;
float *_react;
float *_reactTemp;
float *_reactOld;
// smoke color
float *_color_r;
float *_color_rOld;
float *_color_rTemp;
float *_color_g;
float *_color_gOld;
float *_color_gTemp;
float *_color_b;
float *_color_bOld;
float *_color_bTemp;
// CG fields
int _iterations;
@@ -153,14 +179,16 @@ class FLUID_3D
void wipeBoundariesSL(int zBegin, int zEnd);
void addForce(int zBegin, int zEnd);
void addVorticity(int zBegin, int zEnd);
void addBuoyancy(float *heat, float *density, int zBegin, int zEnd);
void addBuoyancy(float *heat, float *density, float gravity[3], int zBegin, int zEnd);
// solver stuff
void project();
void diffuseHeat();
void diffuseColor();
void solvePressure(float* field, float* b, unsigned char* skip);
void solvePressurePre(float* field, float* b, unsigned char* skip);
void solveHeat(float* field, float* b, unsigned char* skip);
void solveDiffusion(float* field, float* b, float* factor);
// handle obstacle boundaries
@@ -174,6 +202,16 @@ class FLUID_3D
void advectMacCormackEnd1(int zBegin, int zEnd);
void advectMacCormackEnd2(int zBegin, int zEnd);
/* burning */
float *_burning_rate; // RNA pointer
float *_flame_smoke; // RNA pointer
float *_flame_smoke_color; // RNA pointer
float *_flame_vorticity; // RNA pointer
float *_ignition_temp; // RNA pointer
float *_max_temp; // RNA pointer
void processBurn(float *fuel, float *smoke, float *react, float *flame, float *heat,
float *r, float *g, float *b, int total_cells, float dt);
// boundary setting functions
static void copyBorderX(float* field, Vec3Int res, int zBegin, int zEnd);
static void copyBorderY(float* field, Vec3Int res, int zBegin, int zEnd);

View File

@@ -165,7 +165,6 @@ void FLUID_3D::solveHeat(float* field, float* b, unsigned char* skip)
if (_Acenter) delete[] _Acenter;
}
void FLUID_3D::solvePressurePre(float* field, float* b, unsigned char* skip)
{
int x, y, z;

View File

@@ -92,18 +92,10 @@ void FLUID_3D::setNeumannX(float* field, Vec3Int res, int zBegin, int zEnd)
// left slab
index = y * res[0] + z * slabSize;
field[index] = field[index + 2];
/* only allow outwards flux */
if(field[index]>0.) field[index] = 0.;
index += 1;
if(field[index]>0.) field[index] = 0.;
// right slab
index = y * res[0] + z * slabSize + res[0] - 1;
field[index] = field[index - 2];
/* only allow outwards flux */
if(field[index]<0.) field[index] = 0.;
index -= 1;
if(field[index]<0.) field[index] = 0.;
}
}
@@ -120,18 +112,10 @@ void FLUID_3D::setNeumannY(float* field, Vec3Int res, int zBegin, int zEnd)
// front slab
index = x + z * slabSize;
field[index] = field[index + 2 * res[0]];
/* only allow outwards flux */
if(field[index]>0.) field[index] = 0.;
index += res[0];
if(field[index]>0.) field[index] = 0.;
// back slab
index = x + z * slabSize + slabSize - res[0];
field[index] = field[index - 2 * res[0]];
/* only allow outwards flux */
if(field[index]<0.) field[index] = 0.;
index -= res[0];
if(field[index]<0.) field[index] = 0.;
}
}
@@ -152,14 +136,6 @@ void FLUID_3D::setNeumannZ(float* field, Vec3Int res, int zBegin, int zEnd)
// front slab
index = x + y * res[0];
field[index] = field[index + 2 * slabSize];
/* only allow outwards flux */
// DG: Disable this for z-axis.
// The problem is that smoke somehow gets sucked in again
// from the TOP slab when this is enabled
// if(field[index]>0.) field[index] = 0.;
// index += slabSize;
// if(field[index]>0.) field[index] = 0.;
}
}
@@ -170,10 +146,6 @@ void FLUID_3D::setNeumannZ(float* field, Vec3Int res, int zBegin, int zEnd)
// back slab
index = x + y * res[0] + cellsslab;
field[index] = field[index - 2 * slabSize];
/* only allow outwards flux */
if(field[index]<0.) field[index] = 0.;
index -= slabSize;
if(field[index]<0.) field[index] = 0.;
}
}

View File

@@ -51,7 +51,7 @@ static const float persistence = 0.56123f;
//////////////////////////////////////////////////////////////////////
// constructor
//////////////////////////////////////////////////////////////////////
WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype)
WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, int init_fire, int init_colors)
{
// if noise magnitude is below this threshold, its contribution
// is negilgible, so stop evaluating new octaves
@@ -94,6 +94,20 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no
_densityBigOld[i] = 0.;
}
/* fire */
_flameBig = _fuelBig = _fuelBigOld = NULL;
_reactBig = _reactBigOld = NULL;
if (init_fire) {
initFire();
}
/* colors */
_color_rBig = _color_rBigOld = NULL;
_color_gBig = _color_gBigOld = NULL;
_color_bBig = _color_bBigOld = NULL;
if (init_colors) {
initColors(0.0f, 0.0f, 0.0f);
}
// allocate & init texture coordinates
_tcU = new float[_totalCellsSm];
_tcV = new float[_totalCellsSm];
@@ -128,12 +142,64 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no
*/
}
void WTURBULENCE::initFire()
{
if (!_fuelBig) {
_flameBig = new float[_totalCellsBig];
_fuelBig = new float[_totalCellsBig];
_fuelBigOld = new float[_totalCellsBig];
_reactBig = new float[_totalCellsBig];
_reactBigOld = new float[_totalCellsBig];
for(int i = 0; i < _totalCellsBig; i++) {
_flameBig[i] =
_fuelBig[i] =
_fuelBigOld[i] = 0.;
_reactBig[i] =
_reactBigOld[i] = 0.;
}
}
}
void WTURBULENCE::initColors(float init_r, float init_g, float init_b)
{
if (!_color_rBig) {
_color_rBig = new float[_totalCellsBig];
_color_rBigOld = new float[_totalCellsBig];
_color_gBig = new float[_totalCellsBig];
_color_gBigOld = new float[_totalCellsBig];
_color_bBig = new float[_totalCellsBig];
_color_bBigOld = new float[_totalCellsBig];
for(int i = 0; i < _totalCellsBig; i++) {
_color_rBig[i] = _densityBig[i] * init_r;
_color_rBigOld[i] = 0.0f;
_color_gBig[i] = _densityBig[i] * init_g;
_color_gBigOld[i] = 0.0f;
_color_bBig[i] = _densityBig[i] * init_b;
_color_bBigOld[i] = 0.0f;
}
}
}
//////////////////////////////////////////////////////////////////////
// destructor
//////////////////////////////////////////////////////////////////////
WTURBULENCE::~WTURBULENCE() {
delete[] _densityBig;
delete[] _densityBigOld;
if (_flameBig) delete[] _flameBig;
if (_fuelBig) delete[] _fuelBig;
if (_fuelBigOld) delete[] _fuelBigOld;
if (_reactBig) delete[] _reactBig;
if (_reactBigOld) delete[] _reactBigOld;
if (_color_rBig) delete[] _color_rBig;
if (_color_rBigOld) delete[] _color_rBigOld;
if (_color_gBig) delete[] _color_gBig;
if (_color_gBigOld) delete[] _color_gBigOld;
if (_color_bBig) delete[] _color_bBig;
if (_color_bBigOld) delete[] _color_bBigOld;
delete[] _tcU;
delete[] _tcV;
@@ -757,8 +823,10 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
// enlarge timestep to match grid
const float dt = dtOrg * _amplify;
const float invAmp = 1.0f / _amplify;
float *tempBig1 = (float *)calloc(_totalCellsBig, sizeof(float));
float *tempBig2 = (float *)calloc(_totalCellsBig, sizeof(float));
float *tempFuelBig = NULL, *tempReactBig = NULL;
float *tempColor_rBig = NULL, *tempColor_gBig = NULL, *tempColor_bBig = NULL;
float *tempDensityBig = (float *)calloc(_totalCellsBig, sizeof(float));
float *tempBig = (float *)calloc(_totalCellsBig, sizeof(float));
float *bigUx = (float *)calloc(_totalCellsBig, sizeof(float));
float *bigUy = (float *)calloc(_totalCellsBig, sizeof(float));
float *bigUz = (float *)calloc(_totalCellsBig, sizeof(float));
@@ -767,11 +835,21 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
float *eigMin = (float *)calloc(_totalCellsSm, sizeof(float));
float *eigMax = (float *)calloc(_totalCellsSm, sizeof(float));
if (_fuelBig) {
tempFuelBig = (float *)calloc(_totalCellsBig, sizeof(float));
tempReactBig = (float *)calloc(_totalCellsBig, sizeof(float));
}
if (_color_rBig) {
tempColor_rBig = (float *)calloc(_totalCellsBig, sizeof(float));
tempColor_gBig = (float *)calloc(_totalCellsBig, sizeof(float));
tempColor_bBig = (float *)calloc(_totalCellsBig, sizeof(float));
}
memset(_tcTemp, 0, sizeof(float)*_totalCellsSm);
// prepare textures
advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempBig1, tempBig2);
advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempDensityBig, tempBig);
// do wavelet decomposition of energy
computeEnergy(_energy, xvel, yvel, zvel, obstacles);
@@ -972,6 +1050,11 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
// prepare density for an advection
SWAP_POINTERS(_densityBig, _densityBigOld);
SWAP_POINTERS(_fuelBig, _fuelBigOld);
SWAP_POINTERS(_reactBig, _reactBigOld);
SWAP_POINTERS(_color_rBig, _color_rBigOld);
SWAP_POINTERS(_color_gBig, _color_gBigOld);
SWAP_POINTERS(_color_bBig, _color_bBigOld);
// based on the maximum velocity present, see if we need to substep,
// but cap the maximum number of substeps to 5
@@ -1017,7 +1100,21 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
int zEnd = (int)((float)(i+1)*partSize + 0.5f);
#endif
FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
_densityBigOld, tempBig1, _resBig, zBegin, zEnd);
_densityBigOld, tempDensityBig, _resBig, zBegin, zEnd);
if (_fuelBig) {
FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
_fuelBigOld, tempFuelBig, _resBig, zBegin, zEnd);
FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
_reactBigOld, tempReactBig, _resBig, zBegin, zEnd);
}
if (_color_rBig) {
FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
_color_rBigOld, tempColor_rBig, _resBig, zBegin, zEnd);
FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
_color_gBigOld, tempColor_gBig, _resBig, zBegin, zEnd);
FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz,
_color_bBigOld, tempColor_bBig, _resBig, zBegin, zEnd);
}
#if PARALLEL==1
}
@@ -1030,18 +1127,43 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
int zEnd = (int)((float)(i+1)*partSize + 0.5f);
#endif
FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
_densityBigOld, _densityBig, tempBig1, tempBig2, _resBig, NULL, zBegin, zEnd);
_densityBigOld, _densityBig, tempDensityBig, tempBig, _resBig, NULL, zBegin, zEnd);
if (_fuelBig) {
FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
_fuelBigOld, _fuelBig, tempFuelBig, tempBig, _resBig, NULL, zBegin, zEnd);
FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
_reactBigOld, _reactBig, tempReactBig, tempBig, _resBig, NULL, zBegin, zEnd);
}
if (_color_rBig) {
FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
_color_rBigOld, _color_rBig, tempColor_rBig, tempBig, _resBig, NULL, zBegin, zEnd);
FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
_color_gBigOld, _color_gBig, tempColor_gBig, tempBig, _resBig, NULL, zBegin, zEnd);
FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz,
_color_bBigOld, _color_bBig, tempColor_bBig, tempBig, _resBig, NULL, zBegin, zEnd);
}
#if PARALLEL==1
}
}
#endif
if (substep < totalSubsteps - 1)
if (substep < totalSubsteps - 1) {
SWAP_POINTERS(_densityBig, _densityBigOld);
SWAP_POINTERS(_fuelBig, _fuelBigOld);
SWAP_POINTERS(_reactBig, _reactBigOld);
SWAP_POINTERS(_color_rBig, _color_rBigOld);
SWAP_POINTERS(_color_gBig, _color_gBigOld);
SWAP_POINTERS(_color_bBig, _color_bBigOld);
}
} // substep
free(tempBig1);
free(tempBig2);
free(tempDensityBig);
if (tempFuelBig) free(tempFuelBig);
if (tempReactBig) free(tempReactBig);
if (tempColor_rBig) free(tempColor_rBig);
if (tempColor_gBig) free(tempColor_gBig);
if (tempColor_bBig) free(tempColor_bBig);
free(tempBig);
free(bigUx);
free(bigUy);
free(bigUz);
@@ -1050,6 +1172,15 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
// wipe the density borders
FLUID_3D::setZeroBorder(_densityBig, _resBig, 0 , _resBig[2]);
if (_fuelBig) {
FLUID_3D::setZeroBorder(_fuelBig, _resBig, 0 , _resBig[2]);
FLUID_3D::setZeroBorder(_reactBig, _resBig, 0 , _resBig[2]);
}
if (_color_rBig) {
FLUID_3D::setZeroBorder(_color_rBig, _resBig, 0 , _resBig[2]);
FLUID_3D::setZeroBorder(_color_gBig, _resBig, 0 , _resBig[2]);
FLUID_3D::setZeroBorder(_color_bBig, _resBig, 0 , _resBig[2]);
}
// reset texture coordinates now in preparation for next timestep
// Shouldn't do this before generating the noise because then the

View File

@@ -36,11 +36,14 @@ class WTURBULENCE
{
public:
// both config files can be NULL, altCfg might override values from noiseCfg
WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype);
WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, int init_fire, int init_colors);
/// destructor
virtual ~WTURBULENCE();
void initFire();
void initColors(float init_r, float init_g, float init_b);
void setNoise(int type);
void initBlenderRNA(float *strength);
@@ -63,6 +66,8 @@ class WTURBULENCE
// access functions
inline float* getDensityBig() { return _densityBig; }
inline float* getFlameBig() { return _flameBig; }
inline float* getFuelBig() { return _fuelBig; }
inline float* getArrayTcU() { return _tcU; }
inline float* getArrayTcV() { return _tcV; }
inline float* getArrayTcW() { return _tcW; }
@@ -111,6 +116,18 @@ class WTURBULENCE
float* _densityBig;
float* _densityBigOld;
float* _flameBig;
float* _fuelBig;
float* _fuelBigOld;
float* _reactBig;
float* _reactBigOld;
float* _color_rBig;
float* _color_rBigOld;
float* _color_gBig;
float* _color_gBigOld;
float* _color_bBig;
float* _color_bBigOld;
// texture coordinates for noise
float* _tcU;

View File

@@ -30,6 +30,7 @@
#include "FLUID_3D.h"
#include "WTURBULENCE.h"
#include "spectrum.h"
#include <stdio.h>
#include <stdlib.h>
@@ -37,22 +38,16 @@
#include "../extern/smoke_API.h" /* to ensure valid prototypes */
// y in smoke is z in blender
extern "C" FLUID_3D *smoke_init(int *res, float *p0, float dtdef)
extern "C" FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, int use_fire, int use_colors)
{
// smoke lib uses y as top-bottom/vertical axis where blender uses z
FLUID_3D *fluid = new FLUID_3D(res, p0, dtdef);
// printf("xres: %d, yres: %d, zres: %d\n", res[0], res[1], res[2]);
FLUID_3D *fluid = new FLUID_3D(res, dx, dtdef, use_heat, use_fire, use_colors);
return fluid;
}
extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype)
extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, int use_fire, int use_colors)
{
// initialize wavelet turbulence
if(amplify)
return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype);
return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype, use_fire, use_colors);
else
return NULL;
}
@@ -71,7 +66,6 @@ extern "C" void smoke_turbulence_free(WTURBULENCE *wt)
extern "C" size_t smoke_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */)
{
// // const int index = x + y * smd->res[0] + z * smd->res[0]*smd->res[1];
return x + y * max_x + z * max_x*max_y;
}
@@ -80,100 +74,28 @@ extern "C" size_t smoke_get_index2d(int x, int max_x, int y /*, int max_y, int z
return x + y * max_x;
}
extern "C" void smoke_step(FLUID_3D *fluid, float dtSubdiv)
extern "C" void smoke_step(FLUID_3D *fluid, float gravity[3], float dtSubdiv)
{
fluid->step(dtSubdiv);
if (fluid->_fuel) {
fluid->processBurn(fluid->_fuel, fluid->_density, fluid->_react, fluid->_flame, fluid->_heat,
fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_totalCells, (*fluid->_dtFactor)*dtSubdiv);
}
fluid->step(dtSubdiv, gravity);
}
extern "C" void smoke_turbulence_step(WTURBULENCE *wt, FLUID_3D *fluid)
{
if (wt->_fuelBig) {
fluid->processBurn(wt->_fuelBig, wt->_densityBig, wt->_reactBig, wt->_flameBig, 0,
wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_totalCellsBig, fluid->_dt);
}
wt->stepTurbulenceFull(fluid->_dt/fluid->_dx, fluid->_xVelocity, fluid->_yVelocity, fluid->_zVelocity, fluid->_obstacles);
}
extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli)
extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli, float *burning_rate,
float *flame_smoke, float *flame_smoke_color, float *flame_vorticity, float *flame_ignition_temp, float *flame_max_temp)
{
fluid->initBlenderRNA(alpha, beta, dt_factor, vorticity, border_colli);
}
extern "C" void smoke_dissolve(FLUID_3D *fluid, int speed, int log)
{
float *density = fluid->_density;
//float *densityOld = fluid->_densityOld;
float *heat = fluid->_heat;
if(log)
{
/* max density/speed = dydx */
float dydx = 1.0 / (float)speed;
size_t size= fluid->_xRes * fluid->_yRes * fluid->_zRes;
for(size_t i = 0; i < size; i++)
{
density[i] *= (1.0 - dydx);
if(density[i] < 0.0f)
density[i] = 0.0f;
heat[i] *= (1.0 - dydx);
/*if(heat[i] < 0.0f)
heat[i] = 0.0f;*/
}
}
else // linear falloff
{
/* max density/speed = dydx */
float dydx = 1.0 / (float)speed;
size_t size= fluid->_xRes * fluid->_yRes * fluid->_zRes;
for(size_t i = 0; i < size; i++)
{
density[i] -= dydx;
if(density[i] < 0.0f)
density[i] = 0.0f;
if(abs(heat[i]) < dydx) heat[i] = 0.0f;
else if (heat[i]>0.0f) heat[i] -= dydx;
else if (heat[i]<0.0f) heat[i] += dydx;
}
}
}
extern "C" void smoke_dissolve_wavelet(WTURBULENCE *wt, int speed, int log)
{
float *density = wt->getDensityBig();
Vec3Int r = wt->getResBig();
if(log)
{
/* max density/speed = dydx */
float dydx = 1.0 / (float)speed;
size_t size= r[0] * r[1] * r[2];
for(size_t i = 0; i < size; i++)
{
density[i] *= (1.0 - dydx);
if(density[i] < 0.0f)
density[i] = 0.0f;
}
}
else // linear falloff
{
/* max density/speed = dydx */
float dydx = 1.0 / (float)speed;
size_t size= r[0] * r[1] * r[2];
for(size_t i = 0; i < size; i++)
{
density[i] -= dydx;
if(density[i] < 0.0f)
density[i] = 0.0f;
}
}
fluid->initBlenderRNA(alpha, beta, dt_factor, vorticity, border_colli, burning_rate, flame_smoke, flame_smoke_color, flame_vorticity, flame_ignition_temp, flame_max_temp);
}
extern "C" void smoke_initWaveletBlenderRNA(WTURBULENCE *wt, float *strength)
@@ -181,36 +103,105 @@ extern "C" void smoke_initWaveletBlenderRNA(WTURBULENCE *wt, float *strength)
wt->initBlenderRNA(strength);
}
template < class T > inline T ABS( T a )
static void data_dissolve(float *density, float *heat, float *r, float *g, float *b, int total_cells, int speed, int log)
{
return (0 < a) ? a : -a ;
if(log)
{
/* max density/speed = dydx */
float fac = 1.0f - (1.0f / (float)speed);
for(size_t i = 0; i < total_cells; i++)
{
/* density */
density[i] *= fac;
/* heat */
if (heat) {
heat[i] *= fac;
}
extern "C" void smoke_export(FLUID_3D *fluid, float *dt, float *dx, float **dens, float **densold, float **heat, float **heatold, float **vx, float **vy, float **vz, float **vxold, float **vyold, float **vzold, unsigned char **obstacles)
/* color */
if (r) {
r[i] *= fac;
g[i] *= fac;
b[i] *= fac;
}
}
}
else // linear falloff
{
/* max density/speed = dydx */
float dydx = 1.0f / (float)speed;
for(size_t i = 0; i < total_cells; i++)
{
float d = density[i];
/* density */
density[i] -= dydx;
if(density[i] < 0.0f)
density[i] = 0.0f;
/* heat */
if (heat) {
if(abs(heat[i]) < dydx) heat[i] = 0.0f;
else if (heat[i]>0.0f) heat[i] -= dydx;
else if (heat[i]<0.0f) heat[i] += dydx;
}
/* color */
if (r && d) {
r[i] *= (density[i]/d);
g[i] *= (density[i]/d);
b[i] *= (density[i]/d);
}
}
}
}
extern "C" void smoke_dissolve(FLUID_3D *fluid, int speed, int log)
{
data_dissolve(fluid->_density, fluid->_heat, fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_totalCells, speed, log);
}
extern "C" void smoke_dissolve_wavelet(WTURBULENCE *wt, int speed, int log)
{
data_dissolve(wt->_densityBig, 0, wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_totalCellsBig, speed, log);
}
extern "C" void smoke_export(FLUID_3D *fluid, float *dt, float *dx, float **dens, float **react, float **flame, float **fuel, float **heat,
float **heatold, float **vx, float **vy, float **vz, float **r, float **g, float **b, unsigned char **obstacles)
{
*dens = fluid->_density;
*densold = fluid->_densityOld;
*fuel = fluid->_fuel;
*react = fluid->_react;
*flame = fluid->_flame;
*heat = fluid->_heat;
*heatold = fluid->_heatOld;
*vx = fluid->_xVelocity;
*vy = fluid->_yVelocity;
*vz = fluid->_zVelocity;
*vxold = fluid->_xVelocityOld;
*vyold = fluid->_yVelocityOld;
*vzold = fluid->_zVelocityOld;
*r = fluid->_color_r;
*g = fluid->_color_g;
*b = fluid->_color_b;
*obstacles = fluid->_obstacles;
*dt = fluid->_dt;
*dx = fluid->_dx;
}
extern "C" void smoke_turbulence_export(WTURBULENCE *wt, float **dens, float **densold, float **tcu, float **tcv, float **tcw)
extern "C" void smoke_turbulence_export(WTURBULENCE *wt, float **dens, float **react, float **flame, float **fuel,
float **r, float **g, float **b , float **tcu, float **tcv, float **tcw)
{
if(!wt)
return;
*dens = wt->_densityBig;
*densold = wt->_densityBigOld;
*fuel = wt->_fuelBig;
*react = wt->_reactBig;
*flame = wt->_flameBig;
*r = wt->_color_rBig;
*g = wt->_color_gBig;
*b = wt->_color_bBig;
*tcu = wt->_tcU;
*tcv = wt->_tcV;
*tcw = wt->_tcW;
@@ -221,6 +212,16 @@ extern "C" float *smoke_get_density(FLUID_3D *fluid)
return fluid->_density;
}
extern "C" float *smoke_get_fuel(FLUID_3D *fluid)
{
return fluid->_fuel;
}
extern "C" float *smoke_get_react(FLUID_3D *fluid)
{
return fluid->_react;
}
extern "C" float *smoke_get_heat(FLUID_3D *fluid)
{
return fluid->_heat;
@@ -256,15 +257,137 @@ extern "C" float *smoke_get_force_z(FLUID_3D *fluid)
return fluid->_zForce;
}
extern "C" float *smoke_get_flame(FLUID_3D *fluid)
{
return fluid->_flame;
}
extern "C" float *smoke_get_color_r(FLUID_3D *fluid)
{
return fluid->_color_r;
}
extern "C" float *smoke_get_color_g(FLUID_3D *fluid)
{
return fluid->_color_g;
}
extern "C" float *smoke_get_color_b(FLUID_3D *fluid)
{
return fluid->_color_b;
}
static void get_rgba(float *r, float *g, float *b, float *a, int total_cells, float *data, int sequential)
{
int i;
int m = 4, i_g = 1, i_b = 2, i_a = 3;
/* sequential data */
if (sequential) {
m = 1;
i_g *= total_cells;
i_b *= total_cells;
i_a *= total_cells;
}
for (i=0; i<total_cells; i++) {
float alpha = a[i];
if (alpha) {
data[i*m ] = r[i];
data[i*m+i_g] = g[i];
data[i*m+i_b] = b[i];
}
else {
data[i*m ] = data[i*m+i_g] = data[i*m+i_b] = 0.0f;
}
data[i*m+i_a] = alpha;
}
}
extern "C" void smoke_get_rgba(FLUID_3D *fluid, float *data, int sequential)
{
get_rgba(fluid->_color_r, fluid->_color_g, fluid->_color_b, fluid->_density, fluid->_totalCells, data, sequential);
}
extern "C" void smoke_turbulence_get_rgba(WTURBULENCE *wt, float *data, int sequential)
{
get_rgba(wt->_color_rBig, wt->_color_gBig, wt->_color_bBig, wt->_densityBig, wt->_totalCellsBig, data, sequential);
}
/* get a single color premultiplied voxel grid */
static void get_rgba_from_density(float color[3], float *a, int total_cells, float *data, int sequential)
{
int i;
int m = 4, i_g = 1, i_b = 2, i_a = 3;
/* sequential data */
if (sequential) {
m = 1;
i_g *= total_cells;
i_b *= total_cells;
i_a *= total_cells;
}
for (i=0; i<total_cells; i++) {
float alpha = a[i];
if (alpha) {
data[i*m ] = color[0] * alpha;
data[i*m+i_g] = color[1] * alpha;
data[i*m+i_b] = color[2] * alpha;
}
else {
data[i*m ] = data[i*m+i_g] = data[i*m+i_b] = 0.0f;
}
data[i*m+i_a] = alpha;
}
}
extern "C" void smoke_get_rgba_from_density(FLUID_3D *fluid, float color[3], float *data, int sequential)
{
get_rgba_from_density(color, fluid->_density, fluid->_totalCells, data, sequential);
}
extern "C" void smoke_turbulence_get_rgba_from_density(WTURBULENCE *wt, float color[3], float *data, int sequential)
{
get_rgba_from_density(color, wt->_densityBig, wt->_totalCellsBig, data, sequential);
}
extern "C" float *smoke_turbulence_get_density(WTURBULENCE *wt)
{
return wt ? wt->getDensityBig() : NULL;
}
extern "C" float *smoke_turbulence_get_fuel(WTURBULENCE *wt)
{
return wt ? wt->getFuelBig() : NULL;
}
extern "C" float *smoke_turbulence_get_react(WTURBULENCE *wt)
{
return wt ? wt->_reactBig : NULL;
}
extern "C" float *smoke_turbulence_get_color_r(WTURBULENCE *wt)
{
return wt ? wt->_color_rBig : NULL;
}
extern "C" float *smoke_turbulence_get_color_g(WTURBULENCE *wt)
{
return wt ? wt->_color_gBig : NULL;
}
extern "C" float *smoke_turbulence_get_color_b(WTURBULENCE *wt)
{
return wt ? wt->_color_bBig : NULL;
}
extern "C" float *smoke_turbulence_get_flame(WTURBULENCE *wt)
{
return wt ? wt->getFlameBig() : NULL;
}
extern "C" void smoke_turbulence_get_res(WTURBULENCE *wt, int *res)
{
if(wt)
{
if(wt) {
Vec3Int r = wt->getResBig();
res[0] = r[0];
res[1] = r[1];
@@ -272,6 +395,15 @@ extern "C" void smoke_turbulence_get_res(WTURBULENCE *wt, int *res)
}
}
extern "C" int smoke_turbulence_get_cells(WTURBULENCE *wt)
{
if(wt) {
Vec3Int r = wt->getResBig();
return r[0]*r[1]*r[2];
}
return 0;
}
extern "C" unsigned char *smoke_get_obstacle(FLUID_3D *fluid)
{
return fluid->_obstacles;
@@ -295,3 +427,61 @@ extern "C" void smoke_turbulence_set_noise(WTURBULENCE *wt, int type)
{
wt->setNoise(type);
}
extern "C" void flame_get_spectrum(unsigned char *spec, int width, float t1, float t2)
{
spectrum(t1, t2, width, spec);
}
extern "C" int smoke_has_heat(FLUID_3D *fluid)
{
return (fluid->_heat) ? 1 : 0;
}
extern "C" int smoke_has_fuel(FLUID_3D *fluid)
{
return (fluid->_fuel) ? 1 : 0;
}
extern "C" int smoke_has_colors(FLUID_3D *fluid)
{
return (fluid->_color_r && fluid->_color_g && fluid->_color_b) ? 1 : 0;
}
extern "C" int smoke_turbulence_has_fuel(WTURBULENCE *wt)
{
return (wt->_fuelBig) ? 1 : 0;
}
extern "C" int smoke_turbulence_has_colors(WTURBULENCE *wt)
{
return (wt->_color_rBig && wt->_color_gBig && wt->_color_bBig) ? 1 : 0;
}
/* additional field initialization */
extern "C" void smoke_ensure_heat(FLUID_3D *fluid)
{
if (fluid) {
fluid->initHeat();
}
}
extern "C" void smoke_ensure_fire(FLUID_3D *fluid, WTURBULENCE *wt)
{
if (fluid) {
fluid->initFire();
}
if (wt) {
wt->initFire();
}
}
extern "C" void smoke_ensure_colors(FLUID_3D *fluid, WTURBULENCE *wt, float init_r, float init_g, float init_b)
{
if (fluid) {
fluid->initColors(init_r, init_g, init_b);
}
if (wt) {
wt->initColors(init_r, init_g, init_b);
}
}

View File

@@ -0,0 +1,411 @@
/*
Colour Rendering of Spectra
by John Walker
http://www.fourmilab.ch/
Last updated: March 9, 2003
This program is in the public domain.
For complete information about the techniques employed in
this program, see the World-Wide Web document:
http://www.fourmilab.ch/documents/specrend/
The xyz_to_rgb() function, which was wrong in the original
version of this program, was corrected by:
Andrew J. S. Hamilton 21 May 1999
Andrew.Hamilton@Colorado.EDU
http://casa.colorado.edu/~ajsh/
who also added the gamma correction facilities and
modified constrain_rgb() to work by desaturating the
colour by adding white.
A program which uses these functions to plot CIE
"tongue" diagrams called "ppmcie" is included in
the Netpbm graphics toolkit:
http://netpbm.sourceforge.net/
(The program was called cietoppm in earlier
versions of Netpbm.)
*/
#include <stdio.h>
#include <math.h>
/* A colour system is defined by the CIE x and y coordinates of
its three primary illuminants and the x and y coordinates of
the white point. */
struct colourSystem {
char *name; /* Colour system name */
double xRed, yRed, /* Red x, y */
xGreen, yGreen, /* Green x, y */
xBlue, yBlue, /* Blue x, y */
xWhite, yWhite, /* White point x, y */
gamma; /* Gamma correction for system */
};
/* White point chromaticities. */
#define IlluminantC 0.3101, 0.3162 /* For NTSC television */
#define IlluminantD65 0.3127, 0.3291 /* For EBU and SMPTE */
#define IlluminantE 0.33333333, 0.33333333 /* CIE equal-energy illuminant */
/* Gamma of nonlinear correction.
See Charles Poynton's ColorFAQ Item 45 and GammaFAQ Item 6 at:
http://www.poynton.com/ColorFAQ.html
http://www.poynton.com/GammaFAQ.html
*/
#define GAMMA_REC709 0 /* Rec. 709 */
static struct colourSystem
/* Name xRed yRed xGreen yGreen xBlue yBlue White point Gamma */
NTSCsystem = { "NTSC", 0.67, 0.33, 0.21, 0.71, 0.14, 0.08, IlluminantC, GAMMA_REC709 },
EBUsystem = { "EBU (PAL/SECAM)", 0.64, 0.33, 0.29, 0.60, 0.15, 0.06, IlluminantD65, GAMMA_REC709 },
SMPTEsystem = { "SMPTE", 0.630, 0.340, 0.310, 0.595, 0.155, 0.070, IlluminantD65, GAMMA_REC709 },
HDTVsystem = { "HDTV", 0.670, 0.330, 0.210, 0.710, 0.150, 0.060, IlluminantD65, GAMMA_REC709 },
CIEsystem = { "CIE", 0.7355, 0.2645, 0.2658, 0.7243, 0.1669, 0.0085, IlluminantE, GAMMA_REC709 },
Rec709system = { "CIE REC 709", 0.64, 0.33, 0.30, 0.60, 0.15, 0.06, IlluminantD65, GAMMA_REC709 };
/* UPVP_TO_XY
Given 1976 coordinates u', v', determine 1931 chromaticities x, y
*/
void upvp_to_xy(double up, double vp, double *xc, double *yc)
{
*xc = (9 * up) / ((6 * up) - (16 * vp) + 12);
*yc = (4 * vp) / ((6 * up) - (16 * vp) + 12);
}
/* XY_TO_UPVP
Given 1931 chromaticities x, y, determine 1976 coordinates u', v'
*/
void xy_to_upvp(double xc, double yc, double *up, double *vp)
{
*up = (4 * xc) / ((-2 * xc) + (12 * yc) + 3);
*vp = (9 * yc) / ((-2 * xc) + (12 * yc) + 3);
}
/* XYZ_TO_RGB
Given an additive tricolour system CS, defined by the CIE x
and y chromaticities of its three primaries (z is derived
trivially as 1-(x+y)), and a desired chromaticity (XC, YC,
ZC) in CIE space, determine the contribution of each
primary in a linear combination which sums to the desired
chromaticity. If the requested chromaticity falls outside
the Maxwell triangle (colour gamut) formed by the three
primaries, one of the r, g, or b weights will be negative.
Caller can use constrain_rgb() to desaturate an
outside-gamut colour to the closest representation within
the available gamut and/or norm_rgb to normalise the RGB
components so the largest nonzero component has value 1.
*/
void xyz_to_rgb(struct colourSystem *cs,
double xc, double yc, double zc,
double *r, double *g, double *b)
{
double xr, yr, zr, xg, yg, zg, xb, yb, zb;
double xw, yw, zw;
double rx, ry, rz, gx, gy, gz, bx, by, bz;
double rw, gw, bw;
xr = cs->xRed; yr = cs->yRed; zr = 1 - (xr + yr);
xg = cs->xGreen; yg = cs->yGreen; zg = 1 - (xg + yg);
xb = cs->xBlue; yb = cs->yBlue; zb = 1 - (xb + yb);
xw = cs->xWhite; yw = cs->yWhite; zw = 1 - (xw + yw);
/* xyz -> rgb matrix, before scaling to white. */
rx = (yg * zb) - (yb * zg); ry = (xb * zg) - (xg * zb); rz = (xg * yb) - (xb * yg);
gx = (yb * zr) - (yr * zb); gy = (xr * zb) - (xb * zr); gz = (xb * yr) - (xr * yb);
bx = (yr * zg) - (yg * zr); by = (xg * zr) - (xr * zg); bz = (xr * yg) - (xg * yr);
/* White scaling factors.
Dividing by yw scales the white luminance to unity, as conventional. */
rw = ((rx * xw) + (ry * yw) + (rz * zw)) / yw;
gw = ((gx * xw) + (gy * yw) + (gz * zw)) / yw;
bw = ((bx * xw) + (by * yw) + (bz * zw)) / yw;
/* xyz -> rgb matrix, correctly scaled to white. */
rx = rx / rw; ry = ry / rw; rz = rz / rw;
gx = gx / gw; gy = gy / gw; gz = gz / gw;
bx = bx / bw; by = by / bw; bz = bz / bw;
/* rgb of the desired point */
*r = (rx * xc) + (ry * yc) + (rz * zc);
*g = (gx * xc) + (gy * yc) + (gz * zc);
*b = (bx * xc) + (by * yc) + (bz * zc);
}
/* INSIDE_GAMUT
Test whether a requested colour is within the gamut
achievable with the primaries of the current colour
system. This amounts simply to testing whether all the
primary weights are non-negative. */
int inside_gamut(double r, double g, double b)
{
return (r >= 0) && (g >= 0) && (b >= 0);
}
/* CONSTRAIN_RGB
If the requested RGB shade contains a negative weight for
one of the primaries, it lies outside the colour gamut
accessible from the given triple of primaries. Desaturate
it by adding white, equal quantities of R, G, and B, enough
to make RGB all positive. The function returns 1 if the
components were modified, zero otherwise.
*/
int constrain_rgb(double *r, double *g, double *b)
{
double w;
/* Amount of white needed is w = - min(0, *r, *g, *b) */
w = (0 < *r) ? 0 : *r;
w = (w < *g) ? w : *g;
w = (w < *b) ? w : *b;
w = -w;
/* Add just enough white to make r, g, b all positive. */
if (w > 0) {
*r += w; *g += w; *b += w;
return 1; /* Colour modified to fit RGB gamut */
}
return 0; /* Colour within RGB gamut */
}
/* GAMMA_CORRECT_RGB
Transform linear RGB values to nonlinear RGB values. Rec.
709 is ITU-R Recommendation BT. 709 (1990) ``Basic
Parameter Values for the HDTV Standard for the Studio and
for International Programme Exchange'', formerly CCIR Rec.
709. For details see
http://www.poynton.com/ColorFAQ.html
http://www.poynton.com/GammaFAQ.html
*/
void gamma_correct(const struct colourSystem *cs, double *c)
{
double gamma;
gamma = cs->gamma;
if (gamma == GAMMA_REC709) {
/* Rec. 709 gamma correction. */
double cc = 0.018;
if (*c < cc) {
*c *= ((1.099 * pow(cc, 0.45)) - 0.099) / cc;
} else {
*c = (1.099 * pow(*c, 0.45)) - 0.099;
}
} else {
/* Nonlinear colour = (Linear colour)^(1/gamma) */
*c = pow(*c, 1.0 / gamma);
}
}
void gamma_correct_rgb(const struct colourSystem *cs, double *r, double *g, double *b)
{
gamma_correct(cs, r);
gamma_correct(cs, g);
gamma_correct(cs, b);
}
/* NORM_RGB
Normalise RGB components so the most intense (unless all
are zero) has a value of 1.
*/
void norm_rgb(double *r, double *g, double *b)
{
#define Max(a, b) (((a) > (b)) ? (a) : (b))
double greatest = Max(*r, Max(*g, *b));
if (greatest > 0) {
*r /= greatest;
*g /= greatest;
*b /= greatest;
}
#undef Max
}
/* SPECTRUM_TO_XYZ
Calculate the CIE X, Y, and Z coordinates corresponding to
a light source with spectral distribution given by the
function SPEC_INTENS, which is called with a series of
wavelengths between 380 and 780 nm (the argument is
expressed in meters), which returns emittance at that
wavelength in arbitrary units. The chromaticity
coordinates of the spectrum are returned in the x, y, and z
arguments which respect the identity:
x + y + z = 1.
*/
void spectrum_to_xyz(double (*spec_intens)(double wavelength),
double *x, double *y, double *z)
{
int i;
double lambda, X = 0, Y = 0, Z = 0, XYZ;
/* CIE colour matching functions xBar, yBar, and zBar for
wavelengths from 380 through 780 nanometers, every 5
nanometers. For a wavelength lambda in this range:
cie_colour_match[(lambda - 380) / 5][0] = xBar
cie_colour_match[(lambda - 380) / 5][1] = yBar
cie_colour_match[(lambda - 380) / 5][2] = zBar
To save memory, this table can be declared as floats
rather than doubles; (IEEE) float has enough
significant bits to represent the values. It's declared
as a double here to avoid warnings about "conversion
between floating-point types" from certain persnickety
compilers. */
static double cie_colour_match[81][3] = {
{0.0014,0.0000,0.0065}, {0.0022,0.0001,0.0105}, {0.0042,0.0001,0.0201},
{0.0076,0.0002,0.0362}, {0.0143,0.0004,0.0679}, {0.0232,0.0006,0.1102},
{0.0435,0.0012,0.2074}, {0.0776,0.0022,0.3713}, {0.1344,0.0040,0.6456},
{0.2148,0.0073,1.0391}, {0.2839,0.0116,1.3856}, {0.3285,0.0168,1.6230},
{0.3483,0.0230,1.7471}, {0.3481,0.0298,1.7826}, {0.3362,0.0380,1.7721},
{0.3187,0.0480,1.7441}, {0.2908,0.0600,1.6692}, {0.2511,0.0739,1.5281},
{0.1954,0.0910,1.2876}, {0.1421,0.1126,1.0419}, {0.0956,0.1390,0.8130},
{0.0580,0.1693,0.6162}, {0.0320,0.2080,0.4652}, {0.0147,0.2586,0.3533},
{0.0049,0.3230,0.2720}, {0.0024,0.4073,0.2123}, {0.0093,0.5030,0.1582},
{0.0291,0.6082,0.1117}, {0.0633,0.7100,0.0782}, {0.1096,0.7932,0.0573},
{0.1655,0.8620,0.0422}, {0.2257,0.9149,0.0298}, {0.2904,0.9540,0.0203},
{0.3597,0.9803,0.0134}, {0.4334,0.9950,0.0087}, {0.5121,1.0000,0.0057},
{0.5945,0.9950,0.0039}, {0.6784,0.9786,0.0027}, {0.7621,0.9520,0.0021},
{0.8425,0.9154,0.0018}, {0.9163,0.8700,0.0017}, {0.9786,0.8163,0.0014},
{1.0263,0.7570,0.0011}, {1.0567,0.6949,0.0010}, {1.0622,0.6310,0.0008},
{1.0456,0.5668,0.0006}, {1.0026,0.5030,0.0003}, {0.9384,0.4412,0.0002},
{0.8544,0.3810,0.0002}, {0.7514,0.3210,0.0001}, {0.6424,0.2650,0.0000},
{0.5419,0.2170,0.0000}, {0.4479,0.1750,0.0000}, {0.3608,0.1382,0.0000},
{0.2835,0.1070,0.0000}, {0.2187,0.0816,0.0000}, {0.1649,0.0610,0.0000},
{0.1212,0.0446,0.0000}, {0.0874,0.0320,0.0000}, {0.0636,0.0232,0.0000},
{0.0468,0.0170,0.0000}, {0.0329,0.0119,0.0000}, {0.0227,0.0082,0.0000},
{0.0158,0.0057,0.0000}, {0.0114,0.0041,0.0000}, {0.0081,0.0029,0.0000},
{0.0058,0.0021,0.0000}, {0.0041,0.0015,0.0000}, {0.0029,0.0010,0.0000},
{0.0020,0.0007,0.0000}, {0.0014,0.0005,0.0000}, {0.0010,0.0004,0.0000},
{0.0007,0.0002,0.0000}, {0.0005,0.0002,0.0000}, {0.0003,0.0001,0.0000},
{0.0002,0.0001,0.0000}, {0.0002,0.0001,0.0000}, {0.0001,0.0000,0.0000},
{0.0001,0.0000,0.0000}, {0.0001,0.0000,0.0000}, {0.0000,0.0000,0.0000}
};
for (i = 0, lambda = 380; lambda < 780.1; i++, lambda += 5) {
double Me;
Me = (*spec_intens)(lambda);
X += Me * cie_colour_match[i][0];
Y += Me * cie_colour_match[i][1];
Z += Me * cie_colour_match[i][2];
}
XYZ = (X + Y + Z);
*x = X / XYZ;
*y = Y / XYZ;
*z = Z / XYZ;
}
/* BB_SPECTRUM
Calculate, by Planck's radiation law, the emittance of a black body
of temperature bbTemp at the given wavelength (in metres). */
double bbTemp = 5000; /* Hidden temperature argument
to BB_SPECTRUM. */
double bb_spectrum(double wavelength)
{
double wlm = wavelength * 1e-9; /* Wavelength in meters */
return (3.74183e-16 * pow(wlm, -5.0)) /
(exp(1.4388e-2 / (wlm * bbTemp)) - 1.0);
}
void xyz_to_lms(double x, double y, double z, double* l, double* m, double* s)
{
*l = 0.3897*x + 0.6890*y - 0.0787*z;
*m = -0.2298*x + 1.1834*y + 0.0464*z;
*s = z;
}
void lms_to_xyz(double l, double m, double s, double* x, double *y, double* z)
{
*x = 1.9102*l - 1.1121*m + 0.2019*s;
*y = 0.3709*l + 0.6290*m + 0.0000*s;
*z = s;
}
void spectrum(double t1, double t2, int N, unsigned char* d)
{
int i,j,dj;
double X,Y,Z,R,G,B,L,M,S, Lw, Mw, Sw;
struct colourSystem *cs = &CIEsystem;
j = 0; dj = 1;
if (t1<t2) {
double t = t1;
t1 = t2;
t2 = t;
j = N-1; dj=-1;
}
for (i=0; i<N; i++) {
bbTemp = t1 + (t2-t1)/N*i;
// integrate blackbody radiation spectrum to XYZ
spectrum_to_xyz(bb_spectrum, &X, &Y, &Z);
// normalize highest temperature to white (in LMS system)
xyz_to_lms(X,Y,Z,&L,&M,&S);
if (i==0) {
Lw=1/L; Mw=1/M; Sw=1/S;
}
L *= Lw; M *= Mw; S *= Sw;
lms_to_xyz(L,M,S,&X,&Y,&Z);
// convert to RGB
xyz_to_rgb(cs, X, Y, Z, &R, &G, &B);
constrain_rgb(&R, &G, &B);
norm_rgb(&R, &G, &B);
d[(j<<2)] = (unsigned char) ((double)R*255);
d[(j<<2)+1] = (unsigned char) ((double)G*255);
d[(j<<2)+2] = (unsigned char) ((double)B*255);
d[(j<<2)+3] = (B>0.1)? B*255 : 0;
j += dj;
}
}

View File

@@ -0,0 +1,6 @@
#ifndef __SPECTRUM_H
#define __SPECTRUM_H
void spectrum(double t1, double t2, int n, unsigned char* d);
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 204 KiB

View File

@@ -299,7 +299,6 @@ class QuickSmoke(Operator):
style = EnumProperty(
name="Smoke Style",
items=(('STREAM', "Stream", ""),
('PUFF', "Puff", ""),
('FIRE', "Fire", ""),
),
default='STREAM',
@@ -328,20 +327,9 @@ class QuickSmoke(Operator):
bpy.ops.object.modifier_add(fake_context, type='SMOKE')
obj.modifiers[-1].smoke_type = 'FLOW'
psys = obj.particle_systems[-1]
if self.style == 'PUFF':
psys.settings.frame_end = psys.settings.frame_start
psys.settings.emit_from = 'VOLUME'
psys.settings.distribution = 'RAND'
elif self.style == 'FIRE':
psys.settings.effector_weights.gravity = -1
psys.settings.lifetime = 5
psys.settings.count = 100000
if self.style == 'FIRE':
obj.modifiers[-1].flow_settings.smoke_flow_type = 'FIRE'
obj.modifiers[-2].flow_settings.initial_velocity = True
obj.modifiers[-2].flow_settings.temperature = 2
psys.settings.use_render_emitter = self.show_flows
if not self.show_flows:
obj.draw_type = 'WIRE'
@@ -361,8 +349,6 @@ class QuickSmoke(Operator):
bpy.ops.object.modifier_add(type='SMOKE')
obj.modifiers[-1].smoke_type = 'DOMAIN'
if self.style == 'FIRE':
obj.modifiers[-1].domain_settings.use_dissolve_smoke = True
obj.modifiers[-1].domain_settings.dissolve_speed = 20
obj.modifiers[-1].domain_settings.use_high_resolution = True
# create a volume material with a voxel data texture for the domain
@@ -373,6 +359,7 @@ class QuickSmoke(Operator):
mat.type = 'VOLUME'
mat.volume.density = 0
mat.volume.density_scale = 5
mat.volume.step_size = 0.1
tex = bpy.data.textures.new("Smoke Density", 'VOXEL_DATA')
tex.voxel_data.domain_object = obj
@@ -381,29 +368,35 @@ class QuickSmoke(Operator):
tex_slot.texture = tex
tex_slot.use_map_color_emission = False
tex_slot.use_map_density = True
tex_slot.use_map_color_reflection = True
# for fire add a second texture for emission and emission color
if self.style == 'FIRE':
mat.volume.emission = 5
tex = bpy.data.textures.new("Smoke Heat", 'VOXEL_DATA')
# for fire add a second texture for flame emission
mat.volume.emission_color = Vector((0.0, 0.0, 0.0))
tex = bpy.data.textures.new("Flame", 'VOXEL_DATA')
tex.voxel_data.domain_object = obj
tex.voxel_data.smoke_data_type = 'SMOKEFLAME'
tex.use_color_ramp = True
tex_slot = mat.texture_slots.add()
tex_slot.texture = tex
# add color ramp for flame color
ramp = tex.color_ramp
# dark orange
elem = ramp.elements.new(0.333)
elem.color[0] = elem.color[3] = 1
elem.color[1] = elem.color[2] = 0
elem = ramp.elements.new(0.666)
elem.color[0] = elem.color[1] = elem.color[3] = 1
elem.color[0] = 0.2
elem.color[1] = 0.03
elem.color[2] = 0
elem.color[3] = 1
# yellow glow
elem = ramp.elements.new(0.666)
elem.color[0] = elem.color[3] = 1
elem.color[1] = 0.65
elem.color[2] = 0.25
mat.texture_slots[1].use_map_density = True
mat.texture_slots[1].use_map_emission = True
mat.texture_slots[1].blend_type = 'MULTIPLY'
mat.texture_slots[1].emission_factor = 5
return {'FINISHED'}

View File

@@ -1124,7 +1124,7 @@ class PARTICLE_PT_field_weights(ParticleButtonsPanel, Panel):
def draw(self, context):
part = particle_get_settings(context)
effector_weights_ui(self, context, part.effector_weights)
effector_weights_ui(self, context, part.effector_weights, 'PSYS')
if part.type == 'HAIR':
row = self.layout.row()

View File

@@ -197,7 +197,7 @@ class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, Panel):
def draw(self, context):
cloth = context.cloth.settings
effector_weights_ui(self, context, cloth.effector_weights)
effector_weights_ui(self, context, cloth.effector_weights, 'CLOTH')
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

View File

@@ -179,7 +179,7 @@ def point_cache_ui(self, context, cache, enabled, cachetype):
col.operator("ptcache.bake_all", text="Update All To Frame").bake = False
def effector_weights_ui(self, context, weights):
def effector_weights_ui(self, context, weights, weight_type):
layout = self.layout
layout.prop(weights, "group")
@@ -200,6 +200,8 @@ def effector_weights_ui(self, context, weights):
col.prop(weights, "wind", slider=True)
col.prop(weights, "curve_guide", slider=True)
col.prop(weights, "texture", slider=True)
if weight_type != 'SMOKE':
col.prop(weights, "smokeflow", slider=True)
col = split.column()
col.prop(weights, "harmonic", slider=True)

View File

@@ -349,7 +349,7 @@ class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel):
col = layout.column()
col.active = surface.use_drip
effector_weights_ui(self, context, surface.effector_weights)
effector_weights_ui(self, context, surface.effector_weights, 'DYNAMIC_PAINT')
layout.label(text="Surface Movement:")
row = layout.row()

View File

@@ -112,6 +112,14 @@ class PHYSICS_PT_field(PhysicButtonsPanel, Panel):
col = split.column()
col.prop(field, "use_object_coords")
col.prop(field, "use_2d_force")
elif field.type == 'SMOKE_FLOW':
col = split.column()
col.prop(field, "strength")
col.prop(field, "flow")
col = split.column()
col.label(text="Domain Object:")
col.prop(field, "source_object", "")
col.prop(field, "use_smoke_density")
else:
basic_force_field_settings_ui(self, context, field)

View File

@@ -77,27 +77,39 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
flow = md.flow_settings
split = layout.split()
layout.prop(flow, "smoke_flow_type", expand=False)
if flow.smoke_flow_type != "OUTFLOW":
split = layout.split()
col = split.column()
col.prop(flow, "use_outflow")
col.label(text="Flow Source:")
col.prop(flow, "smoke_flow_source", expand=False, text="")
if flow.smoke_flow_source == "PARTICLES":
col.label(text="Particle System:")
col.prop_search(flow, "particle_system", ob, "particle_systems", text="")
else:
col.prop(flow, "surface_distance")
col.prop(flow, "volume_density")
sub = col.column()
sub.active = not md.flow_settings.use_outflow
sub = col.column(align=True)
sub.prop(flow, "initial_velocity", text="Initial Velocity")
sub.prop(flow, "initial_velocity")
sub = sub.column()
sub.active = flow.initial_velocity
sub.prop(flow, "velocity_factor", text="Multiplier")
sub.prop(flow, "velocity_factor")
if flow.smoke_flow_source == "MESH":
sub.prop(flow, "velocity_normal")
#sub.prop(flow, "velocity_random")
sub = split.column()
sub.active = not md.flow_settings.use_outflow
sub.label(text="Initial Values:")
sub.prop(flow, "use_absolute")
if flow.smoke_flow_type in {'SMOKE', 'BOTH'}:
sub.prop(flow, "density")
sub.prop(flow, "temperature")
sub.prop(flow, "smoke_color")
if flow.smoke_flow_type in {'FIRE', 'BOTH'}:
sub.prop(flow, "fuel_amount")
elif md.smoke_type == 'COLLISION':
coll = md.coll_settings
@@ -107,35 +119,98 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
col = split.column()
col.prop(coll, "collision_type")
class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel):
bl_label = "Smoke Groups"
class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
bl_label = "Smoke Flow Advanced"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
md = context.smoke
rd = context.scene.render
return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine)
return md and (md.smoke_type == 'FLOW') and (md.flow_settings.smoke_flow_source == "MESH")
def draw(self, context):
layout = self.layout
ob = context.object
flow = context.smoke.flow_settings
split = layout.split()
col = split.column()
col.prop(flow, "use_texture")
sub = col.column()
sub.active = flow.use_texture
sub.prop(flow, "noise_texture", text="")
sub.label(text="Mapping:")
sub.prop(flow, "texture_map_type", expand=False, text="")
if flow.texture_map_type == "UV":
sub.prop_search(flow, "uv_layer", ob.data, "uv_textures", text="")
if flow.texture_map_type == "AUTO":
sub.prop(flow, "texture_size")
sub.prop(flow, "texture_offset")
col = split.column()
col.label(text="Vertex Group:")
col.prop_search(flow, "density_vertex_group", ob, "vertex_groups", text="")
class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel):
bl_label = "Smoke Flames"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
md = context.smoke
return md and (md.smoke_type == 'DOMAIN')
def draw(self, context):
layout = self.layout
domain = context.smoke.domain_settings
split = layout.split()
split.enabled = not domain.point_cache.is_baked
col = split.column(align=True)
col.label(text="Reaction:")
col.prop(domain, "burning_rate")
col.prop(domain, "flame_smoke")
col.prop(domain, "flame_vorticity")
col = split.column(align=True)
col.label(text="Temperatures:")
col.prop(domain, "flame_ignition")
col.prop(domain, "flame_max_temp")
col.prop(domain, "flame_smoke_color")
class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel):
bl_label = "Smoke Adaptive Domain"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
md = context.smoke
return md and (md.smoke_type == 'DOMAIN')
def draw_header(self, context):
md = context.smoke.domain_settings
self.layout.prop(md, "use_adaptive_domain", text="")
def draw(self, context):
layout = self.layout
group = context.smoke.domain_settings
domain = context.smoke.domain_settings
layout.active = domain.use_adaptive_domain
split = layout.split()
split.enabled = not domain.point_cache.is_baked
col = split.column()
col.label(text="Flow Group:")
col.prop(group, "fluid_group", text="")
#col.label(text="Effector Group:")
#col.prop(group, "effector_group", text="")
col = split.column()
col.label(text="Collision Group:")
col.prop(group, "collision_group", text="")
col = split.column(align=True)
col.label(text="Resolution:")
col.prop(domain, "additional_res")
col.prop(domain, "adapt_margin")
col = split.column(align=True)
col.label(text="Advanced:")
col.prop(domain, "adapt_threshold")
class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
bl_label = "Smoke High Resolution"
@@ -174,6 +249,32 @@ class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
layout.prop(md, "show_high_resolution")
class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel):
bl_label = "Smoke Groups"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
md = context.smoke
rd = context.scene.render
return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine)
def draw(self, context):
layout = self.layout
domain = context.smoke.domain_settings
split = layout.split()
col = split.column()
col.label(text="Flow Group:")
col.prop(domain, "fluid_group", text="")
#col.label(text="Effector Group:")
#col.prop(domain, "effector_group", text="")
col = split.column()
col.label(text="Collision Group:")
col.prop(domain, "collision_group", text="")
class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
bl_label = "Smoke Cache"
@@ -209,7 +310,7 @@ class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel):
def draw(self, context):
domain = context.smoke.domain_settings
effector_weights_ui(self, context, domain.effector_weights)
effector_weights_ui(self, context, domain.effector_weights, 'SMOKE')
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

View File

@@ -231,7 +231,7 @@ class PHYSICS_PT_softbody_field_weights(PhysicButtonsPanel, Panel):
md = context.soft_body
softbody = md.settings
effector_weights_ui(self, context, softbody.effector_weights)
effector_weights_ui(self, context, softbody.effector_weights, 'SOFTBODY')
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

View File

@@ -887,8 +887,12 @@ class TEXTURE_PT_mapping(TextureSlotPanel, Panel):
col = split.column()
if tex.texture_coords in {'ORCO', 'UV'}:
col.prop(tex, "use_from_dupli")
if (idblock.type == 'VOLUME' and tex.texture_coords == 'ORCO'):
col.prop(tex, "use_map_to_bounds")
elif tex.texture_coords == 'OBJECT':
col.prop(tex, "use_from_original")
if (idblock.type == 'VOLUME'):
col.prop(tex, "use_map_to_bounds")
else:
col.label()

View File

@@ -35,8 +35,10 @@
typedef float (*bresenham_callback)(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
void smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
struct DerivedMesh *smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
void smoke_reallocate_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
void smoke_reallocate_highres_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
void smokeModifier_free(struct SmokeModifierData *smd);
void smokeModifier_reset(struct SmokeModifierData *smd);
void smokeModifier_reset_turbulence(struct SmokeModifierData *smd);
@@ -44,5 +46,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd);
void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData *tsmd);
long long smoke_get_mem_req(int xres, int yres, int zres, int amplify);
float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
int smoke_get_data_flags(struct SmokeDomainSettings *sds);
#endif /* __BKE_SMOKE_H__ */

View File

@@ -400,8 +400,7 @@ static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Mat
}
}
static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Object *ob, DagNode *node)
{
static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Object *ob, DagNode *node, int skip_forcefield){
Base *base;
DagNode *node2;
@@ -411,6 +410,8 @@ static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Objec
if ((base->lay & ob->lay) && base->object->pd) {
Object *ob1 = base->object;
if ((ob1->pd->deflect || ob1->pd->forcefield) && (ob1 != ob)) {
if (skip_forcefield && ob1->pd->forcefield == skip_forcefield)
continue;
node2 = dag_get_node(dag, ob1);
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Collision");
}
@@ -572,10 +573,12 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
if (ob->particlesystem.first ||
modifiers_isModifierEnabled(ob, eModifierType_Softbody) ||
modifiers_isModifierEnabled(ob, eModifierType_Cloth) ||
modifiers_isModifierEnabled(ob, eModifierType_Smoke) ||
modifiers_isModifierEnabled(ob, eModifierType_DynamicPaint))
{
dag_add_collision_field_relation(dag, scene, ob, node); /* TODO: use effectorweight->group */
dag_add_collision_field_relation(dag, scene, ob, node, 0); /* TODO: use effectorweight->group */
}
else if (modifiers_isModifierEnabled(ob, eModifierType_Smoke)) {
dag_add_collision_field_relation(dag, scene, ob, node, PFIELD_SMOKEFLOW);
}
}

View File

@@ -84,6 +84,7 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_smoke.h"
#include "RE_render_ext.h"
@@ -137,6 +138,9 @@ PartDeflect *object_add_collision_fields(int type)
case PFIELD_TEXTURE:
pd->f_size = 1.0f;
break;
case PFIELD_SMOKEFLOW:
pd->f_flow = 1.0f;
break;
}
pd->flag = PFIELD_DO_LOCATION|PFIELD_DO_ROTATION;
@@ -922,12 +926,27 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp));
break;
case PFIELD_SMOKEFLOW:
zero_v3(force);
if (pd->f_source) {
float density;
if ((density = smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) {
float influence = strength * efd->falloff;
if (pd->flag & PFIELD_SMOKE_DENSITY)
influence *= density;
mul_v3_fl(force, influence);
/* apply flow */
madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence);
}
}
break;
}
if (pd->flag & PFIELD_DO_LOCATION) {
madd_v3_v3fl(total_force, force, 1.0f/point->vel_to_sec);
if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG)==0 && pd->f_flow != 0.0f) {
if (ELEM3(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) {
madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff);
}
}

View File

@@ -532,20 +532,31 @@ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
SmokeDomainSettings *sds = smd->domain;
if (sds->fluid) {
return sds->res[0]*sds->res[1]*sds->res[2];
return sds->base_res[0]*sds->base_res[1]*sds->base_res[2];
}
else
return 0;
}
#define SMOKE_CACHE_VERSION "1.04"
static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
{
SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
SmokeDomainSettings *sds = smd->domain;
int ret = 0;
int fluid_fields = smoke_get_data_flags(sds);
/* version header */
ptcache_file_write(pf, SMOKE_CACHE_VERSION, 4, sizeof(char));
ptcache_file_write(pf, &fluid_fields, 1, sizeof(int));
ptcache_file_write(pf, &sds->active_fields, 1, sizeof(int));
ptcache_file_write(pf, &sds->res, 3, sizeof(int));
ptcache_file_write(pf, &sds->dx, 1, sizeof(float));
if (sds->fluid) {
size_t res = sds->res[0]*sds->res[1]*sds->res[2];
float dt, dx, *dens, *densold, *heat, *heatold, *vx, *vy, *vz, *vxold, *vyold, *vzold;
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
unsigned int in_len = sizeof(float)*(unsigned int)res;
unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len)*4, "pointcache_lzo_buffer");
@@ -553,22 +564,40 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
int mode=1; // light
if (sds->cache_comp == SM_CACHE_HEAVY) mode=2; // heavy
smoke_export(sds->fluid, &dt, &dx, &dens, &densold, &heat, &heatold, &vx, &vy, &vz, &vxold, &vyold, &vzold, &obstacles);
smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
ptcache_file_compressed_write(pf, (unsigned char *)sds->shadow, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)densold, in_len, out, mode);
if (fluid_fields & SM_ACTIVE_HEAT) {
ptcache_file_compressed_write(pf, (unsigned char *)heat, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)heatold, in_len, out, mode);
}
if (fluid_fields & SM_ACTIVE_FIRE) {
ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)react, in_len, out, mode);
}
if (fluid_fields & SM_ACTIVE_COLORS) {
ptcache_file_compressed_write(pf, (unsigned char *)r, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)g, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)b, in_len, out, mode);
}
ptcache_file_compressed_write(pf, (unsigned char *)vx, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)vy, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)vz, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)vxold, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)vyold, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)vzold, in_len, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)obstacles, (unsigned int)res, out, mode);
ptcache_file_write(pf, &dt, 1, sizeof(float));
ptcache_file_write(pf, &dx, 1, sizeof(float));
ptcache_file_write(pf, &sds->p0, 3, sizeof(float));
ptcache_file_write(pf, &sds->p1, 3, sizeof(float));
ptcache_file_write(pf, &sds->dp0, 3, sizeof(float));
ptcache_file_write(pf, &sds->shift, 3, sizeof(int));
ptcache_file_write(pf, &sds->obj_shift_f, 3, sizeof(float));
ptcache_file_write(pf, &sds->obmat, 16, sizeof(float));
ptcache_file_write(pf, &sds->base_res, 3, sizeof(int));
ptcache_file_write(pf, &sds->res_min, 3, sizeof(int));
ptcache_file_write(pf, &sds->res_max, 3, sizeof(int));
ptcache_file_write(pf, &sds->active_color, 3, sizeof(float));
MEM_freeN(out);
@@ -579,7 +608,7 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
int res_big_array[3];
int res_big;
int res = sds->res[0]*sds->res[1]*sds->res[2];
float *dens, *densold, *tcu, *tcv, *tcw;
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
unsigned int in_len = sizeof(float)*(unsigned int)res;
unsigned int in_len_big;
unsigned char *out;
@@ -593,11 +622,20 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
in_len_big = sizeof(float) * (unsigned int)res_big;
smoke_turbulence_export(sds->wt, &dens, &densold, &tcu, &tcv, &tcw);
smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len_big), "pointcache_lzo_buffer");
ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)densold, in_len_big, out, mode);
if (fluid_fields & SM_ACTIVE_FIRE) {
ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)react, in_len_big, out, mode);
}
if (fluid_fields & SM_ACTIVE_COLORS) {
ptcache_file_compressed_write(pf, (unsigned char *)r, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)g, in_len_big, out, mode);
ptcache_file_compressed_write(pf, (unsigned char *)b, in_len_big, out, mode);
}
MEM_freeN(out);
out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
@@ -615,34 +653,95 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
{
SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
SmokeDomainSettings *sds = smd->domain;
char version[4];
int ch_res[3];
float ch_dx;
int fluid_fields = smoke_get_data_flags(sds);
int cache_fields = 0;
int active_fields = 0;
int reallocate = 0;
/* version header */
ptcache_file_read(pf, version, 4, sizeof(char));
if (strncmp(version, SMOKE_CACHE_VERSION, 4)) return 0;
/* fluid info */
ptcache_file_read(pf, &cache_fields, 1, sizeof(int));
ptcache_file_read(pf, &active_fields, 1, sizeof(int));
ptcache_file_read(pf, &ch_res, 3, sizeof(int));
ptcache_file_read(pf, &ch_dx, 1, sizeof(float));
/* check if resolution has changed */
if (sds->res[0] != ch_res[0] ||
sds->res[1] != ch_res[1] ||
sds->res[2] != ch_res[2]) {
if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN)
reallocate = 1;
else
return 0;
}
/* check if active fields have changed */
if (fluid_fields != cache_fields ||
active_fields != sds->active_fields)
reallocate = 1;
/* reallocate fluid if needed*/
if (reallocate) {
sds->active_fields = active_fields;
smoke_reallocate_fluid(sds, ch_dx, ch_res, 1);
sds->dx = ch_dx;
VECCOPY(sds->res, ch_res);
sds->total_cells = ch_res[0]*ch_res[1]*ch_res[2];
if(sds->flags & MOD_SMOKE_HIGHRES) {
smoke_reallocate_highres_fluid(sds, ch_dx, ch_res, 1);
}
}
if (sds->fluid) {
size_t res = sds->res[0]*sds->res[1]*sds->res[2];
float dt, dx, *dens, *densold, *heat, *heatold, *vx, *vy, *vz, *vxold, *vyold, *vzold;
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
unsigned char *obstacles;
unsigned int out_len = (unsigned int)res * sizeof(float);
smoke_export(sds->fluid, &dt, &dx, &dens, &densold, &heat, &heatold, &vx, &vy, &vz, &vxold, &vyold, &vzold, &obstacles);
smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)dens, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)densold, out_len);
if (cache_fields & SM_ACTIVE_HEAT) {
ptcache_file_compressed_read(pf, (unsigned char*)heat, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)heatold, out_len);
}
if (cache_fields & SM_ACTIVE_FIRE) {
ptcache_file_compressed_read(pf, (unsigned char*)flame, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)fuel, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)react, out_len);
}
if (cache_fields & SM_ACTIVE_COLORS) {
ptcache_file_compressed_read(pf, (unsigned char*)r, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)g, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)b, out_len);
}
ptcache_file_compressed_read(pf, (unsigned char*)vx, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)vy, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)vz, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)vxold, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)vyold, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)vzold, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)obstacles, (unsigned int)res);
ptcache_file_read(pf, &dt, 1, sizeof(float));
ptcache_file_read(pf, &dx, 1, sizeof(float));
ptcache_file_read(pf, &sds->p0, 3, sizeof(float));
ptcache_file_read(pf, &sds->p1, 3, sizeof(float));
ptcache_file_read(pf, &sds->dp0, 3, sizeof(float));
ptcache_file_read(pf, &sds->shift, 3, sizeof(int));
ptcache_file_read(pf, &sds->obj_shift_f, 3, sizeof(float));
ptcache_file_read(pf, &sds->obmat, 16, sizeof(float));
ptcache_file_read(pf, &sds->base_res, 3, sizeof(int));
ptcache_file_read(pf, &sds->res_min, 3, sizeof(int));
ptcache_file_read(pf, &sds->res_max, 3, sizeof(int));
ptcache_file_read(pf, &sds->active_color, 3, sizeof(float));
}
if (pf->data_types & (1<<BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
int res = sds->res[0]*sds->res[1]*sds->res[2];
int res_big, res_big_array[3];
float *dens, *densold, *tcu, *tcv, *tcw;
float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
unsigned int out_len = sizeof(float)*(unsigned int)res;
unsigned int out_len_big;
@@ -650,16 +749,23 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
res_big = res_big_array[0]*res_big_array[1]*res_big_array[2];
out_len_big = sizeof(float) * (unsigned int)res_big;
smoke_turbulence_export(sds->wt, &dens, &densold, &tcu, &tcv, &tcw);
smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
ptcache_file_compressed_read(pf, (unsigned char*)dens, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char*)densold, out_len_big);
if (cache_fields & SM_ACTIVE_FIRE) {
ptcache_file_compressed_read(pf, (unsigned char*)flame, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char*)fuel, out_len_big);
}
if (cache_fields & SM_ACTIVE_COLORS) {
ptcache_file_compressed_read(pf, (unsigned char*)r, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char*)g, out_len_big);
ptcache_file_compressed_read(pf, (unsigned char*)b, out_len_big);
}
ptcache_file_compressed_read(pf, (unsigned char*)tcu, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)tcv, out_len);
ptcache_file_compressed_read(pf, (unsigned char*)tcw, out_len);
}
}
return 1;
}
@@ -2466,10 +2572,10 @@ int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
sbFreeSimulation(pid->calldata);
else if (pid->type == PTCACHE_TYPE_PARTICLES)
psys_reset(pid->calldata, PSYS_RESET_DEPSGRAPH);
else if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
/*else if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
smokeModifier_reset(pid->calldata);
else if (pid->type == PTCACHE_TYPE_SMOKE_HIGHRES)
smokeModifier_reset_turbulence(pid->calldata);
smokeModifier_reset_turbulence(pid->calldata);*/
else if (pid->type == PTCACHE_TYPE_DYNAMICPAINT)
dynamicPaint_clearSurface((DynamicPaintSurface*)pid->calldata);
}

File diff suppressed because it is too large Load Diff

View File

@@ -571,7 +571,7 @@ void default_mtex(MTex *mtex)
mtex->size[1] = 1.0;
mtex->size[2] = 1.0;
mtex->tex = NULL;
mtex->texflag = MTEX_3TAP_BUMP | MTEX_BUMP_OBJECTSPACE;
mtex->texflag = MTEX_3TAP_BUMP | MTEX_BUMP_OBJECTSPACE | MTEX_MAPTO_BOUNDS;
mtex->colormodel = 0;
mtex->r = 1.0;
mtex->g = 0.0;

View File

@@ -67,6 +67,7 @@ MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
MINLINE void copy_v4_v4_short(short r[4], const short a[4]);
/* int */
MINLINE void zero_v3_int(int r[3]);
MINLINE void copy_v2_v2_int(int r[2], const int a[2]);
MINLINE void copy_v3_v3_int(int r[3], const int a[3]);
MINLINE void copy_v4_v4_int(int r[4], const int a[4]);

View File

@@ -193,6 +193,11 @@
*(v1 + 1) = *(v2 + 1) + *(v3 + 1) * (fac); \
*(v1 + 2) = *(v2 + 2) + *(v3 + 2) * (fac); \
} (void)0
#define VECMADD(v1, v2, v3, v4) { \
*(v1) = *(v2) + *(v3) * (*(v4)); \
*(v1 + 1) = *(v2 + 1) + *(v3 + 1) * (*(v4 + 1)); \
*(v1 + 2) = *(v2 + 2) + *(v3 + 2) * (*(v4 + 2)); \
} (void)0
#define VECSUBFAC(v1, v2, v3, fac) { \
*(v1) = *(v2) - *(v3) * (fac); \
*(v1 + 1) = *(v2 + 1) - *(v3 + 1) * (fac); \

View File

@@ -121,6 +121,13 @@ MINLINE void copy_v4_v4_char(char r[4], const char a[4])
}
/* short */
MINLINE void zero_v3_int(int r[3])
{
r[0] = 0;
r[1] = 0;
r[2] = 0;
}
MINLINE void copy_v2_v2_short(short r[2], const short a[2])
{
r[0] = a[0];

View File

@@ -3335,6 +3335,8 @@ static void lib_link_partdeflect(FileData *fd, ID *id, PartDeflect *pd)
{
if (pd && pd->tex)
pd->tex = newlibadr_us(fd, id->lib, pd->tex);
if (pd && pd->f_source)
pd->f_source = newlibadr_us(fd, id->lib, pd->f_source);
}
static void lib_link_particlesettings(FileData *fd, Main *main)
@@ -4333,6 +4335,9 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
smd->coll = NULL;
smd->flow = newdataadr(fd, smd->flow);
smd->flow->smd = smd;
smd->flow->dm = NULL;
smd->flow->verts_old = NULL;
smd->flow->numverts = 0;
smd->flow->psys = newdataadr(fd, smd->flow->psys);
}
else if (smd->type == MOD_SMOKE_TYPE_COLL) {
@@ -4341,11 +4346,15 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
smd->coll = newdataadr(fd, smd->coll);
if (smd->coll) {
smd->coll->smd = smd;
smd->coll->points = NULL;
smd->coll->numpoints = 0;
smd->coll->verts_old = NULL;
smd->coll->numverts = 0;
smd->coll->dm = NULL;
}
else {
smd->type = 0;
smd->flow = NULL;
smd->domain = NULL;
smd->coll = NULL;
}
}
}
@@ -8038,6 +8047,44 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */
{
Object *ob;
for (ob = main->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Smoke) {
SmokeModifierData *smd = (SmokeModifierData *)md;
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
/* keep branch saves if possible */
if (!smd->domain->flame_max_temp) {
smd->domain->burning_rate = 0.75f;
smd->domain->flame_smoke = 1.0f;
smd->domain->flame_vorticity = 0.5f;
smd->domain->flame_ignition = 1.25f;
smd->domain->flame_max_temp = 1.75f;
smd->domain->adapt_threshold = 0.02f;
smd->domain->adapt_margin = 4;
smd->domain->flame_smoke_color[0] = 0.7f;
smd->domain->flame_smoke_color[1] = 0.7f;
smd->domain->flame_smoke_color[2] = 0.7f;
}
}
else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
if (!smd->flow->texture_size) {
smd->flow->fuel_amount = 1.0;
smd->flow->surface_distance = 1.5;
smd->flow->color[0] = 0.7f;
smd->flow->color[1] = 0.7f;
smd->flow->color[2] = 0.7f;
smd->flow->texture_size = 1.0f;
}
}
}
}
}
}
/* don't forget to set version number in blender.c! */
}

View File

@@ -450,8 +450,8 @@ DEF_ICON(FORCE_CURVE)
DEF_ICON(FORCE_BOID)
DEF_ICON(FORCE_TURBULENCE)
DEF_ICON(FORCE_DRAG)
DEF_ICON(FORCE_SMOKEFLOW)
#ifndef DEF_ICON_BLANK_SKIP
DEF_ICON(BLANK672)
DEF_ICON(BLANK673)
DEF_ICON(BLANK674)
DEF_ICON(BLANK675)

View File

@@ -136,6 +136,7 @@ static EnumPropertyItem field_type_items[] = {
{PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""},
{PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", ""},
{PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", ""},
{PFIELD_SMOKEFLOW, "SMOKE", ICON_FORCE_SMOKEFLOW, "Smoke Flow", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -356,7 +357,7 @@ Object *ED_object_add_type(bContext *C, int type, const float loc[3], const floa
Scene *scene = CTX_data_scene(C);
Object *ob;
/* For as long scene has editmode... */
/* for as long scene has editmode... */
if (CTX_data_edit_object(C))
ED_object_exit_editmode(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */

View File

@@ -6625,73 +6625,75 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
/* only draw domains */
if (smd->domain && smd->domain->fluid) {
if (CFRA < smd->domain->point_cache[0]->startframe) {
/* don't show smoke before simulation starts, this could be made an option in the future */
}
else if (!smd->domain->wt || !(smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
// #if 0
smd->domain->tex = NULL;
GPU_create_smoke(smd, 0);
draw_volume(ar, smd->domain->tex,
smd->domain->p0, smd->domain->p1,
smd->domain->res, smd->domain->dx,
smd->domain->tex_shadow);
GPU_free_smoke(smd);
// #endif
#if 0
int x, y, z;
float *density = smoke_get_density(smd->domain->fluid);
if (smd->domain) {
SmokeDomainSettings *sds = smd->domain;
float p0[3], p1[3], viewnormal[3];
BoundBox bb;
glLoadMatrixf(rv3d->viewmat);
// glMultMatrixf(ob->obmat);
if (col || (ob->flag & SELECT)) cpack(0xFFFFFF);
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
// glPointSize(3.0);
bglBegin(GL_POINTS);
for (x = 0; x < smd->domain->res[0]; x++) {
for (y = 0; y < smd->domain->res[1]; y++) {
for (z = 0; z < smd->domain->res[2]; z++) {
float tmp[3];
int index = smoke_get_index(x, smd->domain->res[0], y, smd->domain->res[1], z);
if (density[index] > FLT_EPSILON) {
float color[3];
copy_v3_v3(tmp, smd->domain->p0);
tmp[0] += smd->domain->dx * x + smd->domain->dx * 0.5;
tmp[1] += smd->domain->dx * y + smd->domain->dx * 0.5;
tmp[2] += smd->domain->dx * z + smd->domain->dx * 0.5;
color[0] = color[1] = color[2] = density[index];
glColor3fv(color);
bglVertex3fv(tmp);
}
}
}
}
bglEnd();
glPointSize(1.0);
glMultMatrixf(ob->obmat);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
if (col) cpack(col);
#endif
/* draw adaptive domain bounds */
if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
/* draw domain max bounds */
VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res);
VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res);
BKE_boundbox_init_from_minmax(&bb, p0, p1);
draw_box(bb.vec);
/* draw base resolution bounds */
/*BKE_boundbox_init_from_minmax(&bb, sds->p0, sds->p1);
draw_box(bb.vec);*/
}
else if (smd->domain->wt && (smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
/* don't show smoke before simulation starts, this could be made an option in the future */
if (smd->domain->fluid && CFRA >= smd->domain->point_cache[0]->startframe) {
// get view vector
copy_v3_v3(viewnormal, rv3d->viewinv[2]);
mul_mat3_m4_v3(ob->imat, viewnormal);
normalize_v3(viewnormal);
/* set dynamic boundaries to draw the volume */
p0[0] = sds->p0[0] + sds->cell_size[0]*sds->res_min[0] + sds->obj_shift_f[0];
p0[1] = sds->p0[1] + sds->cell_size[1]*sds->res_min[1] + sds->obj_shift_f[1];
p0[2] = sds->p0[2] + sds->cell_size[2]*sds->res_min[2] + sds->obj_shift_f[2];
p1[0] = sds->p0[0] + sds->cell_size[0]*sds->res_max[0] + sds->obj_shift_f[0];
p1[1] = sds->p0[1] + sds->cell_size[1]*sds->res_max[1] + sds->obj_shift_f[1];
p1[2] = sds->p0[2] + sds->cell_size[2]*sds->res_max[2] + sds->obj_shift_f[2];
/* scale cube to global space to equalize volume slicing on all axises
* (its scaled back before drawing) */
mul_v3_v3(p0, ob->size);
mul_v3_v3(p1, ob->size);
if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
smd->domain->tex = NULL;
GPU_create_smoke(smd, 1);
draw_volume(ar, smd->domain->tex,
smd->domain->p0, smd->domain->p1,
smd->domain->res_wt, smd->domain->dx_wt,
smd->domain->tex_shadow);
GPU_create_smoke(smd, 0);
draw_smoke_volume(sds, ob, ar, sds->tex,
p0, p1,
sds->res, sds->dx, sds->scale*sds->maxres,
viewnormal, sds->tex_shadow, sds->tex_flame);
GPU_free_smoke(smd);
}
else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
sds->tex = NULL;
GPU_create_smoke(smd, 1);
draw_smoke_volume(sds, ob, ar, sds->tex,
p0, p1,
sds->res_wt, sds->dx, sds->scale*sds->maxres,
viewnormal, sds->tex_shadow, sds->tex_flame);
GPU_free_smoke(smd);
}
/* smoke debug render */
#ifdef SMOKE_DEBUG_VELOCITY
draw_smoke_velocity(smd->domain, ob);
#endif
#ifdef SMOKE_DEBUG_HEAT
draw_smoke_heat(smd->domain, ob);
#endif
}
}
}

View File

@@ -36,6 +36,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_smoke_types.h"
#include "DNA_view3d_types.h"
#include "BLI_utildefines.h"
@@ -156,12 +157,9 @@ static int convex(const float p0[3], const float up[3], const float a[3], const
return dot_v3v3(up, tmp) >= 0;
}
void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int res[3], float dx, GPUTexture *tex_shadow)
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, ARegion *ar, GPUTexture *tex, float min[3], float max[3], int res[3], float dx, float base_scale, float viewnormal[3], GPUTexture *tex_shadow, GPUTexture *tex_flame)
{
RegionView3D *rv3d = ar->regiondata;
float viewnormal[3];
int i, j, n, good_index;
int i, j, k, n, good_index;
float d /*, d0 */ /* UNUSED */, dd, ds;
float *points = NULL;
int numpoints = 0;
@@ -193,24 +191,72 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
{{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}
};
unsigned char *spec_data;
float *spec_pixels;
GPUTexture *tex_spec;
/* Fragment program to calculate the view3d of smoke */
/* using 2 textures, density and shadow */
const char *text = "!!ARBfp1.0\n"
/* using 4 textures, density, shadow, flame and flame spectrum */
const char *shader_basic = "!!ARBfp1.0\n"
"PARAM dx = program.local[0];\n"
"PARAM darkness = program.local[1];\n"
"PARAM render = program.local[2];\n"
"PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n"
"TEMP temp, shadow, value;\n"
"TEMP temp, shadow, flame, spec, value;\n"
"TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
"TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
"MUL value, temp, darkness;\n"
"MUL value, value, dx;\n"
"MUL value, value, f;\n"
"TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
"TEX spec, flame.r, texture[3], 1D;\n"
/* calculate shading factor from density */
"MUL value.r, temp.a, darkness.a;\n"
"MUL value.r, value.r, dx.r;\n"
"MUL value.r, value.r, f.r;\n"
"EX2 temp, -value.r;\n"
/* alpha */
"SUB temp.a, 1.0, temp.r;\n"
/* shade colors */
"MUL temp.r, temp.r, shadow.r;\n"
"MUL temp.g, temp.g, shadow.r;\n"
"MUL temp.b, temp.b, shadow.r;\n"
"MOV result.color, temp;\n"
"MUL temp.r, temp.r, darkness.r;\n"
"MUL temp.g, temp.g, darkness.g;\n"
"MUL temp.b, temp.b, darkness.b;\n"
/* for now this just replace smoke shading if rendering fire */
"CMP result.color, render.r, temp, spec;\n"
"END\n";
/* color shader */
const char *shader_color = "!!ARBfp1.0\n"
"PARAM dx = program.local[0];\n"
"PARAM darkness = program.local[1];\n"
"PARAM render = program.local[2];\n"
"PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n"
"TEMP temp, shadow, flame, spec, value;\n"
"TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
"TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
"TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
"TEX spec, flame.r, texture[3], 1D;\n"
/* unpremultiply volume texture */
"RCP value.r, temp.a;\n"
"MUL temp.r, temp.r, value.r;\n"
"MUL temp.g, temp.g, value.r;\n"
"MUL temp.b, temp.b, value.r;\n"
/* calculate shading factor from density */
"MUL value.r, temp.a, darkness.a;\n"
"MUL value.r, value.r, dx.r;\n"
"MUL value.r, value.r, f.r;\n"
"EX2 value.r, -value.r;\n"
/* alpha */
"SUB temp.a, 1.0, value.r;\n"
/* shade colors */
"MUL temp.r, temp.r, shadow.r;\n"
"MUL temp.g, temp.g, shadow.r;\n"
"MUL temp.b, temp.b, shadow.r;\n"
"MUL temp.r, temp.r, value.r;\n"
"MUL temp.g, temp.g, value.r;\n"
"MUL temp.b, temp.b, value.r;\n"
/* for now this just replace smoke shading if rendering fire */
"CMP result.color, render.r, temp, spec;\n"
"END\n";
GLuint prog;
@@ -223,6 +269,32 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
}
tstart();
/* generate flame spectrum texture */
#define SPEC_WIDTH 256
#define FIRE_THRESH 7
#define MAX_FIRE_ALPHA 0.06f
#define FULL_ON_FIRE 100
spec_data = malloc(SPEC_WIDTH*4 * sizeof(unsigned char));
flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000);
spec_pixels = malloc(SPEC_WIDTH*4*16*16 * sizeof(float));
for (i=0;i<16;i++){
for (j=0;j<16;j++) {
for (k=0;k<SPEC_WIDTH;k++) {
int index = (j*SPEC_WIDTH*16+i*SPEC_WIDTH+k)*4;
if (k>=FIRE_THRESH) {
spec_pixels[index] = ((float)spec_data[k*4])/255.0f;
spec_pixels[index+1] = ((float)spec_data[k*4+1])/255.0f;
spec_pixels[index+2] = ((float)spec_data[k*4+2])/255.0f;
spec_pixels[index+3] = MAX_FIRE_ALPHA*(
(k>FULL_ON_FIRE) ? 1.0f : (k-FIRE_THRESH)/((float)FULL_ON_FIRE-FIRE_THRESH));
} else {
spec_pixels[index] = spec_pixels[index+1] = spec_pixels[index+2] = spec_pixels[index+3] = 0.0f;
}
}
}
}
tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL);
sub_v3_v3v3(size, max, min);
@@ -296,24 +368,9 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
glLoadMatrixf(rv3d->viewmat);
// glMultMatrixf(ob->obmat);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#if 0
printf("Viewinv:\n");
printf("%f, %f, %f\n", rv3d->viewinv[0][0], rv3d->viewinv[0][1], rv3d->viewinv[0][2]);
printf("%f, %f, %f\n", rv3d->viewinv[1][0], rv3d->viewinv[1][1], rv3d->viewinv[1][2]);
printf("%f, %f, %f\n", rv3d->viewinv[2][0], rv3d->viewinv[2][1], rv3d->viewinv[2][2]);
#endif
/* get view vector */
copy_v3_v3(viewnormal, rv3d->viewinv[2]);
normalize_v3(viewnormal);
/* find cube vertex that is closest to the viewer */
for (i = 0; i < 8; i++) {
@@ -344,12 +401,19 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
glGenProgramsARB(1, &prog);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(text), text);
/* set shader */
if (sds->active_fields & SM_ACTIVE_COLORS)
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color);
else
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic);
/* cell spacing */
glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0);
/* custom parameter for smoke style (higher = thicker) */
glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 7.0, 7.0, 7.0, 1.0);
if (sds->active_fields & SM_ACTIVE_COLORS)
glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0);
else
glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
}
else
printf("Your gfx card does not support 3D View smoke drawing.\n");
@@ -360,6 +424,11 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
else
printf("No volume shadow\n");
if (tex_flame) {
GPU_texture_bind(tex_flame, 2);
GPU_texture_bind(tex_spec, 3);
}
if (!GPU_non_power_of_two_support()) {
cor[0] = (float)res[0] / (float)power_of_2_max_i(res[0]);
cor[1] = (float)res[1] / (float)power_of_2_max_i(res[1]);
@@ -373,7 +442,7 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
/* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */
ds = (ABS(viewnormal[0]) * size[0] + ABS(viewnormal[1]) * size[1] + ABS(viewnormal[2]) * size[2]);
dd = ds / 96.f;
dd = MAX3(sds->global_size[0],sds->global_size[1],sds->global_size[2])/128.f;
n = 0;
good_index = i;
@@ -416,14 +485,29 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
}
}
// printf("numpoints: %d\n", numpoints);
/* render fire slice */
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
for (i = 0; i < numpoints; i++) {
glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0],
(points[i * 3 + 1] - min[1]) * cor[1] / size[1],
(points[i * 3 + 2] - min[2]) * cor[2] / size[2]);
glVertex3f(points[i * 3 + 0], points[i * 3 + 1], points[i * 3 + 2]);
glVertex3f(points[i * 3 + 0]/ob->size[0], points[i * 3 + 1]/ob->size[1], points[i * 3 + 2]/ob->size[2]);
}
glEnd();
/* render smoke slice */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
for (i = 0; i < numpoints; i++) {
glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0],
(points[i * 3 + 1] - min[1]) * cor[1] / size[1],
(points[i * 3 + 2] - min[2]) * cor[2] / size[2]);
glVertex3f(points[i * 3 + 0]/ob->size[0], points[i * 3 + 1]/ob->size[1], points[i * 3 + 2]/ob->size[2]);
}
glEnd();
}
@@ -436,6 +520,14 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
if (tex_shadow)
GPU_texture_unbind(tex_shadow);
GPU_texture_unbind(tex);
if (tex_flame) {
GPU_texture_unbind(tex_flame);
GPU_texture_unbind(tex_spec);
}
GPU_texture_free(tex_spec);
free(spec_data);
free(spec_pixels);
if (GLEW_ARB_fragment_program) {
glDisable(GL_FRAGMENT_PROGRAM_ARB);
@@ -454,3 +546,106 @@ void draw_volume(ARegion *ar, GPUTexture *tex, float min[3], float max[3], int r
glDepthMask(GL_TRUE);
}
}
#ifdef SMOKE_DEBUG_VELOCITY
void draw_smoke_velocity(SmokeDomainSettings *domain, Object *ob)
{
float x,y,z;
float x0,y0,z0;
int *base_res = domain->base_res;
int *res = domain->res;
int *res_min = domain->res_min;
int *res_max = domain->res_max;
float *vel_x = smoke_get_velocity_x(domain->fluid);
float *vel_y = smoke_get_velocity_y(domain->fluid);
float *vel_z = smoke_get_velocity_z(domain->fluid);
float min[3];
float *cell_size = domain->cell_size;
float step_size = ((float)MAX3(base_res[0], base_res[1], base_res[2]))/16.f;
float vf = domain->scale / 16.f * 2.f; /* velocity factor */
glLineWidth(1.0f);
/* set first position so that it doesn't jump when domain moves */
x0 = res_min[0] + fmod(-(float)domain->shift[0]+res_min[0],step_size);
y0 = res_min[1] + fmod(-(float)domain->shift[1]+res_min[1],step_size);
z0 = res_min[2] + fmod(-(float)domain->shift[2]+res_min[2],step_size);
if (x0<res_min[0]) x0+=step_size;
if (y0<res_min[1]) y0+=step_size;
if (z0<res_min[2]) z0+=step_size;
add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
for (x=floor(x0); x<res_max[0]; x+=step_size)
for (y=floor(y0); y<res_max[1]; y+=step_size)
for (z=floor(z0); z<res_max[2]; z+=step_size) {
int index = (floor(x)-res_min[0]) + (floor(y)-res_min[1])*res[0] + (floor(z)-res_min[2])*res[0]*res[1];
float pos[3] = {min[0]+((float)x + 0.5f)*cell_size[0], min[1]+((float)y + 0.5f)*cell_size[1], min[2]+((float)z + 0.5f)*cell_size[2]};
float vel = sqrtf(vel_x[index]*vel_x[index] + vel_y[index]*vel_y[index] + vel_z[index]*vel_z[index]);
/* draw heat as scaled "arrows" */
if (vel >= 0.01f) {
float col_g = 1.0f - vel;
CLAMP(col_g, 0.0f, 1.0f);
glColor3f(1.0f, col_g, 0.0f);
glPointSize(10.0f * vel);
glBegin(GL_LINES);
glVertex3f(pos[0], pos[1], pos[2]);
glVertex3f(pos[0]+vel_x[index]*vf, pos[1]+vel_y[index]*vf, pos[2]+vel_z[index]*vf);
glEnd();
glBegin(GL_POINTS);
glVertex3f(pos[0]+vel_x[index]*vf, pos[1]+vel_y[index]*vf, pos[2]+vel_z[index]*vf);
glEnd();
}
}
}
#endif
#ifdef SMOKE_DEBUG_HEAT
void draw_smoke_heat(SmokeDomainSettings *domain, Object *ob)
{
float x,y,z;
float x0,y0,z0;
int *base_res = domain->base_res;
int *res = domain->res;
int *res_min = domain->res_min;
int *res_max = domain->res_max;
float *heat = smoke_get_heat(domain->fluid);
float min[3];
float *cell_size = domain->cell_size;
float step_size = ((float)MAX3(base_res[0], base_res[1], base_res[2]))/16.f;
float vf = domain->scale / 16.f * 2.f; /* velocity factor */
/* set first position so that it doesn't jump when domain moves */
x0 = res_min[0] + fmod(-(float)domain->shift[0]+res_min[0],step_size);
y0 = res_min[1] + fmod(-(float)domain->shift[1]+res_min[1],step_size);
z0 = res_min[2] + fmod(-(float)domain->shift[2]+res_min[2],step_size);
if (x0<res_min[0]) x0+=step_size;
if (y0<res_min[1]) y0+=step_size;
if (z0<res_min[2]) z0+=step_size;
add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
for (x=floor(x0); x<res_max[0]; x+=step_size)
for (y=floor(y0); y<res_max[1]; y+=step_size)
for (z=floor(z0); z<res_max[2]; z+=step_size) {
int index = (floor(x)-res_min[0]) + (floor(y)-res_min[1])*res[0] + (floor(z)-res_min[2])*res[0]*res[1];
float pos[3] = {min[0]+((float)x + 0.5f)*cell_size[0], min[1]+((float)y + 0.5f)*cell_size[1], min[2]+((float)z + 0.5f)*cell_size[2]};
/* draw heat as different sized points */
if (heat[index] >= 0.01f) {
float col_gb = 1.0f - heat[index];
CLAMP(col_gb, 0.0f, 1.0f);
glColor3f(1.0f, col_gb, col_gb);
glPointSize(24.0f * heat[index]);
glBegin(GL_POINTS);
glVertex3f(pos[0], pos[1], pos[2]);
glEnd();
}
}
}
#endif

View File

@@ -212,7 +212,16 @@ ARegion *view3d_has_tools_region(ScrArea *sa);
extern const char *view3d_context_dir[]; /* doc access */
/* draw_volume.c */
void draw_volume(struct ARegion *ar, struct GPUTexture *tex, float min[3], float max[3], int res[3], float dx, struct GPUTexture *tex_shadow);
void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob, struct ARegion *ar, struct GPUTexture *tex, float min[3], float max[3], int res[3], float dx, float base_scale, float viewnormal[3], struct GPUTexture *tex_shadow, struct GPUTexture *tex_flame);
//#define SMOKE_DEBUG_VELOCITY
//#define SMOKE_DEBUG_HEAT
#ifdef SMOKE_DEBUG_VELOCITY
void draw_smoke_velocity(struct SmokeDomainSettings *domain, struct Object *ob);
#endif
#ifdef SMOKE_DEBUG_HEAT
void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob);
#endif
/* workaround for trivial but noticeable camera bug caused by imprecision
* between view border calculation in 2D/3D space, workaround for bug [#28037].

View File

@@ -107,7 +107,7 @@ int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver);
GPUTexture *GPU_texture_create_1D(int w, float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_2D(int w, int h, float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels);
GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *fpixels);
GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]);
GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
GPUTexture *GPU_texture_from_blender(struct Image *ima,

View File

@@ -1019,21 +1019,53 @@ void GPU_free_smoke(SmokeModifierData *smd)
if (smd->domain->tex_shadow)
GPU_texture_free(smd->domain->tex_shadow);
smd->domain->tex_shadow = NULL;
if (smd->domain->tex_flame)
GPU_texture_free(smd->domain->tex_flame);
smd->domain->tex_flame = NULL;
}
}
void GPU_create_smoke(SmokeModifierData *smd, int highres)
{
#ifdef WITH_SMOKE
if (smd->type & MOD_SMOKE_TYPE_DOMAIN && !smd->domain->tex && !highres)
smd->domain->tex = GPU_texture_create_3D(smd->domain->res[0], smd->domain->res[1], smd->domain->res[2], smoke_get_density(smd->domain->fluid));
else if (smd->type & MOD_SMOKE_TYPE_DOMAIN && !smd->domain->tex && highres)
smd->domain->tex = GPU_texture_create_3D(smd->domain->res_wt[0], smd->domain->res_wt[1], smd->domain->res_wt[2], smoke_turbulence_get_density(smd->domain->wt));
if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
SmokeDomainSettings *sds = smd->domain;
if (!sds->tex && !highres) {
/* rgba texture for color + density */
if (smoke_has_colors(sds->fluid)) {
float *data = MEM_callocN(sizeof(float)*sds->total_cells*4, "smokeColorTexture");
smoke_get_rgba(sds->fluid, data, 0);
sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data);
MEM_freeN(data);
}
/* density only */
else {
sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_density(sds->fluid));
}
sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_flame(sds->fluid)) : NULL;
}
else if (!sds->tex && highres) {
/* rgba texture for color + density */
if (smoke_turbulence_has_colors(sds->wt)) {
float *data = MEM_callocN(sizeof(float)*smoke_turbulence_get_cells(sds->wt)*4, "smokeColorTexture");
smoke_turbulence_get_rgba(sds->wt, data, 0);
sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data);
MEM_freeN(data);
}
/* density only */
else {
sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_density(sds->wt));
}
sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_flame(sds->wt)) : NULL;
}
smd->domain->tex_shadow = GPU_texture_create_3D(smd->domain->res[0], smd->domain->res[1], smd->domain->res[2], smd->domain->shadow);
sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, sds->shadow);
}
#else // WITH_SMOKE
(void)highres;
smd->domain->tex= NULL;
smd->domain->tex_flame= NULL;
smd->domain->tex_shadow= NULL;
#endif // WITH_SMOKE
}

View File

@@ -442,7 +442,7 @@ static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, in
}
GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels)
GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *fpixels)
{
GPUTexture *tex;
GLenum type, format, internalformat;
@@ -480,9 +480,15 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels)
GPU_print_error("3D glBindTexture");
type = GL_FLOAT; // GL_UNSIGNED_BYTE
type = GL_FLOAT;
if (channels == 4) {
format = GL_RGBA;
internalformat = GL_RGBA;
}
else {
format = GL_RED;
internalformat = GL_INTENSITY;
}
//if (fpixels)
// pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);

View File

@@ -54,6 +54,7 @@ typedef enum PFieldType {
PFIELD_BOID = 10, /* Defines predator / goal for boids */
PFIELD_TURBULENCE = 11, /* Force defined by BLI_gTurbulence */
PFIELD_DRAG = 12, /* Linear & quadratic drag */
PFIELD_SMOKEFLOW = 13, /* Force based on smoke simulation air flow */
NUM_PFIELD_TYPES
} PFieldType;
@@ -110,14 +111,17 @@ typedef struct PartDeflect {
struct RNG *rng; /* random noise generator for e.g. wind */
float f_noise; /* noise of force */
int seed; /* noise random seed */
struct Object *f_source; /* force source object */
} PartDeflect;
typedef struct EffectorWeights {
struct Group *group; /* only use effectors from this group of objects */
float weight[13]; /* effector type specific weights */
float weight[14]; /* effector type specific weights */
float global_gravity;
short flag, rt[3];
int pad;
} EffectorWeights;
/* EffectorWeights->flag */
@@ -365,6 +369,7 @@ typedef struct SoftBody {
#define PFIELD_DO_LOCATION (1<<14)
#define PFIELD_DO_ROTATION (1<<15)
#define PFIELD_GUIDE_PATH_WEIGHT (1<<16) /* apply curve weights */
#define PFIELD_SMOKE_DENSITY (1<<17) /* multiply smoke force by density */
/* pd->falloff */
#define PFIELD_FALL_SPHERE 0

View File

@@ -39,6 +39,7 @@
#define MOD_SMOKE_HIGH_SMOOTH (1<<5) /* smoothens high res emission*/
#define MOD_SMOKE_FILE_LOAD (1<<6) /* flag for file load */
#define MOD_SMOKE_ADAPTIVE_DOMAIN (1<<7)
/* noise */
#define MOD_SMOKE_NOISEWAVE (1<<0)
@@ -61,6 +62,12 @@
#define SM_COLL_RIGID 1
#define SM_COLL_ANIMATED 2
/* smoke data fileds (active_fields) */
#define SM_ACTIVE_HEAT (1<<0)
#define SM_ACTIVE_FIRE (1<<1)
#define SM_ACTIVE_COLORS (1<<2)
#define SM_ACTIVE_COLOR_SET (1<<3)
typedef struct SmokeDomainSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
struct FLUID_3D *fluid;
@@ -71,17 +78,37 @@ typedef struct SmokeDomainSettings {
struct GPUTexture *tex;
struct GPUTexture *tex_wt;
struct GPUTexture *tex_shadow;
struct GPUTexture *tex_flame;
float *shadow;
float p0[3]; /* start point of BB */
float p1[3]; /* end point of BB */
float dx; /* edge length of one cell */
float omega; /* smoke color - from 0 to 1 */
float temp; /* fluid temperature */
float tempAmb; /* ambient temperature */
/* simulation data */
float p0[3]; /* start point of BB in local space (includes sub-cell shift for adaptive domain)*/
float p1[3]; /* end point of BB in local space */
float dp0[3]; /* difference from object center to grid start point */
float cell_size[3]; /* size of simulation cell in local space */
float global_size[3]; /* global size of domain axises */
float prev_loc[3];
int shift[3]; /* current domain shift in simulation cells */
float shift_f[3]; /* exact domain shift */
float obj_shift_f[3]; /* how much object has shifted since previous smoke frame (used to "lock" domain while drawing) */
float imat[4][4]; /* domain object imat */
float obmat[4][4]; /* domain obmat */
int base_res[3]; /* initial "non-adapted" resolution */
int res_min[3]; /* cell min */
int res_max[3]; /* cell max */
int res[3]; /* data resolution (res_max-res_min) */
int total_cells;
float dx; /* 1.0f / res */
float scale; /* largest domain size */
/* user settings */
int adapt_margin;
int adapt_res;
float adapt_threshold;
float alpha;
float beta;
float scale; /* largest domain size */
int res[3]; /* domain resolution */
int amplify; /* wavelet amplification */
int maxres; /* longest axis on the BB gets this resolution assigned */
int flags; /* show up-res or low res, etc */
@@ -92,7 +119,6 @@ typedef struct SmokeDomainSettings {
float strength;
int res_wt[3];
float dx_wt;
int v3dnum;
int cache_comp;
int cache_high_comp;
@@ -103,31 +129,67 @@ typedef struct SmokeDomainSettings {
int border_collisions; /* How domain border collisions are handled */
float time_scale;
float vorticity;
int pad2;
int active_fields;
float active_color[3]; /* monitor color situation of simulation */
int pad;
/* flame parameters */
float burning_rate, flame_smoke, flame_vorticity;
float flame_ignition, flame_max_temp;
float flame_smoke_color[3];
} SmokeDomainSettings;
/* inflow / outflow */
/* type */
#define MOD_SMOKE_FLOW_TYPE_OUTFLOW (1<<1)
#define MOD_SMOKE_FLOW_TYPE_SMOKE 0
#define MOD_SMOKE_FLOW_TYPE_FIRE 1
#define MOD_SMOKE_FLOW_TYPE_OUTFLOW 2
#define MOD_SMOKE_FLOW_TYPE_SMOKEFIRE 3
/* flow source */
#define MOD_SMOKE_FLOW_SOURCE_PARTICLES 0
#define MOD_SMOKE_FLOW_SOURCE_MESH 1
/* flow texture type */
#define MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO 0
#define MOD_SMOKE_FLOW_TEXTURE_MAP_UV 1
/* flags */
#define MOD_SMOKE_FLOW_ABSOLUTE (1<<1) /*old style emission*/
#define MOD_SMOKE_FLOW_INITVELOCITY (1<<2) /* passes particles speed to the smoke */
#define MOD_SMOKE_FLOW_TEXTUREEMIT (1<<3) /* use texture to control emission speed */
typedef struct SmokeFlowSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
struct DerivedMesh *dm;
struct ParticleSystem *psys;
struct Tex *noise_texture;
/* initial velocity */
float *verts_old; /* previous vertex positions in domain space */
int numverts;
float vel_multi; // Multiplier for inherited velocity
float vel_normal;
float vel_random;
/* emission */
float density;
float color[3];
float fuel_amount;
float temp; /* delta temperature (temp - ambient temp) */
float velocity[2]; /* UNUSED, velocity taken from particles */
float vel_multi; // Multiplier for particle velocity
float vgrp_heat_scale[2]; /* min and max scaling for vgroup_heat */
short vgroup_flow; /* where inflow/outflow happens - red=1=action */
float volume_density; /* density emitted within mesh volume */
float surface_distance; /* maximum emission distance from mesh surface */
/* texture control */
float texture_size;
float texture_offset;
int pad;
char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
short vgroup_density;
short vgroup_heat;
short type; /* inflow =0 or outflow = 1 */
short type; /* smoke, flames, both, outflow */
short source;
short texture_type;
int flags; /* absolute emission etc*/
} SmokeFlowSettings;
@@ -139,20 +201,11 @@ typedef struct SmokeFlowSettings {
/* collision objects (filled with smoke) */
typedef struct SmokeCollSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */
float *points;
float *points_old;
float *vel; // UNUSED
int *tridivs;
float mat[4][4];
float mat_old[4][4];
int numpoints;
int numverts; // check if mesh changed
int numtris;
float dx; /* global domain cell length taken from (scale / resolution) */
struct DerivedMesh *dm;
float *verts_old;
int numverts;
short type; // static = 0, rigid = 1, dynamic = 2
short pad;
int pad2;
} SmokeCollSettings;
#endif

View File

@@ -171,6 +171,9 @@ typedef struct VoxelData {
short flag;
short extend;
short smoked_type;
short data_type;
short pad;
int _pad;
struct Object *object; /* for rendering smoke sims */
float int_multiplier;
@@ -470,6 +473,7 @@ typedef struct ColorMapping {
#define MTEX_BUMP_TEXTURESPACE 2048
/* #define MTEX_BUMP_FLIPPED 4096 */ /* UNUSED */
#define MTEX_BICUBIC_BUMP 8192
#define MTEX_MAPTO_BOUNDS 16384
/* blendtype */
#define MTEX_BLEND 0
@@ -577,6 +581,11 @@ typedef struct ColorMapping {
#define TEX_VD_SMOKEDENSITY 0
#define TEX_VD_SMOKEHEAT 1
#define TEX_VD_SMOKEVEL 2
#define TEX_VD_SMOKEFLAME 3
/* data_type */
#define TEX_VD_INTENSITY 0
#define TEX_VD_RGBA_PREMUL 1
/******************** Ocean *****************************/
/* output */

View File

@@ -468,6 +468,12 @@ static void rna_def_material_mtex(BlenderRNA *brna)
"from their parent");
RNA_def_property_update(prop, 0, "rna_Material_update");
prop = RNA_def_property(srna, "use_map_to_bounds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_MAPTO_BOUNDS);
RNA_def_property_ui_text(prop, "Map to Bounds",
"Map coordinates in object bounds");
RNA_def_property_update(prop, 0, "rna_Material_update");
prop = RNA_def_property(srna, "use_from_original", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_OB_DUPLI_ORIG);
RNA_def_property_ui_text(prop, "From Original",

View File

@@ -257,9 +257,6 @@ static void rna_Smoke_set_type(Main *bmain, Scene *scene, PointerRNA *ptr)
{
SmokeModifierData *smd = (SmokeModifierData *)ptr->data;
Object *ob = (Object *)ptr->id.data;
ParticleSystemModifierData *psmd = NULL;
ParticleSystem *psys = NULL;
ParticleSettings *part = NULL;
/* nothing changed */
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
@@ -273,28 +270,6 @@ static void rna_Smoke_set_type(Main *bmain, Scene *scene, PointerRNA *ptr)
ob->dt = OB_WIRE;
break;
case MOD_SMOKE_TYPE_FLOW:
for (psys = ob->particlesystem.first; psys; psys = psys->next)
if (psys->part->type == PART_EMITTER)
break;
if (ob->type == OB_MESH && !psys) {
/* add particle system */
psmd = (ParticleSystemModifierData *)object_add_particle_system(scene, ob, NULL);
if (psmd) {
psys = psmd->psys;
part = psys->part;
part->lifetime = 1.0f;
part->sta = 1.0f;
part->end = 250.0f;
part->ren_as = PART_DRAW_NOT;
part->flag |= PART_UNBORN;
part->draw_as = PART_DRAW_DOT;
BLI_strncpy(psys->name, "SmokeParticles", sizeof(psys->name));
psys->recalc |= (PSYS_RECALC_RESET | PSYS_RECALC_PHYS);
DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
}
}
if (smd->flow)
smd->flow->psys = psys;
case MOD_SMOKE_TYPE_COLL:
case 0:
default:

View File

@@ -1056,6 +1056,13 @@ static void rna_def_effector_weight(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_ui_text(prop, "Drag", "Drag effector weight");
RNA_def_property_update(prop, 0, "rna_EffectorWeight_update");
prop = RNA_def_property(srna, "smokeflow", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "weight[13]");
RNA_def_property_range(prop, -200.0f, 200.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_ui_text(prop, "Smoke Flow", "Smoke Flow effector weight");
RNA_def_property_update(prop, 0, "rna_EffectorWeight_update");
}
static void rna_def_field(BlenderRNA *brna)
@@ -1082,6 +1089,7 @@ static void rna_def_field(BlenderRNA *brna)
{PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""},
{PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", "Create turbulence with a noise field"},
{PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", "Create a force that dampens motion"},
{PFIELD_SMOKEFLOW, "SMOKE_FLOW", ICON_FORCE_SMOKEFLOW, "Smoke Flow", "Create a force based on smoke simulation air flow"},
{0, NULL, 0, NULL, NULL}
};
@@ -1335,6 +1343,11 @@ static void rna_def_field(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Multiple Springs", "Every point is effected by multiple springs");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
prop = RNA_def_property(srna, "use_smoke_density", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_SMOKE_DENSITY);
RNA_def_property_ui_text(prop, "Apply Density", "Adjust force strength based on smoke density");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
/* Pointer */
prop = RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE);
@@ -1343,6 +1356,12 @@ static void rna_def_field(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Texture", "Texture to use as force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
prop = RNA_def_property(srna, "source_object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "f_source");
RNA_def_property_ui_text(prop, "Domain Object", "Select domain object of the smoke simulation");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
/********** Curve Guide Field Settings **********/
prop = RNA_def_property(srna, "guide_minimum", PROP_FLOAT, PROP_NONE);

View File

@@ -65,14 +65,20 @@ static void rna_Smoke_dependency_update(Main *bmain, Scene *scene, PointerRNA *p
DAG_scene_sort(bmain, scene);
}
static void rna_Smoke_resetCache(Main *bmain, Scene *scene, PointerRNA *ptr)
{
SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
if (settings->smd && settings->smd->domain)
settings->point_cache[0]->flag |= PTCACHE_OUTDATED;
DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
}
static void rna_Smoke_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
{
SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
smokeModifier_reset(settings->smd);
if (settings->smd && settings->smd->domain)
settings->point_cache[0]->flag |= PTCACHE_OUTDATED;
rna_Smoke_resetCache(bmain, scene, ptr);
rna_Smoke_update(bmain, scene, ptr);
}
@@ -142,6 +148,30 @@ static void rna_SmokeModifier_density_get(PointerRNA *ptr, float *values)
memcpy(values, density, size * sizeof(float));
}
static void rna_SmokeFlow_density_vgroup_get(PointerRNA *ptr, char *value)
{
SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
rna_object_vgroup_name_index_get(ptr, value, flow->vgroup_density);
}
static int rna_SmokeFlow_density_vgroup_length(PointerRNA *ptr)
{
SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
return rna_object_vgroup_name_index_length(ptr, flow->vgroup_density);
}
static void rna_SmokeFlow_density_vgroup_set(PointerRNA *ptr, const char *value)
{
SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
rna_object_vgroup_name_index_set(ptr, value, &flow->vgroup_density);
}
static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value)
{
SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name));
}
#else
static void rna_def_smoke_domain_settings(BlenderRNA *brna)
@@ -217,7 +247,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
RNA_def_property_ui_text(prop, "Density",
"How much density affects smoke motion (higher value results in faster rising smoke)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "beta", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "beta");
@@ -225,7 +255,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
RNA_def_property_ui_text(prop, "Heat",
"How much heat affects smoke motion (higher value results in faster rising smoke)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "collision_group", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "coll_group");
@@ -253,24 +283,24 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 10.0);
RNA_def_property_ui_range(prop, 0.0, 10.0, 1, 2);
RNA_def_property_ui_text(prop, "Strength", "Strength of noise");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "dissolve_speed", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "diss_speed");
RNA_def_property_range(prop, 1.0, 10000.0);
RNA_def_property_ui_range(prop, 1.0, 10000.0, 1, 0);
RNA_def_property_ui_text(prop, "Dissolve Speed", "Dissolve Speed");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "use_dissolve_smoke", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE);
RNA_def_property_ui_text(prop, "Dissolve Smoke", "Enable smoke to disappear over time");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE_LOG);
RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x ");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -297,21 +327,21 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "smooth_emitter", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGH_SMOOTH);
RNA_def_property_ui_text(prop, "Smooth Emitter", "Smooth emitted smoke to avoid blockiness");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "time_scale");
RNA_def_property_range(prop, 0.2, 1.5);
RNA_def_property_ui_range(prop, 0.2, 1.5, 0.02, 5);
RNA_def_property_ui_text(prop, "Time Scale", "Adjust simulation speed");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "vorticity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vorticity");
RNA_def_property_range(prop, 0.01, 4.0);
RNA_def_property_ui_range(prop, 0.01, 4.0, 0.02, 5);
RNA_def_property_ui_text(prop, "Vorticity", "Amount of turbulence/rotation in fluid");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 32);
@@ -321,25 +351,80 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, "rna_SmokeModifier_density_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Density", "Smoke density");
prop = RNA_def_property(srna, "cell_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "dx");
prop = RNA_def_property(srna, "cell_size", PROP_FLOAT, PROP_XYZ); /* can change each frame when using adaptive domain */
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "dx", "Cell Size");
RNA_def_property_ui_text(prop, "cell_size", "Cell Size");
prop = RNA_def_property(srna, "start_point", PROP_FLOAT, PROP_XYZ);
prop = RNA_def_property(srna, "start_point", PROP_FLOAT, PROP_XYZ); /* can change each frame when using adaptive domain */
RNA_def_property_float_sdna(prop, NULL, "p0");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "p0", "Start point");
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "scale", "Domain scale factor");
prop = RNA_def_property(srna, "domain_resolution", PROP_INT, PROP_XYZ);
prop = RNA_def_property(srna, "domain_resolution", PROP_INT, PROP_XYZ); /* can change each frame when using adaptive domain */
RNA_def_property_int_sdna(prop, NULL, "res");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "res", "Smoke Grid Resolution");
prop = RNA_def_property(srna, "burning_rate", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.01, 4.0);
RNA_def_property_ui_range(prop, 0.01, 2.0, 1.0, 5);
RNA_def_property_ui_text(prop, "Speed", "Speed of the burning reaction. Use larger values for smaller flame");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "flame_smoke", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 8.0);
RNA_def_property_ui_range(prop, 0.0, 4.0, 1.0, 5);
RNA_def_property_ui_text(prop, "Smoke", "Amount of smoke created by burning fuel");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "flame_vorticity", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 2.0);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 5);
RNA_def_property_ui_text(prop, "Vorticity", "Additional vorticity for the flames");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "flame_ignition", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.5, 5.0);
RNA_def_property_ui_range(prop, 0.5, 2.5, 1.0, 5);
RNA_def_property_ui_text(prop, "Ignition", "Minimum temperature of flames");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "flame_max_temp", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 1.0, 10.0);
RNA_def_property_ui_range(prop, 1.0, 5.0, 1.0, 5);
RNA_def_property_ui_text(prop, "Maximum", "Maximum temperature of flames");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "flame_smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke emitted from burning fuel");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "use_adaptive_domain", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_ADAPTIVE_DOMAIN);
RNA_def_property_ui_text(prop, "Adaptive Domain", "Adapt simulation resolution and size to fluid");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "additional_res", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "adapt_res");
RNA_def_property_range(prop, 0, 512);
RNA_def_property_ui_range(prop, 0, 512, 2, 0);
RNA_def_property_ui_text(prop, "Additional", "Maximum number of additional cells");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "adapt_margin", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "adapt_margin");
RNA_def_property_range(prop, 2, 24);
RNA_def_property_ui_range(prop, 2, 24, 2, 0);
RNA_def_property_ui_text(prop, "Margin", "Margin added around fluid to minimize boundary interference");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
prop = RNA_def_property(srna, "adapt_threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.01, 0.5);
RNA_def_property_ui_range(prop, 0.01, 0.5, 1.0, 5);
RNA_def_property_ui_text(prop, "Threshold", "Maximum amount of fluid cell can contain before it's considered empty");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
}
static void rna_def_smoke_flow_settings(BlenderRNA *brna)
@@ -347,6 +432,26 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
static EnumPropertyItem smoke_flow_types[] = {
{MOD_SMOKE_FLOW_TYPE_OUTFLOW, "OUTFLOW", 0, "Outflow", "Delete smoke from simulation"},
{MOD_SMOKE_FLOW_TYPE_SMOKE, "SMOKE", 0, "Smoke", "Add smoke"},
{MOD_SMOKE_FLOW_TYPE_SMOKEFIRE, "BOTH", 0, "Fire + Smoke", "Add fire and smoke"},
{MOD_SMOKE_FLOW_TYPE_FIRE, "FIRE", 0, "Fire", "Add fire"},
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem smoke_flow_sources[] = {
{MOD_SMOKE_FLOW_SOURCE_PARTICLES, "PARTICLES", ICON_PARTICLES, "Particle System", "Emit smoke from particles"},
{MOD_SMOKE_FLOW_SOURCE_MESH, "MESH", ICON_META_CUBE, "Mesh", "Emit smoke from mesh surface or volume"},
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem smoke_flow_texture_types[] = {
{MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO, "AUTO", 0, "Generated", "Generated coordinates centered to flow object"},
{MOD_SMOKE_FLOW_TEXTURE_MAP_UV, "UV", 0, "UV", "Use UV layer for texture coordinates"},
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "SmokeFlowSettings", NULL);
RNA_def_struct_ui_text(srna, "Flow Settings", "Smoke flow settings");
RNA_def_struct_sdna(srna, "SmokeFlowSettings");
@@ -354,11 +459,23 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "density");
RNA_def_property_range(prop, 0.001, 1);
RNA_def_property_ui_range(prop, 0.001, 1.0, 1.0, 4);
RNA_def_property_range(prop, 0.0, 1);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 4);
RNA_def_property_ui_text(prop, "Density", "");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "color");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "fuel_amount", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 10);
RNA_def_property_ui_range(prop, 0.0, 5.0, 1.0, 4);
RNA_def_property_ui_text(prop, "Flame Rate", "");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "temperature", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "temp");
RNA_def_property_range(prop, -10, 10);
@@ -373,9 +490,16 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Particle Systems", "Particle systems emitted from the object");
RNA_def_property_update(prop, 0, "rna_Smoke_reset_dependancy");
prop = RNA_def_property(srna, "use_outflow", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "type", MOD_SMOKE_FLOW_TYPE_OUTFLOW);
RNA_def_property_ui_text(prop, "Outflow", "Delete smoke from simulation");
prop = RNA_def_property(srna, "smoke_flow_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, smoke_flow_types);
RNA_def_property_ui_text(prop, "Flow Type", "Change how flow affects the simulation");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "smoke_flow_source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "source");
RNA_def_property_enum_items(prop, smoke_flow_sources);
RNA_def_property_ui_text(prop, "Source", "Change how smoke is emitted");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "use_absolute", PROP_BOOLEAN, PROP_NONE);
@@ -385,14 +509,82 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "initial_velocity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_INITVELOCITY);
RNA_def_property_ui_text(prop, "Initial Velocity", "Smoke inherits its velocity from the emitter particle");
RNA_def_property_ui_text(prop, "Initial Velocity", "Smoke has some initial velocity when it is emitted");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_multi");
RNA_def_property_range(prop, -2.0, 2.0);
RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Multiplier", "Multiplier to adjust velocity passed to smoke");
RNA_def_property_ui_text(prop, "Source", "Multiplier of source velocity passed to smoke");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "velocity_normal", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_normal");
RNA_def_property_range(prop, -2.0, 2.0);
RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Normal", "Amount of normal directional velocity");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "velocity_random", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_random");
RNA_def_property_range(prop, 0.0, 2.0);
RNA_def_property_ui_range(prop, 0.0, 2.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Random", "Amount of random velocity");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "volume_density", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Volume", "Factor for smoke emitted from inside the mesh volume");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.5, 10.0);
RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Surface", "Maximum distance from mesh surface to emit smoke");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "density_vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_SmokeFlow_density_vgroup_get",
"rna_SmokeFlow_density_vgroup_length",
"rna_SmokeFlow_density_vgroup_set");
RNA_def_property_ui_text(prop, "Vertex Group",
"Name of Vertex Group which determines surface emission rate");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "use_texture", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_TEXTUREEMIT);
RNA_def_property_ui_text(prop, "Use Texture", "Use a texture to controll emission strength");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "texture_map_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "texture_type");
RNA_def_property_enum_items(prop, smoke_flow_texture_types);
RNA_def_property_ui_text(prop, "Mapping", "Texture mapping type");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "uvlayer_name");
RNA_def_property_ui_text(prop, "UV Map", "UV map name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SmokeFlow_uvlayer_set");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "noise_texture", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Texture", "Texture that controls emission strength");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "texture_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.01, 10.0);
RNA_def_property_ui_range(prop, 0.1, 5.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Size", "Size of texture mapping");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 200.0);
RNA_def_property_ui_range(prop, 0.0, 100.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Offset", "Z-offset of texture mapping");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
}

View File

@@ -1800,7 +1800,8 @@ static void rna_def_texture_voxeldata(BlenderRNA *brna)
};
static EnumPropertyItem smoked_type_items[] = {
{TEX_VD_SMOKEDENSITY, "SMOKEDENSITY", 0, "Density", "Use smoke density as texture data"},
{TEX_VD_SMOKEDENSITY, "SMOKEDENSITY", 0, "Smoke", "Use smoke density and color as texture data"},
{TEX_VD_SMOKEFLAME, "SMOKEFLAME", 0, "Flame", "Use flame temperature as texture data"},
{TEX_VD_SMOKEHEAT, "SMOKEHEAT", 0, "Heat", "Use smoke heat as texture data. Values from -2.0 to 2.0 are used"},
{TEX_VD_SMOKEVEL, "SMOKEVEL", 0, "Velocity", "Use smoke velocity as texture data"},
{0, NULL, 0, NULL, NULL}

View File

@@ -81,19 +81,31 @@ static void freeData(ModifierData *md)
smokeModifier_free(smd);
}
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
int UNUSED(numVerts),
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
SmokeModifierData *smd = (SmokeModifierData *)md;
CustomDataMask dataMask = 0;
if (smd && (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
if (smd->flow->source == MOD_SMOKE_FLOW_SOURCE_MESH) {
/* vertex groups */
if (smd->flow->vgroup_density)
dataMask |= CD_MASK_MDEFORMVERT;
/* uv layer */
if (smd->flow->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_UV)
dataMask |= CD_MASK_MTFACE;
}
}
return dataMask;
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm,
ModifierApplyFlag UNUSED(flag))
{
SmokeModifierData *smd = (SmokeModifierData *) md;
DerivedMesh *dm = get_cddm(ob, NULL, derivedData, vertexCos);
smokeModifier_do(smd, md->scene, ob, dm);
if (dm != derivedData)
dm->release(dm);
return smokeModifier_do(smd, md->scene, ob, dm);
}
static int dependsOnTime(ModifierData *UNUSED(md))
@@ -102,11 +114,11 @@ static int dependsOnTime(ModifierData *UNUSED(md))
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
struct Scene *scene,
Object *UNUSED(ob),
struct Scene *scene, struct Object *ob,
DagNode *obNode)
{
SmokeModifierData *smd = (SmokeModifierData *) md;
Base *base;
if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
if (smd->domain->fluid_group || smd->domain->coll_group) {
@@ -139,8 +151,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
else {
Base *base = scene->base.first;
base = scene->base.first;
for (; base; base = base->next) {
SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(base->object, eModifierType_Smoke);
@@ -150,6 +161,14 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
}
/* add relation to all "smoke flow" force fields */
base = scene->base.first;
for (; base; base = base->next) {
if (base->object->pd && base->object->pd->forcefield == PFIELD_SMOKEFLOW && base->object->pd->f_source == ob) {
DagNode *node2 = dag_get_node(forest, base->object);
dag_add_relation(forest, obNode, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Source Object");
}
}
}
}
@@ -167,26 +186,30 @@ static void foreachIDLink(ModifierData *md, Object *ob,
walk(userData, ob, (ID **)&smd->domain->effector_weights->group);
}
}
if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) {
walk(userData, ob, (ID **)&smd->flow->noise_texture);
}
}
ModifierTypeInfo modifierType_Smoke = {
/* name */ "Smoke",
/* structName */ "SmokeModifierData",
/* structSize */ sizeof(SmokeModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_UsesPointCache |
eModifierTypeFlag_Single,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
/* applyModifier */ applyModifier,
/* applyModifierEM */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,

View File

@@ -2660,6 +2660,13 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
mul_m4_v3(shi->obi->duplitexmat, co);
}
mul_m4_v3(ob->imat_ren, co);
if (mtex->texflag & MTEX_MAPTO_BOUNDS && ob->bb) {
/* use bb vec[0] as min and bb vec[6] as max */
co[0] = (co[0] - ob->bb->vec[0][0]) / (ob->bb->vec[6][0]-ob->bb->vec[0][0]) * 2.0f - 1.0f;
co[1] = (co[1] - ob->bb->vec[0][1]) / (ob->bb->vec[6][1]-ob->bb->vec[0][1]) * 2.0f - 1.0f;
co[2] = (co[2] - ob->bb->vec[0][2]) / (ob->bb->vec[6][2]-ob->bb->vec[0][2]) * 2.0f - 1.0f;
}
}
}
/* not really orco, but 'local' */
@@ -2672,6 +2679,13 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
Object *ob= shi->obi->ob;
copy_v3_v3(co, xyz);
mul_m4_v3(ob->imat_ren, co);
if (mtex->texflag & MTEX_MAPTO_BOUNDS && ob->bb) {
/* use bb vec[0] as min and bb vec[6] as max */
co[0] = (co[0] - ob->bb->vec[0][0]) / (ob->bb->vec[6][0]-ob->bb->vec[0][0]) * 2.0f - 1.0f;
co[1] = (co[1] - ob->bb->vec[0][1]) / (ob->bb->vec[6][1]-ob->bb->vec[0][1]) * 2.0f - 1.0f;
co[2] = (co[2] - ob->bb->vec[0][2]) / (ob->bb->vec[6][2]-ob->bb->vec[0][2]) * 2.0f - 1.0f;
}
}
}
else if (mtex->texco==TEXCO_GLOB) {
@@ -2738,6 +2752,12 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
if ((rgbnor & TEX_RGB) == 0) {
copy_v3_v3(tcol, &mtex->r);
}
else if (mtex->mapto & MAP_DENSITY) {
copy_v3_v3(tcol, &texres.tr);
if (texres.talpha) {
texres.tin = stencilTin;
}
}
else {
copy_v3_v3(tcol, &texres.tr);
if (texres.talpha) {

View File

@@ -227,69 +227,102 @@ static void init_frame_smoke(VoxelData *vd, float cfra)
/* draw code for smoke */
if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke))) {
SmokeModifierData *smd = (SmokeModifierData *)md;
SmokeDomainSettings *sds = smd->domain;
if (smd->domain && smd->domain->fluid) {
if (cfra < smd->domain->point_cache[0]->startframe)
if (sds && sds->fluid) {
if (cfra < sds->point_cache[0]->startframe)
; /* don't show smoke before simulation starts, this could be made an option in the future */
else if (vd->smoked_type == TEX_VD_SMOKEHEAT) {
size_t totRes;
size_t i;
float *heat;
copy_v3_v3_int(vd->resol, smd->domain->res);
if (!smoke_has_heat(sds->fluid)) return;
copy_v3_v3_int(vd->resol, sds->res);
totRes = vd_resol_size(vd);
/* scaling heat values from -2.0-2.0 to 0.0-1.0 */
vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
/* get heat data */
heat = smoke_get_heat(sds->fluid);
heat = smoke_get_heat(smd->domain->fluid);
/* scale heat values from -2.0-2.0 to 0.0-1.0 */
for (i = 0; i < totRes; i++) {
vd->dataset[i] = (heat[i] + 2.0f) / 4.0f;
}
/* vd->dataset = smoke_get_heat(smd->domain->fluid); */
}
else if (vd->smoked_type == TEX_VD_SMOKEVEL) {
size_t totRes;
size_t i;
float *xvel, *yvel, *zvel;
copy_v3_v3_int(vd->resol, smd->domain->res);
copy_v3_v3_int(vd->resol, sds->res);
totRes = vd_resol_size(vd);
/* scaling heat values from -2.0-2.0 to 0.0-1.0 */
vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
/* get velocity data */
xvel = smoke_get_velocity_x(sds->fluid);
yvel = smoke_get_velocity_y(sds->fluid);
zvel = smoke_get_velocity_z(sds->fluid);
xvel = smoke_get_velocity_x(smd->domain->fluid);
yvel = smoke_get_velocity_y(smd->domain->fluid);
zvel = smoke_get_velocity_z(smd->domain->fluid);
/* map velocities between 0 and 0.3f */
for (i = 0; i < totRes; i++) {
vd->dataset[i] = sqrt(xvel[i] * xvel[i] + yvel[i] * yvel[i] + zvel[i] * zvel[i]) * 3.0f;
}
}
else {
else if (vd->smoked_type == TEX_VD_SMOKEFLAME) {
size_t totRes;
float *density;
float *flame;
if (smd->domain->flags & MOD_SMOKE_HIGHRES) {
smoke_turbulence_get_res(smd->domain->wt, vd->resol);
density = smoke_turbulence_get_density(smd->domain->wt);
if (sds->flags & MOD_SMOKE_HIGHRES) {
if (!smoke_turbulence_has_fuel(sds->wt)) return;
smoke_turbulence_get_res(sds->wt, vd->resol);
flame = smoke_turbulence_get_flame(sds->wt);
}
else {
copy_v3_v3_int(vd->resol, smd->domain->res);
density = smoke_get_density(smd->domain->fluid);
if (!smoke_has_fuel(sds->fluid)) return;
copy_v3_v3_int(vd->resol, sds->res);
flame = smoke_get_flame(sds->fluid);
}
/* always store copy, as smoke internal data can change */
totRes= vd_resol_size(vd);
vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
memcpy(vd->dataset, flame, sizeof(float)*totRes);
}
else {
size_t totCells;
int depth = 4;
vd->data_type = TEX_VD_RGBA_PREMUL;
/* data resolution */
if (sds->flags & MOD_SMOKE_HIGHRES) {
smoke_turbulence_get_res(sds->wt, vd->resol);
}
else {
copy_v3_v3_int(vd->resol, sds->res);
}
/* TODO: is_vd_res_ok(rvd) doesnt check this resolution */
totRes = vd_resol_size(vd);
totCells = vd_resol_size(vd) * depth;
/* always store copy, as smoke internal data can change */
vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
memcpy(vd->dataset, density, sizeof(float) * totRes);
vd->dataset = MEM_mapallocN(sizeof(float) * totCells, "smoke data");
if (sds->flags & MOD_SMOKE_HIGHRES) {
if (smoke_turbulence_has_colors(sds->wt)) {
smoke_turbulence_get_rgba(sds->wt, vd->dataset, 1);
}
else {
smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, vd->dataset, 1);
}
}
else {
if (smoke_has_colors(sds->fluid)) {
smoke_get_rgba(sds->fluid, vd->dataset, 1);
}
else {
smoke_get_rgba_from_density(sds->fluid, sds->active_color, vd->dataset, 1);
}
}
} /* end of fluid condition */
}
}
@@ -320,6 +353,8 @@ void cache_voxeldata(Tex *tex, int scene_frame)
MEM_freeN(vd->dataset);
vd->dataset = NULL;
}
/* reset data_type */
vd->data_type = TEX_VD_INTENSITY;
if (vd->flag & TEX_VD_STILL)
curframe = vd->still_frame;
@@ -379,9 +414,11 @@ void make_voxeldata(struct Render *re)
int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres)
{
int retval = TEX_INT;
VoxelData *vd = tex->vd;
float co[3], offset[3] = {0.5, 0.5, 0.5};
float co[3], offset[3] = {0.5, 0.5, 0.5}, a;
int retval = (vd->data_type == TEX_VD_RGBA_PREMUL) ? TEX_RGB : TEX_INT;
int depth = (vd->data_type == TEX_VD_RGBA_PREMUL) ? 4 : 1;
int ch;
if (vd->dataset == NULL) {
texres->tin = 0.0f;
@@ -421,28 +458,60 @@ int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texre
}
}
for (ch = 0; ch < depth; ch++) {
float *dataset = vd->dataset + ch*vd->resol[0]*vd->resol[1]*vd->resol[2];
float *result = &texres->tin;
if (vd->data_type == TEX_VD_RGBA_PREMUL) {
switch (ch) {
case 0:
result = &texres->tr;
break;
case 1:
result = &texres->tg;
break;
case 2:
result = &texres->tb;
break;
}
}
switch (vd->interp_type) {
case TEX_VD_NEARESTNEIGHBOR:
texres->tin = BLI_voxel_sample_nearest(vd->dataset, vd->resol, co);
*result = BLI_voxel_sample_nearest(dataset, vd->resol, co);
break;
case TEX_VD_LINEAR:
texres->tin = BLI_voxel_sample_trilinear(vd->dataset, vd->resol, co);
*result = BLI_voxel_sample_trilinear(dataset, vd->resol, co);
break;
case TEX_VD_QUADRATIC:
texres->tin = BLI_voxel_sample_triquadratic(vd->dataset, vd->resol, co);
*result = BLI_voxel_sample_triquadratic(dataset, vd->resol, co);
break;
case TEX_VD_TRICUBIC_CATROM:
case TEX_VD_TRICUBIC_BSPLINE:
texres->tin = BLI_voxel_sample_tricubic(vd->dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE));
*result = BLI_voxel_sample_tricubic(dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE));
break;
}
}
a = texres->tin;
texres->tin *= vd->int_multiplier;
BRICONT;
if (vd->data_type == TEX_VD_RGBA_PREMUL) {
/* unmultiply */
if (a>0.001f) {
texres->tr /= a;
texres->tg /= a;
texres->tb /= a;
}
texres->talpha = 1;
}
else {
texres->tr = texres->tin;
texres->tg = texres->tin;
texres->tb = texres->tin;
}
texres->ta = texres->tin;
BRICONTRGB;