blender/intern/elbeem/intern/isosurface.h
Nils Thuerey 3bea663ffa - bugfixes
#4742 exported normals are now correct
  #4821 & 4956 for complex movements in/outflows can now also
  use the animated mesh option
- new features
  * isosurface subdivision: directly
    creates a finer surface mesh from the simulation data.
    this increases simulation time and harddisk usage, though, so
    be careful - usually values of 2-4 should be enough.
  * fluidsim particles: extended model for particle
    simulation and generation. When isosurface subdivision is enabled,
    the particles are now included in the surface generation,
    giving a better impression of a single connected surface.
    Note - the particles are only included in the final surface
    mesh, so the preview surface shows none of the particle
    effects.
  * particle loading: different types of particles can now be selected for
    display: drops, floats and tracers. This is a bit obsolete
    due to the extensions mentioned above, but might still be useful.
    Floats are just particles floating on the fluid surface, could
    be used for e.g. foam.
  * moving objects impact factor: this is another tweaking option,
    as the handling of moving objects is still not conserving
    mass. setting this to zero simply deletes the fluid, 1 is
    the default, while larger values cause a stronger
    impact. For tweaking the simulation: if fluid disappears, try
    increasing this value, and if too much is appearing reduce it.
    You can even use negative values for some strange results :)
- more code cleanup, e.g. removed config file writing in fluidsim.c,
  added additional safety checks for particles & fluidsim domains (these
  currently dont work together). I also removed the "build particles"
  debug message in effects.c (seemed to be unnecessary?).

Some more info on the new features:
Here are two test animations showing the difference between
using the particle generation with isosurface subdivision.
This is how it would look with the old solver version:
http://www10.informatik.uni-erlangen.de/~sinithue/blender/fluid6_fl6manc4_1noparts.mpg
and this with the new one:
http://www10.informatik.uni-erlangen.de/~sinithue/blender/fluid6_fl6manc4_2wparts.mpg
Both simulations use a resolution of 64, however, the version with particles
takes significantly longer (almost twice as long).
The .blend file for a similar setup can be found here:
http://www10.informatik.uni-erlangen.de/~sinithue/blender/fluid6_testmanc4.blend
(Minor Tips for this file: dont enable subdivions of characters until rendering,
thus leave off for simulation, as it uses the rendering settings! For making
nice pictures switch on subdivion, and OSA.)

And here's a picture of old vs. new (for webpage or so):
http://www10.informatik.uni-erlangen.de/~sinithue/blender/fluid6_manc4compare.png
2006-11-05 16:30:29 +00:00

231 lines
6.9 KiB
C++

/******************************************************************************
*
* El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
* Copyright 2003-2006 Nils Thuerey
*
* Marching Cubes "displayer"
*
*****************************************************************************/
#ifndef ISOSURFACE_H
#include "ntl_geometryobject.h"
#include "ntl_bsptree.h"
#define ISO_STRICT_DEBUG 0
#define ISOSTRICT_EXIT *((int *)0)=0;
/* access some 3d array */
#define ISOLEVEL_INDEX(ii,ij,ik) ((mSizex*mSizey*(ik))+(mSizex*(ij))+((ii)))
class ParticleTracer;
/* struct for a small cube in the scalar field */
typedef struct {
ntlVec3Gfx pos[8];
double value[8];
int i,j,k;
} IsoLevelCube;
typedef struct {
ntlVec3Gfx v; // vertex
ntlVec3Gfx n; // vertex normal
} IsoLevelVertex;
//! class to triangulate a scalar field, e.g. for
// the fluid surface, templated by scalar field access object
class IsoSurface :
public ntlGeometryObject //, public S
{
public:
/*! Constructor */
IsoSurface(double iso);
/*! Destructor */
virtual ~IsoSurface();
/*! Init ararys etc. */
virtual void initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent);
/*! Reset all values */
void resetAll(gfxReal val);
/*! triangulate the scalar field given by pointer*/
void triangulate( void );
/*! set particle pointer */
void setParticles(ParticleTracer *pnt,float psize){ mpIsoParts = pnt; mPartSize=psize; };
/*! set # of subdivisions, this has to be done before init! */
void setSubdivs(int s) {
if(mInitDone) errFatal("IsoSurface::setSubdivs","Changing subdivs after init!", SIMWORLD_INITERROR);
if(s<1) s=1; if(s>10) s=10;
mSubdivs = s; }
int getSubdivs() { return mSubdivs;}
/*! set full edge settings, this has to be done before init! */
void setUseFulledgeArrays(bool set) {
if(mInitDone) errFatal("IsoSurface::setUseFulledgeArrays","Changing usefulledge after init!", SIMWORLD_INITERROR);
mUseFullEdgeArrays = set;}
protected:
/* variables ... */
//! size
int mSizex, mSizey, mSizez;
//! data pointer
float *mpData;
//! Level of the iso surface
double mIsoValue;
//! Store all the triangles vertices
vector<IsoLevelVertex> mPoints;
//! use full arrays? (not for farfield)
bool mUseFullEdgeArrays;
//! Store indices of calculated points along the cubie edges
int *mpEdgeVerticesX;
int *mpEdgeVerticesY;
int *mpEdgeVerticesZ;
int mEdgeArSize;
//! vector for all the triangles (stored as 3 indices)
vector<unsigned int> mIndices;
//! start and end vectors for the triangulation region to create triangles in
ntlVec3Gfx mStart, mEnd;
//! normalized domain extent from parametrizer/visualizer
ntlVec3Gfx mDomainExtent;
//! initialized?
bool mInitDone;
//! amount of surface smoothing
float mSmoothSurface;
//! amount of normal smoothing
float mSmoothNormals;
//! grid data
vector<int> mAcrossEdge;
vector< vector<int> > mAdjacentFaces;
//! cutoff border area
int mCutoff;
//! cutoff heigh values
int *mCutArray;
//! particle pointer
ParticleTracer *mpIsoParts;
//! particle size
float mPartSize;
//! no of subdivisions
int mSubdivs;
//! trimesh vars
vector<int> flags;
int mFlagCnt;
vector<ntlVec3Gfx> cornerareas;
vector<float> pointareas;
vector< vector<int> > neighbors;
public:
// miscelleanous access functions
//! set geometry start (for renderer)
void setStart(ntlVec3Gfx set) { mStart = set; };
ntlVec3Gfx getStart() { return mStart; };
//! set geometry end (for renderer)
void setEnd(ntlVec3Gfx set) { mEnd = set; };
ntlVec3Gfx getEnd() { return mEnd; };
//! set iso level value for surface reconstruction
inline void setIsolevel(double set) { mIsoValue = set; };
//! set loop subdiv num
inline void setSmoothSurface(float set) { mSmoothSurface = set; };
inline void setSmoothNormals(float set) { mSmoothNormals = set; };
inline float getSmoothSurface() { return mSmoothSurface; }
inline float getSmoothNormals() { return mSmoothNormals; }
// geometry object functions
virtual void getTriangles(double t, vector<ntlTriangle> *triangles,
vector<ntlVec3Gfx> *vertices,
vector<ntlVec3Gfx> *normals, int objectId );
//! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB
virtual inline ntlVec3Gfx *getBBStart() { return &mStart; }
virtual inline ntlVec3Gfx *getBBEnd() { return &mEnd; }
//! access data array
inline float* getData(){ return mpData; }
inline float* getData(int ii, int jj, int kk){
#if ISO_STRICT_DEBUG==1
if(ii<0){ errMsg("IsoStrict"," invX- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
if(jj<0){ errMsg("IsoStrict"," invY- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
if(kk<0){ errMsg("IsoStrict"," invZ- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
if(ii>mSizex-1){ errMsg("IsoStrict"," invX+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
if(jj>mSizey-1){ errMsg("IsoStrict"," invY+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
if(kk>mSizez-1){ errMsg("IsoStrict"," invZ+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
return mpData + ISOLEVEL_INDEX(ii, jj, kk);
#else //ISO_STRICT_DEBUG==1
return mpData + ISOLEVEL_INDEX(ii, jj, kk);
#endif
}
inline float* lbmGetData(int ii, int jj, int kk){
#if ISO_STRICT_DEBUG==1
ii++; jj++; kk++;
if(ii<0){ errMsg("IsoStrict"," invX- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
if(jj<0){ errMsg("IsoStrict"," invY- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
if(kk<0){ errMsg("IsoStrict"," invZ- |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
if(ii>mSizex-1){ errMsg("IsoStrict"," invX+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
if(jj>mSizey-1){ errMsg("IsoStrict"," invY+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
if(kk>mSizez-1){ errMsg("IsoStrict"," invZ+ |"<<ii<<","<<jj<<","<<kk); ISOSTRICT_EXIT; }
return mpData + ISOLEVEL_INDEX(ii, jj, kk);
#else //ISO_STRICT_DEBUG==1
return mpData + ISOLEVEL_INDEX(ii+1,jj+1,kk+1);
#endif
}
//! set cut off border
inline void setCutoff(int set) { mCutoff = set; };
//! set cut off border
inline void setCutArray(int *set) { mCutArray = set; };
//! OpenGL viz "interface"
unsigned int getIsoVertexCount() {
return mPoints.size();
}
unsigned int getIsoIndexCount() {
return mIndices.size();
}
char* getIsoVertexArray() {
return (char *) &(mPoints[0]);
}
unsigned int *getIsoIndexArray() {
return &(mIndices[0]);
}
// surface smoothing functions
void setSmoothRad(float radi1, float radi2, ntlVec3Gfx mscc);
void smoothSurface(float val, bool smoothNorm);
void smoothNormals(float val);
void computeNormals();
protected:
//! compute normal
inline ntlVec3Gfx getNormal(int i, int j,int k);
//! smoothing helper function
bool diffuseVertexField(ntlVec3Gfx *field, int pointerScale, int v, float invsigma2, ntlVec3Gfx &flt);
vector<int> mDboundary;
float mSCrad1, mSCrad2;
ntlVec3Gfx mSCcenter;
};
#define ISOSURFACE_H
#endif