// Seed random number generator void BerconGradient::seedRandomGen(ShadeContext& sc) { int seed = 1; if (previewMatIDMode) { seed = sc.mtlNum; } else { if (p_randMat) { seed += sc.mtlNum; } if (p_randObj) { int hand = (int)sc.Node()->GetHandle(); seed += hand*(hand*hand*15731 + 789221); } if (p_randPar) { Object *ob = sc.GetEvalObject(); if (ob && ob->IsParticleSystem()) { ParticleObject *obj = (ParticleObject*)ob; IChkMtlAPI* chkMtlAPI = static_cast<IChkMtlAPI*>(obj->GetInterface(I_NEWMTLINTERFACE)); if ((chkMtlAPI && chkMtlAPI->SupportsParticleIDbyFace())) { int id = chkMtlAPI->GetParticleFromFace(sc.FaceNumber()); seed += id*(id*id*571 + 789221); } } } if (p_randTile) { seed += (int)(sc.UVW(99).z); } } seed *= p_seed; srand(seed*(seed*seed*15731 + 789221)); }
/****************************************************************************** *! dump particles if desired *****************************************************************************/ void ParticleTracer::notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename, double simtime) { debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"obj:"<<this->getName()<<" frame:"<<frameNrStr<<" dumpp"<<mDumpParts<<" t"<<simtime, 10); // DEBUG if( (dumptype==DUMP_FULLGEOMETRY)&& (mDumpParts>0)) { // dump to binary file std::ostringstream boutfilename(""); boutfilename << outfilename <<"_particles_" << frameNrStr; if(glob_mpactive) { if(glob_mpindex>0) { boutfilename << "mp"<<glob_mpindex; } } boutfilename << ".gz"; debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"B-Dumping: "<< this->getName() <<", particles:"<<mParts.size()<<" "<< " to "<<boutfilename.str()<<" #"<<frameNr , 7); //debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"B-Dumping: partgeodeb sim:"<<mSimStart<<","<<mSimEnd<<" geosize:"<<mStart<<","<<mEnd,2 ); // output to zipped file gzFile gzf; gzf = gzopen(boutfilename.str().c_str(), "wb1"); if(gzf) { int numParts; if(sizeof(numParts)!=4) { errMsg("ParticleTracer::notifyOfDump","Invalid int size"); return; } // only dump active particles numParts = 0; for(size_t i=0; i<mParts.size(); i++) { if(!mParts[i].getActive()) continue; numParts++; } gzwrite(gzf, &numParts, sizeof(numParts)); for(size_t i=0; i<mParts.size(); i++) { if(!mParts[i].getActive()) { continue; } ParticleObject *p = &mParts[i]; //int type = p->getType(); // export whole type info int type = p->getFlags(); // debug export whole type & status info ntlVec3Gfx pos = p->getPos(); float size = p->getSize(); if(type&PART_FLOAT) { // WARNING same handling for dump! // add one gridcell offset //pos[2] += 1.0; } // display as drop for now externally //else if(type&PART_TRACER) { type |= PART_DROP; } pos = (*mpTrafo) * pos; ntlVec3Gfx v = p->getVel(); v[0] *= mpTrafo->value[0][0]; v[1] *= mpTrafo->value[1][1]; v[2] *= mpTrafo->value[2][2]; // FIXME check: pos = (*mpTrafo) * pos; gzwrite(gzf, &type, sizeof(type)); gzwrite(gzf, &size, sizeof(size)); for(int j=0; j<3; j++) { gzwrite(gzf, &pos[j], sizeof(float)); } for(int j=0; j<3; j++) { gzwrite(gzf, &v[j], sizeof(float)); } } gzclose( gzf ); } } // dump? }
void gkParticleNode::update(Real tick) { if (GET_SOCKET_VALUE(CREATE)) { gkParticleObject* p = m_scene->createParticleObject(gkUtils::getUniqueName("gkParticleNode")); p->getParticleProperties().m_settings = GET_SOCKET_VALUE(PARTICLE_SYSTEM_NAME); p->createInstance(); p->setOrientation(GET_SOCKET_VALUE(ORIENTATION)); p->setPosition(GET_SOCKET_VALUE(POSITION)); m_particles.push_back(new ParticleObject(p)); } else { ParticleObjectIterator iter(m_particles); while (iter.hasMoreElements()) { ParticleObject* p = iter.getNext(); if (p->isExpired()) { m_particles.erase(p); m_scene->destroyObject(p->m_parObj); delete p; //TODO: check iterator validation at erase. } } } }
void PinMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node) { ParticleObject *obj = GetParticleInterface(os->obj); if (obj) { force.obj=(PinObject*)GetWSMObject(t); force.node=nodeRef; force.tmValid.SetEmpty(); force.fValid.SetEmpty(); force.dt=GetTicksPerFrame(); force.dtsq=force.dt*force.dt; obj->ApplyForceField(&force); //ok } }
void SceneBase::InitParticles(int numParticles) { m_gravity.Set(0.0f, -9.8f, 0.0f); ParticleObject* po; for (int i = 0; i < numParticles; ++i) { po = new ParticleObject; po->SetActive(false); po->SetMass(1.0f); m_particleList.push_back(po); } }
void WindMod::ModifyObject( TimeValue t, ModContext &mc, ObjectState *os, INode *node) { ParticleObject *obj = GetParticleInterface(os->obj); if (obj) { force.obj = (WindObject*)GetWSMObject(t); force.node = nodeRef; force.tmValid.SetEmpty(); force.fValid.SetEmpty(); if (force.obj != NULL) force.obj->pblock2->GetValue(PB_TYPE,t,force.type,FOREVER); obj->ApplyForceField(&force); } }
ParticleObject * SceneBase::SpawnParticle(float mass, Vector3 vel) { for (vector<ParticleObject*>::iterator it = m_particleList.begin(); it != m_particleList.end(); ++it) { ParticleObject* po = *it; if (!po->IsActive()) { po->Activate(mass, vel); return po; } } return NULL; }
void PBombMod::ModifyObject( TimeValue t, ModContext &mc, ObjectState *os, INode *node) { ParticleObject *obj = GetParticleInterface(os->obj); if (obj) { /* if (!mc.localdata) { mc.localdata=seed; seed+=5;} */ force.obj = (PBombObject*)GetWSMObject(t); force.node = nodeRef; force.tmValid.SetEmpty(); force.fValid.SetEmpty(); force.dt=GetTicksPerFrame(); force.dtsq=force.dt*force.dt; obj->ApplyForceField(&force); } }
void EntityDataChannels::addEntity(const ParticleObject &entity) { entityType->setSlice(_index, entity.entityType()); alive->setSlice(_index, entity.alive()); age->setSlice(_index, entity.age().get()); position->setSlice(_index, entity.position()); color->setSlice(_index, entity.color()); size->setSlice(_index, entity.size()); _index++; }
/****************************************************************************** * Get triangles for rendering *****************************************************************************/ void ParticleTracer::getTriangles(double time, vector<ntlTriangle> *triangles, vector<ntlVec3Gfx> *vertices, vector<ntlVec3Gfx> *normals, int objectId ) { #ifdef ELBEEM_PLUGIN // suppress warnings... vertices = NULL; triangles = NULL; normals = NULL; objectId = 0; time = 0.; #else // ELBEEM_PLUGIN int pcnt = 0; // currently not used in blender objectId = 0; // remove, deprecated if(mDumpParts>1) { return; // only dump, no tri-gen } const bool debugParts = false; int tris = 0; int segments = mPartSegments; ntlVec3Gfx scale = ntlVec3Gfx( (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]), (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]), (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2])); ntlVec3Gfx trans = mStart; time = 0.; // doesnt matter for(size_t t=0; t<mPrevs.size()+1; t++) { vector<ParticleObject> *dparts; if(t==0) { dparts = &mParts; } else { dparts = &mPrevs[t-1]; } //errMsg("TRAILT","prevs"<<t<<"/"<<mPrevs.size()<<" parts:"<<dparts->size() ); gfxReal partscale = mPartScale; if(t>1) { partscale *= (gfxReal)(mPrevs.size()+1-t) / (gfxReal)(mPrevs.size()+1); } gfxReal partNormSize = 0.01 * partscale; //for(size_t i=0; i<mParts.size(); i++) { for(size_t i=0; i<dparts->size(); i++) { ParticleObject *p = &( (*dparts)[i] ); // mParts[i]; if(mShowOnly!=10) { // 10=show only deleted if( p->getActive()==false ) continue; } else { if( p->getActive()==true ) continue; } int type = p->getType(); if(mShowOnly>0) { switch(mShowOnly) { case 1: if(!(type&PART_BUBBLE)) continue; break; case 2: if(!(type&PART_DROP)) continue; break; case 3: if(!(type&PART_INTER)) continue; break; case 4: if(!(type&PART_FLOAT)) continue; break; case 5: if(!(type&PART_TRACER)) continue; break; } } else { // by default dont display inter if(type&PART_INTER) continue; } pcnt++; ntlVec3Gfx pnew = p->getPos(); if(type&PART_FLOAT) { // WARNING same handling for dump! if(p->getStatus()&PART_IN) { pnew[2] += 0.8; } // offset for display // add one gridcell offset //pnew[2] += 1.0; } #if LBMDIM==2 pnew[2] += 0.001; // DEBUG pnew[2] += 0.009; // DEBUG #endif ntlVec3Gfx pdir = p->getVel(); gfxReal plen = normalize( pdir ); if( plen < 1e-05) pdir = ntlVec3Gfx(-1.0 ,0.0 ,0.0); ntlVec3Gfx pos = (*mpTrafo) * pnew; gfxReal partsize = 0.0; if(debugParts) errMsg("DebugParts"," i"<<i<<" new"<<pnew<<" vel"<<pdir<<" pos="<<pos ); //if(i==0 &&(debugParts)) errMsg("DebugParts"," i"<<i<<" new"<<pnew[0]<<" pos="<<pos[0]<<" scale="<<scale[0]<<" t="<<trans[0] ); // value length scaling? if(mValueScale==1) { partsize = partscale * plen; } else if(mValueScale==2) { // cut off scaling if(plen > mValueCutoffTop) continue; if(plen < mValueCutoffBottom) continue; partsize = partscale * plen; } else { partsize = partscale; // no length scaling } //if(type&(PART_DROP|PART_BUBBLE)) partsize *= p->getSize()/5.0; ntlVec3Gfx pstart( mPartHeadDist *partsize, 0.0, 0.0 ); ntlVec3Gfx pend ( mPartTailDist *partsize, 0.0, 0.0 ); gfxReal phi = 0.0; gfxReal phiD = 2.0*M_PI / (gfxReal)segments; ntlMat4Gfx cvmat; cvmat.initId(); pdir *= -1.0; ntlVec3Gfx cv1 = pdir; ntlVec3Gfx cv2 = ntlVec3Gfx(pdir[1], -pdir[0], 0.0); ntlVec3Gfx cv3 = cross( cv1, cv2); //? for(int l=0; l<3; l++) { cvmat.value[l][0] = cv1[l]; cvmat.value[l][1] = cv2[l]; cvmat.value[l][2] = cv3[l]; } pstart = (cvmat * pstart); pend = (cvmat * pend); for(int s=0; s<segments; s++) { ntlVec3Gfx p1( 0.0 ); ntlVec3Gfx p2( 0.0 ); gfxReal radscale = partNormSize; radscale = (partsize+partNormSize)*0.5; p1[1] += cos(phi) * radscale; p1[2] += sin(phi) * radscale; p2[1] += cos(phi + phiD) * radscale; p2[2] += sin(phi + phiD) * radscale; ntlVec3Gfx n1 = ntlVec3Gfx( 0.0, cos(phi), sin(phi) ); ntlVec3Gfx n2 = ntlVec3Gfx( 0.0, cos(phi + phiD), sin(phi + phiD) ); ntlVec3Gfx ns = n1*0.5 + n2*0.5; p1 = (cvmat * p1); p2 = (cvmat * p2); sceneAddTriangle( pos+pstart, pos+p1, pos+p2, ns,n1,n2, ntlVec3Gfx(0.0), 1, triangles,vertices,normals ); sceneAddTriangle( pos+pend , pos+p2, pos+p1, ns,n2,n1, ntlVec3Gfx(0.0), 1, triangles,vertices,normals ); phi += phiD; tris += 2; } } } // t debMsgStd("ParticleTracer::getTriangles",DM_MSG,"Dumped "<<pcnt<<"/"<<mParts.size()<<" parts, tris:"<<tris<<", showonly:"<<mShowOnly,10); return; // DEBUG #endif // ELBEEM_PLUGIN }
void ParticleTracer::checkDumpTextPositions(double simtime) { // dfor partial & full dump if(mDumpTextInterval>0.) { debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"t="<<simtime<<" last:"<<mDumpTextLastTime<<" inter:"<<mDumpTextInterval,7); } if((mDumpTextInterval>0.) && (simtime>mDumpTextLastTime+mDumpTextInterval)) { // dump to binary file std::ostringstream boutfilename(""); if(mDumpTextFile.length()>1) { boutfilename << mDumpTextFile << ".cpart2"; } else { boutfilename << "_particles" << ".cpart2"; } debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"T-Dumping: "<< this->getName() <<", particles:"<<mParts.size()<<" "<< " to "<<boutfilename.str()<<" " , 7); int numParts = 0; // only dump bubble particles for(size_t i=0; i<mParts.size(); i++) { //if(!mParts[i].getActive()) continue; //if(!(mParts[i].getType()&PART_BUBBLE)) continue; numParts++; } // output to text file //gzFile gzf; FILE *stf; if(mDumpTextCount==0) { //gzf = gzopen(boutfilename.str().c_str(), "w0"); stf = fopen(boutfilename.str().c_str(), "w"); fprintf( stf, "\n\n# cparts generated by elbeem \n# no. of parts \nN %d \n\n",numParts); // fixed time scale for now fprintf( stf, "T %f \n\n", 1.0); } else { //gzf = gzopen(boutfilename.str().c_str(), "a+0"); stf = fopen(boutfilename.str().c_str(), "a+"); } // add current set if(stf) { fprintf( stf, "\n\n# new set at frame %d,t%f,p%d --------------------------------- \n\n", mDumpTextCount, simtime, numParts ); fprintf( stf, "S %f \n\n", simtime ); for(size_t i=0; i<mParts.size(); i++) { ParticleObject *p = &mParts[i]; ntlVec3Gfx pos = p->getPos(); float size = p->getSize(); float infl = 1.; //if(!mParts[i].getActive()) { size=0.; } // switch "off" if(!mParts[i].getActive()) { infl=0.; } // switch "off" if(!mParts[i].getInFluid()) { infl=0.; } // switch "off" if(mParts[i].getLifeTime()<0.) { infl=0.; } // not yet active... pos = (*mpTrafo) * pos; ntlVec3Gfx v = p->getVel(); v[0] *= mpTrafo->value[0][0]; v[1] *= mpTrafo->value[1][1]; v[2] *= mpTrafo->value[2][2]; fprintf( stf, "P %f %f %f \n", pos[0],pos[1],pos[2] ); if(size!=1.0) fprintf( stf, "s %f \n", size ); if(infl!=1.0) fprintf( stf, "i %f \n", infl ); fprintf( stf, "\n" ); } fprintf( stf, "# %d end ", mDumpTextCount ); //gzclose( gzf ); fclose( stf ); mDumpTextCount++; } mDumpTextLastTime += mDumpTextInterval; } }
// 工厂对象的创建方法 ISceneObject *ParticleObjectFactory::create(const String &name , IScene *scene , const NameValuePairList* params) { ParticleObject *obj = new ParticleObject(name); obj->create(scene , params); return obj; }
// Calculates 0..1 value which is given to the gradient float BerconGradient::getGradientValue(ShadeContext& sc) { switch (p_type) { case 0: { // UVW break; // Handled in main evaluation } case 1: { // Normal switch (p_normalFunction) { case 0: { // Perpendicular / Parallel return fabs(getGradientValueNormal(sc)); } case 1: { // Towards / Away return (getGradientValueNormal(sc) + 1.f) / 2.f; } case 2: { // Fresnel // NOTE: Should this get IOR from sc.GetIOR()? // I think not since its just a map, not material. // You get more predictable behaviour with constant 1.f. static float n1 = 1.0f; float cti = fabs(getGradientValueNormal(sc)); float stt = (n1 / p_ior) * sqrt(1 - cti * cti); float ctt = sqrt(1 - stt * stt); float rs = (p_ior * ctt - n1 * cti ) / (p_ior * ctt + n1 * cti); rs = rs * rs; float rp = (n1 * ctt - p_ior * cti ) / (n1 * ctt + p_ior * cti); rp = rp * rp; return 1.f - 0.5f * (rs + rp); } } } case 2: { // Distance return getGradientValueDist(sc); } case 3: { // Light return Intens(sc.DiffuseIllum()); } case 4: { // Map return p_maptex?p_maptex->EvalMono(sc):0.f; // TODO: Evaluate submaps color, bump is tougher DELTA shift with BerconSC? } case 5: { // Random seedRandomGen(sc); return (float)sfrand(); break; } case 6: { // Particle age Object *ob = sc.GetEvalObject(); if (ob && ob->IsParticleSystem()) { ParticleObject *obj = (ParticleObject*)ob; TimeValue t = sc.CurTime(); TimeValue age = obj->ParticleAge(t,sc.mtlNum); TimeValue life = obj->ParticleLife(t,sc.mtlNum); if (age>=0 && life>=0) return float(age)/float(life); } break; } case 7: { // Particle speed Object *ob = sc.GetEvalObject(); if (ob && ob->IsParticleSystem()) { ParticleObject *obj = (ParticleObject*)ob; /*IChkMtlAPI* chkMtlAPI = static_cast<IChkMtlAPI*>(obj->GetInterface(I_NEWMTLINTERFACE)); if ((chkMtlAPI&&chkMtlAPI->SupportsParticleIDbyFace())) return (Length(obj->ParticleVelocity(sc.CurTime(),chkMtlAPI->GetParticleFromFace(sc.FaceNumber()))) - p_rangeMin) / (p_rangeMax - p_rangeMin); else*/ return Length(obj->ParticleVelocity(sc.CurTime(),sc.mtlNum)); } break; } case 8: { // Particle size Object *ob = sc.GetEvalObject(); if (ob && ob->IsParticleSystem()) { ParticleObject *obj = (ParticleObject*)ob; return obj->ParticleSize(sc.CurTime(),sc.mtlNum); } break; } default: break; } return 0.f; }