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

Comparing ray/src/rt/pmapsrc.c (file contents):
Revision 2.17 by greg, Thu Nov 8 00:54:07 2018 UTC vs.
Revision 2.19 by rschregle, Mon Aug 10 19:51:20 2020 UTC

# Line 2 | Line 2
2   static const char RCSid[] = "$Id$";
3   #endif
4   /*
5 <   ==================================================================
5 >   ======================================================================
6     Photon map support routines for emission from light sources
7  
8     Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
9     (c) Fraunhofer Institute for Solar Energy Systems,
10 +       supported by the German Research Foundation (DFG)
11 +       under the FARESYS project.
12     (c) Lucerne University of Applied Sciences and Arts,
13 <   supported by the Swiss National Science Foundation (SNSF, #147053)
14 <   ==================================================================
15 <
13 >       supported by the Swiss National Science Foundation (SNSF #147053).
14 >   (c) Tokyo University of Science,
15 >       supported by the JSPS KAKENHI Grant Number JP19KK0115.
16 >   ======================================================================
17 >
18 >   $Id$"
19   */
20  
21  
# Line 21 | Line 26 | static const char RCSid[] = "$Id$";
26   #include "otypes.h"
27   #include "otspecial.h"
28  
29 +
30 +
31   /* List of photon port modifier names */
32   char *photonPortList [MAXSET + 1] = {NULL};
33   /* Photon port objects (with modifiers in photonPortMods) */
# Line 30 | Line 37 | unsigned numPhotonPorts = 0;
37   void (*photonPartition [NUMOTYPE]) (EmissionMap*);
38   void (*photonOrigin [NUMOTYPE]) (EmissionMap*);
39  
40 +
41 +
42 + /* PHOTON PORT SUPPORT ROUTINES ------------------------------------------ */
43 +
44 +
45 +
46 + /* Get/set photon port orientation flags from/in source flags.
47 + * HACK: the port orientation flags are embedded in the source flags and
48 + * shifted so they won't clobber the latter, since these are interpreted
49 + * by the *PhotonPartition() and *PhotonOrigin() routines! */
50 + #define PMAP_SETPORTFLAGS(portdir) ((int)(portdir) << 14)
51 + #define PMAP_GETPORTFLAGS(sflags)  ((sflags) >> 14)
52 +
53 + /* Set number of source partitions.
54 + * HACK: this is doubled if the source acts as a bidirectionally
55 + * emitting photon port, resulting in alternating front/backside partitions,
56 + * although essentially each partition is just used twice with opposing
57 + * normals. */
58 + #define PMAP_SETNUMPARTITIONS(emap)   ( \
59 +   (emap) -> numPartitions <<= ( \
60 +      (emap) -> port && \
61 +      PMAP_GETPORTFLAGS((emap) -> port -> sflags) == PMAP_PORTBI \
62 +   ) \
63 + )
64 +
65 + /* Get current source partition and numer of partitions
66 + * HACK: halve the number partitions if the source acts as a bidrectionally
67 + * emitting photon port, since each partition is used twice with opposing
68 + * normals. */
69 + #define PMAP_GETNUMPARTITIONS(emap) (\
70 +   (emap) -> numPartitions >> ( \
71 +      (emap) -> port && \
72 +      PMAP_GETPORTFLAGS((emap) -> port -> sflags) == PMAP_PORTBI \
73 +   ) \
74 + )
75 + #define PMAP_GETPARTITION(emap)  ( \
76 +   (emap) -> partitionCnt >> ( \
77 +      (emap) -> port && \
78 +      PMAP_GETPORTFLAGS((emap) -> port -> sflags) == PMAP_PORTBI \
79 +   ) \
80 + )
81 +
82 +
83 +
84 + void getPhotonPorts (char **portList)
85 + /* Find geometry declared as photon ports from modifiers in portList */
86 + {
87 +   OBJECT   i;
88 +   OBJREC   *obj, *mat;
89 +   int      mLen;
90 +   char     **lp;  
91    
92 +   /* Init photon port objects */
93 +   photonPorts = NULL;
94 +  
95 +   if (!portList [0])
96 +      return;
97 +  
98 +   for (i = numPhotonPorts = 0; i < nobjects; i++) {
99 +      obj = objptr(i);
100 +      mat = findmaterial(obj);
101 +      
102 +      /* Check if object is a surface and NOT a light source (duh) and
103 +       * resolve its material (if any) via any aliases, then check for
104 +       * inclusion in modifier list; note use of strncmp() to ignore port
105 +       * flags */
106 +      if (issurface(obj -> otype) && mat && !islight(mat -> otype)) {
107 +         mLen = strlen(mat -> oname);
108 +         for (lp = portList; *lp && strncmp(mat -> oname, *lp, mLen); lp++);
109 +        
110 +         if (*lp) {
111 +            /* Add photon port */
112 +            photonPorts = (SRCREC*)realloc(
113 +               photonPorts, (numPhotonPorts + 1) * sizeof(SRCREC)
114 +            );
115 +            if (!photonPorts)
116 +               error(USER, "can't allocate photon ports");
117 +            
118 +            photonPorts [numPhotonPorts].so = obj;
119 +            /* Extract port orientation flags and embed in source flags.
120 +             * Note setsource() combines (i.e. ORs) these with the actual
121 +             * source flags below. */
122 +            photonPorts [numPhotonPorts].sflags =
123 +               PMAP_SETPORTFLAGS((*lp) [mLen]);
124 +        
125 +            if (!sfun [obj -> otype].of || !sfun[obj -> otype].of -> setsrc)
126 +               objerror(obj, USER, "illegal photon port");
127 +        
128 +            setsource(photonPorts + numPhotonPorts, obj);
129 +            numPhotonPorts++;
130 +         }
131 +      }
132 +   }
133 +   if (!numPhotonPorts)
134 +      error(USER, "no valid photon ports found");
135 + }
136  
137 < static int flatPhotonPartition2 (EmissionMap* emap, unsigned long mp,
138 <                                 FVECT cent, FVECT u, FVECT v,
139 <                                 double du2, double dv2)
137 >
138 >
139 > static void setPhotonPortNormal (EmissionMap* emap)
140 > /* Set normal for current photon port partition (if defined) based on its
141 > * orientation */
142 > {
143 >
144 >   int i, portFlags;
145 >  
146 >   if (emap -> port) {
147 >      /* Extract photon port orientation flags, set surface normal as follows:
148 >         -- Port oriented forwards --> flip surface normal to point outwards,
149 >            since normal points inwards per mkillum convention)
150 >         -- Port oriented backwards --> surface normal is NOT flipped, since
151 >            it already points inwards.
152 >         -- Port is bidirectionally/bilaterally oriented --> flip normal based
153 >            on the parity of the current partition emap -> partitionCnt. In
154 >            this case, photon emission alternates between port front/back
155 >            faces for consecutive partitions.
156 >      */  
157 >      portFlags = PMAP_GETPORTFLAGS(emap -> port -> sflags);
158 >
159 >      if (
160 >         portFlags == PMAP_PORTFWD ||
161 >         portFlags == PMAP_PORTBI && !(emap -> partitionCnt & 1)
162 >      )
163 >         for (i = 0; i < 3; i++)    
164 >            emap -> ws [i] = -emap -> ws [i];
165 >   }
166 > }
167 >
168 >
169 >
170 > /* SOURCE / PHOTON PORT PARTITIONING ROUTINES----------------------------- */
171 >  
172 >
173 >
174 > static int flatPhotonPartition2 (
175 >   EmissionMap* emap, unsigned long mp, FVECT cent, FVECT u, FVECT v,
176 >   double du2, double dv2
177 > )
178   /* Recursive part of flatPhotonPartition(..) */
179   {
180     FVECT newct, newax;
# Line 43 | Line 183 | static int flatPhotonPartition2 (EmissionMap* emap, un
183     if (mp > emap -> maxPartitions) {
184        /* Enlarge partition array */
185        emap -> maxPartitions <<= 1;
186 <      emap -> partitions = (unsigned char*)realloc(emap -> partitions,
187 <                                           emap -> maxPartitions >> 1);
186 >      emap -> partitions = (unsigned char*)realloc(
187 >         emap -> partitions, emap -> maxPartitions >> 1
188 >      );
189  
190        if (!emap -> partitions)
191           error(USER, "can't allocate source partitions");
192  
193 <      memset(emap -> partitions + (emap -> maxPartitions >> 2), 0,
194 <             emap -> maxPartitions >> 2);
193 >      memset(
194 >         emap -> partitions + (emap -> maxPartitions >> 2), 0,
195 >         emap -> maxPartitions >> 2
196 >      );
197     }
198    
199     if (du2 * dv2 <= 1) {                /* hit limit? */
# Line 111 | Line 254 | static void flatPhotonPartition (EmissionMap* emap)
254     vp = emap -> src -> ss [SV];
255     dv2 = DOT(vp, vp) / emap -> partArea;
256     emap -> partitionCnt = 0;
257 <   emap -> numPartitions = flatPhotonPartition2(emap, 1, emap -> src -> sloc,
258 <                                                emap -> src -> ss [SU],
259 <                                                emap -> src -> ss [SV],
260 <                                                du2, dv2);
257 >   emap -> numPartitions = flatPhotonPartition2(
258 >      emap, 1, emap -> src -> sloc,
259 >      emap -> src -> ss [SU], emap -> src -> ss [SV], du2, dv2
260 >   );
261     emap -> partitionCnt = 0;
262     emap -> partArea = emap -> src -> ss2 / emap -> numPartitions;
263   }
# Line 126 | Line 269 | static void sourcePhotonPartition (EmissionMap* emap)
269     distant source */
270   {  
271     if (emap -> port) {
272 <      /* Partition photon port */
272 >      /* Relay partitioning to photon port */
273        SRCREC *src = emap -> src;
274        emap -> src = emap -> port;
275        photonPartition [emap -> src -> so -> otype] (emap);
276 +      PMAP_SETNUMPARTITIONS(emap);
277        emap -> src = src;
278     }
279    
280     else {
281 <      /* No photon ports defined, so partition scene cube faces */
281 >      /* No photon ports defined; partition scene cube faces (SUBOPTIMAL) */
282        memset(emap -> partitions, 0, emap -> maxPartitions >> 1);
283        setpart(emap -> partitions, 0, S0);
284        emap -> partitionCnt = 0;
# Line 156 | Line 300 | static void spherePhotonPartition (EmissionMap* emap)
300     memset(emap -> partitions, 0, emap -> maxPartitions >> 1);
301     setpart(emap -> partitions, 0, S0);
302     emap -> partArea = 4 * PI * sqr(emap -> src -> srad);
303 <   emap -> numPartitions = emap -> partArea /
304 <                           sqr(srcsizerat * thescene.cusize);
303 >   emap -> numPartitions =
304 >      emap -> partArea / sqr(srcsizerat * thescene.cusize);
305  
306     numTheta = max(sqrt(2 * emap -> numPartitions / PI) + 0.5, 1);
307     numPhi = 0.5 * PI * numTheta + 0.5;
# Line 169 | Line 313 | static void spherePhotonPartition (EmissionMap* emap)
313  
314  
315  
316 < static int cylPhotonPartition2 (EmissionMap* emap, unsigned long mp,
317 <                                FVECT cent, FVECT axis, double d2)
316 > static int cylPhotonPartition2 (
317 >   EmissionMap* emap, unsigned long mp, FVECT cent, FVECT axis, double d2
318 > )
319   /* Recursive part of cyPhotonPartition(..) */
320   {
321     FVECT newct, newax;
# Line 179 | Line 324 | static int cylPhotonPartition2 (EmissionMap* emap, uns
324     if (mp > emap -> maxPartitions) {
325        /* Enlarge partition array */
326        emap -> maxPartitions <<= 1;
327 <      emap -> partitions = (unsigned char*)realloc(emap -> partitions,
328 <                                                   emap -> maxPartitions >> 1);
327 >      emap -> partitions = (unsigned char*)realloc(
328 >         emap -> partitions, emap -> maxPartitions >> 1
329 >      );
330        if (!emap -> partitions)
331           error(USER, "can't allocate source partitions");
332          
333 <      memset(emap -> partitions + (emap -> maxPartitions >> 2), 0,
334 <            emap -> maxPartitions >> 2);
333 >      memset(
334 >         emap -> partitions + (emap -> maxPartitions >> 2), 0,
335 >         emap -> maxPartitions >> 2
336 >      );
337     }
338    
339     if (d2 <= 1) {
# Line 232 | Line 380 | static void cylPhotonPartition (EmissionMap* emap)
380     d2 *= d2 * DOT(emap -> src -> ss [SU], emap -> src -> ss [SU]);
381  
382     emap -> partitionCnt = 0;
383 <   emap -> numPartitions = cylPhotonPartition2(emap, 1, emap -> src -> sloc,
384 <                                               emap -> src -> ss [SU], d2);
383 >   emap -> numPartitions = cylPhotonPartition2(
384 >      emap, 1, emap -> src -> sloc, emap -> src -> ss [SU], d2
385 >   );
386     emap -> partitionCnt = 0;
387     emap -> partArea = PI * emap -> src -> ss2 / emap -> numPartitions;
388   }
389  
390  
391  
392 + /* PHOTON ORIGIN ROUTINES ------------------------------------------------ */
393 +
394 +
395 +
396   static void flatPhotonOrigin (EmissionMap* emap)
397   /* Init emission map with photon origin and associated surface axes on
398     flat light source surface. Also sets source aperture and sampling
# Line 251 | Line 404 | static void flatPhotonOrigin (EmissionMap* emap)
404     cent [0] = cent [1] = cent [2] = 0;
405     size [0] = size [1] = size [2] = emap -> maxPartitions;
406     parr [0] = 0;
407 <   parr [1] = emap -> partitionCnt;
407 >   parr [1] = PMAP_GETPARTITION(emap);
408    
409     if (!skipparts(cent, size, parr, emap -> partitions))
410        error(CONSISTENCY, "bad source partition in flatPhotonOrigin");
# Line 267 | Line 420 | static void flatPhotonOrigin (EmissionMap* emap)
420        
421     /* Get origin */
422     for (i = 0; i < 3; i++)
423 <      emap -> photonOrg [i] = emap -> src -> sloc [i] +
424 <                              vpos [SU] * emap -> src -> ss [SU][i] +
425 <                              vpos [SV] * emap -> src -> ss [SV][i] +
426 <                              vpos [SW] * emap -> src -> ss [SW][i];
423 >      emap -> photonOrg [i] =
424 >         emap -> src -> sloc [i] +
425 >         vpos [SU] * emap -> src -> ss [SU][i] +
426 >         vpos [SV] * emap -> src -> ss [SV][i] +
427 >         vpos [SW] * emap -> src -> ss [SW][i];
428                                
429     /* Get surface axes */
430     VCOPY(emap -> us, emap -> src -> ss [SU]);
431     normalize(emap -> us);
432     VCOPY(emap -> ws, emap -> src -> ss [SW]);
433 <
434 <   if (emap -> port)
281 <      /* Acts as a photon port; reverse normal as it points INSIDE per
282 <       * mkillum convention */
283 <      for (i = 0; i < 3; i++)
284 <         emap -> ws [i] = -emap -> ws [i];
285 <        
433 >   /* Flip normal emap -> ws if port and required by its orientation */
434 >   setPhotonPortNormal(emap);
435     fcross(emap -> vs, emap -> ws, emap -> us);
436    
437     /* Get hemisphere axes & aperture */
# Line 320 | Line 469 | static void spherePhotonOrigin (EmissionMap* emap)
469     RREAL cosTheta, sinTheta, phi;
470  
471     /* Get current partition */
472 <   numTheta = max(sqrt(2 * emap -> numPartitions / PI) + 0.5, 1);
472 >   numTheta = max(sqrt(2 * PMAP_GETNUMPARTITIONS(emap) / PI) + 0.5, 1);
473     numPhi = 0.5 * PI * numTheta + 0.5;
474  
475 <   t = emap -> partitionCnt / numPhi;
476 <   p = emap -> partitionCnt - t * numPhi;
475 >   t = PMAP_GETPARTITION(emap) / numPhi;
476 >   p = PMAP_GETPARTITION(emap) - t * numPhi;
477  
478     emap -> ws [2] = cosTheta = 1 - 2 * (t + pmapRandom(partState)) / numTheta;
479     sinTheta = sqrt(1 - sqr(cosTheta));
480     phi = 2 * PI * (p + pmapRandom(partState)) / numPhi;
481     emap -> ws [0] = cos(phi) * sinTheta;
482     emap -> ws [1] = sin(phi) * sinTheta;
483 +   /* Flip normal emap -> ws if port and required by its orientation */
484 +   setPhotonPortNormal(emap);
485  
335   if (emap -> port)
336      /* Acts as a photon port; reverse normal as it points INSIDE per
337       * mkillum convention */
338      for (i = 0; i < 3; i++)
339         emap -> ws [i] = -emap -> ws [i];  
340
486     /* Get surface axes us & vs perpendicular to ws */
487     do {
488        emap -> vs [0] = emap -> vs [1] = emap -> vs [2] = 0;
# Line 387 | Line 532 | static void sourcePhotonOrigin (EmissionMap* emap)
532     RREAL du, dv;                            
533        
534     if (emap -> port) {
535 <      /* Get origin on photon port */
535 >      /* Relay to photon port; get origin on its surface */
536        SRCREC *src = emap -> src;
537        emap -> src = emap -> port;
538        photonOrigin [emap -> src -> so -> otype] (emap);
# Line 395 | Line 540 | static void sourcePhotonOrigin (EmissionMap* emap)
540     }
541    
542     else {
543 <      /* No ports defined, so get origin on scene cube face and SUFFA! */
543 >      /* No ports defined, so get origin on scene cube face (SUBOPTIMAL) */
544        /* Get current face from partition number */
545        partsPerDim = 1 / srcsizerat;
546        partsPerFace = sqr(partsPerDim);
547        face = emap -> partitionCnt / partsPerFace;
403
548        if (!(emap -> partitionCnt % partsPerFace)) {
549           /* Skipped to a new face; get its normal */
550           emap -> ws [0] = emap -> ws [1] = emap -> ws [2] = 0;
# Line 421 | Line 565 | static void sourcePhotonOrigin (EmissionMap* emap)
565  
566        /* Jittered destination point within partition */
567        for (i = 0; i < 3; i++)
568 <         emap -> photonOrg [i] = thescene.cuorg [i] +
569 <                                 thescene.cusize * (0.5 + du * emap -> us [i] +
570 <                                                    dv * emap -> vs [i] +
571 <                                                    0.5 * emap -> ws [i]);
568 >         emap -> photonOrg [i] = thescene.cuorg [i] + thescene.cusize * (
569 >            0.5 + du * emap -> us [i] + dv * emap -> vs [i] +
570 >            0.5 * emap -> ws [i]
571 >         );
572     }
573    
574     /* Get hemisphere axes & aperture */
# Line 457 | Line 601 | static void cylPhotonOrigin (EmissionMap* emap)
601     cent [0] = cent [1] = cent [2] = 0;
602     size [0] = size [1] = size [2] = emap -> maxPartitions;
603     parr [0] = 0;
604 <   parr [1] = emap -> partitionCnt;
604 >   parr [1] = PMAP_GETPARTITION(emap);
605  
606     if (!skipparts(cent, size, parr, emap -> partitions))
607        error(CONSISTENCY, "bad source partition in cylPhotonOrigin");
# Line 476 | Line 620 | static void cylPhotonOrigin (EmissionMap* emap)
620  
621     /* Get surface axes */
622     for (i = 0; i < 3; i++)
623 <      emap -> photonOrg [i] = emap -> ws [i] =
624 <                              (v [SV] * emap -> src -> ss [SV][i] +
625 <                               v [SW] * emap -> src -> ss [SW][i]) / 0.8559;
623 >      emap -> photonOrg [i] = emap -> ws [i] = (
624 >         v [SV] * emap -> src -> ss [SV][i] +
625 >         v [SW] * emap -> src -> ss [SW][i]
626 >      ) / 0.8559;
627  
628 <   if (emap -> port)
629 <      /* Acts as a photon port; reverse normal as it points INSIDE per
485 <       * mkillum convention */
486 <      for (i = 0; i < 3; i++)
487 <         emap -> ws [i] = -emap -> ws [i];
628 >   /* Flip normal emap -> ws if port and required by its orientation */
629 >   setPhotonPortNormal(emap);
630  
631     normalize(emap -> ws);
632     VCOPY(emap -> us, emap -> src -> ss [SU]);
# Line 493 | Line 635 | static void cylPhotonOrigin (EmissionMap* emap)
635  
636     /* Get origin */
637     for (i = 0; i < 3; i++)
638 <      emap -> photonOrg [i] += v [SU] * emap -> src -> ss [SU][i] +
639 <                               emap -> src -> sloc [i];
638 >      emap -> photonOrg [i] +=
639 >         v [SU] * emap -> src -> ss [SU][i] + emap -> src -> sloc [i];
640  
641     /* Get hemisphere axes & aperture */
642     if (emap -> src -> sflags & SSPOT) {
# Line 521 | Line 663 | static void cylPhotonOrigin (EmissionMap* emap)
663  
664  
665  
666 < void getPhotonPorts (char **portList)
525 < /* Find geometry declared as photon ports from modifiers in portList */
526 < {
527 <   OBJECT i;
528 <   OBJREC *obj, *mat;
529 <   char **lp;  
530 <  
531 <   /* Init photon port objects */
532 <   photonPorts = NULL;
533 <  
534 <   if (!portList [0])
535 <      return;
536 <  
537 <   for (i = 0; i < nobjects; i++) {
538 <      obj = objptr(i);
539 <      mat = findmaterial(obj);
540 <      
541 <      /* Check if object is a surface and NOT a light source (duh) and
542 <       * resolve its material via any aliases, then check for inclusion in
543 <       * modifier list */
544 <      if (issurface(obj -> otype) && mat && !islight(mat -> otype)) {
545 <         for (lp = portList; *lp && strcmp(mat -> oname, *lp); lp++);
546 <        
547 <         if (*lp) {
548 <            /* Add photon port */
549 <            photonPorts = (SRCREC*)realloc(photonPorts,
550 <                                           (numPhotonPorts + 1) *
551 <                                           sizeof(SRCREC));
552 <            if (!photonPorts)
553 <               error(USER, "can't allocate photon ports");
554 <            
555 <            photonPorts [numPhotonPorts].so = obj;
556 <            photonPorts [numPhotonPorts].sflags = 0;
557 <        
558 <            if (!sfun [obj -> otype].of || !sfun[obj -> otype].of -> setsrc)
559 <               objerror(obj, USER, "illegal photon port");
560 <        
561 <            setsource(photonPorts + numPhotonPorts, obj);
562 <            numPhotonPorts++;
563 <         }
564 <      }
565 <   }
566 <  
567 <   if (!numPhotonPorts)
568 <      error(USER, "no valid photon ports found");
569 < }
666 > /* PHOTON EMISSION ROUTINES ---------------------------------------------- */
667  
668  
669  
# Line 600 | Line 697 | void initPhotonEmissionFuncs ()
697  
698  
699   void initPhotonEmission (EmissionMap *emap, float numPdfSamples)
700 < /* Initialize photon emission from partitioned light source emap -> src;
700 > /* Initialise photon emission from partitioned light source emap -> src;
701   * this involves integrating the flux emitted from the current photon
702   * origin emap -> photonOrg and setting up a PDF to sample the emission
703   * distribution with numPdfSamples samples */
# Line 609 | Line 706 | void initPhotonEmission (EmissionMap *emap, float numP
706     double phi, cosTheta, sinTheta, du, dv, dOmega, thetaScale;
707     EmissionSample* sample;
708     const OBJREC* mod =  findmaterial(emap -> src -> so);
709 <   static RAY r;
613 < #if 0  
614 <   static double lastCosNorm = FHUGE;
615 <   static SRCREC *lastSrc = NULL, *lastPort = NULL;
616 < #endif  
709 >   static RAY r;  
710  
618   setcolor(emap -> partFlux, 0, 0, 0);
619
711     photonOrigin [emap -> src -> so -> otype] (emap);
712 <   cosTheta = DOT(emap -> ws, emap -> wh);
622 <
623 < #if 0  
624 <   if (emap -> src == lastSrc && emap -> port == lastPort &&        
625 <       (emap -> src -> sflags & SDISTANT || mod -> omod == OVOID) &&
626 <       cosTheta == lastCosNorm)
627 <      /* Same source, port, and aperture-normal angle, and source is
628 <         either distant (and thus translationally invariant) or has
629 <         no modifier --> flux unchanged */
630 <      /* BUG: this optimisation ignores partial occlusion of ports and
631 <         can lead to erroneous "zero emission" bailouts.
632 <         It can also lead to bias with modifiers exhibiting high variance!
633 <         Disabled for now -- RS 12/13 */        
634 <      return;
635 <      
636 <   lastSrc = emap -> src;
637 <   lastPort = emap -> port;
638 <   lastCosNorm = cosTheta;      
639 < #endif
640 <        
641 <   /* Need to recompute flux & PDF */
712 >   setcolor(emap -> partFlux, 0, 0, 0);  
713     emap -> cdf = 0;
714     emap -> numSamples = 0;
715 +   cosTheta = DOT(emap -> ws, emap -> wh);        
716    
717 <   if (cosTheta <= 0 &&
718 <       sqrt(1 - sqr(cosTheta)) <= emap -> cosThetaMax + FTINY)
647 <      /* Aperture below surface; no emission from current origin */
717 >   if (cosTheta <= 0 && sqrt(1-sqr(cosTheta)) <= emap -> cosThetaMax + FTINY)
718 >      /* Aperture completely below surface; no emission from current origin */
719        return;
720    
721 <   if (mod -> omod == OVOID && !emap -> port &&
722 <       (cosTheta >= 1 - FTINY || (emap -> src -> sflags & SDISTANT &&
723 <        acos(cosTheta) + acos(emap -> cosThetaMax) <= 0.5 * PI))) {
721 >   if (
722 >      mod -> omod == OVOID && !emap -> port && (
723 >         cosTheta >= 1 - FTINY || (
724 >            emap -> src -> sflags & SDISTANT &&
725 >            acos(cosTheta) + acos(emap -> cosThetaMax) <= 0.5 * PI
726 >         )
727 >      )
728 >   ) {
729        /* Source is unmodified and has no port (which requires testing for
730           occlusion), and is either local with normal aligned aperture or
731 <         distant with aperture above surface; analytical flux & PDF */
732 <      setcolor(emap -> partFlux, mod -> oargs.farg [0],
733 <               mod -> oargs.farg [1], mod -> oargs.farg [2]);
731 >         distant with aperture above surface
732 >         --> get flux & PDF via analytical solution */
733 >      setcolor(
734 >         emap -> partFlux, mod -> oargs.farg [0], mod -> oargs.farg [1],
735 >         mod -> oargs.farg [2]
736 >      );
737  
738 <      /* Multiply radiance by Omega * dA to get flux */
739 <      scalecolor(emap -> partFlux,
740 <                 PI * cosTheta * (1 - sqr(max(emap -> cosThetaMax, 0))) *
741 <                 emap -> partArea);
738 >      /* Multiply radiance by projected Omega * dA to get flux */
739 >      scalecolor(
740 >         emap -> partFlux,
741 >         PI * cosTheta * (1 - sqr(max(emap -> cosThetaMax, 0))) *
742 >            emap -> partArea
743 >      );
744     }
745    
746     else {
747        /* Source is either modified, has a port, is local with off-normal
748 <         aperture, or distant with aperture partly below surface; get flux
749 <         via numerical integration */
748 >         aperture, or distant with aperture partly below surface
749 >         --> get flux via numerical integration */
750        thetaScale = (1 - emap -> cosThetaMax);
751        
752        /* Figga out numba of aperture samples for integration;
# Line 678 | Line 759 | void initPhotonEmission (EmissionMap *emap, float numP
759        thetaScale /= emap -> numTheta;
760        
761        /* Allocate PDF, baby */
762 <      sample = emap -> samples = (EmissionSample*)
763 <                                 realloc(emap -> samples,
764 <                                         sizeof(EmissionSample) *
765 <                                         emap -> numTheta * emap -> numPhi);
762 >      sample = emap -> samples = (EmissionSample*)realloc(
763 >         emap -> samples,
764 >         sizeof(EmissionSample) * emap -> numTheta * emap -> numPhi
765 >      );
766        if (!emap -> samples)
767           error(USER, "can't allocate emission PDF");    
768          
# Line 700 | Line 781 | void initPhotonEmission (EmissionMap *emap, float numP
781              rayorigin(&r, PRIMARY, NULL, NULL);
782              
783              for (i = 0; i < 3; i++)
784 <               r.rdir [i] = du * emap -> uh [i] + dv * emap -> vh [i] +
785 <                            cosTheta * emap -> wh [i];            
784 >               r.rdir [i] = (
785 >                  du * emap -> uh [i] + dv * emap -> vh [i] +
786 >                  cosTheta * emap -> wh [i]
787 >               );            
788                              
789              /* Sample behind surface? */
790              VCOPY(r.ron, emap -> ws);
# Line 720 | Line 803 | void initPhotonEmission (EmissionMap *emap, float numP
803                 continue;
804                
805              raytexture(&r, mod -> omod);
806 <            setcolor(r.rcol, mod -> oargs.farg [0], mod -> oargs.farg [1],
807 <                     mod -> oargs.farg [2]);
806 >            setcolor(
807 >               r.rcol, mod -> oargs.farg [0], mod -> oargs.farg [1],
808 >               mod -> oargs.farg [2]
809 >            );
810              multcolor(r.rcol, r.pcol);
811              
812              /* Multiply by cos(theta_surface) */
# Line 765 | Line 850 | void emitPhoton (const EmissionMap* emap, RAY* ray)
850     /* If we have a local glow source with a maximum radius, then
851        restrict our photon to the specified distance, otherwise we set
852        the limit imposed by photonMaxDist (or no limit if 0) */
853 <   if (mod -> otype == MAT_GLOW && !(emap -> src -> sflags & SDISTANT)
854 <                && mod -> oargs.farg[3] > FTINY)
853 >   if (
854 >      mod -> otype == MAT_GLOW &&
855 >      !(emap -> src -> sflags & SDISTANT) && mod -> oargs.farg[3] > FTINY
856 >   )
857        ray -> rmax = mod -> oargs.farg[3];
858     else
859        ray -> rmax = photonMaxDist;
# Line 774 | Line 861 | void emitPhoton (const EmissionMap* emap, RAY* ray)
861    
862     if (!emap -> numSamples) {
863        /* Source is unmodified and has no port, and either local with
864 <         normal aligned aperture, or distant with aperture above surface;
865 <         use cosine weighted distribution */
866 <      cosThetaSqr = 1 - pmapRandom(emitState) *
867 <                        (1 - sqr(max(emap -> cosThetaMax, 0)));
864 >         normal aligned aperture, or distant with aperture above surface
865 >         --> use cosine weighted distribution */
866 >      cosThetaSqr = (1 -
867 >         pmapRandom(emitState) * (1 - sqr(max(emap -> cosThetaMax, 0)))
868 >      );
869        cosTheta = sqrt(cosThetaSqr);
870        sinTheta = sqrt(1 - cosThetaSqr);
871        phi = 2 * PI * pmapRandom(emitState);
872 <      setcolor(ray -> rcol, mod -> oargs.farg [0], mod -> oargs.farg [1],
873 <               mod -> oargs.farg [2]);
872 >      setcolor(
873 >         ray -> rcol, mod -> oargs.farg [0], mod -> oargs.farg [1],
874 >         mod -> oargs.farg [2]
875 >      );
876     }
877    
878     else {
879        /* Source is either modified, has a port, is local with off-normal
880 <         aperture, or distant with aperture partly below surface; choose
881 <         direction from constructed cumulative distribution function with
882 <         Monte Carlo inversion using binary search. */
880 >         aperture, or distant with aperture partly below surface
881 >         --> choose  direction from constructed cumulative distribution
882 >         function with Monte Carlo inversion using binary search. */
883        du = pmapRandom(emitState) * emap -> cdf;
884        lo = 1;
885        hi = emap -> numSamples;
# Line 805 | Line 895 | void emitPhoton (const EmissionMap* emap, RAY* ray)
895        }
896        
897        /* This is a uniform mapping, mon */
898 <      cosTheta = 1 - (sample -> theta + pmapRandom(emitState)) *
899 <                     (1 - emap -> cosThetaMax) / emap -> numTheta;
898 >      cosTheta = (1 -
899 >         (sample -> theta + pmapRandom(emitState)) *
900 >         (1 - emap -> cosThetaMax) / emap -> numTheta
901 >      );
902        sinTheta = sqrt(1 - sqr(cosTheta));
903        phi = 2 * PI * (sample -> phi + pmapRandom(emitState)) / emap -> numPhi;
904        copycolor(ray -> rcol, sample -> pdf);
# Line 840 | Line 932 | void emitPhoton (const EmissionMap* emap, RAY* ray)
932  
933  
934  
935 + /* SOURCE CONTRIBS FROM DIRECT / VOLUME PHOTONS -------------------------- */
936 +
937 +
938 +
939   void multDirectPmap (RAY *r)
940   /* Factor irradiance from direct photons into r -> rcol; interface to
941   * direct() */
# Line 863 | Line 959 | void inscatterVolumePmap (RAY *r, COLOR inscatter)
959     /* Add ambient in-scattering via lookup callback */
960     (volumePmap -> lookup)(volumePmap, r, inscatter);
961   }
962 +

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines