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
36Mutex ProceduralSkyMaterial::shader_mutex;
37RID ProceduralSkyMaterial::shader_cache[2];
38
39void ProceduralSkyMaterial::set_sky_top_color(const Color &p_sky_top) {
40 sky_top_color = p_sky_top;
41 RS::get_singleton()->material_set_param(_get_material(), "sky_top_color", sky_top_color);
42}
43
44Color ProceduralSkyMaterial::get_sky_top_color() const {
45 return sky_top_color;
46}
47
48void ProceduralSkyMaterial::set_sky_horizon_color(const Color &p_sky_horizon) {
49 sky_horizon_color = p_sky_horizon;
50 RS::get_singleton()->material_set_param(_get_material(), "sky_horizon_color", sky_horizon_color);
51}
52
53Color ProceduralSkyMaterial::get_sky_horizon_color() const {
54 return sky_horizon_color;
55}
56
57void ProceduralSkyMaterial::set_sky_curve(float p_curve) {
58 sky_curve = p_curve;
59 RS::get_singleton()->material_set_param(_get_material(), "sky_curve", sky_curve);
60}
61
62float ProceduralSkyMaterial::get_sky_curve() const {
63 return sky_curve;
64}
65
66void ProceduralSkyMaterial::set_sky_energy_multiplier(float p_multiplier) {
67 sky_energy_multiplier = p_multiplier;
68 RS::get_singleton()->material_set_param(_get_material(), "sky_energy", sky_energy_multiplier);
69}
70
71float ProceduralSkyMaterial::get_sky_energy_multiplier() const {
72 return sky_energy_multiplier;
73}
74
75void ProceduralSkyMaterial::set_sky_cover(const Ref<Texture2D> &p_sky_cover) {
76 sky_cover = p_sky_cover;
77 if (p_sky_cover.is_valid()) {
78 RS::get_singleton()->material_set_param(_get_material(), "sky_cover", p_sky_cover->get_rid());
79 } else {
80 RS::get_singleton()->material_set_param(_get_material(), "sky_cover", Variant());
81 }
82}
83
84Ref<Texture2D> ProceduralSkyMaterial::get_sky_cover() const {
85 return sky_cover;
86}
87
88void ProceduralSkyMaterial::set_sky_cover_modulate(const Color &p_sky_cover_modulate) {
89 sky_cover_modulate = p_sky_cover_modulate;
90 RS::get_singleton()->material_set_param(_get_material(), "sky_cover_modulate", sky_cover_modulate);
91}
92
93Color ProceduralSkyMaterial::get_sky_cover_modulate() const {
94 return sky_cover_modulate;
95}
96
97void ProceduralSkyMaterial::set_ground_bottom_color(const Color &p_ground_bottom) {
98 ground_bottom_color = p_ground_bottom;
99 RS::get_singleton()->material_set_param(_get_material(), "ground_bottom_color", ground_bottom_color);
100}
101
102Color ProceduralSkyMaterial::get_ground_bottom_color() const {
103 return ground_bottom_color;
104}
105
106void ProceduralSkyMaterial::set_ground_horizon_color(const Color &p_ground_horizon) {
107 ground_horizon_color = p_ground_horizon;
108 RS::get_singleton()->material_set_param(_get_material(), "ground_horizon_color", ground_horizon_color);
109}
110
111Color ProceduralSkyMaterial::get_ground_horizon_color() const {
112 return ground_horizon_color;
113}
114
115void ProceduralSkyMaterial::set_ground_curve(float p_curve) {
116 ground_curve = p_curve;
117 RS::get_singleton()->material_set_param(_get_material(), "ground_curve", ground_curve);
118}
119
120float ProceduralSkyMaterial::get_ground_curve() const {
121 return ground_curve;
122}
123
124void ProceduralSkyMaterial::set_ground_energy_multiplier(float p_multiplier) {
125 ground_energy_multiplier = p_multiplier;
126 RS::get_singleton()->material_set_param(_get_material(), "ground_energy", ground_energy_multiplier);
127}
128
129float ProceduralSkyMaterial::get_ground_energy_multiplier() const {
130 return ground_energy_multiplier;
131}
132
133void ProceduralSkyMaterial::set_sun_angle_max(float p_angle) {
134 sun_angle_max = p_angle;
135 RS::get_singleton()->material_set_param(_get_material(), "sun_angle_max", Math::deg_to_rad(sun_angle_max));
136}
137
138float ProceduralSkyMaterial::get_sun_angle_max() const {
139 return sun_angle_max;
140}
141
142void ProceduralSkyMaterial::set_sun_curve(float p_curve) {
143 sun_curve = p_curve;
144 RS::get_singleton()->material_set_param(_get_material(), "sun_curve", sun_curve);
145}
146
147float ProceduralSkyMaterial::get_sun_curve() const {
148 return sun_curve;
149}
150
151void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) {
152 use_debanding = p_use_debanding;
153 _update_shader();
154 // Only set if shader already compiled
155 if (shader_set) {
156 RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
157 }
158}
159
160bool ProceduralSkyMaterial::get_use_debanding() const {
161 return use_debanding;
162}
163
164Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {
165 return Shader::MODE_SKY;
166}
167
168RID ProceduralSkyMaterial::get_rid() const {
169 _update_shader();
170 if (!shader_set) {
171 RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]);
172 RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
173 shader_set = true;
174 }
175 return _get_material();
176}
177
178RID ProceduralSkyMaterial::get_shader_rid() const {
179 _update_shader();
180 return shader_cache[int(use_debanding)];
181}
182
183void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const {
184 if ((p_property.name == "sky_luminance" || p_property.name == "ground_luminance") && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
185 p_property.usage = PROPERTY_USAGE_NO_EDITOR;
186 }
187}
188
189void ProceduralSkyMaterial::_bind_methods() {
190 ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSkyMaterial::set_sky_top_color);
191 ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSkyMaterial::get_sky_top_color);
192
193 ClassDB::bind_method(D_METHOD("set_sky_horizon_color", "color"), &ProceduralSkyMaterial::set_sky_horizon_color);
194 ClassDB::bind_method(D_METHOD("get_sky_horizon_color"), &ProceduralSkyMaterial::get_sky_horizon_color);
195
196 ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSkyMaterial::set_sky_curve);
197 ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSkyMaterial::get_sky_curve);
198
199 ClassDB::bind_method(D_METHOD("set_sky_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_sky_energy_multiplier);
200 ClassDB::bind_method(D_METHOD("get_sky_energy_multiplier"), &ProceduralSkyMaterial::get_sky_energy_multiplier);
201
202 ClassDB::bind_method(D_METHOD("set_sky_cover", "sky_cover"), &ProceduralSkyMaterial::set_sky_cover);
203 ClassDB::bind_method(D_METHOD("get_sky_cover"), &ProceduralSkyMaterial::get_sky_cover);
204
205 ClassDB::bind_method(D_METHOD("set_sky_cover_modulate", "color"), &ProceduralSkyMaterial::set_sky_cover_modulate);
206 ClassDB::bind_method(D_METHOD("get_sky_cover_modulate"), &ProceduralSkyMaterial::get_sky_cover_modulate);
207
208 ClassDB::bind_method(D_METHOD("set_ground_bottom_color", "color"), &ProceduralSkyMaterial::set_ground_bottom_color);
209 ClassDB::bind_method(D_METHOD("get_ground_bottom_color"), &ProceduralSkyMaterial::get_ground_bottom_color);
210
211 ClassDB::bind_method(D_METHOD("set_ground_horizon_color", "color"), &ProceduralSkyMaterial::set_ground_horizon_color);
212 ClassDB::bind_method(D_METHOD("get_ground_horizon_color"), &ProceduralSkyMaterial::get_ground_horizon_color);
213
214 ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSkyMaterial::set_ground_curve);
215 ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSkyMaterial::get_ground_curve);
216
217 ClassDB::bind_method(D_METHOD("set_ground_energy_multiplier", "energy"), &ProceduralSkyMaterial::set_ground_energy_multiplier);
218 ClassDB::bind_method(D_METHOD("get_ground_energy_multiplier"), &ProceduralSkyMaterial::get_ground_energy_multiplier);
219
220 ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSkyMaterial::set_sun_angle_max);
221 ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSkyMaterial::get_sun_angle_max);
222
223 ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSkyMaterial::set_sun_curve);
224 ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSkyMaterial::get_sun_curve);
225
226 ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &ProceduralSkyMaterial::set_use_debanding);
227 ClassDB::bind_method(D_METHOD("get_use_debanding"), &ProceduralSkyMaterial::get_use_debanding);
228
229 ADD_GROUP("Sky", "sky_");
230 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color");
231 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_horizon_color", "get_sky_horizon_color");
232 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve");
233 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy_multiplier", "get_sky_energy_multiplier");
234 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_cover", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_sky_cover", "get_sky_cover");
235 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_cover_modulate"), "set_sky_cover_modulate", "get_sky_cover_modulate");
236
237 ADD_GROUP("Ground", "ground_");
238 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_bottom_color", "get_ground_bottom_color");
239 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_horizon_color", "get_ground_horizon_color");
240 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve");
241 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy_multiplier", "get_ground_energy_multiplier");
242
243 ADD_GROUP("Sun", "sun_");
244 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01,degrees"), "set_sun_angle_max", "get_sun_angle_max");
245 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve");
246
247 ADD_GROUP("", "");
248 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");
249}
250
251void ProceduralSkyMaterial::cleanup_shader() {
252 if (shader_cache[0].is_valid()) {
253 RS::get_singleton()->free(shader_cache[0]);
254 RS::get_singleton()->free(shader_cache[1]);
255 }
256}
257
258void ProceduralSkyMaterial::_update_shader() {
259 shader_mutex.lock();
260 if (shader_cache[0].is_null()) {
261 for (int i = 0; i < 2; i++) {
262 shader_cache[i] = RS::get_singleton()->shader_create();
263
264 // Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
265 RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"(
266// NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s ProceduralSkyMaterial.
267
268shader_type sky;
269%s
270
271uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0);
272uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
273uniform float sky_curve : hint_range(0, 1) = 0.15;
274uniform float sky_energy = 1.0; // In Lux.
275uniform sampler2D sky_cover : filter_linear, source_color, hint_default_black;
276uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0);
277uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0);
278uniform vec4 ground_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
279uniform float ground_curve : hint_range(0, 1) = 0.02;
280uniform float ground_energy = 1.0;
281uniform float sun_angle_max = 30.0;
282uniform float sun_curve : hint_range(0, 1) = 0.15;
283
284void sky() {
285 float v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));
286 float c = (1.0 - v_angle / (PI * 0.5));
287 vec3 sky = mix(sky_horizon_color.rgb, sky_top_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / sky_curve), 0.0, 1.0));
288 sky *= sky_energy;
289
290 if (LIGHT0_ENABLED) {
291 float sun_angle = acos(dot(LIGHT0_DIRECTION, EYEDIR));
292 if (sun_angle < LIGHT0_SIZE) {
293 sky = LIGHT0_COLOR * LIGHT0_ENERGY;
294 } else if (sun_angle < sun_angle_max) {
295 float c2 = (sun_angle - LIGHT0_SIZE) / (sun_angle_max - LIGHT0_SIZE);
296 sky = mix(LIGHT0_COLOR * LIGHT0_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));
297 }
298 }
299
300 if (LIGHT1_ENABLED) {
301 float sun_angle = acos(dot(LIGHT1_DIRECTION, EYEDIR));
302 if (sun_angle < LIGHT1_SIZE) {
303 sky = LIGHT1_COLOR * LIGHT1_ENERGY;
304 } else if (sun_angle < sun_angle_max) {
305 float c2 = (sun_angle - LIGHT1_SIZE) / (sun_angle_max - LIGHT1_SIZE);
306 sky = mix(LIGHT1_COLOR * LIGHT1_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));
307 }
308 }
309
310 if (LIGHT2_ENABLED) {
311 float sun_angle = acos(dot(LIGHT2_DIRECTION, EYEDIR));
312 if (sun_angle < LIGHT2_SIZE) {
313 sky = LIGHT2_COLOR * LIGHT2_ENERGY;
314 } else if (sun_angle < sun_angle_max) {
315 float c2 = (sun_angle - LIGHT2_SIZE) / (sun_angle_max - LIGHT2_SIZE);
316 sky = mix(LIGHT2_COLOR * LIGHT2_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));
317 }
318 }
319
320 if (LIGHT3_ENABLED) {
321 float sun_angle = acos(dot(LIGHT3_DIRECTION, EYEDIR));
322 if (sun_angle < LIGHT3_SIZE) {
323 sky = LIGHT3_COLOR * LIGHT3_ENERGY;
324 } else if (sun_angle < sun_angle_max) {
325 float c2 = (sun_angle - LIGHT3_SIZE) / (sun_angle_max - LIGHT3_SIZE);
326 sky = mix(LIGHT3_COLOR * LIGHT3_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));
327 }
328 }
329
330 vec4 sky_cover_texture = texture(sky_cover, SKY_COORDS);
331 sky += (sky_cover_texture.rgb * sky_cover_modulate.rgb) * sky_cover_texture.a * sky_cover_modulate.a * sky_energy;
332
333 c = (v_angle - (PI * 0.5)) / (PI * 0.5);
334 vec3 ground = mix(ground_horizon_color.rgb, ground_bottom_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / ground_curve), 0.0, 1.0));
335 ground *= ground_energy;
336
337 COLOR = mix(ground, sky, step(0.0, EYEDIR.y));
338}
339)",
340 i ? "render_mode use_debanding;" : ""));
341 }
342 }
343 shader_mutex.unlock();
344}
345
346ProceduralSkyMaterial::ProceduralSkyMaterial() {
347 set_sky_top_color(Color(0.385, 0.454, 0.55));
348 set_sky_horizon_color(Color(0.6463, 0.6558, 0.6708));
349 set_sky_curve(0.15);
350 set_sky_energy_multiplier(1.0);
351 set_sky_cover_modulate(Color(1, 1, 1));
352
353 set_ground_bottom_color(Color(0.2, 0.169, 0.133));
354 set_ground_horizon_color(Color(0.6463, 0.6558, 0.6708));
355 set_ground_curve(0.02);
356 set_ground_energy_multiplier(1.0);
357
358 set_sun_angle_max(30.0);
359 set_sun_curve(0.15);
360 set_use_debanding(true);
361}
362
363ProceduralSkyMaterial::~ProceduralSkyMaterial() {
364}
365
366/////////////////////////////////////////
367/* PanoramaSkyMaterial */
368
369void PanoramaSkyMaterial::set_panorama(const Ref<Texture2D> &p_panorama) {
370 panorama = p_panorama;
371 if (p_panorama.is_valid()) {
372 RS::get_singleton()->material_set_param(_get_material(), "source_panorama", p_panorama->get_rid());
373 } else {
374 RS::get_singleton()->material_set_param(_get_material(), "source_panorama", Variant());
375 }
376}
377
378Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const {
379 return panorama;
380}
381
382void PanoramaSkyMaterial::set_filtering_enabled(bool p_enabled) {
383 filter = p_enabled;
384 notify_property_list_changed();
385 _update_shader();
386 // Only set if shader already compiled
387 if (shader_set) {
388 RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);
389 }
390}
391
392bool PanoramaSkyMaterial::is_filtering_enabled() const {
393 return filter;
394}
395
396Shader::Mode PanoramaSkyMaterial::get_shader_mode() const {
397 return Shader::MODE_SKY;
398}
399
400RID PanoramaSkyMaterial::get_rid() const {
401 _update_shader();
402 // Don't compile shaders until first use, then compile both
403 if (!shader_set) {
404 RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(filter)]);
405 RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);
406 shader_set = true;
407 }
408 return _get_material();
409}
410
411RID PanoramaSkyMaterial::get_shader_rid() const {
412 _update_shader();
413 return shader_cache[int(filter)];
414}
415
416void PanoramaSkyMaterial::_bind_methods() {
417 ClassDB::bind_method(D_METHOD("set_panorama", "texture"), &PanoramaSkyMaterial::set_panorama);
418 ClassDB::bind_method(D_METHOD("get_panorama"), &PanoramaSkyMaterial::get_panorama);
419
420 ClassDB::bind_method(D_METHOD("set_filtering_enabled", "enabled"), &PanoramaSkyMaterial::set_filtering_enabled);
421 ClassDB::bind_method(D_METHOD("is_filtering_enabled"), &PanoramaSkyMaterial::is_filtering_enabled);
422
423 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panorama", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_panorama", "get_panorama");
424 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter"), "set_filtering_enabled", "is_filtering_enabled");
425}
426
427Mutex PanoramaSkyMaterial::shader_mutex;
428RID PanoramaSkyMaterial::shader_cache[2];
429
430void PanoramaSkyMaterial::cleanup_shader() {
431 if (shader_cache[0].is_valid()) {
432 RS::get_singleton()->free(shader_cache[0]);
433 RS::get_singleton()->free(shader_cache[1]);
434 }
435}
436
437void PanoramaSkyMaterial::_update_shader() {
438 shader_mutex.lock();
439 if (shader_cache[0].is_null()) {
440 for (int i = 0; i < 2; i++) {
441 shader_cache[i] = RS::get_singleton()->shader_create();
442
443 // Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
444 RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"(
445// NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s PanoramaSkyMaterial.
446
447shader_type sky;
448
449uniform sampler2D source_panorama : %s, source_color, hint_default_black;
450
451void sky() {
452 COLOR = texture(source_panorama, SKY_COORDS).rgb;
453}
454)",
455 i ? "filter_linear" : "filter_nearest"));
456 }
457 }
458
459 shader_mutex.unlock();
460}
461
462PanoramaSkyMaterial::PanoramaSkyMaterial() {
463}
464
465PanoramaSkyMaterial::~PanoramaSkyMaterial() {
466}
467
468//////////////////////////////////
469/* PhysicalSkyMaterial */
470
471void PhysicalSkyMaterial::set_rayleigh_coefficient(float p_rayleigh) {
472 rayleigh = p_rayleigh;
473 RS::get_singleton()->material_set_param(_get_material(), "rayleigh", rayleigh);
474}
475
476float PhysicalSkyMaterial::get_rayleigh_coefficient() const {
477 return rayleigh;
478}
479
480void PhysicalSkyMaterial::set_rayleigh_color(Color p_rayleigh_color) {
481 rayleigh_color = p_rayleigh_color;
482 RS::get_singleton()->material_set_param(_get_material(), "rayleigh_color", rayleigh_color);
483}
484
485Color PhysicalSkyMaterial::get_rayleigh_color() const {
486 return rayleigh_color;
487}
488
489void PhysicalSkyMaterial::set_mie_coefficient(float p_mie) {
490 mie = p_mie;
491 RS::get_singleton()->material_set_param(_get_material(), "mie", mie);
492}
493
494float PhysicalSkyMaterial::get_mie_coefficient() const {
495 return mie;
496}
497
498void PhysicalSkyMaterial::set_mie_eccentricity(float p_eccentricity) {
499 mie_eccentricity = p_eccentricity;
500 RS::get_singleton()->material_set_param(_get_material(), "mie_eccentricity", mie_eccentricity);
501}
502
503float PhysicalSkyMaterial::get_mie_eccentricity() const {
504 return mie_eccentricity;
505}
506
507void PhysicalSkyMaterial::set_mie_color(Color p_mie_color) {
508 mie_color = p_mie_color;
509 RS::get_singleton()->material_set_param(_get_material(), "mie_color", mie_color);
510}
511
512Color PhysicalSkyMaterial::get_mie_color() const {
513 return mie_color;
514}
515
516void PhysicalSkyMaterial::set_turbidity(float p_turbidity) {
517 turbidity = p_turbidity;
518 RS::get_singleton()->material_set_param(_get_material(), "turbidity", turbidity);
519}
520
521float PhysicalSkyMaterial::get_turbidity() const {
522 return turbidity;
523}
524
525void PhysicalSkyMaterial::set_sun_disk_scale(float p_sun_disk_scale) {
526 sun_disk_scale = p_sun_disk_scale;
527 RS::get_singleton()->material_set_param(_get_material(), "sun_disk_scale", sun_disk_scale);
528}
529
530float PhysicalSkyMaterial::get_sun_disk_scale() const {
531 return sun_disk_scale;
532}
533
534void PhysicalSkyMaterial::set_ground_color(Color p_ground_color) {
535 ground_color = p_ground_color;
536 RS::get_singleton()->material_set_param(_get_material(), "ground_color", ground_color);
537}
538
539Color PhysicalSkyMaterial::get_ground_color() const {
540 return ground_color;
541}
542
543void PhysicalSkyMaterial::set_energy_multiplier(float p_multiplier) {
544 energy_multiplier = p_multiplier;
545 RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier);
546}
547
548float PhysicalSkyMaterial::get_energy_multiplier() const {
549 return energy_multiplier;
550}
551
552void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) {
553 use_debanding = p_use_debanding;
554 _update_shader();
555 // Only set if shader already compiled
556 if (shader_set) {
557 RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
558 }
559}
560
561bool PhysicalSkyMaterial::get_use_debanding() const {
562 return use_debanding;
563}
564
565void PhysicalSkyMaterial::set_night_sky(const Ref<Texture2D> &p_night_sky) {
566 night_sky = p_night_sky;
567 if (p_night_sky.is_valid()) {
568 RS::get_singleton()->material_set_param(_get_material(), "night_sky", p_night_sky->get_rid());
569 } else {
570 RS::get_singleton()->material_set_param(_get_material(), "night_sky", Variant());
571 }
572}
573
574Ref<Texture2D> PhysicalSkyMaterial::get_night_sky() const {
575 return night_sky;
576}
577
578Shader::Mode PhysicalSkyMaterial::get_shader_mode() const {
579 return Shader::MODE_SKY;
580}
581
582RID PhysicalSkyMaterial::get_rid() const {
583 _update_shader();
584 if (!shader_set) {
585 RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]);
586 RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
587 shader_set = true;
588 }
589 return _get_material();
590}
591
592RID PhysicalSkyMaterial::get_shader_rid() const {
593 _update_shader();
594 return shader_cache[int(use_debanding)];
595}
596
597void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {
598 if (p_property.name == "exposure_value" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
599 p_property.usage = PROPERTY_USAGE_NO_EDITOR;
600 }
601}
602
603Mutex PhysicalSkyMaterial::shader_mutex;
604RID PhysicalSkyMaterial::shader_cache[2];
605
606void PhysicalSkyMaterial::_bind_methods() {
607 ClassDB::bind_method(D_METHOD("set_rayleigh_coefficient", "rayleigh"), &PhysicalSkyMaterial::set_rayleigh_coefficient);
608 ClassDB::bind_method(D_METHOD("get_rayleigh_coefficient"), &PhysicalSkyMaterial::get_rayleigh_coefficient);
609
610 ClassDB::bind_method(D_METHOD("set_rayleigh_color", "color"), &PhysicalSkyMaterial::set_rayleigh_color);
611 ClassDB::bind_method(D_METHOD("get_rayleigh_color"), &PhysicalSkyMaterial::get_rayleigh_color);
612
613 ClassDB::bind_method(D_METHOD("set_mie_coefficient", "mie"), &PhysicalSkyMaterial::set_mie_coefficient);
614 ClassDB::bind_method(D_METHOD("get_mie_coefficient"), &PhysicalSkyMaterial::get_mie_coefficient);
615
616 ClassDB::bind_method(D_METHOD("set_mie_eccentricity", "eccentricity"), &PhysicalSkyMaterial::set_mie_eccentricity);
617 ClassDB::bind_method(D_METHOD("get_mie_eccentricity"), &PhysicalSkyMaterial::get_mie_eccentricity);
618
619 ClassDB::bind_method(D_METHOD("set_mie_color", "color"), &PhysicalSkyMaterial::set_mie_color);
620 ClassDB::bind_method(D_METHOD("get_mie_color"), &PhysicalSkyMaterial::get_mie_color);
621
622 ClassDB::bind_method(D_METHOD("set_turbidity", "turbidity"), &PhysicalSkyMaterial::set_turbidity);
623 ClassDB::bind_method(D_METHOD("get_turbidity"), &PhysicalSkyMaterial::get_turbidity);
624
625 ClassDB::bind_method(D_METHOD("set_sun_disk_scale", "scale"), &PhysicalSkyMaterial::set_sun_disk_scale);
626 ClassDB::bind_method(D_METHOD("get_sun_disk_scale"), &PhysicalSkyMaterial::get_sun_disk_scale);
627
628 ClassDB::bind_method(D_METHOD("set_ground_color", "color"), &PhysicalSkyMaterial::set_ground_color);
629 ClassDB::bind_method(D_METHOD("get_ground_color"), &PhysicalSkyMaterial::get_ground_color);
630
631 ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PhysicalSkyMaterial::set_energy_multiplier);
632 ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PhysicalSkyMaterial::get_energy_multiplier);
633
634 ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &PhysicalSkyMaterial::set_use_debanding);
635 ClassDB::bind_method(D_METHOD("get_use_debanding"), &PhysicalSkyMaterial::get_use_debanding);
636
637 ClassDB::bind_method(D_METHOD("set_night_sky", "night_sky"), &PhysicalSkyMaterial::set_night_sky);
638 ClassDB::bind_method(D_METHOD("get_night_sky"), &PhysicalSkyMaterial::get_night_sky);
639
640 ADD_GROUP("Rayleigh", "rayleigh_");
641 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rayleigh_coefficient", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_rayleigh_coefficient", "get_rayleigh_coefficient");
642 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "rayleigh_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_rayleigh_color", "get_rayleigh_color");
643
644 ADD_GROUP("Mie", "mie_");
645 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_coefficient", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_mie_coefficient", "get_mie_coefficient");
646 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_eccentricity", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_mie_eccentricity", "get_mie_eccentricity");
647 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "mie_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_mie_color", "get_mie_color");
648
649 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbidity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_turbidity", "get_turbidity");
650 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale");
651 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_color", "get_ground_color");
652 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");
653 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");
654 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "night_sky", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_night_sky", "get_night_sky");
655}
656
657void PhysicalSkyMaterial::cleanup_shader() {
658 if (shader_cache[0].is_valid()) {
659 RS::get_singleton()->free(shader_cache[0]);
660 RS::get_singleton()->free(shader_cache[1]);
661 }
662}
663
664void PhysicalSkyMaterial::_update_shader() {
665 shader_mutex.lock();
666 if (shader_cache[0].is_null()) {
667 for (int i = 0; i < 2; i++) {
668 shader_cache[i] = RS::get_singleton()->shader_create();
669
670 // Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
671 RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"(
672// NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s PhysicalSkyMaterial.
673
674shader_type sky;
675%s
676
677uniform float rayleigh : hint_range(0, 64) = 2.0;
678uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0);
679uniform float mie : hint_range(0, 1) = 0.005;
680uniform float mie_eccentricity : hint_range(-1, 1) = 0.8;
681uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0);
682
683uniform float turbidity : hint_range(0, 1000) = 10.0;
684uniform float sun_disk_scale : hint_range(0, 360) = 1.0;
685uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0);
686uniform float exposure : hint_range(0, 128) = 1.0;
687
688uniform sampler2D night_sky : filter_linear, source_color, hint_default_black;
689
690const vec3 UP = vec3( 0.0, 1.0, 0.0 );
691
692// Optical length at zenith for molecules.
693const float rayleigh_zenith_size = 8.4e3;
694const float mie_zenith_size = 1.25e3;
695
696float henyey_greenstein(float cos_theta, float g) {
697 const float k = 0.0795774715459;
698 return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));
699}
700
701void sky() {
702 if (LIGHT0_ENABLED) {
703 float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );
704 float sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * LIGHT0_ENERGY;
705 float sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);
706
707 // Rayleigh coefficients.
708 float rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) );
709 vec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001;
710 // mie coefficients from Preetham
711 vec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434;
712
713 // Optical length.
714 float zenith = acos(max(0.0, dot(UP, EYEDIR)));
715 float optical_mass = 1.0 / (cos(zenith) + 0.15 * pow(93.885 - degrees(zenith), -1.253));
716 float rayleigh_scatter = rayleigh_zenith_size * optical_mass;
717 float mie_scatter = mie_zenith_size * optical_mass;
718
719 // Light extinction based on thickness of atmosphere.
720 vec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter));
721
722 // In scattering.
723 float cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION));
724
725 float rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0));
726 vec3 betaRTheta = rayleigh_beta * rayleigh_phase;
727
728 float mie_phase = henyey_greenstein(cos_theta, mie_eccentricity);
729 vec3 betaMTheta = mie_beta * mie_phase;
730
731 vec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5));
732 // Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js
733 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));
734
735 // Hack in the ground color.
736 Lin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR)));
737
738 // Solar disk and out-scattering.
739 float sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);
740 float sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale*0.5);
741 float sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);
742 vec3 L0 = (sun_energy * extinction) * sundisk * LIGHT0_COLOR;
743 L0 += texture(night_sky, SKY_COORDS).xyz * extinction;
744
745 vec3 color = Lin + L0;
746 COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));
747 COLOR *= exposure;
748 } else {
749 // There is no sun, so display night_sky and nothing else.
750 COLOR = texture(night_sky, SKY_COORDS).xyz;
751 COLOR *= exposure;
752 }
753}
754)",
755 i ? "render_mode use_debanding;" : ""));
756 }
757 }
758
759 shader_mutex.unlock();
760}
761
762PhysicalSkyMaterial::PhysicalSkyMaterial() {
763 set_rayleigh_coefficient(2.0);
764 set_rayleigh_color(Color(0.3, 0.405, 0.6));
765 set_mie_coefficient(0.005);
766 set_mie_eccentricity(0.8);
767 set_mie_color(Color(0.69, 0.729, 0.812));
768 set_turbidity(10.0);
769 set_sun_disk_scale(1.0);
770 set_ground_color(Color(0.1, 0.07, 0.034));
771 set_energy_multiplier(1.0);
772 set_use_debanding(true);
773}
774
775PhysicalSkyMaterial::~PhysicalSkyMaterial() {
776}
777