30 |
|
#include <sys/mman.h> |
31 |
|
#include <sys/wait.h> |
32 |
|
|
33 |
– |
#define PMAP_REV "$Revision$" |
33 |
|
|
34 |
|
|
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 |
– |
|
35 |
|
void savePmaps (const PhotonMap **pmaps, int argc, char **argv) |
36 |
|
{ |
37 |
|
unsigned t; |
43 |
|
} |
44 |
|
|
45 |
|
|
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 |
– |
|
46 |
|
|
47 |
|
static int photonParticipate (RAY *ray) |
48 |
|
/* Trace photon through participating medium. Returns 1 if passed through, |
696 |
|
/* Precompute photon irradiance if necessary */ |
697 |
|
if (preCompPmap) |
698 |
|
preComputeGlobal(preCompPmap); |
781 |
– |
} |
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); |
804 |
– |
|
805 |
– |
/* Need at least 2 photons */ |
806 |
– |
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 |
699 |
|
} |