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 | |
36 | Mutex ProceduralSkyMaterial::shader_mutex; |
37 | RID ProceduralSkyMaterial::shader_cache[2]; |
38 | |
39 | void 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 | |
44 | Color ProceduralSkyMaterial::get_sky_top_color() const { |
45 | return sky_top_color; |
46 | } |
47 | |
48 | void 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 | |
53 | Color ProceduralSkyMaterial::get_sky_horizon_color() const { |
54 | return sky_horizon_color; |
55 | } |
56 | |
57 | void 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 | |
62 | float ProceduralSkyMaterial::get_sky_curve() const { |
63 | return sky_curve; |
64 | } |
65 | |
66 | void 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 | |
71 | float ProceduralSkyMaterial::get_sky_energy_multiplier() const { |
72 | return sky_energy_multiplier; |
73 | } |
74 | |
75 | void 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 | |
84 | Ref<Texture2D> ProceduralSkyMaterial::get_sky_cover() const { |
85 | return sky_cover; |
86 | } |
87 | |
88 | void 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 | |
93 | Color ProceduralSkyMaterial::get_sky_cover_modulate() const { |
94 | return sky_cover_modulate; |
95 | } |
96 | |
97 | void 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 | |
102 | Color ProceduralSkyMaterial::get_ground_bottom_color() const { |
103 | return ground_bottom_color; |
104 | } |
105 | |
106 | void 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 | |
111 | Color ProceduralSkyMaterial::get_ground_horizon_color() const { |
112 | return ground_horizon_color; |
113 | } |
114 | |
115 | void 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 | |
120 | float ProceduralSkyMaterial::get_ground_curve() const { |
121 | return ground_curve; |
122 | } |
123 | |
124 | void 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 | |
129 | float ProceduralSkyMaterial::get_ground_energy_multiplier() const { |
130 | return ground_energy_multiplier; |
131 | } |
132 | |
133 | void 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 | |
138 | float ProceduralSkyMaterial::get_sun_angle_max() const { |
139 | return sun_angle_max; |
140 | } |
141 | |
142 | void 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 | |
147 | float ProceduralSkyMaterial::get_sun_curve() const { |
148 | return sun_curve; |
149 | } |
150 | |
151 | void 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 | |
160 | bool ProceduralSkyMaterial::get_use_debanding() const { |
161 | return use_debanding; |
162 | } |
163 | |
164 | Shader::Mode ProceduralSkyMaterial::get_shader_mode() const { |
165 | return Shader::MODE_SKY; |
166 | } |
167 | |
168 | RID 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 | |
178 | RID ProceduralSkyMaterial::get_shader_rid() const { |
179 | _update_shader(); |
180 | return shader_cache[int(use_debanding)]; |
181 | } |
182 | |
183 | void 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 | |
189 | void 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 | |
251 | void 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 | |
258 | void 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 | |
268 | shader_type sky; |
269 | %s |
270 | |
271 | uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0); |
272 | uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0); |
273 | uniform float sky_curve : hint_range(0, 1) = 0.15; |
274 | uniform float sky_energy = 1.0; // In Lux. |
275 | uniform sampler2D sky_cover : filter_linear, source_color, hint_default_black; |
276 | uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0); |
277 | uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0); |
278 | uniform vec4 ground_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0); |
279 | uniform float ground_curve : hint_range(0, 1) = 0.02; |
280 | uniform float ground_energy = 1.0; |
281 | uniform float sun_angle_max = 30.0; |
282 | uniform float sun_curve : hint_range(0, 1) = 0.15; |
283 | |
284 | void 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 | |
346 | ProceduralSkyMaterial::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 | |
363 | ProceduralSkyMaterial::~ProceduralSkyMaterial() { |
364 | } |
365 | |
366 | ///////////////////////////////////////// |
367 | /* PanoramaSkyMaterial */ |
368 | |
369 | void 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 | |
378 | Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const { |
379 | return panorama; |
380 | } |
381 | |
382 | void 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 | |
392 | bool PanoramaSkyMaterial::is_filtering_enabled() const { |
393 | return filter; |
394 | } |
395 | |
396 | Shader::Mode PanoramaSkyMaterial::get_shader_mode() const { |
397 | return Shader::MODE_SKY; |
398 | } |
399 | |
400 | RID 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 | |
411 | RID PanoramaSkyMaterial::get_shader_rid() const { |
412 | _update_shader(); |
413 | return shader_cache[int(filter)]; |
414 | } |
415 | |
416 | void 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 | |
427 | Mutex PanoramaSkyMaterial::shader_mutex; |
428 | RID PanoramaSkyMaterial::shader_cache[2]; |
429 | |
430 | void 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 | |
437 | void 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 | |
447 | shader_type sky; |
448 | |
449 | uniform sampler2D source_panorama : %s, source_color, hint_default_black; |
450 | |
451 | void 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 | |
462 | PanoramaSkyMaterial::PanoramaSkyMaterial() { |
463 | } |
464 | |
465 | PanoramaSkyMaterial::~PanoramaSkyMaterial() { |
466 | } |
467 | |
468 | ////////////////////////////////// |
469 | /* PhysicalSkyMaterial */ |
470 | |
471 | void PhysicalSkyMaterial::set_rayleigh_coefficient(float p_rayleigh) { |
472 | rayleigh = p_rayleigh; |
473 | RS::get_singleton()->material_set_param(_get_material(), "rayleigh" , rayleigh); |
474 | } |
475 | |
476 | float PhysicalSkyMaterial::get_rayleigh_coefficient() const { |
477 | return rayleigh; |
478 | } |
479 | |
480 | void 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 | |
485 | Color PhysicalSkyMaterial::get_rayleigh_color() const { |
486 | return rayleigh_color; |
487 | } |
488 | |
489 | void PhysicalSkyMaterial::set_mie_coefficient(float p_mie) { |
490 | mie = p_mie; |
491 | RS::get_singleton()->material_set_param(_get_material(), "mie" , mie); |
492 | } |
493 | |
494 | float PhysicalSkyMaterial::get_mie_coefficient() const { |
495 | return mie; |
496 | } |
497 | |
498 | void 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 | |
503 | float PhysicalSkyMaterial::get_mie_eccentricity() const { |
504 | return mie_eccentricity; |
505 | } |
506 | |
507 | void 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 | |
512 | Color PhysicalSkyMaterial::get_mie_color() const { |
513 | return mie_color; |
514 | } |
515 | |
516 | void PhysicalSkyMaterial::set_turbidity(float p_turbidity) { |
517 | turbidity = p_turbidity; |
518 | RS::get_singleton()->material_set_param(_get_material(), "turbidity" , turbidity); |
519 | } |
520 | |
521 | float PhysicalSkyMaterial::get_turbidity() const { |
522 | return turbidity; |
523 | } |
524 | |
525 | void 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 | |
530 | float PhysicalSkyMaterial::get_sun_disk_scale() const { |
531 | return sun_disk_scale; |
532 | } |
533 | |
534 | void 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 | |
539 | Color PhysicalSkyMaterial::get_ground_color() const { |
540 | return ground_color; |
541 | } |
542 | |
543 | void 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 | |
548 | float PhysicalSkyMaterial::get_energy_multiplier() const { |
549 | return energy_multiplier; |
550 | } |
551 | |
552 | void 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 | |
561 | bool PhysicalSkyMaterial::get_use_debanding() const { |
562 | return use_debanding; |
563 | } |
564 | |
565 | void 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 | |
574 | Ref<Texture2D> PhysicalSkyMaterial::get_night_sky() const { |
575 | return night_sky; |
576 | } |
577 | |
578 | Shader::Mode PhysicalSkyMaterial::get_shader_mode() const { |
579 | return Shader::MODE_SKY; |
580 | } |
581 | |
582 | RID 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 | |
592 | RID PhysicalSkyMaterial::get_shader_rid() const { |
593 | _update_shader(); |
594 | return shader_cache[int(use_debanding)]; |
595 | } |
596 | |
597 | void 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 | |
603 | Mutex PhysicalSkyMaterial::shader_mutex; |
604 | RID PhysicalSkyMaterial::shader_cache[2]; |
605 | |
606 | void 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 | |
657 | void 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 | |
664 | void 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 | |
674 | shader_type sky; |
675 | %s |
676 | |
677 | uniform float rayleigh : hint_range(0, 64) = 2.0; |
678 | uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0); |
679 | uniform float mie : hint_range(0, 1) = 0.005; |
680 | uniform float mie_eccentricity : hint_range(-1, 1) = 0.8; |
681 | uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0); |
682 | |
683 | uniform float turbidity : hint_range(0, 1000) = 10.0; |
684 | uniform float sun_disk_scale : hint_range(0, 360) = 1.0; |
685 | uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0); |
686 | uniform float exposure : hint_range(0, 128) = 1.0; |
687 | |
688 | uniform sampler2D night_sky : filter_linear, source_color, hint_default_black; |
689 | |
690 | const vec3 UP = vec3( 0.0, 1.0, 0.0 ); |
691 | |
692 | // Optical length at zenith for molecules. |
693 | const float rayleigh_zenith_size = 8.4e3; |
694 | const float mie_zenith_size = 1.25e3; |
695 | |
696 | float 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 | |
701 | void 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 | |
762 | PhysicalSkyMaterial::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 | |
775 | PhysicalSkyMaterial::~PhysicalSkyMaterial() { |
776 | } |
777 | |