00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "luxrays/utils/sdl/spd.h"
00023 #include "luxrays/utils/sdl/data/xyzbasis.h"
00024
00025 using namespace luxrays;
00026 using namespace luxrays::sdl;
00027
00028 void SPD::AllocateSamples(u_int n) {
00029
00030 samples = AllocAligned<float>(n);
00031 }
00032
00033 void SPD::FreeSamples() {
00034
00035 if (samples)
00036 FreeAligned(samples);
00037 }
00038
00039 void SPD::Normalize() {
00040 float max = 0.f;
00041
00042 for (u_int i = 0; i < nSamples; ++i)
00043 if(samples[i] > max)
00044 max = samples[i];
00045
00046 const float scale = 1.f / max;
00047
00048 for (u_int i = 0; i < nSamples; ++i)
00049 samples[i] *= scale;
00050 }
00051
00052 void SPD::Clamp() {
00053 for (u_int i = 0; i < nSamples; ++i) {
00054 if (!(samples[i] > 0.f))
00055 samples[i] = 0.f;
00056 }
00057 }
00058
00059 void SPD::Scale(float s) {
00060 for (u_int i = 0; i < nSamples; ++i)
00061 samples[i] *= s;
00062 }
00063
00064 void SPD::Whitepoint(float temp) {
00065 std::vector<float> bbvals;
00066
00067
00068 float w = lambdaMin * 1e-9f;
00069 for (u_int i = 0; i < nSamples; ++i) {
00070
00071 bbvals.push_back(4e-9f * (3.74183e-16f * powf(w, -5.f))
00072 / (expf(1.4388e-2f / (w * temp)) - 1.f));
00073 w += 1e-9f * delta;
00074 }
00075
00076
00077 float max = 0.f;
00078 for (u_int i = 0; i < nSamples; ++i)
00079 if (bbvals[i] > max)
00080 max = bbvals[i];
00081 const float scale = 1.f / max;
00082
00083 for (u_int i = 0; i < nSamples; ++i)
00084 samples[i] *= bbvals[i] * scale;
00085 }
00086
00087 float SPD::Y() const
00088 {
00089 float y = 0.f;
00090 for (u_int i = 0; i < nCIE; ++i)
00091 y += sample(i + CIEstart) * CIE_Y[i];
00092 return y * 683.f;
00093 }
00094
00095 Spectrum SPD::ToRGB() {
00096 Spectrum c;
00097 for (u_int i = 0; i < nCIE; ++i) {
00098 const float v = sample(i + CIEstart);
00099 c.r += v * CIE_X[i];
00100 c.g += v * CIE_Y[i];
00101 c.b += v * CIE_Z[i];
00102 }
00103
00104 return c * 683.f;
00105 }
00106
00107 float SPD::Filter() const
00108 {
00109 float y = 0.f;
00110 for (u_int i = 0; i < nSamples; ++i)
00111 y += samples[i];
00112 return y / nSamples;
00113 }
00114
00115 void RegularSPD::init(float lMin, float lMax, const float* const s, u_int n) {
00116 lambdaMin = lMin;
00117 lambdaMax = lMax;
00118 delta = (lambdaMax - lambdaMin) / (n - 1);
00119 invDelta = 1.f / delta;
00120 nSamples = n;
00121
00122 AllocateSamples(n);
00123
00124
00125 for (u_int i = 0; i < n; ++i)
00126 samples[i] = s[i];
00127 }
00128
00129
00130
00131
00132
00133
00134
00135 IrregularSPD::IrregularSPD(const float* const wavelengths, const float* const samples,
00136 u_int n, float resolution, SPDResamplingMethod resamplignMethod)
00137 : SPD()
00138 {
00139 float lambdaMin = wavelengths[0];
00140 float lambdaMax = wavelengths[n - 1];
00141
00142 u_int sn = Ceil2UInt((lambdaMax - lambdaMin) / resolution) + 1;
00143
00144 std::vector<float> sam(sn);
00145
00146 if (resamplignMethod == Linear) {
00147 u_int k = 0;
00148 for (u_int i = 0; i < sn; i++) {
00149 float lambda = lambdaMin + i * resolution;
00150
00151 if (lambda < wavelengths[0] || lambda > wavelengths[n-1]) {
00152 sam[i] = 0.f;
00153 continue;
00154 }
00155
00156 for (; k < n; ++k) {
00157 if (wavelengths[k] >= lambda)
00158 break;
00159 }
00160
00161 if (wavelengths[k] == lambda)
00162 sam[i] = samples[k];
00163 else {
00164 float intervalWidth = wavelengths[k] - wavelengths[k - 1];
00165 float u = (lambda - wavelengths[k - 1]) / intervalWidth;
00166 sam[i] = Lerp(u, samples[k - 1], samples[k]);
00167 }
00168 }
00169 } else {
00170 std::vector<float> sd(n);
00171
00172 calc_spline_data(wavelengths, samples, n, &sd[0]);
00173
00174 u_int k = 0;
00175 for (u_int i = 0; i < sn; i++) {
00176 float lambda = lambdaMin + i * resolution;
00177
00178 if (lambda < wavelengths[0] || lambda > wavelengths[n-1]) {
00179 sam[i] = 0.f;
00180 continue;
00181 }
00182
00183 while (lambda > wavelengths[k+1])
00184 k++;
00185
00186 float h = wavelengths[k+1] - wavelengths[k];
00187 float a = (wavelengths[k+1] - lambda) / h;
00188 float b = (lambda - wavelengths[k]) / h;
00189
00190 sam[i] = Max(a*samples[k] + b*samples[k+1]+
00191 ((a*a*a-a)*sd[k] + (b*b*b-b)*sd[k+1])*(h*h)/6.f, 0.f);
00192 }
00193 }
00194
00195 init(lambdaMin, lambdaMax, &sam[0], sn);
00196 }
00197
00198 void IrregularSPD::init(float lMin, float lMax, const float* const s, u_int n) {
00199 lambdaMin = lMin;
00200 lambdaMax = lMax;
00201 delta = (lambdaMax - lambdaMin) / (n-1);
00202 invDelta = 1.f / delta;
00203 nSamples = n;
00204
00205 AllocateSamples(n);
00206
00207
00208 for (u_int i = 0; i < n; ++i)
00209 samples[i] = s[i];
00210
00211 }
00212
00213
00214
00215 void IrregularSPD::calc_spline_data(const float* const wavelengths,
00216 const float* const amplitudes, u_int n, float *spline_data)
00217 {
00218 std::vector<float> u(n - 1);
00219
00220
00221 spline_data[0] = u[0] = 0.f;
00222
00223 for (u_int i = 1; i <= n - 2; i++) {
00224 float sig = (wavelengths[i] - wavelengths[i - 1]) /
00225 (wavelengths[i + 1] - wavelengths[i - 1]);
00226 float p = sig * spline_data[i - 1] + 2.f;
00227 spline_data[i] = (sig - 1.f) / p;
00228 u[i] = (amplitudes[i + 1] - amplitudes[i]) /
00229 (wavelengths[i + 1] - wavelengths[i]) -
00230 (amplitudes[i] - amplitudes[i - 1]) /
00231 (wavelengths[i] - wavelengths[i - 1]);
00232 u[i] = (6.f * u[i] /
00233 (wavelengths[i + 1] - wavelengths[i - 1]) -
00234 sig * u[i - 1]) / p;
00235 }
00236
00237 float qn, un;
00238
00239
00240 qn = un = 0.f;
00241 spline_data[n - 1] = (un - qn * u[n-2]) /
00242 (qn * spline_data[n - 2] + 1.f);
00243 for (u_int k = 0; k < n - 1; ++k)
00244 spline_data[n - k - 1] = spline_data[n - k - 1] *
00245 spline_data[n - k] + u[k];
00246 }