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.18 by rschregle, Fri Aug 7 01:21:13 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 based on its orientation */
141 > {
142 >   /* Extract photon port orientation flags, set surface normal as follows:
143 >      -- Port oriented forwards --> flip surface normal to point
144 >         outwards, since normal points inwards per mkillum convention)
145 >      -- Port oriented backwards --> surface normal is NOT flipped,
146 >         since it already points inwards.
147 >      -- Port is bidirectionally/bilaterally oriented --> flip normal based
148 >         on the parity of the current partition emap -> partitionCnt.
149 >         In this case, photon emission alternates between port front/back
150 >         faces for consecutive partitions.
151 >   */
152 >   int i, portFlags = PMAP_GETPORTFLAGS(emap -> port -> sflags);
153 >
154 >   if (
155 >      portFlags == PMAP_PORTFWD ||
156 >      portFlags == PMAP_PORTBI && !(emap -> partitionCnt & 1)
157 >   )
158 >      for (i = 0; i < 3; i++)    
159 >         emap -> ws [i] = -emap -> ws [i];
160 > }
161 >
162 >
163 >
164 > /* SOURCE / PHOTON PORT PARTITIONING ROUTINES----------------------------- */
165 >  
166 >
167 >
168 > static int flatPhotonPartition2 (
169 >   EmissionMap* emap, unsigned long mp, FVECT cent, FVECT u, FVECT v,
170 >   double du2, double dv2
171 > )
172   /* Recursive part of flatPhotonPartition(..) */
173   {
174     FVECT newct, newax;
# Line 43 | Line 177 | static int flatPhotonPartition2 (EmissionMap* emap, un
177     if (mp > emap -> maxPartitions) {
178        /* Enlarge partition array */
179        emap -> maxPartitions <<= 1;
180 <      emap -> partitions = (unsigned char*)realloc(emap -> partitions,
181 <                                           emap -> maxPartitions >> 1);
180 >      emap -> partitions = (unsigned char*)realloc(
181 >         emap -> partitions, emap -> maxPartitions >> 1
182 >      );
183  
184        if (!emap -> partitions)
185           error(USER, "can't allocate source partitions");
186  
187 <      memset(emap -> partitions + (emap -> maxPartitions >> 2), 0,
188 <             emap -> maxPartitions >> 2);
187 >      memset(
188 >         emap -> partitions + (emap -> maxPartitions >> 2), 0,
189 >         emap -> maxPartitions >> 2
190 >      );
191     }
192    
193     if (du2 * dv2 <= 1) {                /* hit limit? */
# Line 111 | Line 248 | static void flatPhotonPartition (EmissionMap* emap)
248     vp = emap -> src -> ss [SV];
249     dv2 = DOT(vp, vp) / emap -> partArea;
250     emap -> partitionCnt = 0;
251 <   emap -> numPartitions = flatPhotonPartition2(emap, 1, emap -> src -> sloc,
252 <                                                emap -> src -> ss [SU],
253 <                                                emap -> src -> ss [SV],
254 <                                                du2, dv2);
251 >   emap -> numPartitions = flatPhotonPartition2(
252 >      emap, 1, emap -> src -> sloc,
253 >      emap -> src -> ss [SU], emap -> src -> ss [SV], du2, dv2
254 >   );
255     emap -> partitionCnt = 0;
256     emap -> partArea = emap -> src -> ss2 / emap -> numPartitions;
257   }
# Line 126 | Line 263 | static void sourcePhotonPartition (EmissionMap* emap)
263     distant source */
264   {  
265     if (emap -> port) {
266 <      /* Partition photon port */
266 >      /* Relay partitioning to photon port */
267        SRCREC *src = emap -> src;
268        emap -> src = emap -> port;
269        photonPartition [emap -> src -> so -> otype] (emap);
270 +      PMAP_SETNUMPARTITIONS(emap);
271        emap -> src = src;
272     }
273    
274     else {
275 <      /* No photon ports defined, so partition scene cube faces */
275 >      /* No photon ports defined; partition scene cube faces (SUBOPTIMAL) */
276        memset(emap -> partitions, 0, emap -> maxPartitions >> 1);
277        setpart(emap -> partitions, 0, S0);
278        emap -> partitionCnt = 0;
# Line 156 | Line 294 | static void spherePhotonPartition (EmissionMap* emap)
294     memset(emap -> partitions, 0, emap -> maxPartitions >> 1);
295     setpart(emap -> partitions, 0, S0);
296     emap -> partArea = 4 * PI * sqr(emap -> src -> srad);
297 <   emap -> numPartitions = emap -> partArea /
298 <                           sqr(srcsizerat * thescene.cusize);
297 >   emap -> numPartitions =
298 >      emap -> partArea / sqr(srcsizerat * thescene.cusize);
299  
300     numTheta = max(sqrt(2 * emap -> numPartitions / PI) + 0.5, 1);
301     numPhi = 0.5 * PI * numTheta + 0.5;
# Line 169 | Line 307 | static void spherePhotonPartition (EmissionMap* emap)
307  
308  
309  
310 < static int cylPhotonPartition2 (EmissionMap* emap, unsigned long mp,
311 <                                FVECT cent, FVECT axis, double d2)
310 > static int cylPhotonPartition2 (
311 >   EmissionMap* emap, unsigned long mp, FVECT cent, FVECT axis, double d2
312 > )
313   /* Recursive part of cyPhotonPartition(..) */
314   {
315     FVECT newct, newax;
# Line 179 | Line 318 | static int cylPhotonPartition2 (EmissionMap* emap, uns
318     if (mp > emap -> maxPartitions) {
319        /* Enlarge partition array */
320        emap -> maxPartitions <<= 1;
321 <      emap -> partitions = (unsigned char*)realloc(emap -> partitions,
322 <                                                   emap -> maxPartitions >> 1);
321 >      emap -> partitions = (unsigned char*)realloc(
322 >         emap -> partitions, emap -> maxPartitions >> 1
323 >      );
324        if (!emap -> partitions)
325           error(USER, "can't allocate source partitions");
326          
327 <      memset(emap -> partitions + (emap -> maxPartitions >> 2), 0,
328 <            emap -> maxPartitions >> 2);
327 >      memset(
328 >         emap -> partitions + (emap -> maxPartitions >> 2), 0,
329 >         emap -> maxPartitions >> 2
330 >      );
331     }
332    
333     if (d2 <= 1) {
# Line 232 | Line 374 | static void cylPhotonPartition (EmissionMap* emap)
374     d2 *= d2 * DOT(emap -> src -> ss [SU], emap -> src -> ss [SU]);
375  
376     emap -> partitionCnt = 0;
377 <   emap -> numPartitions = cylPhotonPartition2(emap, 1, emap -> src -> sloc,
378 <                                               emap -> src -> ss [SU], d2);
377 >   emap -> numPartitions = cylPhotonPartition2(
378 >      emap, 1, emap -> src -> sloc, emap -> src -> ss [SU], d2
379 >   );
380     emap -> partitionCnt = 0;
381     emap -> partArea = PI * emap -> src -> ss2 / emap -> numPartitions;
382   }
383  
384  
385  
386 + /* PHOTON ORIGIN ROUTINES ------------------------------------------------ */
387 +
388 +
389 +
390   static void flatPhotonOrigin (EmissionMap* emap)
391   /* Init emission map with photon origin and associated surface axes on
392     flat light source surface. Also sets source aperture and sampling
# Line 251 | Line 398 | static void flatPhotonOrigin (EmissionMap* emap)
398     cent [0] = cent [1] = cent [2] = 0;
399     size [0] = size [1] = size [2] = emap -> maxPartitions;
400     parr [0] = 0;
401 <   parr [1] = emap -> partitionCnt;
401 >   parr [1] = PMAP_GETPARTITION(emap);
402    
403     if (!skipparts(cent, size, parr, emap -> partitions))
404        error(CONSISTENCY, "bad source partition in flatPhotonOrigin");
# Line 267 | Line 414 | static void flatPhotonOrigin (EmissionMap* emap)
414        
415     /* Get origin */
416     for (i = 0; i < 3; i++)
417 <      emap -> photonOrg [i] = emap -> src -> sloc [i] +
418 <                              vpos [SU] * emap -> src -> ss [SU][i] +
419 <                              vpos [SV] * emap -> src -> ss [SV][i] +
420 <                              vpos [SW] * emap -> src -> ss [SW][i];
417 >      emap -> photonOrg [i] =
418 >         emap -> src -> sloc [i] +
419 >         vpos [SU] * emap -> src -> ss [SU][i] +
420 >         vpos [SV] * emap -> src -> ss [SV][i] +
421 >         vpos [SW] * emap -> src -> ss [SW][i];
422                                
423     /* Get surface axes */
424     VCOPY(emap -> us, emap -> src -> ss [SU]);
425     normalize(emap -> us);
426     VCOPY(emap -> ws, emap -> src -> ss [SW]);
427 <
428 <   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 <        
427 >   /* Flip normal emap -> ws if port and required by its orientation */
428 >   setPhotonPortNormal(emap);
429     fcross(emap -> vs, emap -> ws, emap -> us);
430    
431     /* Get hemisphere axes & aperture */
# Line 320 | Line 463 | static void spherePhotonOrigin (EmissionMap* emap)
463     RREAL cosTheta, sinTheta, phi;
464  
465     /* Get current partition */
466 <   numTheta = max(sqrt(2 * emap -> numPartitions / PI) + 0.5, 1);
466 >   numTheta = max(sqrt(2 * PMAP_GETNUMPARTITIONS(emap) / PI) + 0.5, 1);
467     numPhi = 0.5 * PI * numTheta + 0.5;
468  
469 <   t = emap -> partitionCnt / numPhi;
470 <   p = emap -> partitionCnt - t * numPhi;
469 >   t = PMAP_GETPARTITION(emap) / numPhi;
470 >   p = PMAP_GETPARTITION(emap) - t * numPhi;
471  
472     emap -> ws [2] = cosTheta = 1 - 2 * (t + pmapRandom(partState)) / numTheta;
473     sinTheta = sqrt(1 - sqr(cosTheta));
474     phi = 2 * PI * (p + pmapRandom(partState)) / numPhi;
475     emap -> ws [0] = cos(phi) * sinTheta;
476     emap -> ws [1] = sin(phi) * sinTheta;
477 +   /* Flip normal emap -> ws if port and required by its orientation */
478 +   setPhotonPortNormal(emap);
479  
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
480     /* Get surface axes us & vs perpendicular to ws */
481     do {
482        emap -> vs [0] = emap -> vs [1] = emap -> vs [2] = 0;
# Line 387 | Line 526 | static void sourcePhotonOrigin (EmissionMap* emap)
526     RREAL du, dv;                            
527        
528     if (emap -> port) {
529 <      /* Get origin on photon port */
529 >      /* Relay to photon port; get origin on its surface */
530        SRCREC *src = emap -> src;
531        emap -> src = emap -> port;
532        photonOrigin [emap -> src -> so -> otype] (emap);
# Line 395 | Line 534 | static void sourcePhotonOrigin (EmissionMap* emap)
534     }
535    
536     else {
537 <      /* No ports defined, so get origin on scene cube face and SUFFA! */
537 >      /* No ports defined, so get origin on scene cube face (SUBOPTIMAL) */
538        /* Get current face from partition number */
539        partsPerDim = 1 / srcsizerat;
540        partsPerFace = sqr(partsPerDim);
541        face = emap -> partitionCnt / partsPerFace;
403
542        if (!(emap -> partitionCnt % partsPerFace)) {
543           /* Skipped to a new face; get its normal */
544           emap -> ws [0] = emap -> ws [1] = emap -> ws [2] = 0;
# Line 421 | Line 559 | static void sourcePhotonOrigin (EmissionMap* emap)
559  
560        /* Jittered destination point within partition */
561        for (i = 0; i < 3; i++)
562 <         emap -> photonOrg [i] = thescene.cuorg [i] +
563 <                                 thescene.cusize * (0.5 + du * emap -> us [i] +
564 <                                                    dv * emap -> vs [i] +
565 <                                                    0.5 * emap -> ws [i]);
562 >         emap -> photonOrg [i] = thescene.cuorg [i] + thescene.cusize * (
563 >            0.5 + du * emap -> us [i] + dv * emap -> vs [i] +
564 >            0.5 * emap -> ws [i]
565 >         );
566     }
567    
568     /* Get hemisphere axes & aperture */
# Line 457 | Line 595 | static void cylPhotonOrigin (EmissionMap* emap)
595     cent [0] = cent [1] = cent [2] = 0;
596     size [0] = size [1] = size [2] = emap -> maxPartitions;
597     parr [0] = 0;
598 <   parr [1] = emap -> partitionCnt;
598 >   parr [1] = PMAP_GETPARTITION(emap);
599  
600     if (!skipparts(cent, size, parr, emap -> partitions))
601        error(CONSISTENCY, "bad source partition in cylPhotonOrigin");
# Line 476 | Line 614 | static void cylPhotonOrigin (EmissionMap* emap)
614  
615     /* Get surface axes */
616     for (i = 0; i < 3; i++)
617 <      emap -> photonOrg [i] = emap -> ws [i] =
618 <                              (v [SV] * emap -> src -> ss [SV][i] +
619 <                               v [SW] * emap -> src -> ss [SW][i]) / 0.8559;
617 >      emap -> photonOrg [i] = emap -> ws [i] = (
618 >         v [SV] * emap -> src -> ss [SV][i] +
619 >         v [SW] * emap -> src -> ss [SW][i]
620 >      ) / 0.8559;
621  
622 <   if (emap -> port)
623 <      /* 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];
622 >   /* Flip normal emap -> ws if port and required by its orientation */
623 >   setPhotonPortNormal(emap);
624  
625     normalize(emap -> ws);
626     VCOPY(emap -> us, emap -> src -> ss [SU]);
# Line 493 | Line 629 | static void cylPhotonOrigin (EmissionMap* emap)
629  
630     /* Get origin */
631     for (i = 0; i < 3; i++)
632 <      emap -> photonOrg [i] += v [SU] * emap -> src -> ss [SU][i] +
633 <                               emap -> src -> sloc [i];
632 >      emap -> photonOrg [i] +=
633 >         v [SU] * emap -> src -> ss [SU][i] + emap -> src -> sloc [i];
634  
635     /* Get hemisphere axes & aperture */
636     if (emap -> src -> sflags & SSPOT) {
# Line 521 | Line 657 | static void cylPhotonOrigin (EmissionMap* emap)
657  
658  
659  
660 < 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 < }
660 > /* PHOTON EMISSION ROUTINES ---------------------------------------------- */
661  
662  
663  
# Line 600 | Line 691 | void initPhotonEmissionFuncs ()
691  
692  
693   void initPhotonEmission (EmissionMap *emap, float numPdfSamples)
694 < /* Initialize photon emission from partitioned light source emap -> src;
694 > /* Initialise photon emission from partitioned light source emap -> src;
695   * this involves integrating the flux emitted from the current photon
696   * origin emap -> photonOrg and setting up a PDF to sample the emission
697   * distribution with numPdfSamples samples */
# Line 609 | Line 700 | void initPhotonEmission (EmissionMap *emap, float numP
700     double phi, cosTheta, sinTheta, du, dv, dOmega, thetaScale;
701     EmissionSample* sample;
702     const OBJREC* mod =  findmaterial(emap -> src -> so);
703 <   static RAY r;
613 < #if 0  
614 <   static double lastCosNorm = FHUGE;
615 <   static SRCREC *lastSrc = NULL, *lastPort = NULL;
616 < #endif  
703 >   static RAY r;  
704  
618   setcolor(emap -> partFlux, 0, 0, 0);
619
705     photonOrigin [emap -> src -> so -> otype] (emap);
706 <   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 */
706 >   setcolor(emap -> partFlux, 0, 0, 0);  
707     emap -> cdf = 0;
708     emap -> numSamples = 0;
709 +   cosTheta = DOT(emap -> ws, emap -> wh);        
710    
711 <   if (cosTheta <= 0 &&
712 <       sqrt(1 - sqr(cosTheta)) <= emap -> cosThetaMax + FTINY)
647 <      /* Aperture below surface; no emission from current origin */
711 >   if (cosTheta <= 0 && sqrt(1-sqr(cosTheta)) <= emap -> cosThetaMax + FTINY)
712 >      /* Aperture completely below surface; no emission from current origin */
713        return;
714    
715 <   if (mod -> omod == OVOID && !emap -> port &&
716 <       (cosTheta >= 1 - FTINY || (emap -> src -> sflags & SDISTANT &&
717 <        acos(cosTheta) + acos(emap -> cosThetaMax) <= 0.5 * PI))) {
715 >   if (
716 >      mod -> omod == OVOID && !emap -> port && (
717 >         cosTheta >= 1 - FTINY || (
718 >            emap -> src -> sflags & SDISTANT &&
719 >            acos(cosTheta) + acos(emap -> cosThetaMax) <= 0.5 * PI
720 >         )
721 >      )
722 >   ) {
723        /* Source is unmodified and has no port (which requires testing for
724           occlusion), and is either local with normal aligned aperture or
725 <         distant with aperture above surface; analytical flux & PDF */
726 <      setcolor(emap -> partFlux, mod -> oargs.farg [0],
727 <               mod -> oargs.farg [1], mod -> oargs.farg [2]);
725 >         distant with aperture above surface
726 >         --> get flux & PDF via analytical solution */
727 >      setcolor(
728 >         emap -> partFlux, mod -> oargs.farg [0], mod -> oargs.farg [1],
729 >         mod -> oargs.farg [2]
730 >      );
731  
732 <      /* Multiply radiance by Omega * dA to get flux */
733 <      scalecolor(emap -> partFlux,
734 <                 PI * cosTheta * (1 - sqr(max(emap -> cosThetaMax, 0))) *
735 <                 emap -> partArea);
732 >      /* Multiply radiance by projected Omega * dA to get flux */
733 >      scalecolor(
734 >         emap -> partFlux,
735 >         PI * cosTheta * (1 - sqr(max(emap -> cosThetaMax, 0))) *
736 >            emap -> partArea
737 >      );
738     }
739    
740     else {
741        /* Source is either modified, has a port, is local with off-normal
742 <         aperture, or distant with aperture partly below surface; get flux
743 <         via numerical integration */
742 >         aperture, or distant with aperture partly below surface
743 >         --> get flux via numerical integration */
744        thetaScale = (1 - emap -> cosThetaMax);
745        
746        /* Figga out numba of aperture samples for integration;
# Line 678 | Line 753 | void initPhotonEmission (EmissionMap *emap, float numP
753        thetaScale /= emap -> numTheta;
754        
755        /* Allocate PDF, baby */
756 <      sample = emap -> samples = (EmissionSample*)
757 <                                 realloc(emap -> samples,
758 <                                         sizeof(EmissionSample) *
759 <                                         emap -> numTheta * emap -> numPhi);
756 >      sample = emap -> samples = (EmissionSample*)realloc(
757 >         emap -> samples,
758 >         sizeof(EmissionSample) * emap -> numTheta * emap -> numPhi
759 >      );
760        if (!emap -> samples)
761           error(USER, "can't allocate emission PDF");    
762          
# Line 700 | Line 775 | void initPhotonEmission (EmissionMap *emap, float numP
775              rayorigin(&r, PRIMARY, NULL, NULL);
776              
777              for (i = 0; i < 3; i++)
778 <               r.rdir [i] = du * emap -> uh [i] + dv * emap -> vh [i] +
779 <                            cosTheta * emap -> wh [i];            
778 >               r.rdir [i] = (
779 >                  du * emap -> uh [i] + dv * emap -> vh [i] +
780 >                  cosTheta * emap -> wh [i]
781 >               );            
782                              
783              /* Sample behind surface? */
784              VCOPY(r.ron, emap -> ws);
# Line 720 | Line 797 | void initPhotonEmission (EmissionMap *emap, float numP
797                 continue;
798                
799              raytexture(&r, mod -> omod);
800 <            setcolor(r.rcol, mod -> oargs.farg [0], mod -> oargs.farg [1],
801 <                     mod -> oargs.farg [2]);
800 >            setcolor(
801 >               r.rcol, mod -> oargs.farg [0], mod -> oargs.farg [1],
802 >               mod -> oargs.farg [2]
803 >            );
804              multcolor(r.rcol, r.pcol);
805              
806              /* Multiply by cos(theta_surface) */
# Line 765 | Line 844 | void emitPhoton (const EmissionMap* emap, RAY* ray)
844     /* If we have a local glow source with a maximum radius, then
845        restrict our photon to the specified distance, otherwise we set
846        the limit imposed by photonMaxDist (or no limit if 0) */
847 <   if (mod -> otype == MAT_GLOW && !(emap -> src -> sflags & SDISTANT)
848 <                && mod -> oargs.farg[3] > FTINY)
847 >   if (
848 >      mod -> otype == MAT_GLOW &&
849 >      !(emap -> src -> sflags & SDISTANT) && mod -> oargs.farg[3] > FTINY
850 >   )
851        ray -> rmax = mod -> oargs.farg[3];
852     else
853        ray -> rmax = photonMaxDist;
# Line 774 | Line 855 | void emitPhoton (const EmissionMap* emap, RAY* ray)
855    
856     if (!emap -> numSamples) {
857        /* Source is unmodified and has no port, and either local with
858 <         normal aligned aperture, or distant with aperture above surface;
859 <         use cosine weighted distribution */
860 <      cosThetaSqr = 1 - pmapRandom(emitState) *
861 <                        (1 - sqr(max(emap -> cosThetaMax, 0)));
858 >         normal aligned aperture, or distant with aperture above surface
859 >         --> use cosine weighted distribution */
860 >      cosThetaSqr = (1 -
861 >         pmapRandom(emitState) * (1 - sqr(max(emap -> cosThetaMax, 0)))
862 >      );
863        cosTheta = sqrt(cosThetaSqr);
864        sinTheta = sqrt(1 - cosThetaSqr);
865        phi = 2 * PI * pmapRandom(emitState);
866 <      setcolor(ray -> rcol, mod -> oargs.farg [0], mod -> oargs.farg [1],
867 <               mod -> oargs.farg [2]);
866 >      setcolor(
867 >         ray -> rcol, mod -> oargs.farg [0], mod -> oargs.farg [1],
868 >         mod -> oargs.farg [2]
869 >      );
870     }
871    
872     else {
873        /* Source is either modified, has a port, is local with off-normal
874 <         aperture, or distant with aperture partly below surface; choose
875 <         direction from constructed cumulative distribution function with
876 <         Monte Carlo inversion using binary search. */
874 >         aperture, or distant with aperture partly below surface
875 >         --> choose  direction from constructed cumulative distribution
876 >         function with Monte Carlo inversion using binary search. */
877        du = pmapRandom(emitState) * emap -> cdf;
878        lo = 1;
879        hi = emap -> numSamples;
# Line 805 | Line 889 | void emitPhoton (const EmissionMap* emap, RAY* ray)
889        }
890        
891        /* This is a uniform mapping, mon */
892 <      cosTheta = 1 - (sample -> theta + pmapRandom(emitState)) *
893 <                     (1 - emap -> cosThetaMax) / emap -> numTheta;
892 >      cosTheta = (1 -
893 >         (sample -> theta + pmapRandom(emitState)) *
894 >         (1 - emap -> cosThetaMax) / emap -> numTheta
895 >      );
896        sinTheta = sqrt(1 - sqr(cosTheta));
897        phi = 2 * PI * (sample -> phi + pmapRandom(emitState)) / emap -> numPhi;
898        copycolor(ray -> rcol, sample -> pdf);
# Line 840 | Line 926 | void emitPhoton (const EmissionMap* emap, RAY* ray)
926  
927  
928  
929 + /* SOURCE CONTRIBS FROM DIRECT / VOLUME PHOTONS -------------------------- */
930 +
931 +
932 +
933   void multDirectPmap (RAY *r)
934   /* Factor irradiance from direct photons into r -> rcol; interface to
935   * direct() */
# Line 863 | Line 953 | void inscatterVolumePmap (RAY *r, COLOR inscatter)
953     /* Add ambient in-scattering via lookup callback */
954     (volumePmap -> lookup)(volumePmap, r, inscatter);
955   }
956 +

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines