00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <sofa/component/behaviormodel/eulerianfluid/Fluid3D.h>
00026 #include <sofa/helper/gl/template.h>
00027 #include <sofa/core/ObjectFactory.h>
00028 #include <iostream>
00029 #include <string.h>
00030 namespace sofa
00031 {
00032
00033 namespace component
00034 {
00035
00036 namespace behaviormodel
00037 {
00038
00039 namespace eulerianfluid
00040 {
00041
00042 SOFA_DECL_CLASS(Fluid3D)
00043
00044 int Fluid3DClass = core::RegisterObject("Eulerian 3D fluid")
00045 .add< Fluid3D >()
00046 .addLicense("LGPL")
00047 .addAuthor("Jeremie Allard")
00048 ;
00049
00050 Fluid3D::Fluid3D()
00051 : nx(16), ny(16), nz(16), cellwidth(1.0f),
00052 f_nx ( initDataPtr(&f_nx, &nx, "nx", "grid size along x axis") ),
00053 f_ny ( initDataPtr(&f_ny, &ny, "ny", "grid size along y axis") ),
00054 f_nz ( initDataPtr(&f_nz, &nz, "nz", "grid size along z axis") ),
00055 f_cellwidth ( initDataPtr(&f_cellwidth, &cellwidth, "cellwidth", "width of each cell") ),
00056 f_center ( initData(&f_center, vec3(0,0,0), "center", "position of grid center") ),
00057 f_height ( initData(&f_height, 5.0f, "height", "initial fluid height") ),
00058 f_dir ( initData(&f_dir, vec3(0,1,0), "dir", "initial fluid surface normal") ),
00059 f_tstart ( initData(&f_tstart, 0.0f, "tstart", "starting time for fluid source") ),
00060 f_tstop ( initData(&f_tstop, 60.0f, "tstop", "stopping time for fluid source") )
00061 {
00062 fluid = new Grid3D;
00063 fnext = new Grid3D;
00064 ftemp = new Grid3D;
00065 }
00066
00067 Fluid3D::~Fluid3D()
00068 {
00069 delete fluid;
00070 delete fnext;
00071 delete ftemp;
00072 }
00073
00074 void Fluid3D::init()
00075 {
00076 f_nx.beginEdit();
00077 f_ny.beginEdit();
00078 f_nz.beginEdit();
00079 f_cellwidth.beginEdit();
00080 fluid->clear(nx,ny,nz);
00081 fnext->clear(nx,ny,nz);
00082 ftemp->clear(nx,ny,nz);
00083 if (f_height.getValue() != 0)
00084 {
00085
00086 fluid->seed(f_height.getValue(), f_dir.getValue());
00087
00088 }
00089 fluid->t = -f_tstart.getValue();
00090 fluid->tend = f_tstop.getValue() - f_tstart.getValue();
00091 }
00092
00093 void Fluid3D::reset()
00094 {
00095 init();
00096 }
00097
00098 void Fluid3D::updatePosition(double dt)
00099 {
00100 fnext->gravity = getContext()->getLocalGravity()/cellwidth;
00101 fnext->step(fluid, ftemp, (real)dt);
00102 Grid3D* p = fluid; fluid=fnext; fnext=p;
00103 }
00104
00105 void Fluid3D::drawVisual()
00106 {
00107 glPushMatrix();
00108 vec3 center = f_center.getValue();
00109 glTranslatef(center[0]-(nx-1)*cellwidth/2,center[1]-(ny-1)*cellwidth/2,center[2]-(nz-1)*cellwidth/2);
00110 glScalef(cellwidth,cellwidth,cellwidth);
00111
00112 {
00113 glDisable(GL_LIGHTING);
00114 glColor4f(1,1,1,1);
00115 glBegin(GL_LINES);
00116 glVertex3i( 0, 0, 0 ); glVertex3i( nx-1, 0, 0 );
00117 glVertex3i( 0, ny-1, 0 ); glVertex3i( nx-1, ny-1, 0 );
00118 glVertex3i( 0, 0, nz-1 ); glVertex3i( nx-1, 0, nz-1 );
00119 glVertex3i( 0, ny-1, nz-1 ); glVertex3i( nx-1, ny-1, nz-1 );
00120
00121 glVertex3i( 0, 0, 0 ); glVertex3i( 0, ny-1, 0 );
00122 glVertex3i( nx-1, 0, 0 ); glVertex3i( nx-1, ny-1, 0 );
00123 glVertex3i( 0, 0, nz-1 ); glVertex3i( 0, ny-1, nz-1 );
00124 glVertex3i( nx-1, 0, nz-1 ); glVertex3i( nx-1, ny-1, nz-1 );
00125
00126 glVertex3i( 0, 0, 0 ); glVertex3i( 0, 0, nz-1 );
00127 glVertex3i( nx-1, 0, 0 ); glVertex3i( nx-1, 0, nz-1 );
00128 glVertex3i( 0, ny-1, 0 ); glVertex3i( 0, ny-1, nz-1 );
00129 glVertex3i( nx-1, ny-1, 0 ); glVertex3i( nx-1, ny-1, nz-1 );
00130 glEnd();
00131 }
00132 if (getContext()->getShowBehaviorModels())
00133 {
00134 glDisable(GL_LIGHTING);
00135 const real s = (real)getContext()->getDt()*5;
00136 glBegin(GL_LINES);
00137 for (int z=0;z<nz;z++)
00138 for (int y=0;y<ny;y++)
00139 for (int x=0;x<nx;x++)
00140 {
00141 vec3 u = fluid->get(x,y,z)->u;
00142 real r;
00143 r = u[0]*s;
00144 if (rabs(r) > 0.001f)
00145 {
00146 if (r>0.9f) r=0.9f;
00147 glColor4f(1,0,0,1);
00148 glVertex3f((real)x-0.5f , (real)y, (real)z);
00149 glVertex3f((real)x-0.5f+r, (real)y, (real)z);
00150 }
00151 r = u[1]*s;
00152 if (rabs(r) > 0.001f)
00153 {
00154 if (r>0.9f) r=0.9f;
00155 glColor4f(0,1,0,1);
00156 glVertex3f((real)x, (real)y-0.5f , (real)z);
00157 glVertex3f((real)x, (real)y-0.5f+r, (real)z);
00158 }
00159 r = u[2]*s;
00160 if (rabs(r) > 0.001f)
00161 {
00162 if (r>1) r=1;
00163 glColor4f(0,0,1,1);
00164 glVertex3f((real)x, (real)y, (real)z-0.5f );
00165 glVertex3f((real)x, (real)y, (real)z-0.5f+r);
00166 }
00167 }
00168 glEnd();
00169 glPointSize(3);
00170 glBegin(GL_POINTS);
00171 for (int z=0;z<nz;z++)
00172 for (int y=0;y<ny;y++)
00173 for (int x=0;x<nx;x++)
00174 {
00175 real l = *fluid->getlevelset(x,y,z);
00176 if (rabs(l)>=5) continue;
00177 if (l<0)
00178 {
00179 glColor4f(0,1+l/5,1+l/5,1);
00180 }
00181 else
00182 {
00183 glColor4f(1-l/5,1-l/5,0,1);
00184 }
00185 glVertex3i(x,y,z);
00186 }
00187 glEnd();
00188 glPointSize(1);
00189 }
00190 if (getContext()->getShowVisualModels())
00191 {
00192 if (getContext()->getShowWireFrame())
00193 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00194
00195 glEnable(GL_LIGHTING);
00196
00197 static const float color[4] = { 0.0f, 1.0f, 1.0f, 1.0f};
00198 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
00199 static const float emissive[4] = { 0.0f, 0.0f, 0.0f, 0.0f};
00200 static const float specular[4] = { 1.0f, 1.0f, 1.0f, 1.0f};
00201 glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, emissive);
00202 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, specular);
00203 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 20);
00204
00205 glBegin(GL_TRIANGLES);
00206 for (unsigned int i=0;i<facets.size();i++)
00207 {
00208 for (int j=0;j<3;j++)
00209 {
00210 int idx = facets[i].p[j];
00211 glNormal3fv(points[idx].n.ptr());
00212 glVertex3fv(points[idx].p.ptr());
00213 }
00214 }
00215 glEnd();
00216
00217 glDisable(GL_LIGHTING);
00218 if (getContext()->getShowWireFrame())
00219 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00220 }
00221 glPopMatrix();
00222 }
00223
00224 void Fluid3D::exportOBJ(std::string name, std::ostream* out, std::ostream* , int& vindex, int& nindex, int& )
00225 {
00226 vec3 corner = f_center.getValue() - vec3((real)nx-1,(real)ny-1,(real)nz-1)*cellwidth/2;
00227
00228 *out << "g "<<name<<"\n";
00229
00230 for(unsigned i=0;i<points.size();++i)
00231 {
00232 vec3 p = points[i].p*cellwidth + corner;
00233 *out << "v "<< std::fixed << p[0]<<' '<< std::fixed <<p[1]<<' '<< std::fixed <<p[2]<<'\n';
00234 }
00235
00236
00237 for(unsigned i=0;i<points.size();++i)
00238 *out << "vn "<< std::fixed << points[i].n[0]<<' '<< std::fixed <<points[i].n[1]<<' '<< std::fixed <<points[i].n[2]<<'\n';
00239
00240
00241 for (unsigned int i = 0; i < facets.size() ; i++)
00242 *out << "f "<<facets[i].p[0]+vindex+1<<"//"<<facets[i].p[0]+nindex+1<<' '<< facets[i].p[1]+vindex+1<<"//"<<facets[i].p[1]+nindex+1<<' '<< facets[i].p[2]+vindex+1<<"//"<<facets[i].p[2]+nindex+1<<'\n';
00243
00244
00245 *out << std::endl;
00246
00247 vindex+=points.size();
00248 nindex+=points.size();
00249 }
00250
00251 void Fluid3D::updateVisual()
00252 {
00253 points.clear();
00254 facets.clear();
00255
00256 const real* data = fluid->levelset;
00257
00258 planes.resize(2*nx*ny);
00259 CubeData *P = &(planes[0]);
00260 CubeData *P0 = P;
00261 CubeData *P1 = P+(nx*ny);
00262
00263
00264
00266
00267 const real isoval = 0.0f;
00268 const real iso = isoval;
00269
00270 const int dx = 1;
00271 const int dy = nx;
00272 const int dz = nx*ny;
00273
00274 int x,y,z,i,mk;
00275 const int *tri;
00276
00277
00278 i=0;
00279
00280 memset(P1,-1,nx*ny*sizeof(CubeData));
00281 {
00282 z=0;
00283
00284 {
00285 y=0;
00286 ++i;
00287 for(x=1;x<nx;x++)
00288 {
00289 if ((data[i]>isoval)^(data[i-dx]>isoval))
00290 {
00291 P1[i].p[0] = addPoint<0>(x,y,z,data[i],data[i-dx],iso);
00292 }
00293 ++i;
00294 }
00295 }
00296 for(y=1;y<ny;y++)
00297 {
00298
00299 x=0;
00300 if ((data[i]>isoval)^(data[i-dy]>isoval))
00301 {
00302 P1[i].p[1] = addPoint<1>(x,y,z,data[i],data[i-dy],iso);
00303 }
00304 ++i;
00305
00306 for(x=1;x<nx;x++)
00307 {
00308 if ((data[i]>isoval)^(data[i-dx]>isoval))
00309 {
00310 P1[i].p[0] = addPoint<0>(x,y,z,data[i],data[i-dx],iso);
00311 }
00312 if ((data[i]>isoval)^(data[i-dy]>isoval))
00313 {
00314 P1[i].p[1] = addPoint<1>(x,y,z,data[i],data[i-dy],iso);
00315 }
00316 ++i;
00317 }
00318 }
00319 }
00320 for (z=1;z<nz;z++)
00321 {
00322 i=0; data+=dz;
00323
00324 { CubeData* p=P0; P0=P1; P1=p; }
00325 memset(P1,-1,nx*ny*sizeof(CubeData));
00326
00327 int edgepts[12];
00328 int* base = &(P[0].p[0]);
00329 edgepts[0] = &(P0[-dy].p[0])-base;
00330 edgepts[1] = &(P0[0 ].p[1])-base;
00331 edgepts[2] = &(P0[0 ].p[0])-base;
00332 edgepts[3] = &(P0[-dx].p[1])-base;
00333 edgepts[4] = &(P1[-dy].p[0])-base;
00334 edgepts[5] = &(P1[0 ].p[1])-base;
00335 edgepts[6] = &(P1[0 ].p[0])-base;
00336 edgepts[7] = &(P1[-dx].p[1])-base;
00337 edgepts[8] = &(P1[-dx-dy].p[2])-base;
00338 edgepts[9] = &(P1[ -dy].p[2])-base;
00339 edgepts[10] = &(P1[0 ].p[2])-base;
00340 edgepts[11] = &(P1[-dx ].p[2])-base;
00341
00342
00343 {
00344 y=0;
00345 x=0;
00346 if ((data[i]>isoval)^(data[i-dz]>isoval))
00347 {
00348 P1[i].p[2] = addPoint<2>(x,y,z,data[i],data[i-dz],iso);
00349 }
00350 ++i;
00351 for(x=1;x<nx;x++)
00352 {
00353 if ((data[i]>isoval)^(data[i-dx]>isoval))
00354 {
00355 P1[i].p[0] = addPoint<0>(x,y,z,data[i],data[i-dx],iso);
00356 }
00357 if ((data[i]>isoval)^(data[i-dz]>isoval))
00358 {
00359 P1[i].p[2] = addPoint<2>(x,y,z,data[i],data[i-dz],iso);
00360 }
00361 ++i;
00362 }
00363 }
00364 for(y=1;y<ny;y++)
00365 {
00366
00367 x=0;
00368 if ((data[i]>isoval)^(data[i-dy]>isoval))
00369 {
00370 P1[i].p[1] = addPoint<1>(x,y,z,data[i],data[i-dy],iso);
00371 }
00372 if ((data[i]>isoval)^(data[i-dz]>isoval))
00373 {
00374 P1[i].p[2] = addPoint<2>(x,y,z,data[i],data[i-dz],iso);
00375 }
00376 ++i;
00377
00378 for(x=1;x<nx;x++)
00379 {
00380 if ((data[i]>isoval)^(data[i-dx]>isoval))
00381 {
00382 P1[i].p[0] = addPoint<0>(x,y,z,data[i],data[i-dx],iso);
00383 }
00384 if ((data[i]>isoval)^(data[i-dy]>isoval))
00385 {
00386 P1[i].p[1] = addPoint<1>(x,y,z,data[i],data[i-dy],iso);
00387 }
00388 if ((data[i]>isoval)^(data[i-dz]>isoval))
00389 {
00390 P1[i].p[2] = addPoint<2>(x,y,z,data[i],data[i-dz],iso);
00391 }
00392
00393
00394
00395 if (data[i-dx-dy-dz]>iso) mk = 1; else mk=0;
00396 if (data[i -dy-dz]>iso) mk|= 2;
00397 if (data[i -dz]>iso) mk|= 4;
00398 if (data[i-dx -dz]>iso) mk|= 8;
00399 if (data[i-dx-dy ]>iso) mk|= 16;
00400 if (data[i -dy ]>iso) mk|= 32;
00401 if (data[i ]>iso) mk|= 64;
00402 if (data[i-dx ]>iso) mk|= 128;
00403
00404 tri = helper::MarchingCubeTriTable[mk];
00405 while (*tri>=0)
00406 {
00407 int* b = base+3*i;
00408 if (addFace(b[edgepts[tri[0]]],b[edgepts[tri[1]]],b[edgepts[tri[2]]])<0)
00409 {
00410 std::cerr << " mk=0x"<<std::hex<<mk<<std::dec<<" p1="<<tri[0]<<" p2="<<tri[1]<<" p3="<<tri[2]<<std::endl;
00411 for (int e=0;e<12;e++) std::cerr << " e"<<e<<"="<<b[edgepts[e]];
00412 std::cerr<<std::endl;
00413 for (int ddz=-1;ddz<=0;ddz++)
00414 for (int ddy=-1;ddy<=0;ddy++)
00415 for (int ddx=-1;ddx<=0;ddx++)
00416 {
00417 std::cerr << " val("<<x+ddx<<','<<y+ddy<<','<<z+ddz<<")="<<(double)data[i+ddx*dx+ddy*dy+ddz*dz]<<std::endl;
00418 }
00419 }
00420 tri+=3;
00421 }
00422 ++i;
00423 }
00424 }
00425 }
00426
00427
00428 for (unsigned int i=0;i<points.size();i++)
00429 {
00430 points[i].n.clear();
00431 }
00432
00433 for (unsigned int i=0;i<facets.size();i++)
00434 {
00435 Vec3f n = cross(points[facets[i].p[1]].p-points[facets[i].p[0]].p,points[facets[i].p[2]].p-points[facets[i].p[0]].p);
00436 n.normalize();
00437 points[facets[i].p[0]].n += n;
00438 points[facets[i].p[1]].n += n;
00439 points[facets[i].p[2]].n += n;
00440 }
00441
00442 for (unsigned int i=0;i<points.size();i++)
00443 points[i].n.normalize();
00444 }
00445
00446 bool Fluid3D::addBBox(double* minBBox, double* maxBBox)
00447 {
00448 vec3 center = f_center.getValue();
00449 SReal size[3] = { (nx-1)*cellwidth, (ny-1)*cellwidth, (nz-1)*cellwidth };
00450 SReal pos[3] = { center[0]-size[0]/2, center[1]-size[1]/2, center[2]-size[2]/2 };
00451 for (int c=0;c<3;c++)
00452 {
00453 if (minBBox[c] > pos[c] ) minBBox[c] = pos[c];
00454 if (maxBBox[c] < pos[c]+size[c]) maxBBox[c] = pos[c]+size[c];
00455 }
00456 return true;
00457 }
00458
00459 }
00460
00461 }
00462
00463 }
00464
00465 }
00466