ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmap.c
(Generate patch)

Comparing ray/src/rt/pmap.c (file contents):
Revision 2.11 by rschregle, Tue May 17 17:39:47 2016 UTC vs.
Revision 2.16 by rschregle, Wed Nov 21 19:33:30 2018 UTC

# Line 2 | Line 2
2   static const char RCSid[] = "$Id$";
3   #endif
4  
5 +
6   /*
7     ======================================================================
8     Photon map main module
# Line 16 | Line 17 | static const char RCSid[] = "$Id$";
17   */
18  
19  
19
20   #include "pmap.h"
21   #include "pmapmat.h"
22   #include "pmapsrc.h"
# Line 26 | Line 26 | static const char RCSid[] = "$Id$";
26   #include "pmapdiag.h"
27   #include "otypes.h"
28   #include <time.h>
29 < #include <sys/stat.h>
30 < #include <sys/mman.h>
31 < #include <sys/wait.h>
29 > #if NIX
30 >   #include <sys/stat.h>
31 >   #include <sys/mman.h>
32 >   #include <sys/wait.h>
33 > #endif
34  
33 #define PMAP_REV  "$Revision$"
35  
35
36 extern char *octname;
37
38
39
40 /* Photon map lookup functions per type */
41 void (*pmapLookup [NUM_PMAP_TYPES])(PhotonMap*, RAY*, COLOR) = {
42   photonDensity, photonPreCompDensity, photonDensity, volumePhotonDensity,
43   photonDensity, NULL
44 };
45
46
47
48 void colorNorm (COLOR c)
49 /* Normalise colour channels to average of 1 */
50 {
51   const float avg = colorAvg(c);
52  
53   if (!avg)
54      return;
55      
56   c [0] /= avg;
57   c [1] /= avg;
58   c [2] /= avg;
59 }
60
61
62
63 void loadPmaps (PhotonMap **pmaps, const PhotonMapParams *parm)
64 {
65   unsigned t;
66   struct stat octstat, pmstat;
67   PhotonMap *pm;
68   PhotonMapType type;
69  
70   for (t = 0; t < NUM_PMAP_TYPES; t++)
71      if (setPmapParam(&pm, parm + t)) {        
72         /* Check if photon map newer than octree */
73         if (pm -> fileName && octname &&
74             !stat(pm -> fileName, &pmstat) && !stat(octname, &octstat) &&
75             octstat.st_mtime > pmstat.st_mtime) {
76            sprintf(errmsg, "photon map in file %s may be stale",
77                    pm -> fileName);
78            error(USER, errmsg);
79         }
80        
81         /* Load photon map from file and get its type */
82         if ((type = loadPhotonMap(pm, pm -> fileName)) == PMAP_TYPE_NONE)
83            error(USER, "failed loading photon map");
84            
85         /* Assign to appropriate photon map type (deleting previously
86          * loaded photon map of same type if necessary) */
87         if (pmaps [type]) {
88            deletePhotons(pmaps [type]);
89            free(pmaps [type]);
90         }
91         pmaps [type] = pm;
92        
93         /* Check for invalid density estimate bandwidth */                            
94         if (pm -> maxGather > pm -> numPhotons) {
95            error(WARNING, "adjusting density estimate bandwidth");
96            pm -> minGather = pm -> maxGather = pm -> numPhotons;
97         }
98      }
99 }
100
101
102
36   void savePmaps (const PhotonMap **pmaps, int argc, char **argv)
37   {
38     unsigned t;
# Line 111 | Line 44 | void savePmaps (const PhotonMap **pmaps, int argc, cha
44   }                  
45  
46  
114  
115 void cleanUpPmaps (PhotonMap **pmaps)
116 {
117   unsigned t;
118  
119   for (t = 0; t < NUM_PMAP_TYPES; t++) {
120      if (pmaps [t]) {
121         deletePhotons(pmaps [t]);
122         free(pmaps [t]);
123      }
124   }
125 }
126
127
47      
48   static int photonParticipate (RAY *ray)
49   /* Trace photon through participating medium. Returns 1 if passed through,
# Line 133 | Line 52 | static int photonParticipate (RAY *ray)
52     int i;
53     RREAL cosTheta, cosPhi, du, dv;
54     const float cext = colorAvg(ray -> cext),
55 <               albedo = colorAvg(ray -> albedo);
55 >               albedo = colorAvg(ray -> albedo),
56 >               gecc2 = ray -> gecc * ray -> gecc;
57     FVECT u, v;
58     COLOR cvext;
59  
# Line 141 | Line 61 | static int photonParticipate (RAY *ray)
61     ray -> rmax = -log(pmapRandom(mediumState)) / cext;
62    
63     while (!localhit(ray, &thescene)) {
64 +      if (!incube(&thescene, ray -> rop)) {
65 +         /* Terminate photon if it has leaked from the scene */
66 + #ifdef DEBUG_PMAP
67 +         fprintf(stderr,
68 +                 "Volume photon leaked from scene at [%.3f %.3f %.3f]\n",
69 +                 ray -> rop [0], ray -> rop [1], ray -> rop [2]);
70 + #endif                
71 +         return 0;
72 +      }
73 +        
74        setcolor(cvext, exp(-ray -> rmax * ray -> cext [0]),
75                        exp(-ray -> rmax * ray -> cext [1]),
76                        exp(-ray -> rmax * ray -> cext [2]));
# Line 150 | Line 80 | static int photonParticipate (RAY *ray)
80        colorNorm(ray -> rcol);
81        VCOPY(ray -> rorg, ray -> rop);
82        
83 + #if 0
84        if (albedo > FTINY && ray -> rlvl > 0)
85 + #else
86 +      /* Store volume photons unconditionally in mist to also account for
87 +         direct inscattering from sources */
88 +      if (albedo > FTINY)
89 + #endif      
90           /* Add to volume photon map */
91           newPhoton(volumePmap, ray);
92          
# Line 163 | Line 99 | static int photonParticipate (RAY *ray)
99        scalecolor(ray -> rcol, 1 / albedo);    
100        
101        /* Scatter photon */
102 <      cosTheta = ray -> gecc <= FTINY ? 2 * pmapRandom(scatterState) - 1
103 <                                      : 1 / (2 * ray -> gecc) *
104 <                                            (1 + ray -> gecc * ray -> gecc -
105 <                                               (1 - ray -> gecc * ray -> gecc) /
106 <                                               (1 - ray -> gecc + 2 * ray -> gecc *
171 <                                                  pmapRandom(scatterState)));
102 >      cosTheta = ray -> gecc <= FTINY
103 >                    ? 2 * pmapRandom(scatterState) - 1
104 >                    : 0.5 * (1 + gecc2 -
105 >                         (1 - gecc2) / (1 - ray -> gecc + 2 * ray -> gecc *
106 >                         pmapRandom(scatterState))) / ray -> gecc;
107                                                    
108        cosPhi = cos(2 * PI * pmapRandom(scatterState));
109        du = dv = sqrt(1 - cosTheta * cosTheta);   /* sin(theta) */
# Line 190 | Line 125 | static int photonParticipate (RAY *ray)
125        ray -> rlvl++;
126        ray -> rmax = -log(pmapRandom(mediumState)) / cext;
127     }  
128 <    
128 >  
129 >   /* Passed through medium until intersecting local object */  
130     setcolor(cvext, exp(-ray -> rot * ray -> cext [0]),
131                     exp(-ray -> rot * ray -> cext [1]),
132                     exp(-ray -> rot * ray -> cext [2]));
133                    
134     /* Modify ray color and normalise */
135     multcolor(ray -> rcol, cvext);
136 <   colorNorm(ray -> rcol);
137 <  
202 <   /* Passed through medium */  
136 >   colorNorm(ray -> rcol);  
137 >
138     return 1;
139   }
140  
# Line 209 | Line 144 | void tracePhoton (RAY *ray)
144   /* Follow photon as it bounces around... */
145   {
146     long mod;
147 <   OBJREC* mat;
147 >   OBJREC *mat, *port = NULL;
148 >  
149 >   if (!ray -> parent) {
150 >      /* !!!  PHOTON PORT REJECTION SAMPLING HACK: get photon port for
151 >       * !!!  primary ray from ray -> ro, then reset the latter to NULL so
152 >       * !!!  as not to interfere with localhit() */
153 >      port = ray -> ro;
154 >      ray -> ro = NULL;
155 >   }
156  
157     if (ray -> rlvl > photonMaxBounce) {
158   #ifdef PMAP_RUNAWAY_WARN  
# Line 220 | Line 163 | void tracePhoton (RAY *ray)
163    
164     if (colorAvg(ray -> cext) > FTINY && !photonParticipate(ray))
165        return;
166 <      
166 >
167     if (localhit(ray, &thescene)) {
168        mod = ray -> ro -> omod;
169 <      
169 >
170 >      if (port && ray -> ro != port) {
171 >         /* !!! PHOTON PORT REJECTION SAMPLING HACK !!!
172 >          * Terminate photon if emitted from port without intersecting it;
173 >          * this can happen when the port's partitions extend beyond its
174 >          * actual geometry, e.g.  with polygons.  Since the total flux
175 >          * relayed by the port is based on the (in this case) larger
176 >          * partition area, it is overestimated; terminating these photons
177 >          * constitutes rejection sampling and thereby compensates any bias
178 >          * incurred by the overestimated flux.  */
179 > #ifdef PMAP_PORTREJECT_WARN
180 >         sprintf(errmsg, "photon outside port %s", ray -> ro -> oname);
181 >         error(WARNING, errmsg);
182 > #endif        
183 >         return;
184 >      }
185 >
186        if ((ray -> clipset && inset(ray -> clipset, mod)) || mod == OVOID) {
187           /* Transfer ray if modifier is VOID or clipped within antimatta */
188           RAY tray;
# Line 255 | Line 214 | static void preComputeGlobal (PhotonMap *pmap)
214  
215     repComplete = numPreComp = finalGather * pmap -> numPhotons;
216    
217 <   if (photonRepTime) {
218 <      sprintf(errmsg, "Precomputing irradiance for %ld global photons...\n",
217 >   if (verbose) {
218 >      sprintf(errmsg,
219 >              "\nPrecomputing irradiance for %ld global photons\n",
220                numPreComp);
221        eputs(errmsg);
222 + #if NIX      
223        fflush(stderr);
224 + #endif      
225     }
226    
227     /* Copy photon map for precomputed photons */
# Line 286 | Line 248 | static void preComputeGlobal (PhotonMap *pmap)
248    
249     for (i = 0; i < numPreComp; i++) {
250        /* Get random photon from stratified distribution in source heap to
251 <       * avoid duplicates and clutering */
251 >       * avoid duplicates and clustering */
252        pIdx = firstPhoton(pmap) +
253               (unsigned long)((i + pmapRandom(pmap -> randState)) /
254                               finalGather);
# Line 324 | Line 286 | static void preComputeGlobal (PhotonMap *pmap)
286     deletePhotons(pmap);
287     memcpy(pmap, &nuPmap, sizeof(PhotonMap));
288    
289 <   if (photonRepTime) {
290 <      eputs("Rebuilding precomputed photon map...\n");
289 >   if (verbose) {
290 >      eputs("\nRebuilding precomputed photon map\n");
291 > #if NIX      
292        fflush(stderr);
293 + #endif      
294     }
295  
296     /* Rebuild underlying data structure, destroying heap */  
# Line 345 | Line 309 | typedef struct {
309   void distribPhotons (PhotonMap **pmaps, unsigned numProc)
310   {
311     EmissionMap    emap;
312 <   char           errmsg2 [128], shmFname [255];
312 >   char           errmsg2 [128], shmFname [PMAP_TMPFNLEN];
313     unsigned       t, srcIdx, proc;
314     double         totalFlux = 0;
315     int            shmFile, stat, pid;
# Line 377 | Line 341 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
341           initPhotonHeap(pmaps [t]);
342           /* Per-subprocess target count */
343           pmaps [t] -> distribTarget /= numProc;
344 +        
345 +         if (!pmaps [t] -> distribTarget)
346 +            error(INTERNAL, "no photons to distribute in distribPhotons");
347        }
348  
349     initPhotonEmissionFuncs();
350     initPhotonScatterFuncs();
351    
352 <   /* Get photon ports if specified */
353 <   if (ambincl == 1)
387 <      getPhotonPorts();
352 >   /* Get photon ports from modifier list */
353 >   getPhotonPorts(photonPortList);
354  
355     /* Get photon sensor modifiers */
356     getPhotonSensors(photonSensorList);
357    
358 + #if NIX
359     /* Set up shared mem for photon counters (zeroed by ftruncate) */
360 < #if 0  
394 <   snprintf(shmFname, 255, PMAP_SHMFNAME, getpid());
395 <   shmFile = shm_open(shmFname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
396 < #else
397 <   strcpy(shmFname, PMAP_SHMFNAME);
360 >   strcpy(shmFname, PMAP_TMPFNAME);
361     shmFile = mkstemp(shmFname);
399 #endif      
362  
363 <   if (shmFile < 0)
364 <      error(SYSTEM, "failed opening shared memory file in distribPhotons");
363 >   if (shmFile < 0 || ftruncate(shmFile, sizeof(*photonCnt)) < 0)
364 >      error(SYSTEM, "failed shared mem init in distribPhotons");
365  
404   if (ftruncate(shmFile, sizeof(*photonCnt)) < 0)
405      error(SYSTEM, "failed setting shared memory size in distribPhotons");
406
366     photonCnt = mmap(NULL, sizeof(*photonCnt), PROT_READ | PROT_WRITE,
367                      MAP_SHARED, shmFile, 0);
368                      
369     if (photonCnt == MAP_FAILED)
370 <      error(SYSTEM, "failed mapping shared memory in distribPhotons");
370 >      error(SYSTEM, "failed mapping shared memory in distribPhotons");
371 > #else
372 >   /* Allocate photon counters statically on Windoze */
373 >   if (!(photonCnt = malloc(sizeof(PhotonCnt))))
374 >      error(SYSTEM, "failed trivial malloc in distribPhotons");
375 >   photonCnt -> numEmitted = photonCnt -> numComplete = 0;      
376 > #endif /* NIX */
377  
378 <   if (photonRepTime)
379 <      eputs("\n");
378 >   if (verbose) {
379 >      sprintf(errmsg, "\nIntegrating flux from %d sources", nsources);
380 >      
381 >      if (photonPorts) {
382 >         sprintf(errmsg2, " via %d ports", numPhotonPorts);
383 >         strcat(errmsg, errmsg2);
384 >      }
385 >      
386 >      strcat(errmsg, "\n");
387 >      eputs(errmsg);
388 >   }  
389    
390     /* ===================================================================
391      * FLUX INTEGRATION - Get total photon flux from light sources
# Line 425 | Line 399 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
399                                                     : NULL;
400           photonPartition [emap.src -> so -> otype] (&emap);
401          
402 <         if (photonRepTime) {
403 <            sprintf(errmsg, "Integrating flux from source %s ",
402 >         if (verbose) {
403 >            sprintf(errmsg, "\tIntegrating flux from source %s ",
404                      source [srcIdx].so -> oname);
405 <                    
405 >
406              if (emap.port) {
407                 sprintf(errmsg2, "via port %s ",
408                         photonPorts [portCnt].so -> oname);
409                 strcat(errmsg, errmsg2);
410              }
411 <            
412 <            sprintf(errmsg2, "(%lu partitions)...\n", emap.numPartitions);
411 >
412 >            sprintf(errmsg2, "(%lu partitions)\n", emap.numPartitions);
413              strcat(errmsg, errmsg2);
414              eputs(errmsg);
415 + #if NIX            
416              fflush(stderr);
417 + #endif            
418           }
419          
420           for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
# Line 453 | Line 429 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
429  
430     if (totalFlux < FTINY)
431        error(USER, "zero flux from light sources");
432 +      
433 +   /* Record start time for progress reports */
434 +   repStartTime = time(NULL);
435  
436 +   if (verbose) {
437 +      sprintf(errmsg, "\nPhoton distribution @ %d procs\n", numProc);
438 +      eputs(errmsg);
439 +   }
440 +
441     /* MAIN LOOP */  
442     for (proc = 0; proc < numProc; proc++) {
443 + #if NIX          
444        if (!(pid = fork())) {
445 <         /* SUBPROCESS ENTERS HERE.
446 <            All opened and memory mapped files are inherited */
445 >         /* SUBPROCESS ENTERS HERE; open and mmapped files inherited */
446 > #else
447 >      if (1) {
448 >         /* No subprocess under Windoze */
449 > #endif
450 >         /* Local photon counters for this subprocess */
451           unsigned       passCnt = 0, prePassCnt = 0;
452           unsigned long  lastNumPhotons [NUM_PMAP_TYPES];
453           unsigned long  localNumEmitted = 0; /* Num photons emitted by this
# Line 466 | Line 455 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
455          
456           /* Seed RNGs from PID for decorellated photon distribution */
457           pmapSeed(randSeed + proc, partState);
458 <         pmapSeed(randSeed + proc, emitState);
459 <         pmapSeed(randSeed + proc, cntState);
460 <         pmapSeed(randSeed + proc, mediumState);
461 <         pmapSeed(randSeed + proc, scatterState);
462 <         pmapSeed(randSeed + proc, rouletteState);
463 <                  
458 >         pmapSeed(randSeed + (proc + 1) % numProc, emitState);
459 >         pmapSeed(randSeed + (proc + 2) % numProc, cntState);
460 >         pmapSeed(randSeed + (proc + 3) % numProc, mediumState);
461 >         pmapSeed(randSeed + (proc + 4) % numProc, scatterState);
462 >         pmapSeed(randSeed + (proc + 5) % numProc, rouletteState);
463 >              
464 > #ifdef DEBUG_PMAP          
465 >         /* Output child process PID after random delay to prevent corrupted
466 >          * console output due to race condition */
467 >         usleep(1e6 * pmapRandom(rouletteState));
468 >         fprintf(stderr, "Proc %d: PID = %d "
469 >                 "(waiting 10 sec to attach debugger...)\n",
470 >                 proc, getpid());
471 >         /* Allow time for debugger to attach to child process */
472 >         sleep(10);
473 > #endif            
474 >
475           for (t = 0; t < NUM_PMAP_TYPES; t++)
476              lastNumPhotons [t] = 0;
477              
# Line 491 | Line 491 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
491                  * iterations; make it clear to user which photon maps are
492                  * missing so (s)he can check geometry and materials */
493                 if (++prePassCnt > maxPreDistrib) {
494 <                  sprintf(errmsg,
495 <                          "proc %d, source %s: too many prepasses",
496 <                          proc, source [srcIdx].so -> oname);              
494 >                  sprintf(errmsg, "proc %d: too many prepasses", proc);
495  
496                    for (t = 0; t < NUM_PMAP_TYPES; t++)
497                       if (pmaps [t] && !pmaps [t] -> numPhotons) {
# Line 565 | Line 563 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
563                    break;
564              }
565  
566 <            /* Update shared completion counter for prog.report by parent */
566 >            /* Update shared completion counter for progreport by parent */
567              photonCnt -> numComplete += numEmit;                            
568  
569              /* PHOTON DISTRIBUTION LOOP */
# Line 578 | Line 576 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
576                                ? photonPorts + portCnt : NULL;
577                    photonPartition [emap.src -> so -> otype] (&emap);
578  
579 <                  if (photonRepTime && !proc) {
579 >                  if (verbose && !proc) {
580 >                     /* Output from subproc 0 only to avoid race condition
581 >                      * on console I/O */
582                       if (!passCnt)
583 <                        sprintf(errmsg, "PREPASS %d on source %s ",
583 >                        sprintf(errmsg, "\tPREPASS %d on source %s ",
584                                  prePassCnt, source [srcIdx].so -> oname);
585                       else
586 <                        sprintf(errmsg, "MAIN PASS on source %s ",
586 >                        sprintf(errmsg, "\tMAIN PASS on source %s ",
587                                  source [srcIdx].so -> oname);
588 <                            
588 >
589                       if (emap.port) {
590                          sprintf(errmsg2, "via port %s ",
591                                  photonPorts [portCnt].so -> oname);
592                          strcat(errmsg, errmsg2);
593                       }
594 <                    
594 >
595                       sprintf(errmsg2, "(%lu partitions)\n",
596                               emap.numPartitions);
597                       strcat(errmsg, errmsg2);
598                       eputs(errmsg);
599 + #if NIX                    
600                       fflush(stderr);
601 + #endif                    
602                    }
603                    
604                    for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
# Line 611 | Line 613 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
613                      
614                       /* Number of photons to emit from ziss partishunn --
615                        * proportional to flux; photon ray weight and scalar
616 <                      * flux are uniform (the latter only varying in RGB).
615 <                      * */
616 >                      * flux are uniform (latter only varying in RGB). */
617                       partNumEmit = numEmit * colorAvg(emap.partFlux) /
618                                     totalFlux;
619                       partEmitCnt = (unsigned long)partNumEmit;
# Line 633 | Line 634 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
634                          /* Emit photon based on PDF and trace through scene
635                           * until absorbed/leaked */
636                          emitPhoton(&emap, &photonRay);
637 + #if 1
638 +                        if (emap.port)
639 +                           /* !!!  PHOTON PORT REJECTION SAMPLING HACK: set
640 +                            * !!!  photon port as fake hit object for
641 +                            * !!!  primary ray to check for intersection in
642 +                            * !!!  tracePhoton() */
643 +                           photonRay.ro = emap.port -> so;
644 + #endif
645                          tracePhoton(&photonRay);
646                       }                                          
647 <                    
647 >
648                       /* Update shared global photon count for each pmap */
649                       for (t = 0; t < NUM_PMAP_TYPES; t++)
650                          if (pmaps [t]) {
# Line 643 | Line 652 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
652                                pmaps [t] -> numPhotons - lastNumPhotons [t];
653                             lastNumPhotons [t] = pmaps [t] -> numPhotons;
654                          }
655 + #if !NIX
656 +                     /* Synchronous progress report on Windoze */
657 +                     if (!proc && photonRepTime > 0 &&
658 +                           time(NULL) >= repLastTime + photonRepTime) {
659 +                        repEmitted = repProgress = photonCnt -> numEmitted;
660 +                        repComplete = photonCnt -> numComplete;                          
661 +                        pmapDistribReport();
662 +                     }
663 + #endif
664                    }
665                    
666                    portCnt++;
# Line 658 | Line 676 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
676                    break;
677                 }
678              
679 <            if (t >= NUM_PMAP_TYPES) {
679 >            if (t >= NUM_PMAP_TYPES)
680                 /* No empty photon maps found; now do pass 2 */
681                 passCnt++;
664 #if 0
665               if (photonRepTime)
666                  eputs("\n");
667 #endif
668            }
682           } while (passCnt < 2);
683          
684 <         /* Unmap shared photon counters */
685 < #if 0        
673 <         munmap(photonCnt, sizeof(*photonCnt));
674 <         close(shmFile);
675 < #endif
676 <        
677 <         /* Flush heap buffa for every pmap one final time; this is required
678 <          * to prevent data corruption! */
684 >         /* Flush heap buffa for every pmap one final time;
685 >          * avoids potential data corruption! */
686           for (t = 0; t < NUM_PMAP_TYPES; t++)
687              if (pmaps [t]) {
681 #if 0            
682               eputs("Final flush\n");
683 #endif              
688                 flushPhotonHeap(pmaps [t]);
689 <               fclose(pmaps [t] -> heap);
689 >               /* Heap file closed automatically on exit
690 >                  fclose(pmaps [t] -> heap); */
691   #ifdef DEBUG_PMAP              
692 <               sprintf(errmsg, "Proc %d: total %ld photons\n", getpid(),
692 >               sprintf(errmsg, "Proc %d: total %ld photons\n", proc,
693                         pmaps [t] -> numPhotons);
694                 eputs(errmsg);
695   #endif              
696              }
697 <
697 > #if NIX
698 >         /* Terminate subprocess */
699           exit(0);
700 + #endif
701        }
702        else if (pid < 0)
703           error(SYSTEM, "failed to fork subprocess in distribPhotons");        
704     }
705  
706 + #if NIX
707     /* PARENT PROCESS CONTINUES HERE */
700   /* Record start time and enable progress report signal handler */
701   repStartTime = time(NULL);
708   #ifdef SIGCONT
709 +   /* Enable progress report signal handler */
710     signal(SIGCONT, pmapDistribReport);
711 < #endif
712 <  
706 <   if (photonRepTime)
707 <      eputs("\n");
708 <  
709 <   /* Wait for subprocesses to complete while reporting progress */
711 > #endif  
712 >   /* Wait for subprocesses complete while reporting progress */
713     proc = numProc;
714     while (proc) {
715        while (waitpid(-1, &stat, WNOHANG) > 0) {
# Line 719 | Line 722 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
722        
723        /* Nod off for a bit and update progress  */
724        sleep(1);
725 <      /* Update progress report from shared subprocess counters */
725 >
726 >      /* Asynchronous progress report from shared subprocess counters */  
727        repEmitted = repProgress = photonCnt -> numEmitted;
728 <      repComplete = photonCnt -> numComplete;
728 >      repComplete = photonCnt -> numComplete;      
729  
730 +      repProgress = repComplete = 0;
731        for (t = 0; t < NUM_PMAP_TYPES; t++)
732           if ((pm = pmaps [t])) {
728 #if 0        
729            /* Get photon count from heapfile size for progress update */
730            fseek(pm -> heap, 0, SEEK_END);
731            pm -> numPhotons = ftell(pm -> heap) / sizeof(Photon); */
732 #else            
733              /* Get global photon count from shmem updated by subprocs */
734 <            pm -> numPhotons = photonCnt -> numPhotons [t];
735 < #endif            
734 >            repProgress += pm -> numPhotons = photonCnt -> numPhotons [t];
735 >            repComplete += pm -> distribTarget;
736           }
737 +      repComplete *= numProc;
738  
739        if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime)
740           pmapDistribReport();
# Line 741 | Line 742 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
742        else signal(SIGCONT, pmapDistribReport);
743   #endif
744     }
745 + #endif /* NIX */
746  
747     /* ===================================================================
748      * POST-DISTRIBUTION - Set photon flux and build data struct for photon
749      * storage, etc.
750      * =================================================================== */
751   #ifdef SIGCONT    
752 +   /* Reset signal handler */
753     signal(SIGCONT, SIG_DFL);
754   #endif
755     free(emap.samples);
756    
757 <   /* Set photon flux (repProgress is total num emitted) */
757 >   /* Set photon flux */
758     totalFlux /= photonCnt -> numEmitted;
759 <  
759 > #if NIX  
760     /* Photon counters no longer needed, unmap shared memory */
761     munmap(photonCnt, sizeof(*photonCnt));
762     close(shmFile);
760 #if 0  
761   shm_unlink(shmFname);
762 #else
763     unlink(shmFname);
764 + #else
765 +   free(photonCnt);  
766   #endif      
767 <  
767 >   if (verbose)
768 >      eputs("\n");
769 >      
770     for (t = 0; t < NUM_PMAP_TYPES; t++)
771        if (pmaps [t]) {
772 <         if (photonRepTime) {
773 <            sprintf(errmsg, "\nBuilding %s photon map...\n", pmapName [t]);
772 >         if (verbose) {
773 >            sprintf(errmsg, "Building %s photon map\n", pmapName [t]);
774              eputs(errmsg);
775 + #if NIX            
776              fflush(stderr);
777 + #endif            
778           }
779          
780           /* Build underlying data structure; heap is destroyed */
781           buildPhotonMap(pmaps [t], &totalFlux, NULL, numProc);
782        }
783 <
783 >      
784     /* Precompute photon irradiance if necessary */
785 <   if (preCompPmap)
785 >   if (preCompPmap) {
786 >      if (verbose)
787 >         eputs("\n");
788        preComputeGlobal(preCompPmap);
789 < }
782 <
783 <
784 <
785 < void photonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad)
786 < /* Photon density estimate. Returns irradiance at ray -> rop. */
787 < {
788 <   unsigned                      i;
789 <   float                         r;
790 <   COLOR                         flux;
791 <   Photon                        *photon;
792 <   const PhotonSearchQueueNode   *sqn;
793 <
794 <   setcolor(irrad, 0, 0, 0);
795 <
796 <   if (!pmap -> maxGather)
797 <      return;
798 <      
799 <   /* Ignore sources */
800 <   if (ray -> ro && islight(objptr(ray -> ro -> omod) -> otype))
801 <      return;
802 <        
803 <   findPhotons(pmap, ray);
789 >   }      
790    
791 <   /* Need at least 2 photons */
792 <   if (pmap -> squeue.tail < 2) {
807 < #ifdef PMAP_NONEFOUND  
808 <      sprintf(errmsg, "no photons found on %s at (%.3f, %.3f, %.3f)",
809 <              ray -> ro ? ray -> ro -> oname : "<null>",
810 <              ray -> rop [0], ray -> rop [1], ray -> rop [2]);
811 <      error(WARNING, errmsg);
812 < #endif      
813 <
814 <      return;
815 <   }
816 <
817 <   if (pmap -> minGather == pmap -> maxGather) {
818 <      /* No bias compensation. Just do a plain vanilla estimate */
819 <      sqn = pmap -> squeue.node + 1;
820 <      
821 <      /* Average radius between furthest two photons to improve accuracy */      
822 <      r = max(sqn -> dist2, (sqn + 1) -> dist2);
823 <      r = 0.25 * (pmap -> maxDist2 + r + 2 * sqrt(pmap -> maxDist2 * r));  
824 <      
825 <      /* Skip the extra photon */
826 <      for (i = 1 ; i < pmap -> squeue.tail; i++, sqn++) {
827 <         photon = getNearestPhoton(&pmap -> squeue, sqn -> idx);
828 <         getPhotonFlux(photon, flux);        
829 < #ifdef PMAP_EPANECHNIKOV
830 <         /* Apply Epanechnikov kernel to photon flux based on photon dist */
831 <         scalecolor(flux, 2 * (1 - sqn -> dist2 / r));
832 < #endif  
833 <         addcolor(irrad, flux);
834 <      }
835 <      
836 <      /* Divide by search area PI * r^2, 1 / PI required as ambient
837 <         normalisation factor */        
838 <      scalecolor(irrad, 1 / (PI * PI * r));
839 <      
840 <      return;
841 <   }
842 <   else
843 <      /* Apply bias compensation to density estimate */
844 <      biasComp(pmap, irrad);
845 < }
846 <
847 <
848 <
849 < void photonPreCompDensity (PhotonMap *pmap, RAY *r, COLOR irrad)
850 < /* Returns precomputed photon density estimate at ray -> rop. */
851 < {
852 <   Photon p;
853 <  
854 <   setcolor(irrad, 0, 0, 0);
855 <
856 <   /* Ignore sources */
857 <   if (r -> ro && islight(objptr(r -> ro -> omod) -> otype))
858 <      return;
859 <      
860 <   find1Photon(preCompPmap, r, &p);
861 <   getPhotonFlux(&p, irrad);
862 < }
863 <
864 <
865 <
866 < void volumePhotonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad)
867 < /* Photon volume density estimate. Returns irradiance at ray -> rop. */
868 < {
869 <   unsigned                      i;
870 <   float                         r, gecc2, ph;
871 <   COLOR                         flux;
872 <   Photon                        *photon;
873 <   const PhotonSearchQueueNode   *sqn;
874 <
875 <   setcolor(irrad, 0, 0, 0);
876 <  
877 <   if (!pmap -> maxGather)
878 <      return;
879 <      
880 <   findPhotons(pmap, ray);
881 <  
882 <   /* Need at least 2 photons */
883 <   if (pmap -> squeue.tail < 2)
884 <      return;
885 <
886 < #if 0      
887 <   /* Volume biascomp disabled (probably redundant) */
888 <   if (pmap -> minGather == pmap -> maxGather)
889 < #endif  
890 <   {
891 <      /* No bias compensation. Just do a plain vanilla estimate */
892 <      gecc2 = ray -> gecc * ray -> gecc;
893 <      sqn = pmap -> squeue.node + 1;
894 <      
895 <      /* Average radius between furthest two photons to improve accuracy */      
896 <      r = max(sqn -> dist2, (sqn + 1) -> dist2);
897 <      r = 0.25 * (pmap -> maxDist2 + r + 2 * sqrt(pmap -> maxDist2 * r));  
898 <      
899 <      /* Skip the extra photon */
900 <      for (i = 1; i < pmap -> squeue.tail; i++, sqn++) {
901 <         photon = getNearestPhoton(&pmap -> squeue, sqn -> idx);
902 <        
903 <         /* Compute phase function for inscattering from photon */
904 <         if (gecc2 <= FTINY)
905 <            ph = 1;
906 <         else {
907 <            ph = DOT(ray -> rdir, photon -> norm) / 127;
908 <            ph = 1 + gecc2 - 2 * ray -> gecc * ph;
909 <            ph = (1 - gecc2) / (ph * sqrt(ph));
910 <         }
911 <        
912 <         getPhotonFlux(photon, flux);
913 <         scalecolor(flux, ph);
914 <         addcolor(irrad, flux);
915 <      }
916 <      
917 <      /* Divide by search volume 4 / 3 * PI * r^3 and phase function
918 <         normalization factor 1 / (4 * PI) */
919 <      scalecolor(irrad, 3 / (16 * PI * PI * r * sqrt(r)));
920 <      return;
921 <   }
922 < #if 0
923 <   else
924 <      /* Apply bias compensation to density estimate */
925 <      volumeBiasComp(pmap, ray, irrad);
926 < #endif      
791 >   if (verbose)
792 >      eputs("\n");
793   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines