Blender V4.3
sky_model.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012-2013 Lukas Hosek and Alexander Wilkie. All rights reserved.
2 *
3 * SPDX-License-Identifier: BSD-3-Clause */
4
5/* ============================================================================
6
7This file is part of a sample implementation of the analytical skylight and
8solar radiance models presented in the SIGGRAPH 2012 paper
9
10
11 "An Analytic Model for Full Spectral Sky-Dome Radiance"
12
13and the 2013 IEEE CG&A paper
14
15 "Adding a Solar Radiance Function to the Hosek Skylight Model"
16
17 both by
18
19 Lukas Hosek and Alexander Wilkie
20 Charles University in Prague, Czech Republic
21
22
23 Version: 1.4a, February 22nd, 2013
24
25Version history:
26
271.4a February 22nd, 2013
28 Removed unnecessary and counter-intuitive solar radius parameters
29 from the interface of the color-space sky dome initialization functions.
30
311.4 February 11th, 2013
32 Fixed a bug which caused the relative brightness of the solar disc
33 and the sky dome to be off by a factor of about 6. The sun was too
34 bright: this affected both normal and alien sun scenarios. The
35 coefficients of the solar radiance function were changed to fix this.
36
371.3 January 21st, 2013 (not released to the public)
38 Added support for solar discs that are not exactly the same size as
39 the terrestrial sun. Also added support for suns with a different
40 emission spectrum ("Alien World" functionality).
41
421.2a December 18th, 2012
43 Fixed a mistake and some inaccuracies in the solar radiance function
44 explanations found in ArHosekSkyModel.h. The actual source code is
45 unchanged compared to version 1.2.
46
471.2 December 17th, 2012
48 Native RGB data and a solar radiance function that matches the turbidity
49 conditions were added.
50
511.1 September 2012
52 The coefficients of the spectral model are now scaled so that the output
53 is given in physical units: W / (m^-2 * sr * nm). Also, the output of the
54 XYZ model is now no longer scaled to the range [0...1]. Instead, it is
55 the result of a simple conversion from spectral data via the CIE 2 degree
56 standard observer matching functions. Therefore, after multiplication
57 with 683 lm / W, the Y channel now corresponds to luminance in lm.
58
591.0 May 11th, 2012
60 Initial release.
61
62
63Please visit http://cgg.mff.cuni.cz/projects/SkylightModelling/ to check if
64an updated version of this code has been published!
65
66============================================================================ */
67
68/*
69
70All instructions on how to use this code are in the accompanying header file.
71
72*/
73
78#include "sky_model.h"
79#include "sky_model_data.h"
80
81#include <assert.h>
82#include <math.h>
83#include <stdio.h>
84#include <stdlib.h>
85
86// Some macro definitions that occur elsewhere in ART, and that have to be
87// replicated to make this a stand-alone module.
88
89#ifndef MATH_PI
90# define MATH_PI 3.141592653589793
91#endif
92
93#ifndef MATH_DEG_TO_RAD
94# define MATH_DEG_TO_RAD (MATH_PI / 180.0)
95#endif
96
97#ifndef DEGREES
98# define DEGREES *MATH_DEG_TO_RAD
99#endif
100
101#ifndef TERRESTRIAL_SOLAR_RADIUS
102# define TERRESTRIAL_SOLAR_RADIUS ((0.51 DEGREES) / 2.0)
103#endif
104
105#ifndef ALLOC
106# define ALLOC(_struct) ((_struct *)malloc(sizeof(_struct)))
107#endif
108
109/* Not defined on all platforms (macOS & WIN32). */
110typedef unsigned int uint;
111
112// internal definitions
113
114typedef const double *ArHosekSkyModel_Dataset;
116
117// internal functions
118
121 double turbidity,
122 double albedo,
123 double solar_elevation)
124{
125 const double *elev_matrix;
126
127 int int_turbidity = int(turbidity);
128 double turbidity_rem = turbidity - double(int_turbidity);
129
130 solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
131
132 // alb 0 low turb
133
134 elev_matrix = dataset + (9 * 6 * (int_turbidity - 1));
135
136 for (uint i = 0; i < 9; ++i) {
137 //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
138 config[i] =
139 (1.0 - albedo) * (1.0 - turbidity_rem) *
140 (pow(1.0 - solar_elevation, 5.0) * elev_matrix[i] +
141 5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[i + 9] +
142 10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[i + 18] +
143 10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[i + 27] +
144 5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[i + 36] +
145 pow(solar_elevation, 5.0) * elev_matrix[i + 45]);
146 }
147
148 // alb 1 low turb
149 elev_matrix = dataset + (9 * 6 * 10 + 9 * 6 * (int_turbidity - 1));
150 for (uint i = 0; i < 9; ++i) {
151 //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
152 config[i] +=
153 (albedo) * (1.0 - turbidity_rem) *
154 (pow(1.0 - solar_elevation, 5.0) * elev_matrix[i] +
155 5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[i + 9] +
156 10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[i + 18] +
157 10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[i + 27] +
158 5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[i + 36] +
159 pow(solar_elevation, 5.0) * elev_matrix[i + 45]);
160 }
161
162 if (int_turbidity == 10) {
163 return;
164 }
165
166 // alb 0 high turb
167 elev_matrix = dataset + (9 * 6 * (int_turbidity));
168 for (uint i = 0; i < 9; ++i) {
169 //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
170 config[i] +=
171 (1.0 - albedo) * (turbidity_rem) *
172 (pow(1.0 - solar_elevation, 5.0) * elev_matrix[i] +
173 5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[i + 9] +
174 10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[i + 18] +
175 10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[i + 27] +
176 5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[i + 36] +
177 pow(solar_elevation, 5.0) * elev_matrix[i + 45]);
178 }
179
180 // alb 1 high turb
181 elev_matrix = dataset + (9 * 6 * 10 + 9 * 6 * (int_turbidity));
182 for (uint i = 0; i < 9; ++i) {
183 //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
184 config[i] +=
185 (albedo) * (turbidity_rem) *
186 (pow(1.0 - solar_elevation, 5.0) * elev_matrix[i] +
187 5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[i + 9] +
188 10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[i + 18] +
189 10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[i + 27] +
190 5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[i + 36] +
191 pow(solar_elevation, 5.0) * elev_matrix[i + 45]);
192 }
193}
194
196 double turbidity,
197 double albedo,
198 double solar_elevation)
199{
200 const double *elev_matrix;
201
202 int int_turbidity = int(turbidity);
203 double turbidity_rem = turbidity - double(int_turbidity);
204 double res;
205 solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
206
207 // alb 0 low turb
208 elev_matrix = dataset + (6 * (int_turbidity - 1));
209 //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
210 res = (1.0 - albedo) * (1.0 - turbidity_rem) *
211 (pow(1.0 - solar_elevation, 5.0) * elev_matrix[0] +
212 5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[1] +
213 10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[2] +
214 10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[3] +
215 5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[4] +
216 pow(solar_elevation, 5.0) * elev_matrix[5]);
217
218 // alb 1 low turb
219 elev_matrix = dataset + (6 * 10 + 6 * (int_turbidity - 1));
220 //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
221 res += (albedo) * (1.0 - turbidity_rem) *
222 (pow(1.0 - solar_elevation, 5.0) * elev_matrix[0] +
223 5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[1] +
224 10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[2] +
225 10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[3] +
226 5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[4] +
227 pow(solar_elevation, 5.0) * elev_matrix[5]);
228 if (int_turbidity == 10) {
229 return res;
230 }
231
232 // alb 0 high turb
233 elev_matrix = dataset + (6 * (int_turbidity));
234 //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
235 res += (1.0 - albedo) * (turbidity_rem) *
236 (pow(1.0 - solar_elevation, 5.0) * elev_matrix[0] +
237 5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[1] +
238 10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[2] +
239 10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[3] +
240 5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[4] +
241 pow(solar_elevation, 5.0) * elev_matrix[5]);
242
243 // alb 1 high turb
244 elev_matrix = dataset + (6 * 10 + 6 * (int_turbidity));
245 //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
246 res += (albedo) * (turbidity_rem) *
247 (pow(1.0 - solar_elevation, 5.0) * elev_matrix[0] +
248 5.0 * pow(1.0 - solar_elevation, 4.0) * solar_elevation * elev_matrix[1] +
249 10.0 * pow(1.0 - solar_elevation, 3.0) * pow(solar_elevation, 2.0) * elev_matrix[2] +
250 10.0 * pow(1.0 - solar_elevation, 2.0) * pow(solar_elevation, 3.0) * elev_matrix[3] +
251 5.0 * (1.0 - solar_elevation) * pow(solar_elevation, 4.0) * elev_matrix[4] +
252 pow(solar_elevation, 5.0) * elev_matrix[5]);
253 return res;
254}
255
257 const SKY_ArHosekSkyModelConfiguration configuration, const double theta, const double gamma)
258{
259 const double expM = exp(configuration[4] * gamma);
260 const double rayM = cos(gamma) * cos(gamma);
261 const double mieM =
262 (1.0 + cos(gamma) * cos(gamma)) /
263 pow((1.0 + configuration[8] * configuration[8] - 2.0 * configuration[8] * cos(gamma)), 1.5);
264 const double zenith = sqrt(cos(theta));
265
266 return (1.0 + configuration[0] * exp(configuration[1] / (cos(theta) + 0.01))) *
267 (configuration[2] + configuration[3] * expM + configuration[5] * rayM +
268 configuration[6] * mieM + configuration[7] * zenith);
269}
270
275
277 double theta,
278 double gamma,
279 double wavelength)
280{
281 int low_wl = int((wavelength - 320.0) / 40.0);
282
283 if (low_wl < 0 || low_wl >= 11) {
284 return 0.0;
285 }
286
287 double interp = fmod((wavelength - 320.0) / 40.0, 1.0);
288
289 double val_low = ArHosekSkyModel_GetRadianceInternal(state->configs[low_wl], theta, gamma) *
290 state->radiances[low_wl] * state->emission_correction_factor_sky[low_wl];
291
292 if (interp < 1e-6) {
293 return val_low;
294 }
295
296 double result = (1.0 - interp) * val_low;
297
298 if (low_wl + 1 < 11) {
299 result += interp *
300 ArHosekSkyModel_GetRadianceInternal(state->configs[low_wl + 1], theta, gamma) *
301 state->radiances[low_wl + 1] * state->emission_correction_factor_sky[low_wl + 1];
302 }
303
304 return result;
305}
306
307// xyz and rgb versions
308
310 const double albedo,
311 const double elevation)
312{
314
315 state->solar_radius = TERRESTRIAL_SOLAR_RADIUS;
316 state->turbidity = turbidity;
317 state->albedo = albedo;
318 state->elevation = elevation;
319
320 for (uint channel = 0; channel < 3; ++channel) {
322 datasetsXYZ[channel], state->configs[channel], turbidity, albedo, elevation);
323
325 datasetsXYZRad[channel], turbidity, albedo, elevation);
326 }
327
328 return state;
329}
sqrt(x)+1/max(0
void BLI_kdtree_nd_ free(KDTree *tree)
unsigned int uint
typedef double(DMatrix)[4][4]
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
pow(value.r - subtrahend, 2.0)") .do_static_compilation(true)
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
ccl_device_inline float2 fmod(const float2 a, const float b)
ccl_device_inline float2 interp(const float2 a, const float2 b, float t)
ccl_device_inline float3 exp(float3 v)
ccl_device_inline float3 cos(float3 v)
static ulong state[N]
const double * ArHosekSkyModel_Dataset
static void ArHosekSkyModel_CookConfiguration(ArHosekSkyModel_Dataset dataset, SKY_ArHosekSkyModelConfiguration config, double turbidity, double albedo, double solar_elevation)
void SKY_arhosekskymodelstate_free(SKY_ArHosekSkyModelState *state)
unsigned int uint
#define TERRESTRIAL_SOLAR_RADIUS
SKY_ArHosekSkyModelState * SKY_arhosek_xyz_skymodelstate_alloc_init(const double turbidity, const double albedo, const double elevation)
static double ArHosekSkyModel_CookRadianceConfiguration(ArHosekSkyModel_Radiance_Dataset dataset, double turbidity, double albedo, double solar_elevation)
#define ALLOC(_struct)
double SKY_arhosekskymodel_radiance(SKY_ArHosekSkyModelState *state, double theta, double gamma, double wavelength)
#define MATH_PI
Definition sky_model.cpp:90
const double * ArHosekSkyModel_Radiance_Dataset
static double ArHosekSkyModel_GetRadianceInternal(const SKY_ArHosekSkyModelConfiguration configuration, const double theta, const double gamma)
double SKY_ArHosekSkyModelConfiguration[9]
Definition sky_model.h:286
static const double * datasetsXYZ[]
static const double * datasetsXYZRad[]