/* tracepath.c: random walk generation */ #include "mcradP.h" #include "tracepath.h" #include "localline.h" #include "pools.h" #include "error.h" #include "scene.h" #include "statistics.h" void InitPath(PATH *path) { path->nrnodes = path->nodesalloced = 0; path->nodes = (PATHNODE *)NULL; } void ClearPath(PATH *path) { path->nrnodes = 0; } void PathAddNode(PATH *path, PATCH *patch, double prob, POINT inpoint, POINT outpoint) { PATHNODE *node; if (path->nrnodes >= path->nodesalloced) { PATHNODE *newnodes = (PATHNODE*)Alloc((path->nodesalloced+20)*sizeof(PATHNODE)); if (path->nodesalloced>0) { int i; for (i=0; inrnodes; i++) newnodes[i] = path->nodes[i]; /* copy nodes */ Free((char*)path->nodes, path->nodesalloced*sizeof(PATHNODE)); } path->nodes = newnodes; path->nodesalloced += 20; } node = &path->nodes[path->nrnodes]; node->patch = patch; node->probability = prob; node->inpoint = inpoint; node->outpoint = outpoint; path->nrnodes++; } void FreePathNodes(PATH *path) { if (path->nodes) Free((char*)path->nodes, sizeof(PATHNODE)*path->nodesalloced); path->nodesalloced = 0; path->nodes = (PATHNODE*)NULL; } /* path nodes are filled in 'path', 'path' itself is returned. */ PATH *TracePath(PATCH *origin, double birth_prob, double (*SurvivalProbability)(PATCH *P), PATH *path) { POINT inpoint = {0.,0.,0.}, outpoint = {0.,0.,0.}; PATCH *P = origin; double surv_prob; RAY ray; HITREC *hit, hitstore; mcr.traced_paths ++; ClearPath(path); PathAddNode(path, origin, birth_prob, inpoint, outpoint); do { mcr.traced_rays++; ray = McrGenerateLocalLine(P, Sample4D(RAY_INDEX(P)++)); if (path->nrnodes>1 && mcr.continuous_random_walk) { /* scattered ray originates at point of incidence of previous ray */ ray.pos = path->nodes[path->nrnodes-1].inpoint; } path->nodes[path->nrnodes-1].outpoint = ray.pos; hit = McrShootRay(P, &ray, &hitstore); if (!hit) break; /* path disappears into background */ P = hit->patch; surv_prob = SurvivalProbability(P); PathAddNode(path, P, surv_prob, hit->point, outpoint); } while (drand48() < surv_prob); /* repeat until absorption */ return path; } static double (*birth_prob)(PATCH *), sum_probs; static double PatchNormalisedBirthProbability(PATCH *P) { return birth_prob(P) / sum_probs; } /* traces 'nr_paths' paths with given birth probabilities */ void TracePaths(long nr_paths, double (*BirthProbability)(PATCH *P), double (*SurvivalProbability)(PATCH *P), void (*ScorePath)(PATH *, long nr_paths, double (*birth_prob)(PATCH *)), void (*Update)(PATCH *P, double w)) { double rnd, p_cumul; long path_count; PATH path; mcr.prev_traced_rays = mcr.traced_rays; birth_prob = BirthProbability; /* compute sampling probability normalisation factor */ sum_probs = 0.; ForAllPatches(P, Patches) { sum_probs += BirthProbability(P); CLEARCOEFFICIENTS(RECEIVED_RAD(P), BAS(P)); } EndForAll; if (sum_probs < EPSILON) { Warning("TracePaths", "No sources"); return; } /* fire off paths from the patches, propagate radiance */ InitPath(&path); rnd = drand48(); path_count = 0; p_cumul = 0.; ForAllPatches(P, Patches) { double p = BirthProbability(P) / sum_probs; long i, paths_this_patch = (int)floor((p_cumul+p) * (double)nr_paths + rnd) - path_count; for (i=0; iarea, UNSHOT_RAD(P)[0], mcr.unshot_flux); COLORADDSCALED(mcr.total_flux, M_PI*P->area, RAD(P)[0], mcr.total_flux); } EndForAll; }