Blender  V2.93
sky_model.cpp
Go to the documentation of this file.
1 /*
2 This source is published under the following 3-clause BSD license.
3 
4 Copyright (c) 2012 - 2013, Lukas Hosek and Alexander Wilkie
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10  * Redistributions of source code must retain the above copyright
11  notice, this list of conditions and the following disclaimer.
12  * Redistributions in binary form must reproduce the above copyright
13  notice, this list of conditions and the following disclaimer in the
14  documentation and/or other materials provided with the distribution.
15  * None of the names of the contributors may be used to endorse or promote
16  products derived from this software without specific prior written
17  permission.
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 
31 /* ============================================================================
32 
33 This file is part of a sample implementation of the analytical skylight and
34 solar radiance models presented in the SIGGRAPH 2012 paper
35 
36 
37  "An Analytic Model for Full Spectral Sky-Dome Radiance"
38 
39 and the 2013 IEEE CG&A paper
40 
41  "Adding a Solar Radiance Function to the Hosek Skylight Model"
42 
43  both by
44 
45  Lukas Hosek and Alexander Wilkie
46  Charles University in Prague, Czech Republic
47 
48 
49  Version: 1.4a, February 22nd, 2013
50 
51 Version history:
52 
53 1.4a February 22nd, 2013
54  Removed unnecessary and counter-intuitive solar radius parameters
55  from the interface of the colourspace sky dome initialisation functions.
56 
57 1.4 February 11th, 2013
58  Fixed a bug which caused the relative brightness of the solar disc
59  and the sky dome to be off by a factor of about 6. The sun was too
60  bright: this affected both normal and alien sun scenarios. The
61  coefficients of the solar radiance function were changed to fix this.
62 
63 1.3 January 21st, 2013 (not released to the public)
64  Added support for solar discs that are not exactly the same size as
65  the terrestrial sun. Also added support for suns with a different
66  emission spectrum ("Alien World" functionality).
67 
68 1.2a December 18th, 2012
69  Fixed a mistake and some inaccuracies in the solar radiance function
70  explanations found in ArHosekSkyModel.h. The actual source code is
71  unchanged compared to version 1.2.
72 
73 1.2 December 17th, 2012
74  Native RGB data and a solar radiance function that matches the turbidity
75  conditions were added.
76 
77 1.1 September 2012
78  The coefficients of the spectral model are now scaled so that the output
79  is given in physical units: W / (m^-2 * sr * nm). Also, the output of the
80  XYZ model is now no longer scaled to the range [0...1]. Instead, it is
81  the result of a simple conversion from spectral data via the CIE 2 degree
82  standard observer matching functions. Therefore, after multiplication
83  with 683 lm / W, the Y channel now corresponds to luminance in lm.
84 
85 1.0 May 11th, 2012
86  Initial release.
87 
88 
89 Please visit http://cgg.mff.cuni.cz/projects/SkylightModelling/ to check if
90 an updated version of this code has been published!
91 
92 ============================================================================ */
93 
94 /*
95 
96 All instructions on how to use this code are in the accompanying header file.
97 
98 */
99 
100 #include "sky_model.h"
101 #include "sky_model_data.h"
102 
103 #include <assert.h>
104 #include <math.h>
105 #include <stdio.h>
106 #include <stdlib.h>
107 
108 // Some macro definitions that occur elsewhere in ART, and that have to be
109 // replicated to make this a stand-alone module.
110 
111 #ifndef MATH_PI
112 # define MATH_PI 3.141592653589793
113 #endif
114 
115 #ifndef MATH_DEG_TO_RAD
116 # define MATH_DEG_TO_RAD (MATH_PI / 180.0)
117 #endif
118 
119 #ifndef DEGREES
120 # define DEGREES *MATH_DEG_TO_RAD
121 #endif
122 
123 #ifndef TERRESTRIAL_SOLAR_RADIUS
124 # define TERRESTRIAL_SOLAR_RADIUS ((0.51 DEGREES) / 2.0)
125 #endif
126 
127 #ifndef ALLOC
128 # define ALLOC(_struct) ((_struct *)malloc(sizeof(_struct)))
129 #endif
130 
131 // internal definitions
132 
133 typedef const double *ArHosekSkyModel_Dataset;
134 typedef const double *ArHosekSkyModel_Radiance_Dataset;
135 
136 // internal functions
137 
140  double turbidity,
141  double albedo,
142  double solar_elevation)
143 {
144  const double *elev_matrix;
145 
146  int int_turbidity = (int)turbidity;
147  double turbidity_rem = turbidity - (double)int_turbidity;
148 
149  solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
150 
151  // alb 0 low turb
152 
153  elev_matrix = dataset + (9 * 6 * (int_turbidity - 1));
154 
155  for (unsigned int i = 0; i < 9; ++i) {
156  //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
157  config[i] =
158  (1.0 - albedo) * (1.0 - turbidity_rem) *
159  (pow(1.0 - solar_elevation, 5.0) * elev_matrix[i] +
160  5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[i + 9] +
161  10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[i + 18] +
162  10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[i + 27] +
163  5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[i + 36] +
164  pow(solar_elevation, 5.0) * elev_matrix[i + 45]);
165  }
166 
167  // alb 1 low turb
168  elev_matrix = dataset + (9 * 6 * 10 + 9 * 6 * (int_turbidity - 1));
169  for (unsigned int i = 0; i < 9; ++i) {
170  //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
171  config[i] +=
172  (albedo) * (1.0 - turbidity_rem) *
173  (pow(1.0 - solar_elevation, 5.0) * elev_matrix[i] +
174  5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[i + 9] +
175  10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[i + 18] +
176  10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[i + 27] +
177  5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[i + 36] +
178  pow(solar_elevation, 5.0) * elev_matrix[i + 45]);
179  }
180 
181  if (int_turbidity == 10) {
182  return;
183  }
184 
185  // alb 0 high turb
186  elev_matrix = dataset + (9 * 6 * (int_turbidity));
187  for (unsigned int i = 0; i < 9; ++i) {
188  //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
189  config[i] +=
190  (1.0 - albedo) * (turbidity_rem) *
191  (pow(1.0 - solar_elevation, 5.0) * elev_matrix[i] +
192  5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[i + 9] +
193  10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[i + 18] +
194  10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[i + 27] +
195  5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[i + 36] +
196  pow(solar_elevation, 5.0) * elev_matrix[i + 45]);
197  }
198 
199  // alb 1 high turb
200  elev_matrix = dataset + (9 * 6 * 10 + 9 * 6 * (int_turbidity));
201  for (unsigned int i = 0; i < 9; ++i) {
202  //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
203  config[i] +=
204  (albedo) * (turbidity_rem) *
205  (pow(1.0 - solar_elevation, 5.0) * elev_matrix[i] +
206  5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[i + 9] +
207  10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[i + 18] +
208  10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[i + 27] +
209  5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[i + 36] +
210  pow(solar_elevation, 5.0) * elev_matrix[i + 45]);
211  }
212 }
213 
215  double turbidity,
216  double albedo,
217  double solar_elevation)
218 {
219  const double *elev_matrix;
220 
221  int int_turbidity = (int)turbidity;
222  double turbidity_rem = turbidity - (double)int_turbidity;
223  double res;
224  solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
225 
226  // alb 0 low turb
227  elev_matrix = dataset + (6 * (int_turbidity - 1));
228  //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
229  res = (1.0 - albedo) * (1.0 - turbidity_rem) *
230  (pow(1.0 - solar_elevation, 5.0) * elev_matrix[0] +
231  5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[1] +
232  10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[2] +
233  10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[3] +
234  5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[4] +
235  pow(solar_elevation, 5.0) * elev_matrix[5]);
236 
237  // alb 1 low turb
238  elev_matrix = dataset + (6 * 10 + 6 * (int_turbidity - 1));
239  //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
240  res += (albedo) * (1.0 - turbidity_rem) *
241  (pow(1.0 - solar_elevation, 5.0) * elev_matrix[0] +
242  5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[1] +
243  10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[2] +
244  10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[3] +
245  5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[4] +
246  pow(solar_elevation, 5.0) * elev_matrix[5]);
247  if (int_turbidity == 10) {
248  return res;
249  }
250 
251  // alb 0 high turb
252  elev_matrix = dataset + (6 * (int_turbidity));
253  //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
254  res += (1.0 - albedo) * (turbidity_rem) *
255  (pow(1.0 - solar_elevation, 5.0) * elev_matrix[0] +
256  5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[1] +
257  10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[2] +
258  10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[3] +
259  5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[4] +
260  pow(solar_elevation, 5.0) * elev_matrix[5]);
261 
262  // alb 1 high turb
263  elev_matrix = dataset + (6 * 10 + 6 * (int_turbidity));
264  //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
265  res += (albedo) * (turbidity_rem) *
266  (pow(1.0 - solar_elevation, 5.0) * elev_matrix[0] +
267  5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[1] +
268  10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[2] +
269  10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[3] +
270  5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[4] +
271  pow(solar_elevation, 5.0) * elev_matrix[5]);
272  return res;
273 }
274 
276  const SKY_ArHosekSkyModelConfiguration configuration, const double theta, const double gamma)
277 {
278  const double expM = exp(configuration[4] * gamma);
279  const double rayM = cos(gamma) * cos(gamma);
280  const double mieM =
281  (1.0 + cos(gamma) * cos(gamma)) /
282  pow((1.0 + configuration[8] * configuration[8] - 2.0 * configuration[8] * cos(gamma)), 1.5);
283  const double zenith = sqrt(cos(theta));
284 
285  return (1.0 + configuration[0] * exp(configuration[1] / (cos(theta) + 0.01))) *
286  (configuration[2] + configuration[3] * expM + configuration[5] * rayM +
287  configuration[6] * mieM + configuration[7] * zenith);
288 }
289 
291 {
292  free(state);
293 }
294 
296  double theta,
297  double gamma,
298  double wavelength)
299 {
300  int low_wl = (int)((wavelength - 320.0) / 40.0);
301 
302  if (low_wl < 0 || low_wl >= 11) {
303  return 0.0;
304  }
305 
306  double interp = fmod((wavelength - 320.0) / 40.0, 1.0);
307 
308  double val_low = ArHosekSkyModel_GetRadianceInternal(state->configs[low_wl], theta, gamma) *
309  state->radiances[low_wl] * state->emission_correction_factor_sky[low_wl];
310 
311  if (interp < 1e-6) {
312  return val_low;
313  }
314 
315  double result = (1.0 - interp) * val_low;
316 
317  if (low_wl + 1 < 11) {
318  result += interp *
319  ArHosekSkyModel_GetRadianceInternal(state->configs[low_wl + 1], theta, gamma) *
320  state->radiances[low_wl + 1] * state->emission_correction_factor_sky[low_wl + 1];
321  }
322 
323  return result;
324 }
325 
326 // xyz and rgb versions
327 
329  const double albedo,
330  const double elevation)
331 {
333 
334  state->solar_radius = TERRESTRIAL_SOLAR_RADIUS;
335  state->turbidity = turbidity;
336  state->albedo = albedo;
337  state->elevation = elevation;
338 
339  for (unsigned int channel = 0; channel < 3; ++channel) {
341  datasetsXYZ[channel], state->configs[channel], turbidity, albedo, elevation);
342 
343  state->radiances[channel] = ArHosekSkyModel_CookRadianceConfiguration(
344  datasetsXYZRad[channel], turbidity, albedo, elevation);
345  }
346 
347  return state;
348 }
sqrt(x)+1/max(0
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:116
typedef double(DMatrix)[4][4]
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
static ulong state[N]
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
Definition: rall1d.h:359
INLINE Rall1d< T, V, S > exp(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:295
const double * ArHosekSkyModel_Dataset
Definition: sky_model.cpp:133
static void ArHosekSkyModel_CookConfiguration(ArHosekSkyModel_Dataset dataset, SKY_ArHosekSkyModelConfiguration config, double turbidity, double albedo, double solar_elevation)
Definition: sky_model.cpp:138
void SKY_arhosekskymodelstate_free(SKY_ArHosekSkyModelState *state)
Definition: sky_model.cpp:290
#define TERRESTRIAL_SOLAR_RADIUS
Definition: sky_model.cpp:124
static double ArHosekSkyModel_CookRadianceConfiguration(ArHosekSkyModel_Radiance_Dataset dataset, double turbidity, double albedo, double solar_elevation)
Definition: sky_model.cpp:214
#define ALLOC(_struct)
Definition: sky_model.cpp:128
double SKY_arhosekskymodel_radiance(SKY_ArHosekSkyModelState *state, double theta, double gamma, double wavelength)
Definition: sky_model.cpp:295
#define MATH_PI
Definition: sky_model.cpp:112
const double * ArHosekSkyModel_Radiance_Dataset
Definition: sky_model.cpp:134
static double ArHosekSkyModel_GetRadianceInternal(const SKY_ArHosekSkyModelConfiguration configuration, const double theta, const double gamma)
Definition: sky_model.cpp:275
SKY_ArHosekSkyModelState * SKY_arhosek_xyz_skymodelstate_alloc_init(const double turbidity, const double albedo, const double elevation)
Definition: sky_model.cpp:328
double SKY_ArHosekSkyModelConfiguration[9]
Definition: sky_model.h:308
static const double * datasetsXYZ[]
static const double * datasetsXYZRad[]
ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t)