Path: blob/master/scene/resources/3d/sky_material.cpp
9898 views
/**************************************************************************/1/* sky_material.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "sky_material.h"3132#include "core/config/project_settings.h"33#include "core/version.h"3435Mutex ProceduralSkyMaterial::shader_mutex;36RID ProceduralSkyMaterial::shader_cache[4];3738void ProceduralSkyMaterial::set_sky_top_color(const Color &p_sky_top) {39sky_top_color = p_sky_top;40RS::get_singleton()->material_set_param(_get_material(), "sky_top_color", sky_top_color * sky_energy_multiplier);41}4243Color ProceduralSkyMaterial::get_sky_top_color() const {44return sky_top_color;45}4647void ProceduralSkyMaterial::set_sky_horizon_color(const Color &p_sky_horizon) {48sky_horizon_color = p_sky_horizon;49RS::get_singleton()->material_set_param(_get_material(), "sky_horizon_color", sky_horizon_color * sky_energy_multiplier);50}5152Color ProceduralSkyMaterial::get_sky_horizon_color() const {53return sky_horizon_color;54}5556void ProceduralSkyMaterial::set_sky_curve(float p_curve) {57sky_curve = p_curve;58// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be59// in calculated in angles and now uses cosines.60RS::get_singleton()->material_set_param(_get_material(), "inv_sky_curve", 0.6 / sky_curve);61}6263float ProceduralSkyMaterial::get_sky_curve() const {64return sky_curve;65}6667void ProceduralSkyMaterial::set_sky_energy_multiplier(float p_multiplier) {68sky_energy_multiplier = p_multiplier;69RS::get_singleton()->material_set_param(_get_material(), "sky_top_color", sky_top_color * sky_energy_multiplier);70RS::get_singleton()->material_set_param(_get_material(), "sky_horizon_color", sky_horizon_color * sky_energy_multiplier);71RS::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));72}7374float ProceduralSkyMaterial::get_sky_energy_multiplier() const {75return sky_energy_multiplier;76}7778void ProceduralSkyMaterial::set_sky_cover(const Ref<Texture2D> &p_sky_cover) {79sky_cover = p_sky_cover;8081if (p_sky_cover.is_valid()) {82RS::get_singleton()->material_set_param(_get_material(), "sky_cover", p_sky_cover->get_rid());83} else {84RS::get_singleton()->material_set_param(_get_material(), "sky_cover", Variant());85}8687_update_shader(use_debanding, sky_cover.is_valid());8889if (shader_set) {90RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());91}92}9394Ref<Texture2D> ProceduralSkyMaterial::get_sky_cover() const {95return sky_cover;96}9798void ProceduralSkyMaterial::set_sky_cover_modulate(const Color &p_sky_cover_modulate) {99sky_cover_modulate = p_sky_cover_modulate;100RS::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));101}102103Color ProceduralSkyMaterial::get_sky_cover_modulate() const {104return sky_cover_modulate;105}106107void ProceduralSkyMaterial::set_ground_bottom_color(const Color &p_ground_bottom) {108ground_bottom_color = p_ground_bottom;109RS::get_singleton()->material_set_param(_get_material(), "ground_bottom_color", ground_bottom_color * ground_energy_multiplier);110}111112Color ProceduralSkyMaterial::get_ground_bottom_color() const {113return ground_bottom_color;114}115116void ProceduralSkyMaterial::set_ground_horizon_color(const Color &p_ground_horizon) {117ground_horizon_color = p_ground_horizon;118RS::get_singleton()->material_set_param(_get_material(), "ground_horizon_color", ground_horizon_color * ground_energy_multiplier);119}120121Color ProceduralSkyMaterial::get_ground_horizon_color() const {122return ground_horizon_color;123}124125void ProceduralSkyMaterial::set_ground_curve(float p_curve) {126ground_curve = p_curve;127// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be128// in calculated in angles and now uses cosines.129RS::get_singleton()->material_set_param(_get_material(), "inv_ground_curve", 0.6 / ground_curve);130}131132float ProceduralSkyMaterial::get_ground_curve() const {133return ground_curve;134}135136void ProceduralSkyMaterial::set_ground_energy_multiplier(float p_multiplier) {137ground_energy_multiplier = p_multiplier;138RS::get_singleton()->material_set_param(_get_material(), "ground_bottom_color", ground_bottom_color * ground_energy_multiplier);139RS::get_singleton()->material_set_param(_get_material(), "ground_horizon_color", ground_horizon_color * ground_energy_multiplier);140}141142float ProceduralSkyMaterial::get_ground_energy_multiplier() const {143return ground_energy_multiplier;144}145146void ProceduralSkyMaterial::set_sun_angle_max(float p_angle) {147sun_angle_max = p_angle;148RS::get_singleton()->material_set_param(_get_material(), "sun_angle_max", Math::cos(Math::deg_to_rad(sun_angle_max)));149}150151float ProceduralSkyMaterial::get_sun_angle_max() const {152return sun_angle_max;153}154155void ProceduralSkyMaterial::set_sun_curve(float p_curve) {156sun_curve = p_curve;157// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be158// in calculated in angles and now uses cosines.159RS::get_singleton()->material_set_param(_get_material(), "inv_sun_curve", 1.6f / Math::pow(sun_curve, 1.4f));160}161162float ProceduralSkyMaterial::get_sun_curve() const {163return sun_curve;164}165166void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) {167use_debanding = p_use_debanding;168_update_shader(use_debanding, sky_cover.is_valid());169// Only set if shader already compiled170if (shader_set) {171RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());172}173}174175bool ProceduralSkyMaterial::get_use_debanding() const {176return use_debanding;177}178179void ProceduralSkyMaterial::set_energy_multiplier(float p_multiplier) {180global_energy_multiplier = p_multiplier;181RS::get_singleton()->material_set_param(_get_material(), "exposure", global_energy_multiplier);182}183184float ProceduralSkyMaterial::get_energy_multiplier() const {185return global_energy_multiplier;186}187188Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {189return Shader::MODE_SKY;190}191192// Internal function to grab the current shader RID.193// Must only be called if the shader is initialized.194RID ProceduralSkyMaterial::get_shader_cache() const {195return shader_cache[int(use_debanding) + (sky_cover.is_valid() ? 2 : 0)];196}197198RID ProceduralSkyMaterial::get_rid() const {199_update_shader(use_debanding, sky_cover.is_valid());200if (!shader_set) {201RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());202shader_set = true;203}204return _get_material();205}206207RID ProceduralSkyMaterial::get_shader_rid() const {208_update_shader(use_debanding, sky_cover.is_valid());209return get_shader_cache();210}211212void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const {213if (!Engine::get_singleton()->is_editor_hint()) {214return;215}216if ((p_property.name == "sky_luminance" || p_property.name == "ground_luminance") && !GLOBAL_GET_CACHED(bool, "rendering/lights_and_shadows/use_physical_light_units")) {217p_property.usage = PROPERTY_USAGE_NO_EDITOR;218}219}220221void ProceduralSkyMaterial::_bind_methods() {222ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSkyMaterial::set_sky_top_color);223ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSkyMaterial::get_sky_top_color);224225ClassDB::bind_method(D_METHOD("set_sky_horizon_color", "color"), &ProceduralSkyMaterial::set_sky_horizon_color);226ClassDB::bind_method(D_METHOD("get_sky_horizon_color"), &ProceduralSkyMaterial::get_sky_horizon_color);227228ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSkyMaterial::set_sky_curve);229ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSkyMaterial::get_sky_curve);230231ClassDB::bind_method(D_METHOD("set_sky_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_sky_energy_multiplier);232ClassDB::bind_method(D_METHOD("get_sky_energy_multiplier"), &ProceduralSkyMaterial::get_sky_energy_multiplier);233234ClassDB::bind_method(D_METHOD("set_sky_cover", "sky_cover"), &ProceduralSkyMaterial::set_sky_cover);235ClassDB::bind_method(D_METHOD("get_sky_cover"), &ProceduralSkyMaterial::get_sky_cover);236237ClassDB::bind_method(D_METHOD("set_sky_cover_modulate", "color"), &ProceduralSkyMaterial::set_sky_cover_modulate);238ClassDB::bind_method(D_METHOD("get_sky_cover_modulate"), &ProceduralSkyMaterial::get_sky_cover_modulate);239240ClassDB::bind_method(D_METHOD("set_ground_bottom_color", "color"), &ProceduralSkyMaterial::set_ground_bottom_color);241ClassDB::bind_method(D_METHOD("get_ground_bottom_color"), &ProceduralSkyMaterial::get_ground_bottom_color);242243ClassDB::bind_method(D_METHOD("set_ground_horizon_color", "color"), &ProceduralSkyMaterial::set_ground_horizon_color);244ClassDB::bind_method(D_METHOD("get_ground_horizon_color"), &ProceduralSkyMaterial::get_ground_horizon_color);245246ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSkyMaterial::set_ground_curve);247ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSkyMaterial::get_ground_curve);248249ClassDB::bind_method(D_METHOD("set_ground_energy_multiplier", "energy"), &ProceduralSkyMaterial::set_ground_energy_multiplier);250ClassDB::bind_method(D_METHOD("get_ground_energy_multiplier"), &ProceduralSkyMaterial::get_ground_energy_multiplier);251252ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSkyMaterial::set_sun_angle_max);253ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSkyMaterial::get_sun_angle_max);254255ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSkyMaterial::set_sun_curve);256ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSkyMaterial::get_sun_curve);257258ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &ProceduralSkyMaterial::set_use_debanding);259ClassDB::bind_method(D_METHOD("get_use_debanding"), &ProceduralSkyMaterial::get_use_debanding);260261ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_energy_multiplier);262ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &ProceduralSkyMaterial::get_energy_multiplier);263264ADD_GROUP("Sky", "sky_");265ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color");266ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_horizon_color", "get_sky_horizon_color");267ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve");268ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy_multiplier", "get_sky_energy_multiplier");269ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_cover", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_sky_cover", "get_sky_cover");270ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_cover_modulate"), "set_sky_cover_modulate", "get_sky_cover_modulate");271272ADD_GROUP("Ground", "ground_");273ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_bottom_color", "get_ground_bottom_color");274ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_horizon_color", "get_ground_horizon_color");275ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve");276ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy_multiplier", "get_ground_energy_multiplier");277278ADD_GROUP("Sun", "sun_");279ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01,degrees"), "set_sun_angle_max", "get_sun_angle_max");280ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve");281282ADD_GROUP("", "");283ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");284ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");285}286287void ProceduralSkyMaterial::cleanup_shader() {288for (int i = 0; i < 4; i++) {289if (shader_cache[i].is_valid()) {290RS::get_singleton()->free(shader_cache[i]);291}292}293}294295void ProceduralSkyMaterial::_update_shader(bool p_use_debanding, bool p_use_sky_cover) {296MutexLock shader_lock(shader_mutex);297int index = int(p_use_debanding) + int(p_use_sky_cover) * 2;298if (shader_cache[index].is_null()) {299shader_cache[index] = RS::get_singleton()->shader_create();300301// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).302RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(303// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s ProceduralSkyMaterial.304305shader_type sky;306%s307308uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0);309uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);310uniform float inv_sky_curve : hint_range(1, 100) = 4.0;311uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0);312uniform vec4 ground_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);313uniform float inv_ground_curve : hint_range(1, 100) = 30.0;314uniform float sun_angle_max = 0.877;315uniform float inv_sun_curve : hint_range(1, 100) = 22.78;316uniform float exposure : hint_range(0, 128) = 1.0;317318uniform sampler2D sky_cover : filter_linear, source_color, hint_default_black;319uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0);320321void sky() {322float v_angle = clamp(EYEDIR.y, -1.0, 1.0);323vec3 sky = mix(sky_top_color.rgb, sky_horizon_color.rgb, clamp(pow(1.0 - v_angle, inv_sky_curve), 0.0, 1.0));324325if (LIGHT0_ENABLED) {326float sun_angle = dot(LIGHT0_DIRECTION, EYEDIR);327float sun_size = cos(LIGHT0_SIZE);328if (sun_angle > sun_size) {329sky = LIGHT0_COLOR * LIGHT0_ENERGY;330} else if (sun_angle > sun_angle_max) {331float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);332sky = mix(sky, LIGHT0_COLOR * LIGHT0_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));333}334}335336if (LIGHT1_ENABLED) {337float sun_angle = dot(LIGHT1_DIRECTION, EYEDIR);338float sun_size = cos(LIGHT1_SIZE);339if (sun_angle > sun_size) {340sky = LIGHT1_COLOR * LIGHT1_ENERGY;341} else if (sun_angle > sun_angle_max) {342float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);343sky = mix(sky, LIGHT1_COLOR * LIGHT1_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));344}345}346347if (LIGHT2_ENABLED) {348float sun_angle = dot(LIGHT2_DIRECTION, EYEDIR);349float sun_size = cos(LIGHT2_SIZE);350if (sun_angle > sun_size) {351sky = LIGHT2_COLOR * LIGHT2_ENERGY;352} else if (sun_angle > sun_angle_max) {353float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);354sky = mix(sky, LIGHT2_COLOR * LIGHT2_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));355}356}357358if (LIGHT3_ENABLED) {359float sun_angle = dot(LIGHT3_DIRECTION, EYEDIR);360float sun_size = cos(LIGHT3_SIZE);361if (sun_angle > sun_size) {362sky = LIGHT3_COLOR * LIGHT3_ENERGY;363} else if (sun_angle > sun_angle_max) {364float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);365sky = mix(sky, LIGHT3_COLOR * LIGHT3_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));366}367}368369%s370%s371vec3 ground = mix(ground_bottom_color.rgb, ground_horizon_color.rgb, clamp(pow(1.0 + v_angle, inv_ground_curve), 0.0, 1.0));372373COLOR = mix(ground, sky, step(0.0, EYEDIR.y)) * exposure;374}375)",376p_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;" : ""));377}378}379380ProceduralSkyMaterial::ProceduralSkyMaterial() {381_set_material(RS::get_singleton()->material_create());382set_sky_top_color(Color(0.385, 0.454, 0.55));383set_sky_horizon_color(Color(0.6463, 0.6558, 0.6708));384set_sky_curve(0.15);385set_sky_energy_multiplier(1.0);386set_sky_cover_modulate(Color(1, 1, 1));387388set_ground_bottom_color(Color(0.2, 0.169, 0.133));389set_ground_horizon_color(Color(0.6463, 0.6558, 0.6708));390set_ground_curve(0.02);391set_ground_energy_multiplier(1.0);392393set_sun_angle_max(30.0);394set_sun_curve(0.15);395set_use_debanding(true);396set_energy_multiplier(1.0);397}398399ProceduralSkyMaterial::~ProceduralSkyMaterial() {400}401402/////////////////////////////////////////403/* PanoramaSkyMaterial */404405void PanoramaSkyMaterial::set_panorama(const Ref<Texture2D> &p_panorama) {406panorama = p_panorama;407if (p_panorama.is_valid()) {408RS::get_singleton()->material_set_param(_get_material(), "source_panorama", p_panorama->get_rid());409} else {410RS::get_singleton()->material_set_param(_get_material(), "source_panorama", Variant());411}412}413414Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const {415return panorama;416}417418void PanoramaSkyMaterial::set_filtering_enabled(bool p_enabled) {419filter = p_enabled;420notify_property_list_changed();421_update_shader(filter);422// Only set if shader already compiled423if (shader_set) {424RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);425}426}427428bool PanoramaSkyMaterial::is_filtering_enabled() const {429return filter;430}431432void PanoramaSkyMaterial::set_energy_multiplier(float p_multiplier) {433energy_multiplier = p_multiplier;434RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier);435}436437float PanoramaSkyMaterial::get_energy_multiplier() const {438return energy_multiplier;439}440441Shader::Mode PanoramaSkyMaterial::get_shader_mode() const {442return Shader::MODE_SKY;443}444445RID PanoramaSkyMaterial::get_rid() const {446_update_shader(filter);447if (!shader_set) {448RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);449shader_set = true;450}451return _get_material();452}453454RID PanoramaSkyMaterial::get_shader_rid() const {455_update_shader(filter);456return shader_cache[int(filter)];457}458459void PanoramaSkyMaterial::_bind_methods() {460ClassDB::bind_method(D_METHOD("set_panorama", "texture"), &PanoramaSkyMaterial::set_panorama);461ClassDB::bind_method(D_METHOD("get_panorama"), &PanoramaSkyMaterial::get_panorama);462463ClassDB::bind_method(D_METHOD("set_filtering_enabled", "enabled"), &PanoramaSkyMaterial::set_filtering_enabled);464ClassDB::bind_method(D_METHOD("is_filtering_enabled"), &PanoramaSkyMaterial::is_filtering_enabled);465466ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PanoramaSkyMaterial::set_energy_multiplier);467ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PanoramaSkyMaterial::get_energy_multiplier);468469ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panorama", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_panorama", "get_panorama");470ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter"), "set_filtering_enabled", "is_filtering_enabled");471ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");472}473474Mutex PanoramaSkyMaterial::shader_mutex;475RID PanoramaSkyMaterial::shader_cache[2];476477void PanoramaSkyMaterial::cleanup_shader() {478for (int i = 0; i < 2; i++) {479if (shader_cache[i].is_valid()) {480RS::get_singleton()->free(shader_cache[i]);481}482}483}484485void PanoramaSkyMaterial::_update_shader(bool p_filter) {486MutexLock shader_lock(shader_mutex);487int index = int(p_filter);488if (shader_cache[index].is_null()) {489shader_cache[index] = RS::get_singleton()->shader_create();490491// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).492RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(493// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s PanoramaSkyMaterial.494495shader_type sky;496497uniform sampler2D source_panorama : %s, source_color, hint_default_black;498uniform float exposure : hint_range(0, 128) = 1.0;499500void sky() {501COLOR = texture(source_panorama, SKY_COORDS).rgb * exposure;502}503)",504p_filter ? "filter_linear" : "filter_nearest"));505}506}507508PanoramaSkyMaterial::PanoramaSkyMaterial() {509_set_material(RS::get_singleton()->material_create());510set_energy_multiplier(1.0);511}512513PanoramaSkyMaterial::~PanoramaSkyMaterial() {514}515516//////////////////////////////////517/* PhysicalSkyMaterial */518519void PhysicalSkyMaterial::set_rayleigh_coefficient(float p_rayleigh) {520rayleigh = p_rayleigh;521RS::get_singleton()->material_set_param(_get_material(), "rayleigh", rayleigh);522}523524float PhysicalSkyMaterial::get_rayleigh_coefficient() const {525return rayleigh;526}527528void PhysicalSkyMaterial::set_rayleigh_color(Color p_rayleigh_color) {529rayleigh_color = p_rayleigh_color;530RS::get_singleton()->material_set_param(_get_material(), "rayleigh_color", rayleigh_color);531}532533Color PhysicalSkyMaterial::get_rayleigh_color() const {534return rayleigh_color;535}536537void PhysicalSkyMaterial::set_mie_coefficient(float p_mie) {538mie = p_mie;539RS::get_singleton()->material_set_param(_get_material(), "mie", mie);540}541542float PhysicalSkyMaterial::get_mie_coefficient() const {543return mie;544}545546void PhysicalSkyMaterial::set_mie_eccentricity(float p_eccentricity) {547mie_eccentricity = p_eccentricity;548RS::get_singleton()->material_set_param(_get_material(), "mie_eccentricity", mie_eccentricity);549}550551float PhysicalSkyMaterial::get_mie_eccentricity() const {552return mie_eccentricity;553}554555void PhysicalSkyMaterial::set_mie_color(Color p_mie_color) {556mie_color = p_mie_color;557RS::get_singleton()->material_set_param(_get_material(), "mie_color", mie_color);558}559560Color PhysicalSkyMaterial::get_mie_color() const {561return mie_color;562}563564void PhysicalSkyMaterial::set_turbidity(float p_turbidity) {565turbidity = p_turbidity;566RS::get_singleton()->material_set_param(_get_material(), "turbidity", turbidity);567}568569float PhysicalSkyMaterial::get_turbidity() const {570return turbidity;571}572573void PhysicalSkyMaterial::set_sun_disk_scale(float p_sun_disk_scale) {574sun_disk_scale = p_sun_disk_scale;575RS::get_singleton()->material_set_param(_get_material(), "sun_disk_scale", sun_disk_scale);576}577578float PhysicalSkyMaterial::get_sun_disk_scale() const {579return sun_disk_scale;580}581582void PhysicalSkyMaterial::set_ground_color(Color p_ground_color) {583ground_color = p_ground_color;584RS::get_singleton()->material_set_param(_get_material(), "ground_color", ground_color);585}586587Color PhysicalSkyMaterial::get_ground_color() const {588return ground_color;589}590591void PhysicalSkyMaterial::set_energy_multiplier(float p_multiplier) {592energy_multiplier = p_multiplier;593RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier);594}595596float PhysicalSkyMaterial::get_energy_multiplier() const {597return energy_multiplier;598}599600void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) {601use_debanding = p_use_debanding;602_update_shader(use_debanding, night_sky.is_valid());603// Only set if shader already compiled604if (shader_set) {605RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());606}607}608609bool PhysicalSkyMaterial::get_use_debanding() const {610return use_debanding;611}612613void PhysicalSkyMaterial::set_night_sky(const Ref<Texture2D> &p_night_sky) {614night_sky = p_night_sky;615if (p_night_sky.is_valid()) {616RS::get_singleton()->material_set_param(_get_material(), "night_sky", p_night_sky->get_rid());617} else {618RS::get_singleton()->material_set_param(_get_material(), "night_sky", Variant());619}620621_update_shader(use_debanding, night_sky.is_valid());622623if (shader_set) {624RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());625}626}627628Ref<Texture2D> PhysicalSkyMaterial::get_night_sky() const {629return night_sky;630}631632Shader::Mode PhysicalSkyMaterial::get_shader_mode() const {633return Shader::MODE_SKY;634}635636// Internal function to grab the current shader RID.637// Must only be called if the shader is initialized.638RID PhysicalSkyMaterial::get_shader_cache() const {639return shader_cache[int(use_debanding) + (night_sky.is_valid() ? 2 : 0)];640}641642RID PhysicalSkyMaterial::get_rid() const {643_update_shader(use_debanding, night_sky.is_valid());644if (!shader_set) {645RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());646shader_set = true;647}648return _get_material();649}650651RID PhysicalSkyMaterial::get_shader_rid() const {652_update_shader(use_debanding, night_sky.is_valid());653return get_shader_cache();654}655656void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {657if (!Engine::get_singleton()->is_editor_hint()) {658return;659}660if (p_property.name == "exposure_value" && !GLOBAL_GET_CACHED(bool, "rendering/lights_and_shadows/use_physical_light_units")) {661p_property.usage = PROPERTY_USAGE_NO_EDITOR;662}663}664665Mutex PhysicalSkyMaterial::shader_mutex;666RID PhysicalSkyMaterial::shader_cache[4];667668void PhysicalSkyMaterial::_bind_methods() {669ClassDB::bind_method(D_METHOD("set_rayleigh_coefficient", "rayleigh"), &PhysicalSkyMaterial::set_rayleigh_coefficient);670ClassDB::bind_method(D_METHOD("get_rayleigh_coefficient"), &PhysicalSkyMaterial::get_rayleigh_coefficient);671672ClassDB::bind_method(D_METHOD("set_rayleigh_color", "color"), &PhysicalSkyMaterial::set_rayleigh_color);673ClassDB::bind_method(D_METHOD("get_rayleigh_color"), &PhysicalSkyMaterial::get_rayleigh_color);674675ClassDB::bind_method(D_METHOD("set_mie_coefficient", "mie"), &PhysicalSkyMaterial::set_mie_coefficient);676ClassDB::bind_method(D_METHOD("get_mie_coefficient"), &PhysicalSkyMaterial::get_mie_coefficient);677678ClassDB::bind_method(D_METHOD("set_mie_eccentricity", "eccentricity"), &PhysicalSkyMaterial::set_mie_eccentricity);679ClassDB::bind_method(D_METHOD("get_mie_eccentricity"), &PhysicalSkyMaterial::get_mie_eccentricity);680681ClassDB::bind_method(D_METHOD("set_mie_color", "color"), &PhysicalSkyMaterial::set_mie_color);682ClassDB::bind_method(D_METHOD("get_mie_color"), &PhysicalSkyMaterial::get_mie_color);683684ClassDB::bind_method(D_METHOD("set_turbidity", "turbidity"), &PhysicalSkyMaterial::set_turbidity);685ClassDB::bind_method(D_METHOD("get_turbidity"), &PhysicalSkyMaterial::get_turbidity);686687ClassDB::bind_method(D_METHOD("set_sun_disk_scale", "scale"), &PhysicalSkyMaterial::set_sun_disk_scale);688ClassDB::bind_method(D_METHOD("get_sun_disk_scale"), &PhysicalSkyMaterial::get_sun_disk_scale);689690ClassDB::bind_method(D_METHOD("set_ground_color", "color"), &PhysicalSkyMaterial::set_ground_color);691ClassDB::bind_method(D_METHOD("get_ground_color"), &PhysicalSkyMaterial::get_ground_color);692693ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PhysicalSkyMaterial::set_energy_multiplier);694ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PhysicalSkyMaterial::get_energy_multiplier);695696ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &PhysicalSkyMaterial::set_use_debanding);697ClassDB::bind_method(D_METHOD("get_use_debanding"), &PhysicalSkyMaterial::get_use_debanding);698699ClassDB::bind_method(D_METHOD("set_night_sky", "night_sky"), &PhysicalSkyMaterial::set_night_sky);700ClassDB::bind_method(D_METHOD("get_night_sky"), &PhysicalSkyMaterial::get_night_sky);701702ADD_GROUP("Rayleigh", "rayleigh_");703ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rayleigh_coefficient", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_rayleigh_coefficient", "get_rayleigh_coefficient");704ADD_PROPERTY(PropertyInfo(Variant::COLOR, "rayleigh_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_rayleigh_color", "get_rayleigh_color");705706ADD_GROUP("Mie", "mie_");707ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_coefficient", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_mie_coefficient", "get_mie_coefficient");708ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_eccentricity", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_mie_eccentricity", "get_mie_eccentricity");709ADD_PROPERTY(PropertyInfo(Variant::COLOR, "mie_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_mie_color", "get_mie_color");710711ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbidity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_turbidity", "get_turbidity");712ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale");713ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_color", "get_ground_color");714ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");715ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");716ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "night_sky", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_night_sky", "get_night_sky");717}718719void PhysicalSkyMaterial::cleanup_shader() {720for (int i = 0; i < 4; i++) {721if (shader_cache[i].is_valid()) {722RS::get_singleton()->free(shader_cache[i]);723}724}725}726727void PhysicalSkyMaterial::_update_shader(bool p_use_debanding, bool p_use_night_sky) {728MutexLock shader_lock(shader_mutex);729int index = int(p_use_debanding) + int(p_use_night_sky) * 2;730if (shader_cache[index].is_null()) {731shader_cache[index] = RS::get_singleton()->shader_create();732733// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).734RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(735// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s PhysicalSkyMaterial.736737shader_type sky;738%s739740uniform float rayleigh : hint_range(0, 64) = 2.0;741uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0);742uniform float mie : hint_range(0, 1) = 0.005;743uniform float mie_eccentricity : hint_range(-1, 1) = 0.8;744uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0);745746uniform float turbidity : hint_range(0, 1000) = 10.0;747uniform float sun_disk_scale : hint_range(0, 360) = 1.0;748uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0);749uniform float exposure : hint_range(0, 128) = 1.0;750751uniform sampler2D night_sky : filter_linear, source_color, hint_default_black;752753const vec3 UP = vec3( 0.0, 1.0, 0.0 );754755// Optical length at zenith for molecules.756const float rayleigh_zenith_size = 8.4e3;757const float mie_zenith_size = 1.25e3;758759float henyey_greenstein(float cos_theta, float g) {760const float k = 0.0795774715459;761return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));762}763764void sky() {765if (LIGHT0_ENABLED) {766float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );767float sun_energy = max(0.0, 0.757 * zenith_angle) * LIGHT0_ENERGY;768float sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);769770// Rayleigh coefficients.771float rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) );772vec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001;773// mie coefficients from Preetham774vec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434;775776// Optical length.777float zenith = max(0.0, dot(UP, EYEDIR));778float optical_mass = 1.0 / (zenith + 0.15 * pow(3.885 + 54.5 * zenith, -1.253));779float rayleigh_scatter = rayleigh_zenith_size * optical_mass;780float mie_scatter = mie_zenith_size * optical_mass;781782// Light extinction based on thickness of atmosphere.783vec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter));784785// In scattering.786float cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION));787788float rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0));789vec3 betaRTheta = rayleigh_beta * rayleigh_phase;790791float mie_phase = henyey_greenstein(cos_theta, mie_eccentricity);792vec3 betaMTheta = mie_beta * mie_phase;793794vec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5));795// Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js796Lin *= 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));797798// Hack in the ground color.799Lin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR)));800801// Solar disk and out-scattering.802float sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);803float sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale * 0.5);804float sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);805vec3 L0 = (sun_energy * extinction) * sundisk * LIGHT0_COLOR;806%s807808vec3 color = Lin + L0;809COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));810COLOR *= exposure;811} else {812// There is no sun, so display night_sky and nothing else.813%s814COLOR *= exposure;815}816}817)",818p_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;" : ""));819}820}821822PhysicalSkyMaterial::PhysicalSkyMaterial() {823_set_material(RS::get_singleton()->material_create());824set_rayleigh_coefficient(2.0);825set_rayleigh_color(Color(0.3, 0.405, 0.6));826set_mie_coefficient(0.005);827set_mie_eccentricity(0.8);828set_mie_color(Color(0.69, 0.729, 0.812));829set_turbidity(10.0);830set_sun_disk_scale(1.0);831set_ground_color(Color(0.1, 0.07, 0.034));832set_energy_multiplier(1.0);833set_use_debanding(true);834}835836PhysicalSkyMaterial::~PhysicalSkyMaterial() {837}838839840