-
Notifications
You must be signed in to change notification settings - Fork 1
/
SunSky.h
240 lines (189 loc) · 10.5 KB
/
SunSky.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
//
// File: SunSky.h
//
// Function: Implements various sky models -- Preetham, Hosek, CIE* -- as
// well as a separable table-based model for fast BRDF convolutions
//
// Author: Andrew Willmott, Preetham sun/sky based on code by Brian Smits,
// Hosek code used L. Hosek & A. Wilkie code Version 1.4a as reference
//
// Copyright: Andrew Willmott, see HosekDataXYZ.h for Hosek data copyright
//
#ifndef SUNSKY_H
#define SUNSKY_H
#include "VL234f.h"
namespace SSLib
{
extern const float kSunDiameter;
extern const float kSunDistance;
extern const float kSunCosAngle;
extern const float kSunSolidAngle;
Vec3f SunDirection
(
float elevation
);
Vec3f SunDirection
(
float timeOfDay, // 24-hour, decimal: 0.0-23.99
float timeZone, // relative to UTC: west -ve, east +ve
int julianDay, // day of year: 1-365
float latitude, // Degrees: north is positive
float longitude // Degrees: east is positive
);
// Returns the local sun direction at the given time/location. +Y = north, +X = east, +Z = up.
// Utilities
Vec3f SunRGB(float cosTheta, float turbidity = 3.0f); // Returns RGB for given sun elevation
float ZenithLuminance(float thetaS, float T); // Returns luminance estimate for given solar altitude and turbidity
float CIEOvercastSkyLuminance (const Vec3f& v, float Lz); // CIE standard overcast sky
float CIEClearSkyLuminance (const Vec3f& v, const Vec3f& toSun, float Lz); // CIE standard clear sky
float CIEPartlyCloudySkyLuminance(const Vec3f& v, const Vec3f& toSun, float Lz); // CIE standard partly cloudy sky
float CIEStandardSky (int type, const Vec3f& v, const Vec3f& toSun, float Lz); // Returns one of 15 standard skies: type = 0-14. See kCIEStandardSkyCoeffs
//--------------------------------------------------------------------------
// cSunSkyPreetham
//--------------------------------------------------------------------------
class cSunSkyPreetham
{
public:
cSunSkyPreetham();
void Update(const Vec3f& sun, float turbidity, float overcast = 0.0f, float hCrush = 0.0f); // update model with given settings
Vec3f SkyRGB (const Vec3f &v) const; // Returns luminance/chroma converted to RGB
float SkyLuminance(const Vec3f &v) const; // Returns the luminance of the sky in direction v. v must be normalized. Luminance is in Nits = cd/m^2 = lumens/sr/m^2 */
Vec2f SkyChroma (const Vec3f &v) const; // Returns the chroma of the sky in direction v. v must be normalized.
// Data
Vec3f mToSun;
float mPerez_x[5];
float mPerez_y[5];
float mPerez_Y[5];
Vec3f mZenith;
Vec3f mPerezInvDen;
};
//--------------------------------------------------------------------------
// cSunSkyHosek
//--------------------------------------------------------------------------
class cSunSkyHosek
{
public:
cSunSkyHosek();
void Update(const Vec3f& sun, float turbidity, Vec3f albedo = vl_0, float overcast = 0.0f); // update model with given settings
Vec3f SkyXYZ (const Vec3f &v) const; // Returns CIE XYZ
Vec3f SkyRGB (const Vec3f &v) const; // Returns luminance/chroma converted to RGB
float SkyLuminance(const Vec3f &v) const; // Returns CIE XYZ
// Data
Vec3f mToSun;
float mCoeffsXYZ[3][9]; // Hosek 9-term distribution coefficients
Vec3f mRadXYZ; // Overall average radiance
};
//--------------------------------------------------------------------------
// cSunSkyTable
//--------------------------------------------------------------------------
class cSunSkyTable
{
public:
// Table-based version - faster than per-sample Perez/Hosek function evaluation, suitable for shader use via 64 x 2 texture
// For a fixed time, Preetham can be expressed in the form
// K (1 + F(theta))(1 + G(gamma))
// where theta is the zenith angle of v, and gamma the angle between v and the sun direction.
// Hosek can be expressed in the form
// K (1 + F(theta))(1 + G(gamma) + H(theta))
// where H is trivial to evaluate in a shader, involving a constant term and sqrt(v.z).
// Note: the F term is generally negative, so we use F' = -F in the tables.
void FindThetaGammaTables(const cSunSkyPreetham& pt);
void FindThetaGammaTables(const cSunSkyHosek& pt);
Vec3f SkyRGB(const cSunSkyPreetham& pt, const Vec3f& v) const; // Use precalculated table to return fast sky colour on CPU
Vec3f SkyRGB(const cSunSkyHosek& hk, const Vec3f& v) const; // Use precalculated table to return fast sky colour on CPU
void FillTexture(int width, int height, uint8_t image[][4]) const; // Fill kTableSize x 2 BGRA8 texture with tables
void FillTexture(int width, int height, float image[][4]) const; // Fill kTableSize x 2 RGBAF32 texture with tables
// Table acceleration
enum { kTableSize = 64 };
Vec3f mThetaTable[kTableSize];
Vec3f mGammaTable[kTableSize];
float mMaxTheta = 1.0f; // To avoid clipping when using non-float textures. Currently only necessary if overcast is being used.
float mMaxGamma = 1.0f; // To avoid clipping when using non-float textures.
bool mXYZ = false; // Whether tables are storing xyY (Preetham) or XYZ (Hosek)
};
//--------------------------------------------------------------------------
// cSunSkyBRDF
//--------------------------------------------------------------------------
// #define COMPACT_BRDF_TABLE // enable for smaller half-size table
class cSunSkyBRDF
{
public:
// Extended version of cSunSkyTable that uses zonal harmonics to produce table rows
// convolved with increasing cosine powers. This is an approximation, because
// conv(AB) != conv(A) conv(B), but, because the Perez-form evaluation is
// (1 + F(theta)) (1 + G(gamma)), the approximation is only for the small
// order-2 FG term.
void FindBRDFTables(const cSunSkyTable& table, const cSunSkyPreetham& pt);
void FindBRDFTables(const cSunSkyTable& table, const cSunSkyHosek& hk);
Vec3f ConvolvedSkyRGB(const cSunSkyPreetham& pt, const Vec3f& v, float roughness) const; // return sky term convolved with roughness, 1 = fully diffuse
Vec3f ConvolvedSkyRGB(const cSunSkyHosek& pt, const Vec3f& v, float roughness) const; // return sky term convolved with roughness, 1 = fully diffuse
void FillBRDFTexture(int width, int height, uint8_t image[][4]) const; // Fill kTableSize x (kBRDFSamples x 2|4) BGRA8 texture with tables
void FillBRDFTexture(int width, int height, float image[][4]) const; // Fill kTableSize x (kBRDFSamples x 2|4) RGBAF32 texture with tables
// Note: for Hosek, the H term will be in the 'w' component of the theta section, and if a kBRDFSamples x 4 size texture is supplied,
// the two additional sections will contain the FH term table. (Using this improves accuracy but can be skipped.)
enum { kTableSize = cSunSkyTable::kTableSize };
#ifdef COMPACT_BRDF_TABLE
enum { kBRDFSamples = 4 };
#else
enum { kBRDFSamples = 8 };
#endif
Vec3f mBRDFThetaTable[kBRDFSamples][kTableSize];
Vec3f mBRDFGammaTable[kBRDFSamples][kTableSize];
// Additional tables for 'H' term in Hosek.
float mBRDFThetaTableH [kBRDFSamples][kTableSize];
Vec3f mBRDFThetaTableFH[kBRDFSamples][kTableSize];
bool mHasHTerm = false;
float mMaxTheta = 1.0f; // To avoid clipping when using non-float textures. Currently only necessary if overcast is being used.
float mMaxGamma = 1.0f; // To avoid clipping when using non-float textures.
bool mXYZ = false; // Whether tables are storing xyY (Preetham) or XYZ (Hosek)
};
//--------------------------------------------------------------------------
// cSunSky
// Composite sun/sky model for easy comparisons
//--------------------------------------------------------------------------
enum tSkyType
{
kPreetham,
kPreethamTable, // Table accelerated version, for sanity checking -- really designed for texture/shader use
kPreethamBRDF, // Sky model convolved with roughness (sat(cos^n) brdf)
kHosek,
kHosekTable,
kHosekBRDF,
kCIEClear,
kCIEOvercast,
kCIEPartlyCloudy,
kNumSkyTypes
};
class cSunSky
{
public:
cSunSky();
void SetSkyType(tSkyType skyType);
tSkyType SkyType() const;
void SetSunDir (const Vec3f& sun);
void SetTurbidity(float turbidity);
void SetAlbedo (Vec3f rgb); // Set ground-bounce factor
void SetOvercast (float overcast); // 0 = clear, 1 = completely overcast
void SetRoughness(float roughness); // Set roughness for BRDF tables
void Update(); // update model given above settings
float SkyLuminance(const Vec3f &v) const; // Returns the luminance of the sky in direction v. v must be normalized. Luminance is in Nits = cd/m^2 = lumens/sr/m^2 */
Vec2f SkyChroma (const Vec3f &v) const; // Returns the chroma of the sky in direction v. v must be normalized.
Vec3f SkyRGB (const Vec3f &v) const; // Returns luminance/chroma converted to RGB
float AverageLuminance() const;
protected:
// Data
tSkyType mSkyType;
Vec3f mToSun;
float mTurbidity;
Vec3f mAlbedo;
float mOvercast;
float mRoughness;
// Various models
float mZenithY; // for CIE functions
cSunSkyPreetham mPreetham;
cSunSkyHosek mHosek;
cSunSkyTable mTable;
cSunSkyBRDF mBRDF;
};
}
#endif