1 /******************************************************************************
3 * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
4 * Copyright 2003-2006 Nils Thuerey
7 * all other geometry objects are derived from this one
9 *****************************************************************************/
12 #include "ntl_geometryobject.h"
13 #include "ntl_world.h"
14 #include "ntl_matrices.h"
19 #define TRI_UVOFFSET (1./4.)
20 //#define TRI_UVOFFSET (1./3.)
23 /*****************************************************************************/
24 /* Default constructor */
25 /*****************************************************************************/
26 ntlGeometryObject::ntlGeometryObject() :
27 mIsInitialized(false), mpMaterial( NULL ),
28 mMaterialName( "default" ),
29 mCastShadows( 1 ), mReceiveShadows( 1 ),
31 mInitialVelocity(0.0), mcInitialVelocity(0.0), mLocalCoordInivel(false),
32 mGeoInitIntersect(false),
33 mGeoPartSlipValue(0.0),
34 mcGeoImpactFactor(1.),
35 mVolumeInit(VOLUMEINIT_VOLUME),
37 mcTrans(0.), mcRot(0.), mcScale(1.),
39 mMovPoints(), mMovNormals(),
40 mHaveCachedMov(false),
41 mCachedMovPoints(), mCachedMovNormals(),
42 mTriangleDivs1(), mTriangleDivs2(), mTriangleDivs3(),
43 mMovPntsInited(-100.0), mMaxMovPnt(-1),
49 /*****************************************************************************/
50 /* Default destructor */
51 /*****************************************************************************/
52 ntlGeometryObject::~ntlGeometryObject()
56 /*! is the mesh animated? */
57 bool ntlGeometryObject::getMeshAnimated() {
58 // off by default, on for e.g. ntlGeometryObjModel
62 /*! init object anim flag */
63 bool ntlGeometryObject::checkIsAnimated() {
64 if( (mcTrans.accessValues().size()>1) // VALIDATE
65 || (mcRot.accessValues().size()>1)
66 || (mcScale.accessValues().size()>1)
67 || (mcGeoActive.accessValues().size()>1)
68 // mcGeoImpactFactor only needed when moving
69 || (mcInitialVelocity.accessValues().size()>1)
74 // fluid objects always have static init!
75 if(mGeoInitType==FGI_FLUID) {
78 //errMsg("ntlGeometryObject::checkIsAnimated","obj="<<getName()<<" debug: trans:"<<mcTrans.accessValues().size()<<" rot:"<<mcRot.accessValues().size()<<" scale:"<<mcScale.accessValues().size()<<" active:"<<mcGeoActive.accessValues().size()<<" inivel:"<<mcInitialVelocity.accessValues().size()<<". isani?"<<mIsAnimated ); // DEBUG
82 /*****************************************************************************/
83 /* Init attributes etc. of this object */
84 /*****************************************************************************/
85 #define GEOINIT_STRINGS 9
86 static const char *initStringStrs[GEOINIT_STRINGS] = {
88 "bnd_no","bnd_noslip",
89 "bnd_free","bnd_freeslip",
90 "bnd_part","bnd_partslip",
93 static int initStringTypes[GEOINIT_STRINGS] = {
96 FGI_BNDFREE, FGI_BNDFREE,
97 FGI_BNDPART, FGI_BNDPART,
98 FGI_MBNDINFLOW, FGI_MBNDOUTFLOW
100 void ntlGeometryObject::initialize(ntlRenderGlobals *glob)
102 //debugOut("ntlGeometryObject::initialize: '"<<getName()<<"' ", 10);
103 // initialize only once...
104 if(mIsInitialized) return;
106 // init material, always necessary
107 searchMaterial( glob->getMaterials() );
109 this->mGeoInitId = mpAttrs->readInt("geoinitid", this->mGeoInitId,"ntlGeometryObject", "mGeoInitId", false);
110 mGeoInitIntersect = mpAttrs->readInt("geoinit_intersect", mGeoInitIntersect,"ntlGeometryObject", "mGeoInitIntersect", false);
111 string ginitStr = mpAttrs->readString("geoinittype", "", "ntlGeometryObject", "mGeoInitType", false);
112 if(this->mGeoInitId>=0) {
114 for(int i=0; i<GEOINIT_STRINGS; i++) {
115 if(ginitStr== initStringStrs[i]) {
117 mGeoInitType = initStringTypes[i];
122 errFatal("ntlGeometryObject::initialize","Obj '"<<mName<<"', Unkown 'geoinittype' value: '"<< ginitStr <<"' ", SIMWORLD_INITERROR);
127 int geoActive = mpAttrs->readInt("geoinitactive", 1,"ntlGeometryObject", "geoActive", false);
129 // disable geo init again...
130 this->mGeoInitId = -1;
132 mInitialVelocity = vec2G( mpAttrs->readVec3d("initial_velocity", vec2D(mInitialVelocity),"ntlGeometryObject", "mInitialVelocity", false));
133 if(getAttributeList()->exists("initial_velocity") || (!mcInitialVelocity.isInited()) ) {
134 mcInitialVelocity = mpAttrs->readChannelVec3f("initial_velocity");
136 // always use channel
137 if(!mcInitialVelocity.isInited()) { mcInitialVelocity = AnimChannel<ntlVec3Gfx>(mInitialVelocity); }
138 mLocalCoordInivel = mpAttrs->readBool("geoinit_localinivel", mLocalCoordInivel,"ntlGeometryObject", "mLocalCoordInivel", false);
140 mGeoPartSlipValue = mpAttrs->readFloat("geoinit_partslip", mGeoPartSlipValue,"ntlGeometryObject", "mGeoPartSlipValue", false);
141 bool mOnlyThinInit = false; // deprecated!
142 mOnlyThinInit = mpAttrs->readBool("geoinit_onlythin", mOnlyThinInit,"ntlGeometryObject", "mOnlyThinInit", false);
143 if(mOnlyThinInit) mVolumeInit = VOLUMEINIT_SHELL;
144 mVolumeInit = mpAttrs->readInt("geoinit_volumeinit", mVolumeInit,"ntlGeometryObject", "mVolumeInit", false);
145 if((mVolumeInit<VOLUMEINIT_VOLUME)||(mVolumeInit>VOLUMEINIT_BOTH)) mVolumeInit = VOLUMEINIT_VOLUME;
147 // moving obs correction factor
148 float impactfactor=1.;
149 impactfactor = (float)mpAttrs->readFloat("impactfactor", impactfactor,"ntlGeometryObject", "impactfactor", false);
150 if(getAttributeList()->exists("impactfactor") || (!mcGeoImpactFactor.isInited()) ) {
151 mcGeoImpactFactor = mpAttrs->readChannelSinglePrecFloat("impactfactor");
154 // override cfg types
155 mVisible = mpAttrs->readBool("visible", mVisible,"ntlGeometryObject", "mVisible", false);
156 mReceiveShadows = mpAttrs->readBool("recv_shad", mReceiveShadows,"ntlGeometryObject", "mReceiveShadows", false);
157 mCastShadows = mpAttrs->readBool("cast_shad", mCastShadows,"ntlGeometryObject", "mCastShadows", false);
159 // read mesh animation channels
160 ntlVec3d translation(0.0);
161 translation = mpAttrs->readVec3d("translation", translation,"ntlGeometryObject", "translation", false);
162 if(getAttributeList()->exists("translation") || (!mcTrans.isInited()) ) {
163 mcTrans = mpAttrs->readChannelVec3f("translation");
165 ntlVec3d rotation(0.0);
166 rotation = mpAttrs->readVec3d("rotation", rotation,"ntlGeometryObject", "rotation", false);
167 if(getAttributeList()->exists("rotation") || (!mcRot.isInited()) ) {
168 mcRot = mpAttrs->readChannelVec3f("rotation");
171 scale = mpAttrs->readVec3d("scale", scale,"ntlGeometryObject", "scale", false);
172 if(getAttributeList()->exists("scale") || (!mcScale.isInited()) ) {
173 mcScale = mpAttrs->readChannelVec3f("scale");
177 geoactive = (float)mpAttrs->readFloat("geoactive", geoactive,"ntlGeometryObject", "geoactive", false);
178 if(getAttributeList()->exists("geoactive") || (!mcGeoActive.isInited()) ) {
179 mcGeoActive = mpAttrs->readChannelSinglePrecFloat("geoactive");
181 // always use channel
182 if(!mcGeoActive.isInited()) { mcGeoActive = AnimChannel<float>(geoactive); }
186 mIsInitialized = true;
187 debMsgStd("ntlGeometryObject::initialize",DM_MSG,"GeoObj '"<<this->getName()<<"': visible="<<this->mVisible<<" gid="<<this->mGeoInitId<<" gtype="<<mGeoInitType<<","<<ginitStr<<
188 " gvel="<<mInitialVelocity<<" gisect="<<mGeoInitIntersect, 10); // debug
191 /*! notify object that dump is in progress (e.g. for particles) */
192 // default action - do nothing...
193 void ntlGeometryObject::notifyOfDump(int dumtp, int frameNr,char *frameNrStr,string outfilename, double simtime) {
195 if(debugOut) debMsgStd("ntlGeometryObject::notifyOfDump",DM_MSG," dt:"<<dumtp<<" obj:"<<this->getName()<<" frame:"<<frameNrStr<<","<<frameNr<<",t"<<simtime<<" to "<<outfilename, 10); // DEBUG
198 /*****************************************************************************/
199 /* Search the material for this object from the material list */
200 /*****************************************************************************/
201 void ntlGeometryObject::searchMaterial(vector<ntlMaterial *> *mat)
203 /* search the list... */
205 for (vector<ntlMaterial*>::iterator iter = mat->begin();
206 iter != mat->end(); iter++) {
207 if( mMaterialName == (*iter)->getName() ) {
208 //warnMsg("ntlGeometryObject::searchMaterial","for obj '"<<getName()<<"' found - '"<<(*iter)->getName()<<"' "<<i); // DEBUG
209 mpMaterial = (*iter);
214 errFatal("ntlGeometryObject::searchMaterial","Unknown material '"<<mMaterialName<<"' ! ", SIMWORLD_INITERROR);
215 mpMaterial = new ntlMaterial();
219 /******************************************************************************
220 * static add triangle function
221 *****************************************************************************/
222 void ntlGeometryObject::sceneAddTriangle(
223 ntlVec3Gfx p1,ntlVec3Gfx p2,ntlVec3Gfx p3,
224 ntlVec3Gfx pn1,ntlVec3Gfx pn2,ntlVec3Gfx pn3,
225 ntlVec3Gfx trin, bool smooth,
226 vector<ntlTriangle> *triangles,
227 vector<ntlVec3Gfx> *vertices,
228 vector<ntlVec3Gfx> *normals) {
232 if(normals->size() != vertices->size()) {
233 errFatal("ntlGeometryObject::sceneAddTriangle","For '"<<this->mName<<"': Vertices and normals sizes to not match!!!",SIMWORLD_GENERICERROR);
237 vertices->push_back( p1 );
238 normals->push_back( pn1 );
239 tempVert = normals->size()-1;
240 tri.getPoints()[0] = tempVert;
242 vertices->push_back( p2 );
243 normals->push_back( pn2 );
244 tempVert = normals->size()-1;
245 tri.getPoints()[1] = tempVert;
247 vertices->push_back( p3 );
248 normals->push_back( pn3 );
249 tempVert = normals->size()-1;
250 tri.getPoints()[2] = tempVert;
253 /* init flags from ntl_ray.h */
255 if(getVisible()){ flag |= TRI_GEOMETRY; }
256 if(getCastShadows() ) {
257 flag |= TRI_CASTSHADOWS; }
259 /* init geo init id */
260 int geoiId = getGeoInitId();
261 //if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME) && (!mIsAnimated)) {
262 if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME)) {
263 flag |= (1<< (geoiId+4));
264 flag |= mGeoInitType;
266 /*errMsg("ntlScene::addTriangle","DEBUG flag="<<convertFlags2String(flag) ); */
267 tri.setFlags( flag );
269 /* triangle normal missing */
270 tri.setNormal( trin );
271 tri.setSmoothNormals( smooth );
272 tri.setObjectId( this->mObjectId );
273 triangles->push_back( tri );
277 void ntlGeometryObject::sceneAddTriangleNoVert(int *trips,
278 ntlVec3Gfx trin, bool smooth,
279 vector<ntlTriangle> *triangles) {
282 tri.getPoints()[0] = trips[0];
283 tri.getPoints()[1] = trips[1];
284 tri.getPoints()[2] = trips[2];
286 // same as normal sceneAddTriangle
288 /* init flags from ntl_ray.h */
290 if(getVisible()){ flag |= TRI_GEOMETRY; }
291 if(getCastShadows() ) {
292 flag |= TRI_CASTSHADOWS; }
294 /* init geo init id */
295 int geoiId = getGeoInitId();
296 if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME)) {
297 flag |= (1<< (geoiId+4));
298 flag |= mGeoInitType;
300 /*errMsg("ntlScene::addTriangle","DEBUG flag="<<convertFlags2String(flag) ); */
301 tri.setFlags( flag );
303 /* triangle normal missing */
304 tri.setNormal( trin );
305 tri.setSmoothNormals( smooth );
306 tri.setObjectId( this->mObjectId );
307 triangles->push_back( tri );
311 /******************************************************************************/
312 /* Init channels from float arrays (for elbeem API) */
313 /******************************************************************************/
315 #define ADD_CHANNEL_VEC(dst,nvals,val) \
316 vals.clear(); time.clear(); elbeemSimplifyChannelVec3(val,&nvals); \
317 for(int i=0; i<(nvals); i++) { \
318 vals.push_back(ntlVec3Gfx((val)[i*4+0], (val)[i*4+1],(val)[i*4+2] )); \
319 time.push_back( (val)[i*4+3] ); \
321 (dst) = AnimChannel< ntlVec3Gfx >(vals,time);
323 #define ADD_CHANNEL_FLOAT(dst,nvals,val) \
324 valsfloat.clear(); time.clear(); elbeemSimplifyChannelFloat(val,&nvals); \
325 for(int i=0; i<(nvals); i++) { \
326 valsfloat.push_back( (val)[i*2+0] ); \
327 time.push_back( (val)[i*2+1] ); \
329 (dst) = AnimChannel< float >(valsfloat,time);
331 void ntlGeometryObject::initChannels(
332 int nTrans, float *trans, int nRot, float *rot, int nScale, float *scale,
333 int nAct, float *act, int nIvel, float *ivel
335 const bool debugInitc=true;
336 if(debugInitc) { debMsgStd("ntlGeometryObject::initChannels",DM_MSG,"nt:"<<nTrans<<" nr:"<<nRot<<" ns:"<<nScale, 10);
337 debMsgStd("ntlGeometryObject::initChannels",DM_MSG,"na:"<<nAct<<" niv:"<<nIvel<<" ", 10); }
338 vector<ntlVec3Gfx> vals;
339 vector<float> valsfloat;
341 if((trans)&&(nTrans>0)) { ADD_CHANNEL_VEC(mcTrans, nTrans, trans); }
342 if((rot)&&(nRot>0)) { ADD_CHANNEL_VEC(mcRot, nRot, rot); }
343 if((scale)&&(nScale>0)) { ADD_CHANNEL_VEC(mcScale, nScale, scale); }
344 if((act)&&(nAct>0)) { ADD_CHANNEL_FLOAT(mcGeoActive, nAct, act); }
345 if((ivel)&&(nIvel>0)) { ADD_CHANNEL_VEC(mcInitialVelocity, nIvel, ivel); }
349 debMsgStd("ntlGeometryObject::initChannels",DM_MSG,getName()<<
350 " nt:"<<mcTrans.accessValues().size()<<" nr:"<<mcRot.accessValues().size()<<
351 " ns:"<<mcScale.accessValues().size()<<" isAnim:"<<mIsAnimated, 10); }
354 std::ostringstream ostr;
356 for(size_t i=0; i<mcTrans.accessValues().size(); i++) {
357 ostr<<" "<<mcTrans.accessValues()[i]<<"@"<<mcTrans.accessTimes()[i]<<" ";
360 for(size_t i=0; i<mcRot.accessValues().size(); i++) {
361 ostr<<" "<<mcRot.accessValues()[i]<<"@"<<mcRot.accessTimes()[i]<<" ";
364 for(size_t i=0; i<mcScale.accessValues().size(); i++) {
365 ostr<<" "<<mcScale.accessValues()[i]<<"@"<<mcScale.accessTimes()[i]<<" ";
368 for(size_t i=0; i<mcGeoActive.accessValues().size(); i++) {
369 ostr<<" "<<mcGeoActive.accessValues()[i]<<"@"<<mcGeoActive.accessTimes()[i]<<" ";
372 for(size_t i=0; i<mcInitialVelocity.accessValues().size(); i++) {
373 ostr<<" "<<mcInitialVelocity.accessValues()[i]<<"@"<<mcInitialVelocity.accessTimes()[i]<<" ";
375 debMsgStd("ntlGeometryObject::initChannels",DM_MSG,"Inited "<<ostr.str(),10);
381 /*****************************************************************************/
382 /* apply object translation at time t*/
383 /*****************************************************************************/
384 void ntlGeometryObject::applyTransformation(double t, vector<ntlVec3Gfx> *verts, vector<ntlVec3Gfx> *norms, int vstart, int vend, int forceTrafo) {
385 if( (mcTrans.accessValues().size()>1) // VALIDATE
386 || (mcRot.accessValues().size()>1)
387 || (mcScale.accessValues().size()>1)
391 // transformation is animated, continue
392 ntlVec3Gfx pos = getTranslation(t);
393 ntlVec3Gfx scale = mcScale.get(t);
394 ntlVec3Gfx rot = mcRot.get(t);
396 rotMat.initRotationXYZ(rot[0],rot[1],rot[2]);
398 errMsg("ntlGeometryObject::applyTransformation","obj="<<getName()<<" t"<<pos<<" r"<<rot<<" s"<<scale);
399 for(int i=vstart; i<vend; i++) {
400 (*verts)[i] *= scale;
401 (*verts)[i] = rotMat * (*verts)[i];
403 //if(i<10) errMsg("ntlGeometryObject::applyTransformation"," v"<<i<<"/"<<vend<<"="<<(*verts)[i]);
406 for(int i=vstart; i<vend; i++) {
407 (*norms)[i] = rotMat * (*norms)[i];
411 // not animated, cached points were already returned
412 errMsg ("ntlGeometryObject::applyTransformation","Object "<<getName()<<" used cached points ");
416 /*! init triangle divisions */
417 void ntlGeometryObject::calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntlTriangle> &tris, gfxReal fsTri) {
418 mTriangleDivs1.resize( tris.size() );
419 mTriangleDivs2.resize( tris.size() );
420 mTriangleDivs3.resize( tris.size() );
422 //fsTri *= 2.; // DEBUG! , wrong init!
424 for(size_t i=0; i<tris.size(); i++) {
425 const ntlVec3Gfx p0 = verts[ tris[i].getPoints()[0] ];
426 const ntlVec3Gfx p1 = verts[ tris[i].getPoints()[1] ];
427 const ntlVec3Gfx p2 = verts[ tris[i].getPoints()[2] ];
428 const ntlVec3Gfx side1 = p1 - p0;
429 const ntlVec3Gfx side2 = p2 - p0;
430 const ntlVec3Gfx side3 = p1 - p2;
431 int divs1=0, divs2=0, divs3=0;
432 if(normNoSqrt(side1) > fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); }
433 if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); }
435 mTriangleDivs1[i] = divs1;
436 mTriangleDivs2[i] = divs2;
437 mTriangleDivs3[i] = divs3;
441 /*! Prepare points for moving objects */
442 void ntlGeometryObject::initMovingPoints(double time, gfxReal featureSize) {
443 if((mMovPntsInited==featureSize)&&(!getMeshAnimated())) return;
444 const bool debugMoinit=false;
446 vector<ntlTriangle> triangles;
447 vector<ntlVec3Gfx> vertices;
448 vector<ntlVec3Gfx> vnormals;
450 this->getTriangles(time, &triangles,&vertices,&vnormals,objectId);
454 if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","Object "<<getName()<<" has v:"<<vertices.size()<<" t:"<<triangles.size() );
456 if(vertices.size()<1) {
460 ntlVec3f maxscale = channelFindMaxVf(mcScale);
461 float maxpart = ABS(maxscale[0]);
462 if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
463 if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
464 float scaleFac = 1.0/(maxpart);
465 // TODO - better reinit from time to time?
466 const gfxReal fsTri = featureSize*0.5 *scaleFac;
467 if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","maxscale:"<<maxpart<<" featureSize:"<<featureSize<<" fsTri:"<<fsTri );
469 if(mTriangleDivs1.size()!=triangles.size()) {
470 calcTriangleDivs(vertices,triangles,fsTri);
473 // debug: count points to init
475 errMsg("ntlGeometryObject::initMovingPoints","Object "<<getName()<<" estimating...");
476 int countp=vertices.size()*2;
477 for(size_t i=0; i<triangles.size(); i++) {
478 ntlVec3Gfx p0 = vertices[ triangles[i].getPoints()[0] ];
479 ntlVec3Gfx side1 = vertices[ triangles[i].getPoints()[1] ] - p0;
480 ntlVec3Gfx side2 = vertices[ triangles[i].getPoints()[2] ] - p0;
481 int divs1=0, divs2=0;
482 if(normNoSqrt(side1) > fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); }
483 if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); }
484 errMsg("ntlGeometryObject::initMovingPoints","tri:"<<i<<" p:"<<p0<<" s1:"<<side1<<" s2:"<<side2<<" -> "<<divs1<<","<<divs2 );
485 if(divs1+divs2 > 0) {
486 for(int u=0; u<=divs1; u++) {
487 for(int v=0; v<=divs2; v++) {
488 const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0);
489 const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0);
490 if(uf+vf>1.0) continue;
496 errMsg("ntlGeometryObject::initMovingPoints","Object "<<getName()<<" requires:"<<countp*2);
499 bool discardInflowBack = false;
500 if( (mGeoInitType==FGI_MBNDINFLOW) && (mcInitialVelocity.accessValues().size()<1) ) discardInflowBack = true;
501 discardInflowBack = false; // DEBUG disable for now
505 for(size_t i=0; i<vertices.size(); i++) {
506 ntlVec3Gfx p = vertices[ i ];
507 ntlVec3Gfx n = vnormals[ i ];
508 // discard inflow backsides
509 //if( (mGeoInitType==FGI_MBNDINFLOW) && (!mIsAnimated)) {
510 if(discardInflowBack) { //if( (mGeoInitType==FGI_MBNDINFLOW) && (!mIsAnimated)) {
511 if(dot(mInitialVelocity,n)<0.0) continue;
513 mMovPoints.push_back(p);
514 mMovNormals.push_back(n);
515 if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","std"<<i<<" p"<<p<<" n"<<n<<" ");
517 // init points & refine...
518 for(size_t i=0; i<triangles.size(); i++) {
519 int *trips = triangles[i].getPoints();
520 const ntlVec3Gfx p0 = vertices[ trips[0] ];
521 const ntlVec3Gfx side1 = vertices[ trips[1] ] - p0;
522 const ntlVec3Gfx side2 = vertices[ trips[2] ] - p0;
523 int divs1=mTriangleDivs1[i], divs2=mTriangleDivs2[i];
525 const ntlVec3Gfx trinormOrg = getNormalized(cross(side1,side2));
526 const ntlVec3Gfx trinorm = trinormOrg*0.25*featureSize;
527 if(discardInflowBack) {
528 if(dot(mInitialVelocity,trinorm)<0.0) continue;
530 if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","Tri1 "<<vertices[trips[0]]<<","<<vertices[trips[1]]<<","<<vertices[trips[2]]<<" "<<divs1<<","<<divs2 );
531 if(divs1+divs2 > 0) {
532 for(int u=0; u<=divs1; u++) {
533 for(int v=0; v<=divs2; v++) {
534 const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0);
535 const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0);
536 if(uf+vf>1.0) continue;
538 vertices[ trips[0] ] * (1.0-uf-vf)+
539 vertices[ trips[1] ] * uf +
540 vertices[ trips[2] ] * vf;
541 //ntlVec3Gfx n = vnormals[
542 //trips[0] ] * (1.0-uf-vf)+
543 //vnormals[ trips[1] ]*uf +
544 //vnormals[ trips[2] ]*vf;
546 // discard inflow backsides
548 mMovPoints.push_back(p + trinorm); // NEW!?
549 mMovPoints.push_back(p - trinorm);
550 mMovNormals.push_back(trinormOrg);
551 mMovNormals.push_back(trinormOrg);
552 //errMsg("TRINORM","p"<<p<<" n"<<n<<" trin"<<trinorm);
560 gfxReal dist = normNoSqrt(mMovPoints[0]);
561 for(size_t i=0; i<mMovPoints.size(); i++) {
562 if(normNoSqrt(mMovPoints[i])>dist) {
564 dist = normNoSqrt(mMovPoints[0]);
568 if( (this-getMeshAnimated())
569 || (mcTrans.accessValues().size()>1) // VALIDATE
570 || (mcRot.accessValues().size()>1)
571 || (mcScale.accessValues().size()>1)
575 mCachedMovPoints = mMovPoints;
576 mCachedMovNormals = mMovNormals;
577 //applyTransformation(time, &mCachedMovPoints, &mCachedMovNormals, 0, mCachedMovPoints.size(), true);
578 applyTransformation(time, &mCachedMovPoints, NULL, 0, mCachedMovPoints.size(), true);
579 mHaveCachedMov = true;
580 debMsgStd("ntlGeometryObject::initMovingPoints",DM_MSG,"Object "<<getName()<<" cached points ", 7);
583 mMovPntsInited = featureSize;
584 debMsgStd("ntlGeometryObject::initMovingPoints",DM_MSG,"Object "<<getName()<<" inited v:"<<vertices.size()<<"->"<<mMovPoints.size() , 5);
586 /*! Prepare points for animated objects,
587 * init both sets, never used cached points
588 * discardInflowBack ignore */
589 void ntlGeometryObject::initMovingPointsAnim(
590 double srctime, vector<ntlVec3Gfx> &srcmovPoints,
591 double dsttime, vector<ntlVec3Gfx> &dstmovPoints,
592 vector<ntlVec3Gfx> *dstmovNormals,
594 ntlVec3Gfx geostart, ntlVec3Gfx geoend
596 const bool debugMoinit=false;
598 vector<ntlTriangle> srctriangles;
599 vector<ntlVec3Gfx> srcvertices;
600 vector<ntlVec3Gfx> unused_normals;
601 vector<ntlTriangle> dsttriangles;
602 vector<ntlVec3Gfx> dstvertices;
603 vector<ntlVec3Gfx> dstnormals;
605 // TODO optimize? , get rid of normals?
606 unused_normals.clear();
607 this->getTriangles(srctime, &srctriangles,&srcvertices,&unused_normals,objectId);
608 unused_normals.clear();
609 this->getTriangles(dsttime, &dsttriangles,&dstvertices,&dstnormals,objectId);
611 srcmovPoints.clear();
612 dstmovPoints.clear();
613 if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","Object "<<getName()<<" has srcv:"<<srcvertices.size()<<" srct:"<<srctriangles.size() );
614 if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","Object "<<getName()<<" has dstv:"<<dstvertices.size()<<" dstt:"<<dsttriangles.size() );
616 if(srcvertices.size()<1) {
620 if((srctriangles.size() != dsttriangles.size()) ||
621 (srcvertices.size() != dstvertices.size()) ) {
622 errMsg("ntlGeometryObject::initMovingPointsAnim","Invalid triangle numbers! Aborting...");
625 ntlVec3f maxscale = channelFindMaxVf(mcScale);
626 float maxpart = ABS(maxscale[0]);
627 if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
628 if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
629 float scaleFac = 1.0/(maxpart);
630 // TODO - better reinit from time to time?
631 const gfxReal fsTri = featureSize*0.5 *scaleFac;
632 if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","maxscale:"<<maxpart<<" featureSize:"<<featureSize<<" fsTri:"<<fsTri );
634 if(mTriangleDivs1.size()!=srctriangles.size()) {
635 calcTriangleDivs(srcvertices,srctriangles,fsTri);
640 for(size_t i=0; i<srcvertices.size(); i++) {
641 srcmovPoints.push_back(srcvertices[i]);
642 //srcmovNormals.push_back(srcnormals[i]);
644 for(size_t i=0; i<dstvertices.size(); i++) {
645 dstmovPoints.push_back(dstvertices[i]);
646 if(dstmovNormals) (*dstmovNormals).push_back(dstnormals[i]);
648 if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","stats src:"<<srcmovPoints.size()<<" dst:"<<dstmovPoints.size()<<" " );
649 // init points & refine...
650 for(size_t i=0; i<srctriangles.size(); i++) {
651 const int divs1=mTriangleDivs1[i];
652 const int divs2=mTriangleDivs2[i];
653 if(divs1+divs2 > 0) {
654 int *srctrips = srctriangles[i].getPoints();
655 int *dsttrips = dsttriangles[i].getPoints();
656 const ntlVec3Gfx srcp0 = srcvertices[ srctrips[0] ];
657 const ntlVec3Gfx srcside1 = srcvertices[ srctrips[1] ] - srcp0;
658 const ntlVec3Gfx srcside2 = srcvertices[ srctrips[2] ] - srcp0;
659 const ntlVec3Gfx dstp0 = dstvertices[ dsttrips[0] ];
660 const ntlVec3Gfx dstside1 = dstvertices[ dsttrips[1] ] - dstp0;
661 const ntlVec3Gfx dstside2 = dstvertices[ dsttrips[2] ] - dstp0;
662 const ntlVec3Gfx src_trinorm = getNormalized(cross(srcside1,srcside2))*0.25*featureSize;
663 const ntlVec3Gfx dst_trinormOrg = getNormalized(cross(dstside1,dstside2));
664 const ntlVec3Gfx dst_trinorm = dst_trinormOrg *0.25*featureSize;
665 //errMsg("ntlGeometryObject::initMovingPointsAnim","Tri1 "<<srcvertices[srctrips[0]]<<","<<srcvertices[srctrips[1]]<<","<<srcvertices[srctrips[2]]<<" "<<divs1<<","<<divs2 );
666 for(int u=0; u<=divs1; u++) {
667 for(int v=0; v<=divs2; v++) {
668 const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0);
669 const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0);
670 if(uf+vf>1.0) continue;
672 srcvertices[ srctrips[0] ] * (1.0-uf-vf)+
673 srcvertices[ srctrips[1] ] * uf +
674 srcvertices[ srctrips[2] ] * vf;
676 dstvertices[ dsttrips[0] ] * (1.0-uf-vf)+
677 dstvertices[ dsttrips[1] ] * uf +
678 dstvertices[ dsttrips[2] ] * vf;
681 if((srcp[0]<geostart[0]) && (dstp[0]<geostart[0])) continue;
682 if((srcp[1]<geostart[1]) && (dstp[1]<geostart[1])) continue;
683 if((srcp[2]<geostart[2]) && (dstp[2]<geostart[2])) continue;
684 if((srcp[0]>geoend[0] ) && (dstp[0]>geoend[0] )) continue;
685 if((srcp[1]>geoend[1] ) && (dstp[1]>geoend[1] )) continue;
686 if((srcp[2]>geoend[2] ) && (dstp[2]>geoend[2] )) continue;
688 srcmovPoints.push_back(srcp+src_trinorm); // SURFENHTEST
689 srcmovPoints.push_back(srcp-src_trinorm);
691 dstmovPoints.push_back(dstp+dst_trinorm); // SURFENHTEST
692 dstmovPoints.push_back(dstp-dst_trinorm);
694 (*dstmovNormals).push_back(dst_trinormOrg);
695 (*dstmovNormals).push_back(dst_trinormOrg); }
701 // find max point not necessary
702 debMsgStd("ntlGeometryObject::initMovingPointsAnim",DM_MSG,"Object "<<getName()<<" inited v:"<<srcvertices.size()<<"->"<<srcmovPoints.size()<<","<<dstmovPoints.size() , 5);
705 /*! Prepare points for moving objects */
706 void ntlGeometryObject::getMovingPoints(vector<ntlVec3Gfx> &ret, vector<ntlVec3Gfx> *norms) {
708 ret = mCachedMovPoints;
710 *norms = mCachedMovNormals;
711 //errMsg("ntlGeometryObject","getMovingPoints - Normals currently unused!");
713 //errMsg ("ntlGeometryObject::getMovingPoints","Object "<<getName()<<" used cached points "); // DEBUG
719 //errMsg("ntlGeometryObject","getMovingPoints - Normals currently unused!");
720 *norms = mMovNormals;
725 /*! Calculate max. velocity on object from t1 to t2 */
726 ntlVec3Gfx ntlGeometryObject::calculateMaxVel(double t1, double t2) {
728 if(mMaxMovPnt<0) return vel;
730 vector<ntlVec3Gfx> verts1,verts2;
731 verts1.push_back(mMovPoints[mMaxMovPnt]);
733 applyTransformation(t1,&verts1,NULL, 0,verts1.size(), true);
734 applyTransformation(t2,&verts2,NULL, 0,verts2.size(), true);
736 vel = (verts2[0]-verts1[0]); // /(t2-t1);
737 //errMsg("ntlGeometryObject::calculateMaxVel","t1="<<t1<<" t2="<<t2<<" p1="<<verts1[0]<<" p2="<<verts2[0]<<" v="<<vel);
741 /*! get translation at time t*/
742 ntlVec3Gfx ntlGeometryObject::getTranslation(double t) {
743 ntlVec3Gfx pos = mcTrans.get(t);
744 // DEBUG CP_FORCECIRCLEINIT 1
746 (mName.compare(string("0__ts1"))==0) ||
747 (mName.compare(string("1__ts1"))==0) ||
748 (mName.compare(string("2__ts1"))==0) ||
749 (mName.compare(string("3__ts1"))==0) ||
750 (mName.compare(string("4__ts1"))==0) ||
751 (mName.compare(string("5__ts1"))==0) ||
752 (mName.compare(string("6__ts1"))==0) ||
753 (mName.compare(string("7__ts1"))==0) ||
754 (mName.compare(string("8__ts1"))==0) ||
755 (mName.compare(string("9__ts1"))==0)
756 ) { int j=mName[0]-'0';
757 ntlVec3Gfx ppos(0.); { // DEBUG
758 const float tscale=10.;
759 const float tprevo = 0.33;
760 const ntlVec3Gfx toff(50,50,0);
761 const ntlVec3Gfx oscale(30,30,0);
762 ppos[0] = cos(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[0] + toff[0];
763 ppos[1] = -sin(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[1] + toff[1];
764 ppos[2] = toff[2]; } // DEBUG
768 // DEBUG CP_FORCECIRCLEINIT 1 */
771 /*! get active flag time t*/
772 float ntlGeometryObject::getGeoActive(double t) {
773 float act = mcGeoActive.get(t); // if <= 0.0 -> off
777 void ntlGeometryObject::setInitialVelocity(ntlVec3Gfx set) {
778 mInitialVelocity=set;
779 mcInitialVelocity = AnimChannel<ntlVec3Gfx>(set);
781 ntlVec3Gfx ntlGeometryObject::getInitialVelocity(double t) {
782 ntlVec3Gfx v = mcInitialVelocity.get(t); //return mInitialVelocity;
783 if(!mLocalCoordInivel) return v;
785 ntlVec3Gfx rot = mcRot.get(t);
787 rotMat.initRotationXYZ(rot[0],rot[1],rot[2]);