Path: blob/master/scene/resources/3d/sky_material.cpp
20920 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"34#include "scene/resources/texture.h"3536Mutex ProceduralSkyMaterial::shader_mutex;37RID ProceduralSkyMaterial::shader_cache[4];3839void ProceduralSkyMaterial::set_sky_top_color(const Color &p_sky_top) {40sky_top_color = p_sky_top;41RS::get_singleton()->material_set_param(_get_material(), "sky_top_color", sky_top_color * sky_energy_multiplier);42}4344Color ProceduralSkyMaterial::get_sky_top_color() const {45return sky_top_color;46}4748void ProceduralSkyMaterial::set_sky_horizon_color(const Color &p_sky_horizon) {49sky_horizon_color = p_sky_horizon;50RS::get_singleton()->material_set_param(_get_material(), "sky_horizon_color", sky_horizon_color * sky_energy_multiplier);51}5253Color ProceduralSkyMaterial::get_sky_horizon_color() const {54return sky_horizon_color;55}5657void ProceduralSkyMaterial::set_sky_curve(float p_curve) {58sky_curve = p_curve;59// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be60// in calculated in angles and now uses cosines.61RS::get_singleton()->material_set_param(_get_material(), "inv_sky_curve", 0.6 / sky_curve);62}6364float ProceduralSkyMaterial::get_sky_curve() const {65return sky_curve;66}6768void ProceduralSkyMaterial::set_sky_energy_multiplier(float p_multiplier) {69sky_energy_multiplier = p_multiplier;70RS::get_singleton()->material_set_param(_get_material(), "sky_top_color", sky_top_color * sky_energy_multiplier);71RS::get_singleton()->material_set_param(_get_material(), "sky_horizon_color", sky_horizon_color * sky_energy_multiplier);72RS::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));73}7475float ProceduralSkyMaterial::get_sky_energy_multiplier() const {76return sky_energy_multiplier;77}7879void ProceduralSkyMaterial::set_sky_cover(const Ref<Texture2D> &p_sky_cover) {80sky_cover = p_sky_cover;8182if (p_sky_cover.is_valid()) {83RS::get_singleton()->material_set_param(_get_material(), "sky_cover", p_sky_cover->get_rid());84} else {85RS::get_singleton()->material_set_param(_get_material(), "sky_cover", Variant());86}8788_update_shader(use_debanding, sky_cover.is_valid());8990if (shader_set) {91RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());92}93}9495Ref<Texture2D> ProceduralSkyMaterial::get_sky_cover() const {96return sky_cover;97}9899void ProceduralSkyMaterial::set_sky_cover_modulate(const Color &p_sky_cover_modulate) {100sky_cover_modulate = p_sky_cover_modulate;101RS::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));102}103104Color ProceduralSkyMaterial::get_sky_cover_modulate() const {105return sky_cover_modulate;106}107108void ProceduralSkyMaterial::set_ground_bottom_color(const Color &p_ground_bottom) {109ground_bottom_color = p_ground_bottom;110RS::get_singleton()->material_set_param(_get_material(), "ground_bottom_color", ground_bottom_color * ground_energy_multiplier);111}112113Color ProceduralSkyMaterial::get_ground_bottom_color() const {114return ground_bottom_color;115}116117void ProceduralSkyMaterial::set_ground_horizon_color(const Color &p_ground_horizon) {118ground_horizon_color = p_ground_horizon;119RS::get_singleton()->material_set_param(_get_material(), "ground_horizon_color", ground_horizon_color * ground_energy_multiplier);120}121122Color ProceduralSkyMaterial::get_ground_horizon_color() const {123return ground_horizon_color;124}125126void ProceduralSkyMaterial::set_ground_curve(float p_curve) {127ground_curve = p_curve;128// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be129// in calculated in angles and now uses cosines.130RS::get_singleton()->material_set_param(_get_material(), "inv_ground_curve", 0.6 / ground_curve);131}132133float ProceduralSkyMaterial::get_ground_curve() const {134return ground_curve;135}136137void ProceduralSkyMaterial::set_ground_energy_multiplier(float p_multiplier) {138ground_energy_multiplier = p_multiplier;139RS::get_singleton()->material_set_param(_get_material(), "ground_bottom_color", ground_bottom_color * ground_energy_multiplier);140RS::get_singleton()->material_set_param(_get_material(), "ground_horizon_color", ground_horizon_color * ground_energy_multiplier);141}142143float ProceduralSkyMaterial::get_ground_energy_multiplier() const {144return ground_energy_multiplier;145}146147void ProceduralSkyMaterial::set_sun_angle_max(float p_angle) {148sun_angle_max = p_angle;149RS::get_singleton()->material_set_param(_get_material(), "sun_angle_max", Math::cos(Math::deg_to_rad(sun_angle_max)));150}151152float ProceduralSkyMaterial::get_sun_angle_max() const {153return sun_angle_max;154}155156void ProceduralSkyMaterial::set_sun_curve(float p_curve) {157sun_curve = p_curve;158// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be159// in calculated in angles and now uses cosines.160RS::get_singleton()->material_set_param(_get_material(), "inv_sun_curve", 1.6f / Math::pow(sun_curve, 1.4f));161}162163float ProceduralSkyMaterial::get_sun_curve() const {164return sun_curve;165}166167void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) {168use_debanding = p_use_debanding;169_update_shader(use_debanding, sky_cover.is_valid());170// Only set if shader already compiled171if (shader_set) {172RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());173}174}175176bool ProceduralSkyMaterial::get_use_debanding() const {177return use_debanding;178}179180void ProceduralSkyMaterial::set_energy_multiplier(float p_multiplier) {181global_energy_multiplier = p_multiplier;182RS::get_singleton()->material_set_param(_get_material(), "exposure", global_energy_multiplier);183}184185float ProceduralSkyMaterial::get_energy_multiplier() const {186return global_energy_multiplier;187}188189Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {190return Shader::MODE_SKY;191}192193// Internal function to grab the current shader RID.194// Must only be called if the shader is initialized.195RID ProceduralSkyMaterial::get_shader_cache() const {196return shader_cache[int(use_debanding) + (sky_cover.is_valid() ? 2 : 0)];197}198199RID ProceduralSkyMaterial::get_rid() const {200_update_shader(use_debanding, sky_cover.is_valid());201if (!shader_set) {202RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());203shader_set = true;204}205return _get_material();206}207208RID ProceduralSkyMaterial::get_shader_rid() const {209_update_shader(use_debanding, sky_cover.is_valid());210return get_shader_cache();211}212213void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const {214if (!Engine::get_singleton()->is_editor_hint()) {215return;216}217if ((p_property.name == "sky_luminance" || p_property.name == "ground_luminance") && !GLOBAL_GET_CACHED(bool, "rendering/lights_and_shadows/use_physical_light_units")) {218p_property.usage = PROPERTY_USAGE_NO_EDITOR;219}220}221222void ProceduralSkyMaterial::_bind_methods() {223ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSkyMaterial::set_sky_top_color);224ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSkyMaterial::get_sky_top_color);225226ClassDB::bind_method(D_METHOD("set_sky_horizon_color", "color"), &ProceduralSkyMaterial::set_sky_horizon_color);227ClassDB::bind_method(D_METHOD("get_sky_horizon_color"), &ProceduralSkyMaterial::get_sky_horizon_color);228229ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSkyMaterial::set_sky_curve);230ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSkyMaterial::get_sky_curve);231232ClassDB::bind_method(D_METHOD("set_sky_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_sky_energy_multiplier);233ClassDB::bind_method(D_METHOD("get_sky_energy_multiplier"), &ProceduralSkyMaterial::get_sky_energy_multiplier);234235ClassDB::bind_method(D_METHOD("set_sky_cover", "sky_cover"), &ProceduralSkyMaterial::set_sky_cover);236ClassDB::bind_method(D_METHOD("get_sky_cover"), &ProceduralSkyMaterial::get_sky_cover);237238ClassDB::bind_method(D_METHOD("set_sky_cover_modulate", "color"), &ProceduralSkyMaterial::set_sky_cover_modulate);239ClassDB::bind_method(D_METHOD("get_sky_cover_modulate"), &ProceduralSkyMaterial::get_sky_cover_modulate);240241ClassDB::bind_method(D_METHOD("set_ground_bottom_color", "color"), &ProceduralSkyMaterial::set_ground_bottom_color);242ClassDB::bind_method(D_METHOD("get_ground_bottom_color"), &ProceduralSkyMaterial::get_ground_bottom_color);243244ClassDB::bind_method(D_METHOD("set_ground_horizon_color", "color"), &ProceduralSkyMaterial::set_ground_horizon_color);245ClassDB::bind_method(D_METHOD("get_ground_horizon_color"), &ProceduralSkyMaterial::get_ground_horizon_color);246247ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSkyMaterial::set_ground_curve);248ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSkyMaterial::get_ground_curve);249250ClassDB::bind_method(D_METHOD("set_ground_energy_multiplier", "energy"), &ProceduralSkyMaterial::set_ground_energy_multiplier);251ClassDB::bind_method(D_METHOD("get_ground_energy_multiplier"), &ProceduralSkyMaterial::get_ground_energy_multiplier);252253ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSkyMaterial::set_sun_angle_max);254ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSkyMaterial::get_sun_angle_max);255256ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSkyMaterial::set_sun_curve);257ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSkyMaterial::get_sun_curve);258259ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &ProceduralSkyMaterial::set_use_debanding);260ClassDB::bind_method(D_METHOD("get_use_debanding"), &ProceduralSkyMaterial::get_use_debanding);261262ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_energy_multiplier);263ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &ProceduralSkyMaterial::get_energy_multiplier);264265ADD_GROUP("Sky", "sky_");266ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color");267ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_horizon_color", "get_sky_horizon_color");268ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve");269ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy_multiplier", "get_sky_energy_multiplier");270ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_cover", PROPERTY_HINT_RESOURCE_TYPE, Texture2D::get_class_static()), "set_sky_cover", "get_sky_cover");271ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_cover_modulate"), "set_sky_cover_modulate", "get_sky_cover_modulate");272273ADD_GROUP("Ground", "ground_");274ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_bottom_color", "get_ground_bottom_color");275ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_horizon_color", "get_ground_horizon_color");276ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve");277ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy_multiplier", "get_ground_energy_multiplier");278279ADD_GROUP("Sun", "sun_");280ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01,degrees"), "set_sun_angle_max", "get_sun_angle_max");281ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve");282283ADD_GROUP("", "");284ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");285ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");286}287288void ProceduralSkyMaterial::cleanup_shader() {289for (int i = 0; i < 4; i++) {290if (shader_cache[i].is_valid()) {291RS::get_singleton()->free_rid(shader_cache[i]);292}293}294}295296void ProceduralSkyMaterial::_update_shader(bool p_use_debanding, bool p_use_sky_cover) {297MutexLock shader_lock(shader_mutex);298int index = int(p_use_debanding) + int(p_use_sky_cover) * 2;299if (shader_cache[index].is_null()) {300shader_cache[index] = RS::get_singleton()->shader_create();301302// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).303RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(304// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s ProceduralSkyMaterial.305306shader_type sky;307%s308309uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0);310uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);311uniform float inv_sky_curve : hint_range(1, 100) = 4.0;312uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0);313uniform vec4 ground_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);314uniform float inv_ground_curve : hint_range(1, 100) = 30.0;315uniform float sun_angle_max = 0.877;316uniform float inv_sun_curve : hint_range(1, 100) = 22.78;317uniform float exposure : hint_range(0, 128) = 1.0;318319uniform sampler2D sky_cover : filter_linear, source_color, hint_default_black;320uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0);321322void sky() {323float v_angle = clamp(EYEDIR.y, -1.0, 1.0);324vec3 sky = mix(sky_top_color.rgb, sky_horizon_color.rgb, clamp(pow(1.0 - v_angle, inv_sky_curve), 0.0, 1.0));325326if (LIGHT0_ENABLED) {327float sun_angle = dot(LIGHT0_DIRECTION, EYEDIR);328float sun_size = cos(LIGHT0_SIZE);329if (sun_angle > sun_size) {330sky = LIGHT0_COLOR * LIGHT0_ENERGY;331} else if (sun_angle > sun_angle_max) {332float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);333sky = mix(sky, LIGHT0_COLOR * LIGHT0_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));334}335}336337if (LIGHT1_ENABLED) {338float sun_angle = dot(LIGHT1_DIRECTION, EYEDIR);339float sun_size = cos(LIGHT1_SIZE);340if (sun_angle > sun_size) {341sky = LIGHT1_COLOR * LIGHT1_ENERGY;342} else if (sun_angle > sun_angle_max) {343float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);344sky = mix(sky, LIGHT1_COLOR * LIGHT1_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));345}346}347348if (LIGHT2_ENABLED) {349float sun_angle = dot(LIGHT2_DIRECTION, EYEDIR);350float sun_size = cos(LIGHT2_SIZE);351if (sun_angle > sun_size) {352sky = LIGHT2_COLOR * LIGHT2_ENERGY;353} else if (sun_angle > sun_angle_max) {354float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);355sky = mix(sky, LIGHT2_COLOR * LIGHT2_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));356}357}358359if (LIGHT3_ENABLED) {360float sun_angle = dot(LIGHT3_DIRECTION, EYEDIR);361float sun_size = cos(LIGHT3_SIZE);362if (sun_angle > sun_size) {363sky = LIGHT3_COLOR * LIGHT3_ENERGY;364} else if (sun_angle > sun_angle_max) {365float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);366sky = mix(sky, LIGHT3_COLOR * LIGHT3_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));367}368}369370%s371%s372vec3 ground = mix(ground_bottom_color.rgb, ground_horizon_color.rgb, clamp(pow(1.0 + v_angle, inv_ground_curve), 0.0, 1.0));373374COLOR = mix(ground, sky, step(0.0, EYEDIR.y)) * exposure;375}376)",377p_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;" : ""));378}379}380381ProceduralSkyMaterial::ProceduralSkyMaterial() {382_set_material(RS::get_singleton()->material_create());383set_sky_top_color(Color(0.385, 0.454, 0.55));384set_sky_horizon_color(Color(0.6463, 0.6558, 0.6708));385set_sky_curve(0.15);386set_sky_energy_multiplier(1.0);387set_sky_cover_modulate(Color(1, 1, 1));388389set_ground_bottom_color(Color(0.2, 0.169, 0.133));390set_ground_horizon_color(Color(0.6463, 0.6558, 0.6708));391set_ground_curve(0.02);392set_ground_energy_multiplier(1.0);393394set_sun_angle_max(30.0);395set_sun_curve(0.15);396set_use_debanding(true);397set_energy_multiplier(1.0);398}399400ProceduralSkyMaterial::~ProceduralSkyMaterial() {401}402403/////////////////////////////////////////404/* PanoramaSkyMaterial */405406void PanoramaSkyMaterial::set_panorama(const Ref<Texture2D> &p_panorama) {407panorama = p_panorama;408if (p_panorama.is_valid()) {409RS::get_singleton()->material_set_param(_get_material(), "source_panorama", p_panorama->get_rid());410} else {411RS::get_singleton()->material_set_param(_get_material(), "source_panorama", Variant());412}413}414415Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const {416return panorama;417}418419void PanoramaSkyMaterial::set_filtering_enabled(bool p_enabled) {420filter = p_enabled;421notify_property_list_changed();422_update_shader(filter);423// Only set if shader already compiled424if (shader_set) {425RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);426}427}428429bool PanoramaSkyMaterial::is_filtering_enabled() const {430return filter;431}432433void PanoramaSkyMaterial::set_energy_multiplier(float p_multiplier) {434energy_multiplier = p_multiplier;435RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier);436}437438float PanoramaSkyMaterial::get_energy_multiplier() const {439return energy_multiplier;440}441442Shader::Mode PanoramaSkyMaterial::get_shader_mode() const {443return Shader::MODE_SKY;444}445446RID PanoramaSkyMaterial::get_rid() const {447_update_shader(filter);448if (!shader_set) {449RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);450shader_set = true;451}452return _get_material();453}454455RID PanoramaSkyMaterial::get_shader_rid() const {456_update_shader(filter);457return shader_cache[int(filter)];458}459460void PanoramaSkyMaterial::_bind_methods() {461ClassDB::bind_method(D_METHOD("set_panorama", "texture"), &PanoramaSkyMaterial::set_panorama);462ClassDB::bind_method(D_METHOD("get_panorama"), &PanoramaSkyMaterial::get_panorama);463464ClassDB::bind_method(D_METHOD("set_filtering_enabled", "enabled"), &PanoramaSkyMaterial::set_filtering_enabled);465ClassDB::bind_method(D_METHOD("is_filtering_enabled"), &PanoramaSkyMaterial::is_filtering_enabled);466467ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PanoramaSkyMaterial::set_energy_multiplier);468ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PanoramaSkyMaterial::get_energy_multiplier);469470ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panorama", PROPERTY_HINT_RESOURCE_TYPE, Texture2D::get_class_static()), "set_panorama", "get_panorama");471ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter"), "set_filtering_enabled", "is_filtering_enabled");472ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");473}474475Mutex PanoramaSkyMaterial::shader_mutex;476RID PanoramaSkyMaterial::shader_cache[2];477478void PanoramaSkyMaterial::cleanup_shader() {479for (int i = 0; i < 2; i++) {480if (shader_cache[i].is_valid()) {481RS::get_singleton()->free_rid(shader_cache[i]);482}483}484}485486void PanoramaSkyMaterial::_update_shader(bool p_filter) {487MutexLock shader_lock(shader_mutex);488int index = int(p_filter);489if (shader_cache[index].is_null()) {490shader_cache[index] = RS::get_singleton()->shader_create();491492// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).493RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(494// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s PanoramaSkyMaterial.495496shader_type sky;497498uniform sampler2D source_panorama : %s, source_color, hint_default_black;499uniform float exposure : hint_range(0, 128) = 1.0;500501void sky() {502COLOR = texture(source_panorama, SKY_COORDS).rgb * exposure;503}504)",505p_filter ? "filter_linear" : "filter_nearest"));506}507}508509PanoramaSkyMaterial::PanoramaSkyMaterial() {510_set_material(RS::get_singleton()->material_create());511set_energy_multiplier(1.0);512}513514PanoramaSkyMaterial::~PanoramaSkyMaterial() {515}516517//////////////////////////////////518/* PhysicalSkyMaterial */519520void PhysicalSkyMaterial::set_rayleigh_coefficient(float p_rayleigh) {521rayleigh = p_rayleigh;522RS::get_singleton()->material_set_param(_get_material(), "rayleigh", rayleigh);523}524525float PhysicalSkyMaterial::get_rayleigh_coefficient() const {526return rayleigh;527}528529void PhysicalSkyMaterial::set_rayleigh_color(Color p_rayleigh_color) {530rayleigh_color = p_rayleigh_color;531RS::get_singleton()->material_set_param(_get_material(), "rayleigh_color", rayleigh_color);532}533534Color PhysicalSkyMaterial::get_rayleigh_color() const {535return rayleigh_color;536}537538void PhysicalSkyMaterial::set_mie_coefficient(float p_mie) {539mie = p_mie;540RS::get_singleton()->material_set_param(_get_material(), "mie", mie);541}542543float PhysicalSkyMaterial::get_mie_coefficient() const {544return mie;545}546547void PhysicalSkyMaterial::set_mie_eccentricity(float p_eccentricity) {548mie_eccentricity = p_eccentricity;549RS::get_singleton()->material_set_param(_get_material(), "mie_eccentricity", mie_eccentricity);550}551552float PhysicalSkyMaterial::get_mie_eccentricity() const {553return mie_eccentricity;554}555556void PhysicalSkyMaterial::set_mie_color(Color p_mie_color) {557mie_color = p_mie_color;558RS::get_singleton()->material_set_param(_get_material(), "mie_color", mie_color);559}560561Color PhysicalSkyMaterial::get_mie_color() const {562return mie_color;563}564565void PhysicalSkyMaterial::set_turbidity(float p_turbidity) {566turbidity = p_turbidity;567RS::get_singleton()->material_set_param(_get_material(), "turbidity", turbidity);568}569570float PhysicalSkyMaterial::get_turbidity() const {571return turbidity;572}573574void PhysicalSkyMaterial::set_sun_disk_scale(float p_sun_disk_scale) {575sun_disk_scale = p_sun_disk_scale;576RS::get_singleton()->material_set_param(_get_material(), "sun_disk_scale", sun_disk_scale);577}578579float PhysicalSkyMaterial::get_sun_disk_scale() const {580return sun_disk_scale;581}582583void PhysicalSkyMaterial::set_ground_color(Color p_ground_color) {584ground_color = p_ground_color;585RS::get_singleton()->material_set_param(_get_material(), "ground_color", ground_color);586}587588Color PhysicalSkyMaterial::get_ground_color() const {589return ground_color;590}591592void PhysicalSkyMaterial::set_energy_multiplier(float p_multiplier) {593energy_multiplier = p_multiplier;594RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier);595}596597float PhysicalSkyMaterial::get_energy_multiplier() const {598return energy_multiplier;599}600601void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) {602use_debanding = p_use_debanding;603_update_shader(use_debanding, night_sky.is_valid());604// Only set if shader already compiled605if (shader_set) {606RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());607}608}609610bool PhysicalSkyMaterial::get_use_debanding() const {611return use_debanding;612}613614void PhysicalSkyMaterial::set_night_sky(const Ref<Texture2D> &p_night_sky) {615night_sky = p_night_sky;616if (p_night_sky.is_valid()) {617RS::get_singleton()->material_set_param(_get_material(), "night_sky", p_night_sky->get_rid());618} else {619RS::get_singleton()->material_set_param(_get_material(), "night_sky", Variant());620}621622_update_shader(use_debanding, night_sky.is_valid());623624if (shader_set) {625RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());626}627}628629Ref<Texture2D> PhysicalSkyMaterial::get_night_sky() const {630return night_sky;631}632633Shader::Mode PhysicalSkyMaterial::get_shader_mode() const {634return Shader::MODE_SKY;635}636637// Internal function to grab the current shader RID.638// Must only be called if the shader is initialized.639RID PhysicalSkyMaterial::get_shader_cache() const {640return shader_cache[int(use_debanding) + (night_sky.is_valid() ? 2 : 0)];641}642643RID PhysicalSkyMaterial::get_rid() const {644_update_shader(use_debanding, night_sky.is_valid());645if (!shader_set) {646RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());647shader_set = true;648}649return _get_material();650}651652RID PhysicalSkyMaterial::get_shader_rid() const {653_update_shader(use_debanding, night_sky.is_valid());654return get_shader_cache();655}656657void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {658if (!Engine::get_singleton()->is_editor_hint()) {659return;660}661if (p_property.name == "exposure_value" && !GLOBAL_GET_CACHED(bool, "rendering/lights_and_shadows/use_physical_light_units")) {662p_property.usage = PROPERTY_USAGE_NO_EDITOR;663}664}665666Mutex PhysicalSkyMaterial::shader_mutex;667RID PhysicalSkyMaterial::shader_cache[4];668669void PhysicalSkyMaterial::_bind_methods() {670ClassDB::bind_method(D_METHOD("set_rayleigh_coefficient", "rayleigh"), &PhysicalSkyMaterial::set_rayleigh_coefficient);671ClassDB::bind_method(D_METHOD("get_rayleigh_coefficient"), &PhysicalSkyMaterial::get_rayleigh_coefficient);672673ClassDB::bind_method(D_METHOD("set_rayleigh_color", "color"), &PhysicalSkyMaterial::set_rayleigh_color);674ClassDB::bind_method(D_METHOD("get_rayleigh_color"), &PhysicalSkyMaterial::get_rayleigh_color);675676ClassDB::bind_method(D_METHOD("set_mie_coefficient", "mie"), &PhysicalSkyMaterial::set_mie_coefficient);677ClassDB::bind_method(D_METHOD("get_mie_coefficient"), &PhysicalSkyMaterial::get_mie_coefficient);678679ClassDB::bind_method(D_METHOD("set_mie_eccentricity", "eccentricity"), &PhysicalSkyMaterial::set_mie_eccentricity);680ClassDB::bind_method(D_METHOD("get_mie_eccentricity"), &PhysicalSkyMaterial::get_mie_eccentricity);681682ClassDB::bind_method(D_METHOD("set_mie_color", "color"), &PhysicalSkyMaterial::set_mie_color);683ClassDB::bind_method(D_METHOD("get_mie_color"), &PhysicalSkyMaterial::get_mie_color);684685ClassDB::bind_method(D_METHOD("set_turbidity", "turbidity"), &PhysicalSkyMaterial::set_turbidity);686ClassDB::bind_method(D_METHOD("get_turbidity"), &PhysicalSkyMaterial::get_turbidity);687688ClassDB::bind_method(D_METHOD("set_sun_disk_scale", "scale"), &PhysicalSkyMaterial::set_sun_disk_scale);689ClassDB::bind_method(D_METHOD("get_sun_disk_scale"), &PhysicalSkyMaterial::get_sun_disk_scale);690691ClassDB::bind_method(D_METHOD("set_ground_color", "color"), &PhysicalSkyMaterial::set_ground_color);692ClassDB::bind_method(D_METHOD("get_ground_color"), &PhysicalSkyMaterial::get_ground_color);693694ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PhysicalSkyMaterial::set_energy_multiplier);695ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PhysicalSkyMaterial::get_energy_multiplier);696697ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &PhysicalSkyMaterial::set_use_debanding);698ClassDB::bind_method(D_METHOD("get_use_debanding"), &PhysicalSkyMaterial::get_use_debanding);699700ClassDB::bind_method(D_METHOD("set_night_sky", "night_sky"), &PhysicalSkyMaterial::set_night_sky);701ClassDB::bind_method(D_METHOD("get_night_sky"), &PhysicalSkyMaterial::get_night_sky);702703ADD_GROUP("Rayleigh", "rayleigh_");704ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rayleigh_coefficient", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_rayleigh_coefficient", "get_rayleigh_coefficient");705ADD_PROPERTY(PropertyInfo(Variant::COLOR, "rayleigh_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_rayleigh_color", "get_rayleigh_color");706707ADD_GROUP("Mie", "mie_");708ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_coefficient", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_mie_coefficient", "get_mie_coefficient");709ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_eccentricity", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_mie_eccentricity", "get_mie_eccentricity");710ADD_PROPERTY(PropertyInfo(Variant::COLOR, "mie_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_mie_color", "get_mie_color");711712ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbidity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_turbidity", "get_turbidity");713ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale");714ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_color", "get_ground_color");715ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");716ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");717ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "night_sky", PROPERTY_HINT_RESOURCE_TYPE, Texture2D::get_class_static()), "set_night_sky", "get_night_sky");718}719720void PhysicalSkyMaterial::cleanup_shader() {721for (int i = 0; i < 4; i++) {722if (shader_cache[i].is_valid()) {723RS::get_singleton()->free_rid(shader_cache[i]);724}725}726}727728void PhysicalSkyMaterial::_update_shader(bool p_use_debanding, bool p_use_night_sky) {729MutexLock shader_lock(shader_mutex);730int index = int(p_use_debanding) + int(p_use_night_sky) * 2;731if (shader_cache[index].is_null()) {732shader_cache[index] = RS::get_singleton()->shader_create();733734// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).735RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(736// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s PhysicalSkyMaterial.737738shader_type sky;739%s740741uniform float rayleigh : hint_range(0, 64) = 2.0;742uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0);743uniform float mie : hint_range(0, 1) = 0.005;744uniform float mie_eccentricity : hint_range(-1, 1) = 0.8;745uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0);746747uniform float turbidity : hint_range(0, 1000) = 10.0;748uniform float sun_disk_scale : hint_range(0, 360) = 1.0;749uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0);750uniform float exposure : hint_range(0, 128) = 1.0;751752uniform sampler2D night_sky : filter_linear, source_color, hint_default_black;753754const vec3 UP = vec3( 0.0, 1.0, 0.0 );755756// Optical length at zenith for molecules.757const float rayleigh_zenith_size = 8.4e3;758const float mie_zenith_size = 1.25e3;759760float henyey_greenstein(float cos_theta, float g) {761const float k = 0.0795774715459;762return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));763}764765void sky() {766if (LIGHT0_ENABLED) {767float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );768float sun_energy = max(0.0, 0.757 * zenith_angle) * LIGHT0_ENERGY;769float sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);770771// Rayleigh coefficients.772float rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) );773vec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001;774// mie coefficients from Preetham775vec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434;776777// Optical length.778float zenith = max(0.0, dot(UP, EYEDIR));779float optical_mass = 1.0 / (zenith + 0.15 * pow(3.885 + 54.5 * zenith, -1.253));780float rayleigh_scatter = rayleigh_zenith_size * optical_mass;781float mie_scatter = mie_zenith_size * optical_mass;782783// Light extinction based on thickness of atmosphere.784vec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter));785786// In scattering.787float cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION));788789float rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0));790vec3 betaRTheta = rayleigh_beta * rayleigh_phase;791792float mie_phase = henyey_greenstein(cos_theta, mie_eccentricity);793vec3 betaMTheta = mie_beta * mie_phase;794795vec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5));796// Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js797Lin *= 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));798799// Hack in the ground color.800Lin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR)));801802// Solar disk and out-scattering.803float sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);804float sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale * 0.5);805float sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);806vec3 L0 = (sun_energy * extinction) * sundisk * LIGHT0_COLOR;807%s808809vec3 color = Lin + L0;810COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));811COLOR *= exposure;812} else {813// There is no sun, so display night_sky and nothing else.814%s815COLOR *= exposure;816}817}818)",819p_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;" : ""));820}821}822823PhysicalSkyMaterial::PhysicalSkyMaterial() {824_set_material(RS::get_singleton()->material_create());825set_rayleigh_coefficient(2.0);826set_rayleigh_color(Color(0.3, 0.405, 0.6));827set_mie_coefficient(0.005);828set_mie_eccentricity(0.8);829set_mie_color(Color(0.69, 0.729, 0.812));830set_turbidity(10.0);831set_sun_disk_scale(1.0);832set_ground_color(Color(0.1, 0.07, 0.034));833set_energy_multiplier(1.0);834set_use_debanding(true);835}836837PhysicalSkyMaterial::~PhysicalSkyMaterial() {838}839840841