void PhotonQuery::push_back(Photon const &data, Photon::vector_type const &vDistance) { tgir::Real const rCosTheta = -hi::dot(data.dir(), pathVertex_.vGeometricNormal); if (rCosTheta <= 0) { return; } tgir::Vector3 const vPoint = vDistance + data.dir() * hi::dot(vDistance, pathVertex_.vGeometricNormal); tgir::Real const rDistanceSquared = hi::length_squared(vPoint); if (rDistanceSquared >= PhotonQuery::max_search_range()) { return; } #if 0 // フィルタをかけるか #if 1 // コーンフィルタか static tgir::Real const k = 1.1; // 円錐フィルタのパラメータ tgir::Real const w = 1 - std::sqrt(rDistanceSquared) / (k * PhotonQuery::max_distance()); #else static tgir::Real const alpha = 0.918; // ガウスフィルタのパラメータ static tgir::Real const beta = 1.953; tgir::Real const u = 1 - std::exp(-beta * rDistanceSquared / (2 * PhotonQuery::max_search_range())); tgir::Real const s = 1 - std::exp(-beta); tgir::Real const w = alpha * (1 - u / s); #endif rPower_ += data.pow() * w; #else rPower_ += data.pow(); #endif }
Photon::Photon(const Photon& o) : Worldline(o), SmartPointee(o), object_(NULL), freq_obs_(o.freq_obs_), transmission_freqobs_(o.transmission_freqobs_), spectro_(NULL), transmission_(NULL) { if (o.object_()) { object_ = o.object_ -> clone(); object_ -> metric(metric_); } if (o.spectro_()) { spectro_ = o.spectro_ -> clone(); _allocateTransmission(); if (size_t nsamples = spectro_->nSamples()) memcpy(transmission_, o.getTransmission(), nsamples*sizeof(double)); } }
PhotonMap* PhotonMap::PrecomputeIrradiance(int increment, const int N, const float maxDistance) { std::cout << "Precomputing irradiance" << std::endl; PhotonMap *precomputed = new PhotonMap(MAX_PHOTON_COUNT); for(int i = 0; i < (int)m_photons.size(); i += increment) { Photon p = m_photons[i]; p.Power(GetRadianceEstimate(N, maxDistance, m_photons[i].Position(), m_photons[i].SurfNormal())); precomputed->AddPhoton(p); } precomputed->BalanceAndConstruct(); return precomputed; }
void PhotonMap::Map::PrecomputeIrradianceEstimates( unsigned int numThreads, unsigned int threadNum, float searchRadius, unsigned int searchCount ) { assert(finalized); if (numPhotons > 0) { static boost::mutex progressMutex; const unsigned int photonsPerThread = numPhotons / numThreads; const unsigned int photonsRemaining = numPhotons % photonsPerThread; const unsigned int photonIdxL = (photonsPerThread * threadNum) + 1; const unsigned int photonIdxR = (photonsPerThread * (threadNum + 1)) + ((threadNum == (numThreads - 1))? photonsRemaining: 0); const float photonRange = photonIdxR - photonIdxL; unsigned int prevProgress = 0; unsigned int currProgress = 0; for (unsigned int photonIdx = photonIdxL; photonIdx <= photonIdxR; photonIdx++) { Photon* p = &photonArray[photonIdx]; p->SetIrr(GetIrradianceEstimate(p->GetPos(), p->GetNrm(), searchRadius, searchCount, true)); currProgress = ((photonIdx - photonIdxL) / photonRange) * 100; if ((currProgress > prevProgress) && ((currProgress % 10) == 0)) { prevProgress = currProgress; boost::mutex::scoped_lock lock(progressMutex); std::cout << "[PhotonMap::Map::PrecomputeIrradiance]"; std::cout << " thread: " << threadNum << ", progress: " << currProgress << "%"; std::cout << " (photon " << (photonIdx - photonIdxL) << " of " << (photonIdxR - photonIdxL + 1) << ")"; std::cout << std::endl; } } } }
void unittest::LineOnEllipseIntersection(){ Point3D centre(13,5,0); double a = 3; double b = 2; ellipse e(centre, a, b); Point3D position(1,3.005,0); Vector3D momentum(1,0,0); Photon testphoton; testphoton.SetPosition(position); testphoton.SetMomentum(momentum); e.LineOnEllipseIntersection(testphoton); }
void unittest::Ellipse_Points3D(){ Point3D centre(13,5,0); double a = 3; double b = 2; ellipse e(centre, a, b); Point3D position(2,2,0); Vector3D momentum(11,3,-1); Photon testphoton; testphoton.SetPosition(position); testphoton.SetMomentum(momentum); e.points3D(testphoton); Test reader; reader.PrintPoint(e.GetStorage().GetPoint()); reader.PrintPoint(e.GetStorage().GetPoint2()); }
void PhotonMapProperty::operator()(Photon const &photon) { ++nPhotons_; tgir::Real const rPower = photon.pow(); rPowerAvg_ += rPower; rPowerVar_ += hi::square_of(rPower); if (rPowerMin_ > rPower) { rPowerMin_ = rPower; } if (rPowerMax_ < rPower) { rPowerMax_ = rPower; } }
void Surface::stop_photon(Photon& p) { if (p.is_valid()==false) return; if(isinf(_dCurvature)) { p.valid=false; return; } // flat case (intersect with z=0) if (p.dz==0.) { // TODO p.valid=false; return; } double tmin=-p.z/p.dz; if(_bIsFlat && (tmin<0.) ) { // in the past of the photon p.valid=false; return; } // TODO optimise in case of spherical // stop the photon in z=0 p.x+=tmin*p.dx; p.y+=tmin*p.dy; p.z=0.; if(_bIsFlat || _bIsPerfect) { p.valid=update_auto_diameter(p.x,p.y); return; } //compute the coef of the 2nd degree eq in t: //the equation is t^2A+tB+C=0 // use p.z=0. double dA=_dCurvature*(sqr(p.dx)+sqr(p.dy)+(_dConic+1.)*sqr(p.dz)); double dB=2.*(_dCurvature*(p.x*p.dx+p.y*p.dy)-p.dz); double dC=_dCurvature*(sqr(p.x)+sqr(p.y)); double tfinal; if (dA==0.) { if (dB==0.) { p.valid=false; return; } //the equation is now : t*dB+dC=0 so: tfinal=-dC/dB; } else //dA!=0 { //solve the equation double dB2=dB*dB; double delta=dB2-4.*dC*dA; if (delta<0.) { p.valid=false; return; } double t1,t2; if (delta!=dB2) // TODO enhance test { double sqrtDelta=sqrt(delta); t1=(2.*dC)/(+sqrtDelta-dB); t2=(2.*dC)/(-sqrtDelta-dB); } else { // delta~=dB2 // use approximate solution: if (dB!=0.) { t1=-dC/dB; t2=10.*t1; // to choose t1 } else { p.valid=false; // bug if we are here return; } } // select t that gives the lowest abs(z) //t1ok=abs(z+t1.*dz)<abs(z+t2.*dz); //oct ver if (t1*t1<t2*t2) // todo optimize tfinal=t1; else tfinal=t2; } // check if intersection is in the futur of the photon if ( tmin+tfinal<0 ) { p.valid=false; return; } p.x+=p.dx*tfinal; p.y+=p.dy*tfinal; p.z+=p.dz*tfinal; assert(p.is_valid()); p.valid=update_auto_diameter(p.x,p.y); if(!_bIsAspheric) return; //aspheric mode //p.x,p.y,p.z is already a good approximation of the surface (as a conic), but make some newton step double x=p.x; double y=p.y; // double z=p.z; double dOldT=0; for(int iLoop=0;iLoop<NB_ITER_STOP_NEWTON;iLoop++) { //reproject z on aspheric curve double zproj; compute_z(x,y,zproj); //compute normal on aspheric surface double nx,ny,nz; compute_normal(x,y,zproj,nx,ny,nz); //compute the d value to have the plane x*nx+y*ny+z*nz+d=0 double d=-(x*nx+y*ny+zproj*nz); //compute the intersect of this plane and the line defined by p (one newton step) double t=(-d-p.x*nx-p.y*ny-p.z*nz)/(p.dx*nx+p.dy*ny+p.dz*nz); //TODO tester !=0 double distSQ=sqr(t-dOldT)*(sqr(p.dx)+sqr(p.dy)+sqr(p.dz)); x=p.x+t*p.dx; y=p.y+t*p.dy; double z=p.z+t*p.dz; if(distSQ<sqr(RESOLUTION_STOP_NEWTON)) { p.x=x; p.y=y; p.z=z; p.valid=update_auto_diameter(p.x,p.y); return; } dOldT=t; } //too many iterations p.valid=false; return; }
void Surface::reflect_photon(Photon &p) { if (!p.is_valid()) return; stop_photon(p); if (!p.is_valid()) return; if(_bIsPerfect) { //TODO optimise and merge tests if(p.dz==0.) //no intersection { p.valid=false; return; } //compute AP if( (_dCurvature<CURVATURE_FLAT) && (_dCurvature>-CURVATURE_FLAT)) { p.dz=-p.dz; return; //flat mirror } double dFocal=0.5/_dCurvature; double t=dFocal/p.dz; double ax=p.dx*t; double ay=p.dy*t; double az=p.dz*t; //TODO optimise tests with sign(t) if(_dCurvature>0.) { if(p.dz>0.) { p.dx=+ax+p.x; p.dy=+ay+p.y; p.dz=-az-p.z; } else { p.dx=-ax-p.x; p.dy=-ay-p.y; p.dz=+az-p.z; } } else { if(p.dz>0.) { p.dx=-ax-p.x; p.dy=-ay-p.y; p.dz=+az-p.z; } else { p.dx=+ax+p.x; p.dy=+ay+p.y; p.dz=-az-p.z; } } return; } double nx,ny,nz; compute_normal(p.x,p.y,p.z,nx,ny,nz); // compute with the normal (nx,ny,nz) double dRayonSq=sqr(nx)+sqr(ny)+sqr(nz); assert(dRayonSq>0.); double u=2.*(nx*p.dx+ny*p.dy+nz*p.dz)/dRayonSq; p.dx-=nx*u; p.dy-=ny*u; p.dz-=nz*u; }
void Surface::transmit_photon(Photon& p) { if (!p.is_valid()) return; stop_photon(p); if (!p.is_valid()) return; if(_bIsPerfect) { //TODO optimise and merge tests if(p.dz==0.) //no intersection { p.valid=false; return; } //compute AP if( (_dCurvature<CURVATURE_FLAT) && (_dCurvature>-CURVATURE_FLAT)) return; //flat lens double dFocal=0.5/_dCurvature; double t=dFocal/p.dz; if(p.dz<0.) t=-t; double ax=p.dx*t; double ay=p.dy*t; double az=p.dz*t; p.dx=ax-p.x; p.dy=ay-p.y; p.dz=az-p.z; if(dFocal<0.) { p.dx=-p.dx; p.dy=-p.dy; p.dz=-p.dz; } return; } assert(_pMaterialNext!=0); assert(_pMaterialPrev!=0); double nx,ny,nz; //compute the normal in p (center distance : ro) double dRadiusSq=sqr(p.x)+sqr(p.y); if (dRadiusSq!=0.) { compute_normal(p.x,p.y,p.z,nx,ny,nz); Vector3D::normalize(nx,ny,nz); } else // at surface center or flat surface { nx=0.; ny=0.; nz=1.; } double u=nx*p.dx+ny*p.dy+nz*p.dz; // compute with the normal (dx,dy,dz) // u is the projection of I on the normal //calcule de C1=u/I double dC12=u*u/(sqr(p.dx)+sqr(p.dy)+sqr(p.dz)); double dRatioN=_pMaterialNext->index(p.lambda())/_pMaterialPrev->index(p.lambda()); //TODO store index and reuse double denom=sqr(dRatioN)+dC12-1.; if (denom<=0.) { // total reflexion p.valid=false; return; } double dT2T1=sqrt(dC12/denom); double k=(1.-dT2T1)*u; p.dx=nx*k+dT2T1*p.dx; p.dy=ny*k+dT2T1*p.dy; p.dz=nz*k+dT2T1*p.dz; }
void LaserSource::reaction(Photon& photon, std::vector<std::vector<Photon>>& lightPaths) { photon.setVelocity(0.0); }
void preprocess(const Scene *scene) { /* Create a sample generator for the preprocess step */ Sampler *sampler = static_cast<Sampler *>( NoriObjectFactory::createInstance("independent", PropertyList())); Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk != nullptr ) { float lngstDir = scene->getBoundingBox().getLongestDirection(); distantsDisk->setMaxRadius(lngstDir); } /* Allocate memory for the photon map */ m_photonMap = std::unique_ptr<PhotonMap>(new PhotonMap()); m_photonMap->reserve(m_photonCount); /* Estimate a default photon radius */ if (m_photonRadius == 0) m_photonRadius = scene->getBoundingBox().getExtents().norm() / 500.0f; int storedPhotons = 0; const std::vector<Emitter *> lights = scene->getEmitters(); int nLights = lights.size(); Color3f tp(1.0f, 1.0f, 1.0f); cout << "Starting to create "<< m_photonCount << " photons!" << endl; int percentDone= 0; int onePercent = int(floor(m_photonCount / 100.0)); // create the expected number of photons while(storedPhotons < m_photonCount) { //uniformly sample 1 light (assuming that we only have area lights) int var = int(std::min(sampler->next1D()*nLights, float(nLights) - 1.0f)); const areaLight* curLight = static_cast<const areaLight *> (lights[var]); //sample a photon Photon curPhoton; Vector3f unQuantDir(0.0f,0.0f,0.0f); curLight->samplePhoton(sampler, curPhoton, 1, nLights, unQuantDir); Color3f alpha = curPhoton.getPower(); Color3f tp(1.0f, 1.0f, 1.0f); //trace the photon Intersection its; Ray3f photonRay(curPhoton.getPosition(), unQuantDir); m_shootedRays++; if (scene->rayIntersect(photonRay, its)) { while(true) { const BSDF* curBSDF = its.mesh->getBSDF(); if (curBSDF->isDiffuse()) { //store the photon m_photonMap->push_back(Photon( its.p /* Position */, -photonRay.d /* Direction*/, tp * alpha /* Power */ )); storedPhotons++; } if(!(storedPhotons < m_photonCount)) break; BSDFQueryRecord query = BSDFQueryRecord(its.toLocal(-photonRay.d), Vector3f(0.0f), EMeasure::ESolidAngle); Color3f fi = curBSDF->sample(query, sampler->next2D()); if(fi.maxCoeff() == 0.0f) break; tp *= fi; Vector3f wo = its.toWorld(query.wo); photonRay = Ray3f(its.p, wo); //ray escapes the scene if (!scene->rayIntersect(photonRay, its)) break; //stop critirium russian roulette float q = tp.maxCoeff(); if(q < sampler->next1D()) break; tp /= q; } } if(onePercent != 0) { if(storedPhotons % onePercent == 0){ int percent = int(floor(storedPhotons / onePercent)); if(percent % 10 == 0 && percentDone != percent){ percentDone = percent; cout << percent << "%" << endl; } } } } /* Build the photon map */ m_photonMap->build(); }
vector<Photon> selectPhotonsCMG(const Event & ev) { const SingleVariableContainer<int> * gn = dynamic_cast<const SingleVariableContainer<int> *>(ev.findVariable("gn")); const ArrayVariableContainer<float> * gn_px = dynamic_cast<const ArrayVariableContainer<float> *>(ev.findVariable("gn_px")); const ArrayVariableContainer<float> * gn_py = dynamic_cast<const ArrayVariableContainer<float> *>(ev.findVariable("gn_py")); const ArrayVariableContainer<float> * gn_pz = dynamic_cast<const ArrayVariableContainer<float> *>(ev.findVariable("gn_pz")); const ArrayVariableContainer<float> * gn_en = dynamic_cast<const ArrayVariableContainer<float> *>(ev.findVariable("gn_en")); const ArrayVariableContainer<int> * gn_idbits = dynamic_cast<const ArrayVariableContainer<int> *>(ev.findVariable("gn_idbits")); const ArrayVariableContainer<float> * gn_chIso03 = dynamic_cast<const ArrayVariableContainer<float> *>(ev.findVariable("gn_chIso03")); const ArrayVariableContainer<float> * gn_nhIso03 = dynamic_cast<const ArrayVariableContainer<float> *>(ev.findVariable("gn_nhIso03")); const ArrayVariableContainer<float> * gn_gIso03 = dynamic_cast<const ArrayVariableContainer<float> *>(ev.findVariable("gn_gIso03")); const ArrayVariableContainer<float> * egn_sceta = dynamic_cast<const ArrayVariableContainer<float> *>(ev.findVariable("egn_sceta")); const ArrayVariableContainer<bool> * egn_isConv = dynamic_cast<const ArrayVariableContainer<bool> *>(ev.findVariable("egn_isConv")); const ArrayVariableContainer<float> * egn_hoe = dynamic_cast<const ArrayVariableContainer<float> *>(ev.findVariable("egn_hoe")); const ArrayVariableContainer<float> * egn_sihih = dynamic_cast<const ArrayVariableContainer<float> *>(ev.findVariable("egn_sihih")); const ArrayVariableContainer<float> * egn_r9 = dynamic_cast<const ArrayVariableContainer<float> *>(ev.findVariable("egn_r9")); const ArrayVariableContainer<int> * pidC = dynamic_cast<const ArrayVariableContainer<int> *>(ev.findVariable("gn_pid")); vector<Photon> photons; for ( int i = 0; i < gn->getVal(); ++i ) { Photon tmpPhoton; tmpPhoton.addFloatVar( gn_px->getName(), gn_px->getVal(i) ); tmpPhoton.addFloatVar( gn_py->getName(), gn_py->getVal(i) ); tmpPhoton.addFloatVar( gn_pz->getName(), gn_pz->getVal(i) ); tmpPhoton.addFloatVar( gn_en->getName(), gn_en->getVal(i) ); tmpPhoton.addIntVar( gn_idbits->getName(), gn_idbits->getVal(i) ); tmpPhoton.addFloatVar( gn_chIso03->getName(), gn_chIso03->getVal(i) ); tmpPhoton.addFloatVar( gn_nhIso03->getName(), gn_nhIso03->getVal(i) ); tmpPhoton.addFloatVar( gn_gIso03->getName(), gn_gIso03->getVal(i) ); int pid = pidC->getVal(i); tmpPhoton.addFloatVar( egn_sceta->getName(), egn_sceta->getVal(pid) ); tmpPhoton.addBoolVar( egn_isConv->getName(), egn_isConv->getVal(pid) ); tmpPhoton.addFloatVar( egn_hoe->getName(), egn_hoe->getVal(pid) ); tmpPhoton.addFloatVar( egn_sihih->getName(), egn_sihih->getVal(pid) ); tmpPhoton.addFloatVar( egn_r9->getName(), egn_r9->getVal(pid) ); photons.push_back(tmpPhoton); } return photons; }
void GameScreen::calculatePath() { /* std::map<int, std::shared_ptr<Equipment>>::iterator it_on_grid = tool_manager.equipments_on_grid_.begin(); for(; it_on_grid!=tool_manager.equipments_on_grid_.end(); it_on_grid ++) { (*it_on_grid).second->lightOff(); } */ for(int i = 0; i != GameScreen::tool_manager.my_targets_.size(); i++) { GameScreen::tool_manager.my_targets_[i]->lightOff(); } GameScreen::tool_manager.my_targets_[0]->lightOff(); sf::FloatRect windowRect(MARGIN, MARGIN, GRID_WIDTH*(BLOCK_SIZE), GRID_HEIGHT*(BLOCK_SIZE)); if(lightPaths.size() == 0) { for(int i = 0; i != tool_manager.my_lasers_.size(); i++) { std::vector<Photon> lightPath; lightPath.push_back(tool_manager.my_lasers_[i].getPhoton()); lightPaths.push_back(lightPath); } } for(int i = 0; i != lightPaths.size(); i++) { Photon current = lightPaths[i].back(); while(current.getVelocity() != 0.0 && windowRect.contains(current.getPosition())) { Photon nextPhoton = current; int idx = nextPhoton.getIndex(); if(tool_manager.equipments_on_grid_.count(idx) > 0) { tool_manager.equipments_on_grid_[idx]->reaction(nextPhoton, lightPaths); lightPaths[i].push_back(nextPhoton); } else { nextPhoton.myMove(); lightPaths[i].push_back(nextPhoton); } current = nextPhoton; } } bool isAllHit = true; /* it_on_grid = tool_manager.equipments_on_grid_.begin(); for(; it_on_grid!=tool_manager.equipments_on_grid_.end(); it_on_grid ++) { if(!(*it_on_grid).second->isHit()) { isAllHit = false; break; } } */ for(int i = 0; i != GameScreen::tool_manager.my_targets_.size(); i++) { if(!GameScreen::tool_manager.my_targets_[0]->isHit()) { isAllHit = false; break; } } if(isAllHit) { std::cout<<"all hit"<<std::endl; } }
void MCMLModel::DoOneRun (long numPhotonsSet) { Photon photon; for (long i = 0; i < numPhotonsSet; i++) { photon.RunOnePhoton(this); } }
// ====================================================================== // During ray tracing, when a diffuse (or partially diffuse) object is // hit, gather the nearby photons to approximate indirect illumination bool comparePhotons(const Photon& p1,const Photon& p2) { double dis1 = (p1.getPosition()-p1.getPoint()).Length(); double dis2 = (p2.getPosition()-p2.getPoint()).Length(); return dis1<dis2; }
// combines "tauint" (used to find the location of the // forced first scattering event) and "tauint2" (used // to find subsequent scattering positions within the // grid from RANDOM optical depths) bool Grid::Integrate(Photon& p, cfloat tau, IntegrateMode im) const { bool ret = true; float taurun = 0.0f, taucell = 0.0f; float dtmp = 0.0f, dpath = 0.0f, dcell = 0.0f; // translate by half the grid's represented dimensions // (so pcur corresponds to the photon cell indices) vec3 pcur = p.pos + hsize; int celli = p.xcell; int cellj = p.ycell; int cellk = p.zcell; #ifdef DEBUG assert(IndicesInBounds(celli, cellj, cellk)); #endif cfloat dsx = GetMaxXDistance(p, pcur); float dx = 0.0f; cfloat dsy = GetMaxYDistance(p, pcur); float dy = 0.0f; cfloat dsz = GetMaxZDistance(p, pcur); float dz = 0.0f; cfloat dmax = std::min(std::min(dsx, dsy), dsz); if (dmax < .001f) { return false; } // start the path integration while (taurun < tau && dpath < dmax * 0.999f) { if (p.dir.x > 0.0f) { dx = (xfaces[celli + 1] - pcur.x) / p.dir.x; if (dx < EPSILON) { pcur.x = xfaces[celli + 1]; celli += 1; dx = (xfaces[celli + 1] - pcur.x) / p.dir.x; } } else if (p.dir.x < 0.0f) { dx = (xfaces[celli] - pcur.x) / p.dir.x; if (dx < EPSILON) { pcur.x = xfaces[celli]; dx = (xfaces[celli - 1] - pcur.x) / p.dir.x; celli -= 1; } } else if (p.dir.x == 0.0f) { dx = hsize.x * 10000.0f; } if (p.dir.y > 0.0f) { dy = (yfaces[cellj + 1] - pcur.y) / p.dir.y; if (dy < EPSILON) { pcur.y = yfaces[cellj + 1]; cellj += 1; dy = (yfaces[cellj + 1] - pcur.y) / p.dir.y; } } else if (p.dir.y < 0.0f) { dy = (yfaces[cellj] - pcur.y) / p.dir.y; if (dy < EPSILON) { pcur.y = yfaces[cellj]; dy = (yfaces[cellj - 1] - pcur.y) / p.dir.y; cellj -= 1; } } else if (p.dir.y == 0.0f) { dy = hsize.y * 10000.0f; } if (p.dir.z > 0.0f) { dz = (zfaces[cellk + 1] - pcur.z) / p.dir.z; if (dz < EPSILON) { pcur.z = zfaces[cellk + 1]; cellk += 1; dz = (zfaces[cellk + 1] - pcur.z) / p.dir.z; } } else if (p.dir.z < 0.0f) { dz = (zfaces[cellk] - pcur.z) / p.dir.z; if (dz < EPSILON) { pcur.z = zfaces[cellk]; dz = (zfaces[cellk - 1] - pcur.z) / p.dir.z; cellk -= 1; } } else if (p.dir.z == 0.0f) { dz = hsize.z * 10000.0f; } // distances can be zero if we // are right on a cell boundary if (dx == 0.0f || fabs(dx) < .001f) { dx = hsize.x * 10000.0f; } if (dy == 0.0f || fabs(dy) < .001f) { dy = hsize.y * 10000.0f; } if (dz == 0.0f || fabs(dz) < .001f) { dz = hsize.z * 10000.0f; } // find distance to next cell wall // (minimum value of dx, dy, and dz) dcell = std::min(std::min(dx, dy), dz); if (dx < 0.0f) { dcell = std::min(dy, dz); } if (dy < 0.0f) { dcell = std::min(dx, dz); } if (dz < 0.0f) { dcell = std::min(dx, dy); } // if moving through a "thicker" region of the grid // where the cells are denser, we reach tau quicker taucell = dcell * rhokappa[celli][cellj][cellk]; // (if taurun + taucell > tau) then the photon's next // interaction event will be at distance d + dtmp, so // update photon position and cell indices; otherwise // photon moves over a distance dcell to the next cell // wall if (taurun + taucell >= tau) { dtmp = (tau - taurun) / rhokappa[celli][cellj][cellk]; dpath += dtmp; taurun += taucell; pcur += (p.dir * dtmp); } else { dpath += dcell; taurun += taucell; pcur += (p.dir * dcell); } if (!GPosInBounds(pcur)) { // fight numerical inaccuracy ClampGPos(pcur); } celli = GetXCellIdx(pcur.x - hsize.x); // GetXCellIdx() already adds hsize.x to x! cellj = GetYCellIdx(pcur.y - hsize.y); // GetYCellIdx() already adds hsize.y to y! cellk = GetZCellIdx(pcur.z - hsize.z); // GetZCellIdx() already adds hsize.z to z! #ifdef DEBUG assert(IndicesInBounds(celli, cellj, cellk)); #endif } switch (im) { case IM_RANDOM: { if (dpath >= dmax * 0.999f) { // photon escapes grid ret = false; } else { // photon stays inside, update // its pos and cell indices to // the next interaction coords p.UpdatePos(dpath); if (!RPosInBounds(p.pos)) { // fight numerical inaccuracy ClampRPos(p.pos); } p.UpdateCellIndices(*this); } } break; case IM_FORCED: { p.pos = pcur - hsize; if (!RPosInBounds(p.pos)) { // fight numerical inaccuracy ClampRPos(p.pos); } p.UpdateCellIndices(*this); } break; } return ret; }