Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/resources/3d/sky_material.cpp
20920 views
1
/**************************************************************************/
2
/* sky_material.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "sky_material.h"
32
33
#include "core/config/project_settings.h"
34
#include "core/version.h"
35
#include "scene/resources/texture.h"
36
37
Mutex ProceduralSkyMaterial::shader_mutex;
38
RID ProceduralSkyMaterial::shader_cache[4];
39
40
void ProceduralSkyMaterial::set_sky_top_color(const Color &p_sky_top) {
41
sky_top_color = p_sky_top;
42
RS::get_singleton()->material_set_param(_get_material(), "sky_top_color", sky_top_color * sky_energy_multiplier);
43
}
44
45
Color ProceduralSkyMaterial::get_sky_top_color() const {
46
return sky_top_color;
47
}
48
49
void ProceduralSkyMaterial::set_sky_horizon_color(const Color &p_sky_horizon) {
50
sky_horizon_color = p_sky_horizon;
51
RS::get_singleton()->material_set_param(_get_material(), "sky_horizon_color", sky_horizon_color * sky_energy_multiplier);
52
}
53
54
Color ProceduralSkyMaterial::get_sky_horizon_color() const {
55
return sky_horizon_color;
56
}
57
58
void ProceduralSkyMaterial::set_sky_curve(float p_curve) {
59
sky_curve = p_curve;
60
// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be
61
// in calculated in angles and now uses cosines.
62
RS::get_singleton()->material_set_param(_get_material(), "inv_sky_curve", 0.6 / sky_curve);
63
}
64
65
float ProceduralSkyMaterial::get_sky_curve() const {
66
return sky_curve;
67
}
68
69
void ProceduralSkyMaterial::set_sky_energy_multiplier(float p_multiplier) {
70
sky_energy_multiplier = p_multiplier;
71
RS::get_singleton()->material_set_param(_get_material(), "sky_top_color", sky_top_color * sky_energy_multiplier);
72
RS::get_singleton()->material_set_param(_get_material(), "sky_horizon_color", sky_horizon_color * sky_energy_multiplier);
73
RS::get_singleton()->material_set_param(_get_material(), "sky_cover_modulate", Color(sky_cover_modulate.r, sky_cover_modulate.g, sky_cover_modulate.b, sky_cover_modulate.a * sky_energy_multiplier));
74
}
75
76
float ProceduralSkyMaterial::get_sky_energy_multiplier() const {
77
return sky_energy_multiplier;
78
}
79
80
void ProceduralSkyMaterial::set_sky_cover(const Ref<Texture2D> &p_sky_cover) {
81
sky_cover = p_sky_cover;
82
83
if (p_sky_cover.is_valid()) {
84
RS::get_singleton()->material_set_param(_get_material(), "sky_cover", p_sky_cover->get_rid());
85
} else {
86
RS::get_singleton()->material_set_param(_get_material(), "sky_cover", Variant());
87
}
88
89
_update_shader(use_debanding, sky_cover.is_valid());
90
91
if (shader_set) {
92
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
93
}
94
}
95
96
Ref<Texture2D> ProceduralSkyMaterial::get_sky_cover() const {
97
return sky_cover;
98
}
99
100
void ProceduralSkyMaterial::set_sky_cover_modulate(const Color &p_sky_cover_modulate) {
101
sky_cover_modulate = p_sky_cover_modulate;
102
RS::get_singleton()->material_set_param(_get_material(), "sky_cover_modulate", Color(sky_cover_modulate.r, sky_cover_modulate.g, sky_cover_modulate.b, sky_cover_modulate.a * sky_energy_multiplier));
103
}
104
105
Color ProceduralSkyMaterial::get_sky_cover_modulate() const {
106
return sky_cover_modulate;
107
}
108
109
void ProceduralSkyMaterial::set_ground_bottom_color(const Color &p_ground_bottom) {
110
ground_bottom_color = p_ground_bottom;
111
RS::get_singleton()->material_set_param(_get_material(), "ground_bottom_color", ground_bottom_color * ground_energy_multiplier);
112
}
113
114
Color ProceduralSkyMaterial::get_ground_bottom_color() const {
115
return ground_bottom_color;
116
}
117
118
void ProceduralSkyMaterial::set_ground_horizon_color(const Color &p_ground_horizon) {
119
ground_horizon_color = p_ground_horizon;
120
RS::get_singleton()->material_set_param(_get_material(), "ground_horizon_color", ground_horizon_color * ground_energy_multiplier);
121
}
122
123
Color ProceduralSkyMaterial::get_ground_horizon_color() const {
124
return ground_horizon_color;
125
}
126
127
void ProceduralSkyMaterial::set_ground_curve(float p_curve) {
128
ground_curve = p_curve;
129
// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be
130
// in calculated in angles and now uses cosines.
131
RS::get_singleton()->material_set_param(_get_material(), "inv_ground_curve", 0.6 / ground_curve);
132
}
133
134
float ProceduralSkyMaterial::get_ground_curve() const {
135
return ground_curve;
136
}
137
138
void ProceduralSkyMaterial::set_ground_energy_multiplier(float p_multiplier) {
139
ground_energy_multiplier = p_multiplier;
140
RS::get_singleton()->material_set_param(_get_material(), "ground_bottom_color", ground_bottom_color * ground_energy_multiplier);
141
RS::get_singleton()->material_set_param(_get_material(), "ground_horizon_color", ground_horizon_color * ground_energy_multiplier);
142
}
143
144
float ProceduralSkyMaterial::get_ground_energy_multiplier() const {
145
return ground_energy_multiplier;
146
}
147
148
void ProceduralSkyMaterial::set_sun_angle_max(float p_angle) {
149
sun_angle_max = p_angle;
150
RS::get_singleton()->material_set_param(_get_material(), "sun_angle_max", Math::cos(Math::deg_to_rad(sun_angle_max)));
151
}
152
153
float ProceduralSkyMaterial::get_sun_angle_max() const {
154
return sun_angle_max;
155
}
156
157
void ProceduralSkyMaterial::set_sun_curve(float p_curve) {
158
sun_curve = p_curve;
159
// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be
160
// in calculated in angles and now uses cosines.
161
RS::get_singleton()->material_set_param(_get_material(), "inv_sun_curve", 1.6f / Math::pow(sun_curve, 1.4f));
162
}
163
164
float ProceduralSkyMaterial::get_sun_curve() const {
165
return sun_curve;
166
}
167
168
void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) {
169
use_debanding = p_use_debanding;
170
_update_shader(use_debanding, sky_cover.is_valid());
171
// Only set if shader already compiled
172
if (shader_set) {
173
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
174
}
175
}
176
177
bool ProceduralSkyMaterial::get_use_debanding() const {
178
return use_debanding;
179
}
180
181
void ProceduralSkyMaterial::set_energy_multiplier(float p_multiplier) {
182
global_energy_multiplier = p_multiplier;
183
RS::get_singleton()->material_set_param(_get_material(), "exposure", global_energy_multiplier);
184
}
185
186
float ProceduralSkyMaterial::get_energy_multiplier() const {
187
return global_energy_multiplier;
188
}
189
190
Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {
191
return Shader::MODE_SKY;
192
}
193
194
// Internal function to grab the current shader RID.
195
// Must only be called if the shader is initialized.
196
RID ProceduralSkyMaterial::get_shader_cache() const {
197
return shader_cache[int(use_debanding) + (sky_cover.is_valid() ? 2 : 0)];
198
}
199
200
RID ProceduralSkyMaterial::get_rid() const {
201
_update_shader(use_debanding, sky_cover.is_valid());
202
if (!shader_set) {
203
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
204
shader_set = true;
205
}
206
return _get_material();
207
}
208
209
RID ProceduralSkyMaterial::get_shader_rid() const {
210
_update_shader(use_debanding, sky_cover.is_valid());
211
return get_shader_cache();
212
}
213
214
void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const {
215
if (!Engine::get_singleton()->is_editor_hint()) {
216
return;
217
}
218
if ((p_property.name == "sky_luminance" || p_property.name == "ground_luminance") && !GLOBAL_GET_CACHED(bool, "rendering/lights_and_shadows/use_physical_light_units")) {
219
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
220
}
221
}
222
223
void ProceduralSkyMaterial::_bind_methods() {
224
ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSkyMaterial::set_sky_top_color);
225
ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSkyMaterial::get_sky_top_color);
226
227
ClassDB::bind_method(D_METHOD("set_sky_horizon_color", "color"), &ProceduralSkyMaterial::set_sky_horizon_color);
228
ClassDB::bind_method(D_METHOD("get_sky_horizon_color"), &ProceduralSkyMaterial::get_sky_horizon_color);
229
230
ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSkyMaterial::set_sky_curve);
231
ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSkyMaterial::get_sky_curve);
232
233
ClassDB::bind_method(D_METHOD("set_sky_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_sky_energy_multiplier);
234
ClassDB::bind_method(D_METHOD("get_sky_energy_multiplier"), &ProceduralSkyMaterial::get_sky_energy_multiplier);
235
236
ClassDB::bind_method(D_METHOD("set_sky_cover", "sky_cover"), &ProceduralSkyMaterial::set_sky_cover);
237
ClassDB::bind_method(D_METHOD("get_sky_cover"), &ProceduralSkyMaterial::get_sky_cover);
238
239
ClassDB::bind_method(D_METHOD("set_sky_cover_modulate", "color"), &ProceduralSkyMaterial::set_sky_cover_modulate);
240
ClassDB::bind_method(D_METHOD("get_sky_cover_modulate"), &ProceduralSkyMaterial::get_sky_cover_modulate);
241
242
ClassDB::bind_method(D_METHOD("set_ground_bottom_color", "color"), &ProceduralSkyMaterial::set_ground_bottom_color);
243
ClassDB::bind_method(D_METHOD("get_ground_bottom_color"), &ProceduralSkyMaterial::get_ground_bottom_color);
244
245
ClassDB::bind_method(D_METHOD("set_ground_horizon_color", "color"), &ProceduralSkyMaterial::set_ground_horizon_color);
246
ClassDB::bind_method(D_METHOD("get_ground_horizon_color"), &ProceduralSkyMaterial::get_ground_horizon_color);
247
248
ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSkyMaterial::set_ground_curve);
249
ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSkyMaterial::get_ground_curve);
250
251
ClassDB::bind_method(D_METHOD("set_ground_energy_multiplier", "energy"), &ProceduralSkyMaterial::set_ground_energy_multiplier);
252
ClassDB::bind_method(D_METHOD("get_ground_energy_multiplier"), &ProceduralSkyMaterial::get_ground_energy_multiplier);
253
254
ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSkyMaterial::set_sun_angle_max);
255
ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSkyMaterial::get_sun_angle_max);
256
257
ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSkyMaterial::set_sun_curve);
258
ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSkyMaterial::get_sun_curve);
259
260
ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &ProceduralSkyMaterial::set_use_debanding);
261
ClassDB::bind_method(D_METHOD("get_use_debanding"), &ProceduralSkyMaterial::get_use_debanding);
262
263
ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_energy_multiplier);
264
ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &ProceduralSkyMaterial::get_energy_multiplier);
265
266
ADD_GROUP("Sky", "sky_");
267
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color");
268
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_horizon_color", "get_sky_horizon_color");
269
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve");
270
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy_multiplier", "get_sky_energy_multiplier");
271
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_cover", PROPERTY_HINT_RESOURCE_TYPE, Texture2D::get_class_static()), "set_sky_cover", "get_sky_cover");
272
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_cover_modulate"), "set_sky_cover_modulate", "get_sky_cover_modulate");
273
274
ADD_GROUP("Ground", "ground_");
275
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_bottom_color", "get_ground_bottom_color");
276
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_horizon_color", "get_ground_horizon_color");
277
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve");
278
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy_multiplier", "get_ground_energy_multiplier");
279
280
ADD_GROUP("Sun", "sun_");
281
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01,degrees"), "set_sun_angle_max", "get_sun_angle_max");
282
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve");
283
284
ADD_GROUP("", "");
285
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");
286
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");
287
}
288
289
void ProceduralSkyMaterial::cleanup_shader() {
290
for (int i = 0; i < 4; i++) {
291
if (shader_cache[i].is_valid()) {
292
RS::get_singleton()->free_rid(shader_cache[i]);
293
}
294
}
295
}
296
297
void ProceduralSkyMaterial::_update_shader(bool p_use_debanding, bool p_use_sky_cover) {
298
MutexLock shader_lock(shader_mutex);
299
int index = int(p_use_debanding) + int(p_use_sky_cover) * 2;
300
if (shader_cache[index].is_null()) {
301
shader_cache[index] = RS::get_singleton()->shader_create();
302
303
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
304
RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(
305
// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s ProceduralSkyMaterial.
306
307
shader_type sky;
308
%s
309
310
uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0);
311
uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
312
uniform float inv_sky_curve : hint_range(1, 100) = 4.0;
313
uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0);
314
uniform vec4 ground_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
315
uniform float inv_ground_curve : hint_range(1, 100) = 30.0;
316
uniform float sun_angle_max = 0.877;
317
uniform float inv_sun_curve : hint_range(1, 100) = 22.78;
318
uniform float exposure : hint_range(0, 128) = 1.0;
319
320
uniform sampler2D sky_cover : filter_linear, source_color, hint_default_black;
321
uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0);
322
323
void sky() {
324
float v_angle = clamp(EYEDIR.y, -1.0, 1.0);
325
vec3 sky = mix(sky_top_color.rgb, sky_horizon_color.rgb, clamp(pow(1.0 - v_angle, inv_sky_curve), 0.0, 1.0));
326
327
if (LIGHT0_ENABLED) {
328
float sun_angle = dot(LIGHT0_DIRECTION, EYEDIR);
329
float sun_size = cos(LIGHT0_SIZE);
330
if (sun_angle > sun_size) {
331
sky = LIGHT0_COLOR * LIGHT0_ENERGY;
332
} else if (sun_angle > sun_angle_max) {
333
float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);
334
sky = mix(sky, LIGHT0_COLOR * LIGHT0_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));
335
}
336
}
337
338
if (LIGHT1_ENABLED) {
339
float sun_angle = dot(LIGHT1_DIRECTION, EYEDIR);
340
float sun_size = cos(LIGHT1_SIZE);
341
if (sun_angle > sun_size) {
342
sky = LIGHT1_COLOR * LIGHT1_ENERGY;
343
} else if (sun_angle > sun_angle_max) {
344
float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);
345
sky = mix(sky, LIGHT1_COLOR * LIGHT1_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));
346
}
347
}
348
349
if (LIGHT2_ENABLED) {
350
float sun_angle = dot(LIGHT2_DIRECTION, EYEDIR);
351
float sun_size = cos(LIGHT2_SIZE);
352
if (sun_angle > sun_size) {
353
sky = LIGHT2_COLOR * LIGHT2_ENERGY;
354
} else if (sun_angle > sun_angle_max) {
355
float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);
356
sky = mix(sky, LIGHT2_COLOR * LIGHT2_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));
357
}
358
}
359
360
if (LIGHT3_ENABLED) {
361
float sun_angle = dot(LIGHT3_DIRECTION, EYEDIR);
362
float sun_size = cos(LIGHT3_SIZE);
363
if (sun_angle > sun_size) {
364
sky = LIGHT3_COLOR * LIGHT3_ENERGY;
365
} else if (sun_angle > sun_angle_max) {
366
float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);
367
sky = mix(sky, LIGHT3_COLOR * LIGHT3_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));
368
}
369
}
370
371
%s
372
%s
373
vec3 ground = mix(ground_bottom_color.rgb, ground_horizon_color.rgb, clamp(pow(1.0 + v_angle, inv_ground_curve), 0.0, 1.0));
374
375
COLOR = mix(ground, sky, step(0.0, EYEDIR.y)) * exposure;
376
}
377
)",
378
p_use_debanding ? "render_mode use_debanding;" : "", p_use_sky_cover ? "vec4 sky_cover_texture = texture(sky_cover, SKY_COORDS);" : "", p_use_sky_cover ? "sky += (sky_cover_texture.rgb * sky_cover_modulate.rgb) * sky_cover_texture.a * sky_cover_modulate.a;" : ""));
379
}
380
}
381
382
ProceduralSkyMaterial::ProceduralSkyMaterial() {
383
_set_material(RS::get_singleton()->material_create());
384
set_sky_top_color(Color(0.385, 0.454, 0.55));
385
set_sky_horizon_color(Color(0.6463, 0.6558, 0.6708));
386
set_sky_curve(0.15);
387
set_sky_energy_multiplier(1.0);
388
set_sky_cover_modulate(Color(1, 1, 1));
389
390
set_ground_bottom_color(Color(0.2, 0.169, 0.133));
391
set_ground_horizon_color(Color(0.6463, 0.6558, 0.6708));
392
set_ground_curve(0.02);
393
set_ground_energy_multiplier(1.0);
394
395
set_sun_angle_max(30.0);
396
set_sun_curve(0.15);
397
set_use_debanding(true);
398
set_energy_multiplier(1.0);
399
}
400
401
ProceduralSkyMaterial::~ProceduralSkyMaterial() {
402
}
403
404
/////////////////////////////////////////
405
/* PanoramaSkyMaterial */
406
407
void PanoramaSkyMaterial::set_panorama(const Ref<Texture2D> &p_panorama) {
408
panorama = p_panorama;
409
if (p_panorama.is_valid()) {
410
RS::get_singleton()->material_set_param(_get_material(), "source_panorama", p_panorama->get_rid());
411
} else {
412
RS::get_singleton()->material_set_param(_get_material(), "source_panorama", Variant());
413
}
414
}
415
416
Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const {
417
return panorama;
418
}
419
420
void PanoramaSkyMaterial::set_filtering_enabled(bool p_enabled) {
421
filter = p_enabled;
422
notify_property_list_changed();
423
_update_shader(filter);
424
// Only set if shader already compiled
425
if (shader_set) {
426
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);
427
}
428
}
429
430
bool PanoramaSkyMaterial::is_filtering_enabled() const {
431
return filter;
432
}
433
434
void PanoramaSkyMaterial::set_energy_multiplier(float p_multiplier) {
435
energy_multiplier = p_multiplier;
436
RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier);
437
}
438
439
float PanoramaSkyMaterial::get_energy_multiplier() const {
440
return energy_multiplier;
441
}
442
443
Shader::Mode PanoramaSkyMaterial::get_shader_mode() const {
444
return Shader::MODE_SKY;
445
}
446
447
RID PanoramaSkyMaterial::get_rid() const {
448
_update_shader(filter);
449
if (!shader_set) {
450
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);
451
shader_set = true;
452
}
453
return _get_material();
454
}
455
456
RID PanoramaSkyMaterial::get_shader_rid() const {
457
_update_shader(filter);
458
return shader_cache[int(filter)];
459
}
460
461
void PanoramaSkyMaterial::_bind_methods() {
462
ClassDB::bind_method(D_METHOD("set_panorama", "texture"), &PanoramaSkyMaterial::set_panorama);
463
ClassDB::bind_method(D_METHOD("get_panorama"), &PanoramaSkyMaterial::get_panorama);
464
465
ClassDB::bind_method(D_METHOD("set_filtering_enabled", "enabled"), &PanoramaSkyMaterial::set_filtering_enabled);
466
ClassDB::bind_method(D_METHOD("is_filtering_enabled"), &PanoramaSkyMaterial::is_filtering_enabled);
467
468
ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PanoramaSkyMaterial::set_energy_multiplier);
469
ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PanoramaSkyMaterial::get_energy_multiplier);
470
471
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panorama", PROPERTY_HINT_RESOURCE_TYPE, Texture2D::get_class_static()), "set_panorama", "get_panorama");
472
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter"), "set_filtering_enabled", "is_filtering_enabled");
473
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");
474
}
475
476
Mutex PanoramaSkyMaterial::shader_mutex;
477
RID PanoramaSkyMaterial::shader_cache[2];
478
479
void PanoramaSkyMaterial::cleanup_shader() {
480
for (int i = 0; i < 2; i++) {
481
if (shader_cache[i].is_valid()) {
482
RS::get_singleton()->free_rid(shader_cache[i]);
483
}
484
}
485
}
486
487
void PanoramaSkyMaterial::_update_shader(bool p_filter) {
488
MutexLock shader_lock(shader_mutex);
489
int index = int(p_filter);
490
if (shader_cache[index].is_null()) {
491
shader_cache[index] = RS::get_singleton()->shader_create();
492
493
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
494
RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(
495
// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s PanoramaSkyMaterial.
496
497
shader_type sky;
498
499
uniform sampler2D source_panorama : %s, source_color, hint_default_black;
500
uniform float exposure : hint_range(0, 128) = 1.0;
501
502
void sky() {
503
COLOR = texture(source_panorama, SKY_COORDS).rgb * exposure;
504
}
505
)",
506
p_filter ? "filter_linear" : "filter_nearest"));
507
}
508
}
509
510
PanoramaSkyMaterial::PanoramaSkyMaterial() {
511
_set_material(RS::get_singleton()->material_create());
512
set_energy_multiplier(1.0);
513
}
514
515
PanoramaSkyMaterial::~PanoramaSkyMaterial() {
516
}
517
518
//////////////////////////////////
519
/* PhysicalSkyMaterial */
520
521
void PhysicalSkyMaterial::set_rayleigh_coefficient(float p_rayleigh) {
522
rayleigh = p_rayleigh;
523
RS::get_singleton()->material_set_param(_get_material(), "rayleigh", rayleigh);
524
}
525
526
float PhysicalSkyMaterial::get_rayleigh_coefficient() const {
527
return rayleigh;
528
}
529
530
void PhysicalSkyMaterial::set_rayleigh_color(Color p_rayleigh_color) {
531
rayleigh_color = p_rayleigh_color;
532
RS::get_singleton()->material_set_param(_get_material(), "rayleigh_color", rayleigh_color);
533
}
534
535
Color PhysicalSkyMaterial::get_rayleigh_color() const {
536
return rayleigh_color;
537
}
538
539
void PhysicalSkyMaterial::set_mie_coefficient(float p_mie) {
540
mie = p_mie;
541
RS::get_singleton()->material_set_param(_get_material(), "mie", mie);
542
}
543
544
float PhysicalSkyMaterial::get_mie_coefficient() const {
545
return mie;
546
}
547
548
void PhysicalSkyMaterial::set_mie_eccentricity(float p_eccentricity) {
549
mie_eccentricity = p_eccentricity;
550
RS::get_singleton()->material_set_param(_get_material(), "mie_eccentricity", mie_eccentricity);
551
}
552
553
float PhysicalSkyMaterial::get_mie_eccentricity() const {
554
return mie_eccentricity;
555
}
556
557
void PhysicalSkyMaterial::set_mie_color(Color p_mie_color) {
558
mie_color = p_mie_color;
559
RS::get_singleton()->material_set_param(_get_material(), "mie_color", mie_color);
560
}
561
562
Color PhysicalSkyMaterial::get_mie_color() const {
563
return mie_color;
564
}
565
566
void PhysicalSkyMaterial::set_turbidity(float p_turbidity) {
567
turbidity = p_turbidity;
568
RS::get_singleton()->material_set_param(_get_material(), "turbidity", turbidity);
569
}
570
571
float PhysicalSkyMaterial::get_turbidity() const {
572
return turbidity;
573
}
574
575
void PhysicalSkyMaterial::set_sun_disk_scale(float p_sun_disk_scale) {
576
sun_disk_scale = p_sun_disk_scale;
577
RS::get_singleton()->material_set_param(_get_material(), "sun_disk_scale", sun_disk_scale);
578
}
579
580
float PhysicalSkyMaterial::get_sun_disk_scale() const {
581
return sun_disk_scale;
582
}
583
584
void PhysicalSkyMaterial::set_ground_color(Color p_ground_color) {
585
ground_color = p_ground_color;
586
RS::get_singleton()->material_set_param(_get_material(), "ground_color", ground_color);
587
}
588
589
Color PhysicalSkyMaterial::get_ground_color() const {
590
return ground_color;
591
}
592
593
void PhysicalSkyMaterial::set_energy_multiplier(float p_multiplier) {
594
energy_multiplier = p_multiplier;
595
RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier);
596
}
597
598
float PhysicalSkyMaterial::get_energy_multiplier() const {
599
return energy_multiplier;
600
}
601
602
void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) {
603
use_debanding = p_use_debanding;
604
_update_shader(use_debanding, night_sky.is_valid());
605
// Only set if shader already compiled
606
if (shader_set) {
607
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
608
}
609
}
610
611
bool PhysicalSkyMaterial::get_use_debanding() const {
612
return use_debanding;
613
}
614
615
void PhysicalSkyMaterial::set_night_sky(const Ref<Texture2D> &p_night_sky) {
616
night_sky = p_night_sky;
617
if (p_night_sky.is_valid()) {
618
RS::get_singleton()->material_set_param(_get_material(), "night_sky", p_night_sky->get_rid());
619
} else {
620
RS::get_singleton()->material_set_param(_get_material(), "night_sky", Variant());
621
}
622
623
_update_shader(use_debanding, night_sky.is_valid());
624
625
if (shader_set) {
626
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
627
}
628
}
629
630
Ref<Texture2D> PhysicalSkyMaterial::get_night_sky() const {
631
return night_sky;
632
}
633
634
Shader::Mode PhysicalSkyMaterial::get_shader_mode() const {
635
return Shader::MODE_SKY;
636
}
637
638
// Internal function to grab the current shader RID.
639
// Must only be called if the shader is initialized.
640
RID PhysicalSkyMaterial::get_shader_cache() const {
641
return shader_cache[int(use_debanding) + (night_sky.is_valid() ? 2 : 0)];
642
}
643
644
RID PhysicalSkyMaterial::get_rid() const {
645
_update_shader(use_debanding, night_sky.is_valid());
646
if (!shader_set) {
647
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
648
shader_set = true;
649
}
650
return _get_material();
651
}
652
653
RID PhysicalSkyMaterial::get_shader_rid() const {
654
_update_shader(use_debanding, night_sky.is_valid());
655
return get_shader_cache();
656
}
657
658
void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {
659
if (!Engine::get_singleton()->is_editor_hint()) {
660
return;
661
}
662
if (p_property.name == "exposure_value" && !GLOBAL_GET_CACHED(bool, "rendering/lights_and_shadows/use_physical_light_units")) {
663
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
664
}
665
}
666
667
Mutex PhysicalSkyMaterial::shader_mutex;
668
RID PhysicalSkyMaterial::shader_cache[4];
669
670
void PhysicalSkyMaterial::_bind_methods() {
671
ClassDB::bind_method(D_METHOD("set_rayleigh_coefficient", "rayleigh"), &PhysicalSkyMaterial::set_rayleigh_coefficient);
672
ClassDB::bind_method(D_METHOD("get_rayleigh_coefficient"), &PhysicalSkyMaterial::get_rayleigh_coefficient);
673
674
ClassDB::bind_method(D_METHOD("set_rayleigh_color", "color"), &PhysicalSkyMaterial::set_rayleigh_color);
675
ClassDB::bind_method(D_METHOD("get_rayleigh_color"), &PhysicalSkyMaterial::get_rayleigh_color);
676
677
ClassDB::bind_method(D_METHOD("set_mie_coefficient", "mie"), &PhysicalSkyMaterial::set_mie_coefficient);
678
ClassDB::bind_method(D_METHOD("get_mie_coefficient"), &PhysicalSkyMaterial::get_mie_coefficient);
679
680
ClassDB::bind_method(D_METHOD("set_mie_eccentricity", "eccentricity"), &PhysicalSkyMaterial::set_mie_eccentricity);
681
ClassDB::bind_method(D_METHOD("get_mie_eccentricity"), &PhysicalSkyMaterial::get_mie_eccentricity);
682
683
ClassDB::bind_method(D_METHOD("set_mie_color", "color"), &PhysicalSkyMaterial::set_mie_color);
684
ClassDB::bind_method(D_METHOD("get_mie_color"), &PhysicalSkyMaterial::get_mie_color);
685
686
ClassDB::bind_method(D_METHOD("set_turbidity", "turbidity"), &PhysicalSkyMaterial::set_turbidity);
687
ClassDB::bind_method(D_METHOD("get_turbidity"), &PhysicalSkyMaterial::get_turbidity);
688
689
ClassDB::bind_method(D_METHOD("set_sun_disk_scale", "scale"), &PhysicalSkyMaterial::set_sun_disk_scale);
690
ClassDB::bind_method(D_METHOD("get_sun_disk_scale"), &PhysicalSkyMaterial::get_sun_disk_scale);
691
692
ClassDB::bind_method(D_METHOD("set_ground_color", "color"), &PhysicalSkyMaterial::set_ground_color);
693
ClassDB::bind_method(D_METHOD("get_ground_color"), &PhysicalSkyMaterial::get_ground_color);
694
695
ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PhysicalSkyMaterial::set_energy_multiplier);
696
ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PhysicalSkyMaterial::get_energy_multiplier);
697
698
ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &PhysicalSkyMaterial::set_use_debanding);
699
ClassDB::bind_method(D_METHOD("get_use_debanding"), &PhysicalSkyMaterial::get_use_debanding);
700
701
ClassDB::bind_method(D_METHOD("set_night_sky", "night_sky"), &PhysicalSkyMaterial::set_night_sky);
702
ClassDB::bind_method(D_METHOD("get_night_sky"), &PhysicalSkyMaterial::get_night_sky);
703
704
ADD_GROUP("Rayleigh", "rayleigh_");
705
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rayleigh_coefficient", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_rayleigh_coefficient", "get_rayleigh_coefficient");
706
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "rayleigh_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_rayleigh_color", "get_rayleigh_color");
707
708
ADD_GROUP("Mie", "mie_");
709
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_coefficient", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_mie_coefficient", "get_mie_coefficient");
710
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_eccentricity", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_mie_eccentricity", "get_mie_eccentricity");
711
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "mie_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_mie_color", "get_mie_color");
712
713
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbidity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_turbidity", "get_turbidity");
714
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale");
715
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_color", "get_ground_color");
716
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");
717
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");
718
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "night_sky", PROPERTY_HINT_RESOURCE_TYPE, Texture2D::get_class_static()), "set_night_sky", "get_night_sky");
719
}
720
721
void PhysicalSkyMaterial::cleanup_shader() {
722
for (int i = 0; i < 4; i++) {
723
if (shader_cache[i].is_valid()) {
724
RS::get_singleton()->free_rid(shader_cache[i]);
725
}
726
}
727
}
728
729
void PhysicalSkyMaterial::_update_shader(bool p_use_debanding, bool p_use_night_sky) {
730
MutexLock shader_lock(shader_mutex);
731
int index = int(p_use_debanding) + int(p_use_night_sky) * 2;
732
if (shader_cache[index].is_null()) {
733
shader_cache[index] = RS::get_singleton()->shader_create();
734
735
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
736
RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(
737
// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s PhysicalSkyMaterial.
738
739
shader_type sky;
740
%s
741
742
uniform float rayleigh : hint_range(0, 64) = 2.0;
743
uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0);
744
uniform float mie : hint_range(0, 1) = 0.005;
745
uniform float mie_eccentricity : hint_range(-1, 1) = 0.8;
746
uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0);
747
748
uniform float turbidity : hint_range(0, 1000) = 10.0;
749
uniform float sun_disk_scale : hint_range(0, 360) = 1.0;
750
uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0);
751
uniform float exposure : hint_range(0, 128) = 1.0;
752
753
uniform sampler2D night_sky : filter_linear, source_color, hint_default_black;
754
755
const vec3 UP = vec3( 0.0, 1.0, 0.0 );
756
757
// Optical length at zenith for molecules.
758
const float rayleigh_zenith_size = 8.4e3;
759
const float mie_zenith_size = 1.25e3;
760
761
float henyey_greenstein(float cos_theta, float g) {
762
const float k = 0.0795774715459;
763
return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));
764
}
765
766
void sky() {
767
if (LIGHT0_ENABLED) {
768
float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );
769
float sun_energy = max(0.0, 0.757 * zenith_angle) * LIGHT0_ENERGY;
770
float sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);
771
772
// Rayleigh coefficients.
773
float rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) );
774
vec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001;
775
// mie coefficients from Preetham
776
vec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434;
777
778
// Optical length.
779
float zenith = max(0.0, dot(UP, EYEDIR));
780
float optical_mass = 1.0 / (zenith + 0.15 * pow(3.885 + 54.5 * zenith, -1.253));
781
float rayleigh_scatter = rayleigh_zenith_size * optical_mass;
782
float mie_scatter = mie_zenith_size * optical_mass;
783
784
// Light extinction based on thickness of atmosphere.
785
vec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter));
786
787
// In scattering.
788
float cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION));
789
790
float rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0));
791
vec3 betaRTheta = rayleigh_beta * rayleigh_phase;
792
793
float mie_phase = henyey_greenstein(cos_theta, mie_eccentricity);
794
vec3 betaMTheta = mie_beta * mie_phase;
795
796
vec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5));
797
// Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js
798
Lin *= mix(vec3(1.0), pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * extinction, vec3(0.5)), clamp(pow(1.0 - zenith_angle, 5.0), 0.0, 1.0));
799
800
// Hack in the ground color.
801
Lin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR)));
802
803
// Solar disk and out-scattering.
804
float sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);
805
float sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale * 0.5);
806
float sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);
807
vec3 L0 = (sun_energy * extinction) * sundisk * LIGHT0_COLOR;
808
%s
809
810
vec3 color = Lin + L0;
811
COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));
812
COLOR *= exposure;
813
} else {
814
// There is no sun, so display night_sky and nothing else.
815
%s
816
COLOR *= exposure;
817
}
818
}
819
)",
820
p_use_debanding ? "render_mode use_debanding;" : "", p_use_night_sky ? "L0 += texture(night_sky, SKY_COORDS).xyz * extinction;" : "", p_use_night_sky ? "COLOR = texture(night_sky, SKY_COORDS).xyz;" : ""));
821
}
822
}
823
824
PhysicalSkyMaterial::PhysicalSkyMaterial() {
825
_set_material(RS::get_singleton()->material_create());
826
set_rayleigh_coefficient(2.0);
827
set_rayleigh_color(Color(0.3, 0.405, 0.6));
828
set_mie_coefficient(0.005);
829
set_mie_eccentricity(0.8);
830
set_mie_color(Color(0.69, 0.729, 0.812));
831
set_turbidity(10.0);
832
set_sun_disk_scale(1.0);
833
set_ground_color(Color(0.1, 0.07, 0.034));
834
set_energy_multiplier(1.0);
835
set_use_debanding(true);
836
}
837
838
PhysicalSkyMaterial::~PhysicalSkyMaterial() {
839
}
840
841