2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
7 // Ward 97 Tone Reproduction Operator
8 // **********************************
10 const double DisplayLuminanceMax
=80.0;
13 bool HistogramCeiling(ArrayT
<unsigned long>& Bins
, double DeltaBin
)
15 unsigned long Total
=0;
18 for (BinNr
=0; BinNr
<Bins
.Size(); BinNr
++) Total
+=Bins
[BinNr
];
20 unsigned long Tolerance
=(unsigned long)(0.025*Total
);
21 unsigned long Trimmings
;
27 for (BinNr
=0; BinNr
<Bins
.Size(); BinNr
++) Total
+=Bins
[BinNr
];
29 if (Total
<Tolerance
) return false;
31 for (BinNr
=0; BinNr
<Bins
.Size(); BinNr
++)
33 unsigned long Ceiling
=(unsigned long)(Total
*DeltaBin
/log(DisplayLuminanceMax
));
35 if (Bins
[BinNr
]>Ceiling
)
37 Trimmings
+=Bins
[BinNr
]-Ceiling
;
41 } while (Trimmings
>Tolerance
);
47 double MaxAbsCoeff(const ArrayT
<double>& Coeffs
)
49 if (Coeffs
.Size()==0) return 0.0;
51 double m
=fabs(Coeffs
[0]);
53 for (unsigned long CoeffNr
=1; CoeffNr
<Coeffs
.Size(); CoeffNr
++)
54 if (fabs(Coeffs
[CoeffNr
])>m
) m
=fabs(Coeffs
[CoeffNr
]);
60 // Diese Funktion findet einen Tone-Reproduction Operator (Funktion) nach Ward97,
61 // anhand dessen die Energiewerte der Patches in RGB-Tripel umgewandelt werden.
62 void ToneReproduction(const cf::SceneGraph::BspTreeNodeT
& Map
)
64 printf("\n%-50s %s\n", "*** Tone Reproduction (Ward97) ***", GetTimeSinceProgramStart());
66 const unsigned long NR_OF_SH_COEFFS
=cf::SceneGraph::SHLMapManT::NrOfBands
* cf::SceneGraph::SHLMapManT::NrOfBands
;
67 const unsigned long NrOfBins
=300;
68 ArrayT
<unsigned long> Bins
;
71 for (BinNr
=0; BinNr
<NrOfBins
; BinNr
++) Bins
.PushBack(0);
73 double MinBrightness
=log(0.0001);
74 double MaxBrightness
=MinBrightness
;
76 // Suche die MaxBrightness
77 for (unsigned long FaceNr
=0; FaceNr
<Map
.FaceChildren
.Size(); FaceNr
++)
78 for (unsigned long PatchNr
=0; PatchNr
<Patches
[FaceNr
].Size(); PatchNr
++)
80 if (!Patches
[FaceNr
][PatchNr
].InsideFace
) continue;
82 double Luminance
=MaxAbsCoeff(Patches
[FaceNr
][PatchNr
].SHCoeffs_TotalTransfer
);
84 if (Luminance
<0.0001) continue;
85 double Brightness
=log(Luminance
);
87 if (Brightness
>MaxBrightness
) MaxBrightness
=Brightness
;
90 printf("MinBrightness: %9.5f\n", MinBrightness
);
91 printf("MaxBrightness: %9.5f\n", MaxBrightness
);
93 // Bilde das Histogram
94 for (unsigned long FaceNr
=0; FaceNr
<Map
.FaceChildren
.Size(); FaceNr
++)
95 for (unsigned long PatchNr
=0; PatchNr
<Patches
[FaceNr
].Size(); PatchNr
++)
97 if (!Patches
[FaceNr
][PatchNr
].InsideFace
) continue;
99 double Luminance
=MaxAbsCoeff(Patches
[FaceNr
][PatchNr
].SHCoeffs_TotalTransfer
);
101 if (Luminance
<0.0001) Luminance
=0.0001;
102 double Brightness
=log(Luminance
);
104 BinNr
=(unsigned long)((Brightness
-MinBrightness
)/(MaxBrightness
-MinBrightness
)*NrOfBins
);
105 if (BinNr
>NrOfBins
-1) BinNr
=NrOfBins
-1;
109 /***********************************************************************************************
110 printf("Writing histogram file...\n");
111 FILE* FilePtr=fopen("histogr.dat", "wb");
115 fwrite(&NrOfBins, sizeof(NrOfBins), 1, FilePtr);
117 for (BinNr=0; BinNr<Bins.Size(); BinNr++)
118 fwrite(&Bins[BinNr], sizeof(unsigned long), 1, FilePtr);
122 else printf(" WARNING: Unable to write histogram data file!\n");
123 ***********************************************************************************************/
125 // Arbeite die Ceiling in das Histogram ein
126 if (HistogramCeiling(Bins
, (MaxBrightness
-MinBrightness
)/double(NrOfBins
)))
128 // Bilde das Integral über Bins[0..NrOfBins-1] als einfache Summe und normalisiere
129 ArrayT
<double> BinsNormSum
;
132 for (BinNr
=0; BinNr
<Bins
.Size(); BinNr
++)
134 BinsNormSum
.PushBack(Sum
);
137 for (BinNr
=0; BinNr
<Bins
.Size(); BinNr
++) BinsNormSum
[BinNr
]/=double(Sum
);
139 // Ordne nun anhand der DisplayLuminanceMax^BinsNormSum[i] Funktion RGB-Werte zu
140 for (unsigned long FaceNr
=0; FaceNr
<Map
.FaceChildren
.Size(); FaceNr
++)
141 for (unsigned long PatchNr
=0; PatchNr
<Patches
[FaceNr
].Size(); PatchNr
++)
143 if (!Patches
[FaceNr
][PatchNr
].InsideFace
) continue;
145 ArrayT
<double>& TotalTransfer
=Patches
[FaceNr
][PatchNr
].SHCoeffs_TotalTransfer
;
146 double Luminance
=MaxAbsCoeff(TotalTransfer
);
148 if (Luminance
<0.0001) Luminance
=0.0001;
149 double Brightness
=log(Luminance
);
151 BinNr
=(unsigned long)((Brightness
-MinBrightness
)/(MaxBrightness
-MinBrightness
)*NrOfBins
);
152 if (BinNr
>NrOfBins
-1) BinNr
=NrOfBins
-1;
154 double DisplayLuminance
=pow(DisplayLuminanceMax
, BinsNormSum
[BinNr
]);
156 for (unsigned long CoeffNr
=0; CoeffNr
<NR_OF_SH_COEFFS
; CoeffNr
++)
157 TotalTransfer
[CoeffNr
]*=DisplayLuminance
/Luminance
;
161 // Skaliere die nun vorhandenen RGB-Werte der Patches linear in den gewünschten [0, 255] Bereich.
163 for (unsigned long FaceNr
=0; FaceNr
<Map
.FaceChildren
.Size(); FaceNr
++)
164 for (unsigned long PatchNr
=0; PatchNr
<Patches
[FaceNr
].Size(); PatchNr
++)
166 if (!Patches
[FaceNr
][PatchNr
].InsideFace
) continue;
168 for (unsigned long CoeffNr
=0; CoeffNr
<NR_OF_SH_COEFFS
; CoeffNr
++)
169 if (fabs(Patches
[FaceNr
][PatchNr
].SHCoeffs_TotalTransfer
[CoeffNr
])>Max
) Max
=fabs(Patches
[FaceNr
][PatchNr
].SHCoeffs_TotalTransfer
[CoeffNr
]);
172 if (Max
==0.0) Max
=1.0;
174 // The 1.0 was 255.0 for CaLight, and should probably be 0.7... here (the fabs() value of the min/max values reported by DirectLighting()).
177 for (unsigned long FaceNr
=0; FaceNr
<Map
.FaceChildren
.Size(); FaceNr
++)
178 for (unsigned long PatchNr
=0; PatchNr
<Patches
[FaceNr
].Size(); PatchNr
++)
179 for (unsigned long CoeffNr
=0; CoeffNr
<NR_OF_SH_COEFFS
; CoeffNr
++)
180 Patches
[FaceNr
][PatchNr
].SHCoeffs_TotalTransfer
[CoeffNr
]*=Max
;