diff options
Diffstat (limited to 'scene')
27 files changed, 1053 insertions, 474 deletions
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index b8b6296c45..304e56326d 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -31,6 +31,7 @@ #include "camera_3d.h" #include "collision_object_3d.h" +#include "core/core_string_names.h" #include "core/math/projection.h" #include "scene/main/viewport.h" @@ -71,6 +72,17 @@ void Camera3D::_validate_property(PropertyInfo &p_property) const { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } + + if (attributes.is_valid()) { + const CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr()); + if (physical_attributes) { + if (p_property.name == "near" || p_property.name == "far" || p_property.name == "fov" || p_property.name == "keep_aspect") { + p_property.usage = PROPERTY_USAGE_READ_ONLY | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR; + } + } + } + + Node3D::_validate_property(p_property); } void Camera3D::_update_camera() { @@ -400,18 +412,44 @@ Ref<Environment> Camera3D::get_environment() const { return environment; } -void Camera3D::set_effects(const Ref<CameraEffects> &p_effects) { - effects = p_effects; - if (effects.is_valid()) { - RS::get_singleton()->camera_set_camera_effects(camera, effects->get_rid()); +void Camera3D::set_attributes(const Ref<CameraAttributes> &p_attributes) { + if (attributes.is_valid()) { + CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr()); + if (physical_attributes) { + attributes->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Camera3D::_attributes_changed)); + } + } + + attributes = p_attributes; + + if (attributes.is_valid()) { + CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr()); + if (physical_attributes) { + attributes->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Camera3D::_attributes_changed)); + _attributes_changed(); + } + + RS::get_singleton()->camera_set_camera_attributes(camera, attributes->get_rid()); } else { - RS::get_singleton()->camera_set_camera_effects(camera, RID()); + RS::get_singleton()->camera_set_camera_attributes(camera, RID()); } - _update_camera_mode(); + + notify_property_list_changed(); } -Ref<CameraEffects> Camera3D::get_effects() const { - return effects; +Ref<CameraAttributes> Camera3D::get_attributes() const { + return attributes; +} + +void Camera3D::_attributes_changed() { + CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr()); + ERR_FAIL_COND(!physical_attributes); + + fov = physical_attributes->get_fov(); + near = physical_attributes->get_near(); + far = physical_attributes->get_far(); + keep_aspect = KEEP_HEIGHT; + _update_camera_mode(); } void Camera3D::set_keep_aspect_mode(KeepAspect p_aspect) { @@ -479,8 +517,8 @@ void Camera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_cull_mask"), &Camera3D::get_cull_mask); ClassDB::bind_method(D_METHOD("set_environment", "env"), &Camera3D::set_environment); ClassDB::bind_method(D_METHOD("get_environment"), &Camera3D::get_environment); - ClassDB::bind_method(D_METHOD("set_effects", "env"), &Camera3D::set_effects); - ClassDB::bind_method(D_METHOD("get_effects"), &Camera3D::get_effects); + ClassDB::bind_method(D_METHOD("set_attributes", "env"), &Camera3D::set_attributes); + ClassDB::bind_method(D_METHOD("get_attributes"), &Camera3D::get_attributes); ClassDB::bind_method(D_METHOD("set_keep_aspect_mode", "mode"), &Camera3D::set_keep_aspect_mode); ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera3D::get_keep_aspect_mode); ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera3D::set_doppler_tracking); @@ -498,7 +536,7 @@ void Camera3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_effects", "get_effects"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_attributes", "get_attributes"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking"); diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index bba9b7d1e4..f150a23e27 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -33,7 +33,7 @@ #include "scene/3d/node_3d.h" #include "scene/3d/velocity_tracker_3d.h" -#include "scene/resources/camera_effects.h" +#include "scene/resources/camera_attributes.h" #include "scene/resources/environment.h" class Camera3D : public Node3D { @@ -64,11 +64,11 @@ private: ProjectionType mode = PROJECTION_PERSPECTIVE; - real_t fov = 0.0; + real_t fov = 75.0; real_t size = 1.0; Vector2 frustum_offset; - real_t near = 0.0; - real_t far = 0.0; + real_t near = 0.05; + real_t far = 4000.0; real_t v_offset = 0.0; real_t h_offset = 0.0; KeepAspect keep_aspect = KEEP_HEIGHT; @@ -81,7 +81,8 @@ private: uint32_t layers = 0xfffff; Ref<Environment> environment; - Ref<CameraEffects> effects; + Ref<CameraAttributes> attributes; + void _attributes_changed(); // void _camera_make_current(Node *p_camera); friend class Viewport; @@ -159,8 +160,8 @@ public: void set_environment(const Ref<Environment> &p_environment); Ref<Environment> get_environment() const; - void set_effects(const Ref<CameraEffects> &p_effects); - Ref<CameraEffects> get_effects() const; + void set_attributes(const Ref<CameraAttributes> &p_effects); + Ref<CameraAttributes> get_attributes() const; void set_keep_aspect_mode(KeepAspect p_aspect); KeepAspect get_keep_aspect_mode() const; diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp index 319129603e..cfee7028d4 100644 --- a/scene/3d/fog_volume.cpp +++ b/scene/3d/fog_volume.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "fog_volume.h" +#include "scene/resources/environment.h" /////////////////////////// diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 66f4fa2bcc..e51f06e083 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -28,6 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "core/config/project_settings.h" + #include "light_3d.h" void Light3D::set_param(Param p_param, real_t p_value) { @@ -122,7 +124,14 @@ uint32_t Light3D::get_cull_mask() const { void Light3D::set_color(const Color &p_color) { color = p_color; - RS::get_singleton()->light_set_color(light, p_color); + + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + Color combined = color.srgb_to_linear(); + combined *= correlated_color.srgb_to_linear(); + RS::get_singleton()->light_set_color(light, combined.linear_to_srgb()); + } else { + RS::get_singleton()->light_set_color(light, color); + } // The gizmo color depends on the light color, so update it. update_gizmos(); } @@ -181,6 +190,56 @@ void Light3D::owner_changed_notify() { _update_visibility(); } +// Temperature expressed in Kelvins. Valid range 1000 - 15000 +// First converts to CIE 1960 then to sRGB +// As explained in the Filament documentation: https://google.github.io/filament/Filament.md.html#lighting/directlighting/lightsparameterization +Color _color_from_temperature(float p_temperature) { + float T2 = p_temperature * p_temperature; + float u = (0.860117757f + 1.54118254e-4f * p_temperature + 1.28641212e-7f * T2) / + (1.0f + 8.42420235e-4f * p_temperature + 7.08145163e-7f * T2); + float v = (0.317398726f + 4.22806245e-5f * p_temperature + 4.20481691e-8f * T2) / + (1.0f - 2.89741816e-5f * p_temperature + 1.61456053e-7f * T2); + + // Convert to xyY space. + float d = 1.0f / (2.0f * u - 8.0f * v + 4.0f); + float x = 3.0f * u * d; + float y = 2.0f * v * d; + + // Convert to XYZ space + const float a = 1.0 / MAX(y, 1e-5f); + Vector3 xyz = Vector3(x * a, 1.0, (1.0f - x - y) * a); + + // Convert from XYZ to sRGB(linear) + Vector3 linear = Vector3(3.2404542f * xyz.x - 1.5371385f * xyz.y - 0.4985314f * xyz.z, + -0.9692660f * xyz.x + 1.8760108f * xyz.y + 0.0415560f * xyz.z, + 0.0556434f * xyz.x - 0.2040259f * xyz.y + 1.0572252f * xyz.z); + linear /= MAX(1e-5f, linear[linear.max_axis_index()]); + // Normalize, clamp, and convert to sRGB. + return Color(linear.x, linear.y, linear.z).clamp().linear_to_srgb(); +} + +void Light3D::set_temperature(const float p_temperature) { + temperature = p_temperature; + if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + return; + } + correlated_color = _color_from_temperature(temperature); + + Color combined = color.srgb_to_linear() * correlated_color.srgb_to_linear(); + + RS::get_singleton()->light_set_color(light, combined.linear_to_srgb()); + // The gizmo color depends on the light color, so update it. + update_gizmos(); +} + +Color Light3D::get_correlated_color() const { + return correlated_color; +} + +float Light3D::get_temperature() const { + return temperature; +} + void Light3D::_update_visibility() { if (!is_inside_tree()) { return; @@ -228,8 +287,14 @@ void Light3D::_validate_property(PropertyInfo &p_property) const { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (get_light_type() != RS::LIGHT_DIRECTIONAL && p_property.name == "light_angular_distance") { - // Angular distance is only used in DirectionalLight3D. + if (get_light_type() != RS::LIGHT_DIRECTIONAL && (p_property.name == "light_angular_distance" || p_property.name == "light_intensity_lux")) { + // Angular distance and Light Intensity Lux are only used in DirectionalLight3D. + p_property.usage = PROPERTY_USAGE_NONE; + } else if (get_light_type() == RS::LIGHT_DIRECTIONAL && p_property.name == "light_intensity_lumens") { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units") && (p_property.name == "light_intensity_lumens" || p_property.name == "light_intensity_lux" || p_property.name == "light_temperature")) { p_property.usage = PROPERTY_USAGE_NONE; } @@ -278,7 +343,14 @@ void Light3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_projector", "projector"), &Light3D::set_projector); ClassDB::bind_method(D_METHOD("get_projector"), &Light3D::get_projector); + ClassDB::bind_method(D_METHOD("set_temperature", "temperature"), &Light3D::set_temperature); + ClassDB::bind_method(D_METHOD("get_temperature"), &Light3D::get_temperature); + ClassDB::bind_method(D_METHOD("get_correlated_color"), &Light3D::get_correlated_color); + ADD_GROUP("Light", "light_"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_intensity_lumens", PROPERTY_HINT_RANGE, "0,100000.0,0.01,or_greater,suffix:lm"), "set_param", "get_param", PARAM_INTENSITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_intensity_lux", PROPERTY_HINT_RANGE, "0,150000.0,0.01,or_greater,suffix:lx"), "set_param", "get_param", PARAM_INTENSITY); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "light_temperature", PROPERTY_HINT_RANGE, "1000,15000.0,1.0,suffix:k"), "set_temperature", "get_temperature"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.001,or_greater"), "set_param", "get_param", PARAM_ENERGY); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.001,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY); @@ -331,6 +403,7 @@ void Light3D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_SHADOW_OPACITY); BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR); BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS); + BIND_ENUM_CONSTANT(PARAM_INTENSITY); BIND_ENUM_CONSTANT(PARAM_MAX); BIND_ENUM_CONSTANT(BAKE_DISABLED); @@ -382,6 +455,9 @@ Light3D::Light3D(RenderingServer::LightType p_type) { set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0); set_param(PARAM_TRANSMITTANCE_BIAS, 0.05); set_param(PARAM_SHADOW_FADE_START, 1); + // For OmniLight3D and SpotLight3D, specified in Lumens. + set_param(PARAM_INTENSITY, 1000.0); + set_temperature(6500.0); // Nearly white. set_disable_scale(true); } @@ -487,6 +563,7 @@ DirectionalLight3D::DirectionalLight3D() : set_param(PARAM_SHADOW_FADE_START, 0.8); // Increase the default shadow bias to better suit most scenes. set_param(PARAM_SHADOW_BIAS, 0.1); + set_param(PARAM_INTENSITY, 100000.0); // Specified in Lux, approximate mid-day sun. set_shadow_mode(SHADOW_PARALLEL_4_SPLITS); blend_splits = false; set_sky_mode(SKY_MODE_LIGHT_AND_SKY); diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index 0792f21c6e..e43d6f0419 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -58,6 +58,7 @@ public: PARAM_SHADOW_OPACITY = RS::LIGHT_PARAM_SHADOW_OPACITY, PARAM_SHADOW_BLUR = RS::LIGHT_PARAM_SHADOW_BLUR, PARAM_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS, + PARAM_INTENSITY = RS::LIGHT_PARAM_INTENSITY, PARAM_MAX = RS::LIGHT_PARAM_MAX }; @@ -83,6 +84,8 @@ private: void _update_visibility(); BakeMode bake_mode = BAKE_DYNAMIC; Ref<Texture2D> projector; + Color correlated_color = Color(1.0, 1.0, 1.0); + float temperature = 6500.0; // bind helpers @@ -139,6 +142,10 @@ public: void set_projector(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_projector() const; + void set_temperature(const float p_temperature); + float get_temperature() const; + Color get_correlated_color() const; + virtual AABB get_aabb() const override; Light3D(); diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 7efda6db32..41a537f7cb 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -30,10 +30,14 @@ #include "lightmap_gi.h" +#include "core/config/project_settings.h" #include "core/io/config_file.h" #include "core/math/delaunay_3d.h" #include "lightmap_probe.h" #include "scene/3d/mesh_instance_3d.h" +#include "scene/resources/camera_attributes.h" +#include "scene/resources/environment.h" +#include "scene/resources/sky.h" void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) { User user; @@ -207,7 +211,7 @@ bool LightmapGIData::is_using_spherical_harmonics() const { return uses_spherical_harmonics; } -void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { +void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree, float p_baked_exposure) { if (p_points.size()) { int pc = p_points.size(); ERR_FAIL_COND(pc * 9 != p_point_sh.size()); @@ -221,6 +225,8 @@ void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, con RS::get_singleton()->lightmap_set_probe_bounds(lightmap, AABB()); RS::get_singleton()->lightmap_set_probe_interior(lightmap, false); } + RS::get_singleton()->lightmap_set_baked_exposure_normalization(lightmap, p_baked_exposure); + baked_exposure = p_baked_exposure; interior = p_interior; bounds = p_bounds; } @@ -249,6 +255,10 @@ bool LightmapGIData::is_interior() const { return interior; } +float LightmapGIData::get_baked_exposure() const { + return baked_exposure; +} + void LightmapGIData::_set_probe_data(const Dictionary &p_data) { ERR_FAIL_COND(!p_data.has("bounds")); ERR_FAIL_COND(!p_data.has("points")); @@ -256,7 +266,8 @@ void LightmapGIData::_set_probe_data(const Dictionary &p_data) { ERR_FAIL_COND(!p_data.has("bsp")); ERR_FAIL_COND(!p_data.has("sh")); ERR_FAIL_COND(!p_data.has("interior")); - set_capture_data(p_data["bounds"], p_data["interior"], p_data["points"], p_data["sh"], p_data["tetrahedra"], p_data["bsp"]); + ERR_FAIL_COND(!p_data.has("baked_exposure")); + set_capture_data(p_data["bounds"], p_data["interior"], p_data["points"], p_data["sh"], p_data["tetrahedra"], p_data["bsp"], p_data["baked_exposure"]); } Dictionary LightmapGIData::_get_probe_data() const { @@ -267,6 +278,7 @@ Dictionary LightmapGIData::_get_probe_data() const { d["bsp"] = get_capture_bsp_tree(); d["sh"] = get_capture_sh(); d["interior"] = is_interior(); + d["baked_exposure"] = get_baked_exposure(); return d; } @@ -977,15 +989,21 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa Transform3D xf = lights_found[i].xform; Color linear_color = light->get_color().srgb_to_linear(); + float energy = light->get_param(Light3D::PARAM_ENERGY); + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + energy *= light->get_param(Light3D::PARAM_INTENSITY); + linear_color *= light->get_correlated_color().srgb_to_linear(); + } + if (Object::cast_to<DirectionalLight3D>(light)) { DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light); - lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); + lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy, l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } else if (Object::cast_to<OmniLight3D>(light)) { OmniLight3D *l = Object::cast_to<OmniLight3D>(light); - lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); + lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, energy * (1.0 / (Math_PI * 4.0)), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } else if (Object::cast_to<SpotLight3D>(light)) { SpotLight3D *l = Object::cast_to<SpotLight3D>(light); - lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); + lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy * (1.0 / Math_PI), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } } for (int i = 0; i < probes_found.size(); i++) { @@ -1040,7 +1058,12 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } } - Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bias, max_texture_size, directional, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud); + float exposure_normalization = 1.0; + if (camera_attributes.is_valid()) { + exposure_normalization = camera_attributes->calculate_exposure_normalization() * camera_attributes->get_exposure_multiplier(); + } + + Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bias, max_texture_size, directional, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud, exposure_normalization); if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES) { return BAKE_ERROR_MESHES_INVALID; @@ -1214,7 +1237,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa /* Obtain the colors from the images, they will be re-created as cubemaps on the server, depending on the driver */ - data->set_capture_data(bounds, interior, points, sh, tetrahedrons, bsp_array); + data->set_capture_data(bounds, interior, points, sh, tetrahedrons, bsp_array, exposure_normalization); /* Compute a BSP tree of the simplices, so it's easy to find the exact one */ } @@ -1410,6 +1433,14 @@ LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const { return gen_probes; } +void LightmapGI::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) { + camera_attributes = p_camera_attributes; +} + +Ref<CameraAttributes> LightmapGI::get_camera_attributes() const { + return camera_attributes; +} + void LightmapGI::_validate_property(PropertyInfo &p_property) const { if (p_property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { p_property.usage = PROPERTY_USAGE_NONE; @@ -1462,6 +1493,9 @@ void LightmapGI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_directional", "directional"), &LightmapGI::set_directional); ClassDB::bind_method(D_METHOD("is_directional"), &LightmapGI::is_directional); + ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &LightmapGI::set_camera_attributes); + ClassDB::bind_method(D_METHOD("get_camera_attributes"), &LightmapGI::get_camera_attributes); + // ClassDB::bind_method(D_METHOD("bake", "from_node"), &LightmapGI::bake, DEFVAL(Variant())); ADD_GROUP("Tweaks", ""); @@ -1477,6 +1511,7 @@ void LightmapGI::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment_custom_sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_environment_custom_sky", "get_environment_custom_sky"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "environment_custom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_environment_custom_color", "get_environment_custom_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "environment_custom_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_environment_custom_energy", "get_environment_custom_energy"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes"); ADD_GROUP("Gen Probes", "generate_probes_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "generate_probes_subdiv", PROPERTY_HINT_ENUM, "Disabled,4,8,16,32"), "set_generate_probes", "get_generate_probes"); ADD_GROUP("Data", ""); diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index 87add9facc..0062a4a093 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -36,6 +36,9 @@ #include "scene/3d/lightmapper.h" #include "scene/3d/visual_instance_3d.h" +class Sky; +class CameraAttributes; + class LightmapGIData : public Resource { GDCLASS(LightmapGIData, Resource); RES_BASE_EXTENSION("lmbake") @@ -47,6 +50,7 @@ class LightmapGIData : public Resource { RID lightmap; AABB bounds; + float baked_exposure = 1.0; struct User { NodePath path; @@ -83,8 +87,9 @@ public: bool is_using_spherical_harmonics() const; bool is_interior() const; + float get_baked_exposure() const; - void set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree); + void set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree, float p_baked_exposure); PackedVector3Array get_capture_points() const; PackedColorArray get_capture_sh() const; PackedInt32Array get_capture_tetrahedra() const; @@ -147,6 +152,7 @@ private: float environment_custom_energy = 1.0; bool directional = false; GenerateProbes gen_probes = GENERATE_PROBES_DISABLED; + Ref<CameraAttributes> camera_attributes; Ref<LightmapGIData> light_data; @@ -260,6 +266,9 @@ public: void set_generate_probes(GenerateProbes p_generate_probes); GenerateProbes get_generate_probes() const; + void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes); + Ref<CameraAttributes> get_camera_attributes() const; + AABB get_aabb() const override; BakeError bake(Node *p_from_node, String p_image_data_path = "", Lightmapper::BakeStepFunc p_bake_step = nullptr, void *p_bake_userdata = nullptr); diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h index 9b973fd6bc..5b5c6cf53a 100644 --- a/scene/3d/lightmapper.h +++ b/scene/3d/lightmapper.h @@ -180,7 +180,7 @@ public: virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) = 0; virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) = 0; virtual void add_probe(const Vector3 &p_position) = 0; - virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr) = 0; + virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr, float p_exposure_normalization = 1.0) = 0; virtual int get_bake_texture_count() const = 0; virtual Ref<Image> get_bake_texture(int p_index) const = 0; diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index ae231026a7..c97af087bf 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -30,8 +30,10 @@ #include "voxel_gi.h" +#include "core/core_string_names.h" #include "mesh_instance_3d.h" #include "multimesh_instance_3d.h" +#include "scene/resources/camera_attributes.h" #include "voxelizer.h" void VoxelGIData::_set_data(const Dictionary &p_data) { @@ -281,6 +283,14 @@ Vector3 VoxelGI::get_extents() const { return extents; } +void VoxelGI::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) { + camera_attributes = p_camera_attributes; +} + +Ref<CameraAttributes> VoxelGI::get_camera_attributes() const { + return camera_attributes; +} + void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node); if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_STATIC && mi->is_visible_in_tree()) { @@ -370,9 +380,14 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) { p_from_node = p_from_node ? p_from_node : get_parent(); ERR_FAIL_NULL(p_from_node); + float exposure_normalization = 1.0; + if (camera_attributes.is_valid()) { + exposure_normalization = camera_attributes->calculate_exposure_normalization() * camera_attributes->get_exposure_multiplier(); + } + Voxelizer baker; - baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0)); + baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0), exposure_normalization); List<PlotMesh> mesh_list; @@ -428,6 +443,8 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) { Vector<uint8_t> df = baker.get_sdf_3d_image(); + RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data->get_rid(), exposure_normalization); + probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count()); set_probe_data(probe_data); @@ -472,12 +489,16 @@ void VoxelGI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_extents", "extents"), &VoxelGI::set_extents); ClassDB::bind_method(D_METHOD("get_extents"), &VoxelGI::get_extents); + ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &VoxelGI::set_camera_attributes); + ClassDB::bind_method(D_METHOD("get_camera_attributes"), &VoxelGI::get_camera_attributes); + ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &VoxelGI::bake, DEFVAL(Variant()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("debug_bake"), &VoxelGI::_debug_bake); ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_NONE, "suffix:m"), "set_extents", "get_extents"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "VoxelGIData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data"); BIND_ENUM_CONSTANT(SUBDIV_64); diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h index 6d173dea87..b31ae4cd95 100644 --- a/scene/3d/voxel_gi.h +++ b/scene/3d/voxel_gi.h @@ -33,6 +33,8 @@ #include "scene/3d/visual_instance_3d.h" +class CameraAttributes; + class VoxelGIData : public Resource { GDCLASS(VoxelGIData, Resource); @@ -117,6 +119,7 @@ private: Subdiv subdiv = SUBDIV_128; Vector3 extents = Vector3(10, 10, 10); + Ref<CameraAttributes> camera_attributes; struct PlotMesh { Ref<Material> override_material; @@ -144,6 +147,10 @@ public: void set_extents(const Vector3 &p_extents); Vector3 get_extents() const; + + void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes); + Ref<CameraAttributes> get_camera_attributes() const; + Vector3i get_estimated_cell_size() const; void bake(Node *p_from_node = nullptr, bool p_create_visual_debug = false); diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp index 9380d1cf32..6daa9e0aec 100644 --- a/scene/3d/voxelizer.cpp +++ b/scene/3d/voxelizer.cpp @@ -30,6 +30,8 @@ #include "voxelizer.h" +#include "core/config/project_settings.h" + static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) { if (p_pos.is_equal_approx(p_vtx[0])) { r_uv = p_uv[0]; @@ -348,7 +350,10 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material Ref<Texture2D> emission_tex = mat->get_texture(BaseMaterial3D::TEXTURE_EMISSION); Color emission_col = mat->get_emission(); - float emission_energy = mat->get_emission_energy(); + float emission_energy = mat->get_emission_energy_multiplier() * exposure_normalization; + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + emission_energy *= mat->get_emission_intensity(); + } Ref<Image> img_emission; @@ -608,10 +613,11 @@ void Voxelizer::_fixup_plot(int p_idx, int p_level) { } } -void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds) { +void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds, float p_exposure_normalization) { sorted = false; original_bounds = p_bounds; cell_subdiv = p_subdiv; + exposure_normalization = p_exposure_normalization; bake_cells.resize(1); material_cache.clear(); diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h index 68bce768b7..f5bb9af107 100644 --- a/scene/3d/voxelizer.h +++ b/scene/3d/voxelizer.h @@ -87,6 +87,7 @@ private: }; HashMap<Ref<Material>, MaterialCache> material_cache; + float exposure_normalization = 1.0; AABB original_bounds; AABB po2_bounds; int axis_cell_size[3] = {}; @@ -111,7 +112,7 @@ private: void _sort(); public: - void begin_bake(int p_subdiv, const AABB &p_bounds); + void begin_bake(int p_subdiv, const AABB &p_bounds, float p_exposure_normalization); void plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material); void end_bake(); diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp index fe9d9ae4dd..ae7d79e8b0 100644 --- a/scene/3d/world_environment.cpp +++ b/scene/3d/world_environment.cpp @@ -42,9 +42,9 @@ void WorldEnvironment::_notification(int p_what) { _update_current_environment(); } - if (camera_effects.is_valid()) { - add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); - _update_current_camera_effects(); + if (camera_attributes.is_valid()) { + add_to_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_camera_attributes(); } } break; @@ -55,9 +55,9 @@ void WorldEnvironment::_notification(int p_what) { _update_current_environment(); } - if (camera_effects.is_valid()) { - remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); - _update_current_camera_effects(); + if (camera_attributes.is_valid()) { + remove_from_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_camera_attributes(); } } break; } @@ -74,15 +74,15 @@ void WorldEnvironment::_update_current_environment() { get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings"); } -void WorldEnvironment::_update_current_camera_effects() { - WorldEnvironment *first = Object::cast_to<WorldEnvironment>(get_tree()->get_first_node_in_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()))); +void WorldEnvironment::_update_current_camera_attributes() { + WorldEnvironment *first = Object::cast_to<WorldEnvironment>(get_tree()->get_first_node_in_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()))); if (first) { - get_viewport()->find_world_3d()->set_camera_effects(first->camera_effects); + get_viewport()->find_world_3d()->set_camera_attributes(first->camera_attributes); } else { - get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>()); + get_viewport()->find_world_3d()->set_camera_attributes(Ref<CameraAttributes>()); } - get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings"); + get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings"); } void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) { @@ -110,36 +110,36 @@ Ref<Environment> WorldEnvironment::get_environment() const { return environment; } -void WorldEnvironment::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) { - if (camera_effects == p_camera_effects) { +void WorldEnvironment::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) { + if (camera_attributes == p_camera_attributes) { return; } - if (is_inside_tree() && camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() == camera_effects) { - remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + if (is_inside_tree() && camera_attributes.is_valid() && get_viewport()->find_world_3d()->get_camera_attributes() == camera_attributes) { + remove_from_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); } - camera_effects = p_camera_effects; - if (is_inside_tree() && camera_effects.is_valid()) { - add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + camera_attributes = p_camera_attributes; + if (is_inside_tree() && camera_attributes.is_valid()) { + add_to_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); } if (is_inside_tree()) { - _update_current_camera_effects(); + _update_current_camera_attributes(); } else { update_configuration_warnings(); } } -Ref<CameraEffects> WorldEnvironment::get_camera_effects() const { - return camera_effects; +Ref<CameraAttributes> WorldEnvironment::get_camera_attributes() const { + return camera_attributes; } TypedArray<String> WorldEnvironment::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); - if (!environment.is_valid() && !camera_effects.is_valid()) { - warnings.push_back(RTR("To have any visible effect, WorldEnvironment requires its \"Environment\" property to contain an Environment, its \"Camera Effects\" property to contain a CameraEffects resource, or both.")); + if (!environment.is_valid() && !camera_attributes.is_valid()) { + warnings.push_back(RTR("To have any visible effect, WorldEnvironment requires its \"Environment\" property to contain an Environment, its \"Camera Attributes\" property to contain a CameraAttributes resource, or both.")); } if (!is_inside_tree()) { @@ -150,7 +150,7 @@ TypedArray<String> WorldEnvironment::get_configuration_warnings() const { warnings.push_back(("Only the first Environment has an effect in a scene (or set of instantiated scenes).")); } - if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) { + if (camera_attributes.is_valid() && get_viewport()->find_world_3d()->get_camera_attributes() != camera_attributes) { warnings.push_back(RTR("Only one WorldEnvironment is allowed per scene (or set of instantiated scenes).")); } @@ -162,9 +162,9 @@ void WorldEnvironment::_bind_methods() { ClassDB::bind_method(D_METHOD("get_environment"), &WorldEnvironment::get_environment); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); - ClassDB::bind_method(D_METHOD("set_camera_effects", "env"), &WorldEnvironment::set_camera_effects); - ClassDB::bind_method(D_METHOD("get_camera_effects"), &WorldEnvironment::get_camera_effects); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects"); + ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &WorldEnvironment::set_camera_attributes); + ClassDB::bind_method(D_METHOD("get_camera_attributes"), &WorldEnvironment::get_camera_attributes); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes"); } WorldEnvironment::WorldEnvironment() { diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h index 9955aa72a8..07f243c750 100644 --- a/scene/3d/world_environment.h +++ b/scene/3d/world_environment.h @@ -32,17 +32,17 @@ #define WORLD_ENVIRONMENT_H #include "scene/main/node.h" -#include "scene/resources/camera_effects.h" +#include "scene/resources/camera_attributes.h" #include "scene/resources/environment.h" class WorldEnvironment : public Node { GDCLASS(WorldEnvironment, Node); Ref<Environment> environment; - Ref<CameraEffects> camera_effects; + Ref<CameraAttributes> camera_attributes; void _update_current_environment(); - void _update_current_camera_effects(); + void _update_current_camera_attributes(); protected: void _notification(int p_what); @@ -52,8 +52,8 @@ public: void set_environment(const Ref<Environment> &p_environment); Ref<Environment> get_environment() const; - void set_camera_effects(const Ref<CameraEffects> &p_camera_effects); - Ref<CameraEffects> get_camera_effects() const; + void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes); + Ref<CameraAttributes> get_camera_attributes() const; TypedArray<String> get_configuration_warnings() const override; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index ec98ff36a0..268b381029 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -46,6 +46,7 @@ #include "scene/debugger/scene_debugger.h" #include "scene/main/multiplayer_api.h" #include "scene/main/viewport.h" +#include "scene/resources/environment.h" #include "scene/resources/font.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" @@ -1472,18 +1473,18 @@ SceneTree::SceneTree() { } } - int shadowmap_size = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_size", 4096); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_size", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_size", PROPERTY_HINT_RANGE, "256,16384")); - GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_size.mobile", 2048); - bool shadowmap_16_bits = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_16_bits", true); - int atlas_q0 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv", 2); - int atlas_q1 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv", 2); - int atlas_q2 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv", 3); - int atlas_q3 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv", 4); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + int shadowmap_size = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_size", 4096); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_size", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_size", PROPERTY_HINT_RANGE, "256,16384")); + GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_size.mobile", 2048); + bool shadowmap_16_bits = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_16_bits", true); + int atlas_q0 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv", 2); + int atlas_q1 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv", 2); + int atlas_q2 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv", 3); + int atlas_q3 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv", 4); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); root->set_positional_shadow_atlas_size(shadowmap_size); root->set_positional_shadow_atlas_16_bits(shadowmap_16_bits); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 6c7bc552bf..cc40d36fa3 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -142,7 +142,7 @@ #include "scene/resources/bit_map.h" #include "scene/resources/bone_map.h" #include "scene/resources/box_shape_3d.h" -#include "scene/resources/camera_effects.h" +#include "scene/resources/camera_attributes.h" #include "scene/resources/capsule_shape_2d.h" #include "scene/resources/capsule_shape_3d.h" #include "scene/resources/circle_shape_2d.h" @@ -152,6 +152,7 @@ #include "scene/resources/convex_polygon_shape_3d.h" #include "scene/resources/cylinder_shape_3d.h" #include "scene/resources/default_theme/default_theme.h" +#include "scene/resources/environment.h" #include "scene/resources/font.h" #include "scene/resources/gradient.h" #include "scene/resources/height_map_shape_3d.h" @@ -836,7 +837,9 @@ void register_scene_types() { GDREGISTER_CLASS(PhysicsMaterial); GDREGISTER_CLASS(World3D); GDREGISTER_CLASS(Environment); - GDREGISTER_CLASS(CameraEffects); + GDREGISTER_VIRTUAL_CLASS(CameraAttributes); + GDREGISTER_CLASS(CameraAttributesPhysical); + GDREGISTER_CLASS(CameraAttributesPractical); GDREGISTER_CLASS(World2D); GDREGISTER_VIRTUAL_CLASS(Texture); GDREGISTER_VIRTUAL_CLASS(Texture2D); diff --git a/scene/resources/camera_attributes.cpp b/scene/resources/camera_attributes.cpp new file mode 100644 index 0000000000..3c322f32b6 --- /dev/null +++ b/scene/resources/camera_attributes.cpp @@ -0,0 +1,493 @@ +/*************************************************************************/ +/* camera_attributes.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "camera_attributes.h" + +#include "core/config/project_settings.h" +#include "servers/rendering_server.h" + +void CameraAttributes::set_exposure_multiplier(float p_multiplier) { + exposure_multiplier = p_multiplier; + _update_exposure(); + emit_changed(); +} + +float CameraAttributes::get_exposure_multiplier() const { + return exposure_multiplier; +} + +void CameraAttributes::set_exposure_sensitivity(float p_sensitivity) { + exposure_sensitivity = p_sensitivity; + _update_exposure(); + emit_changed(); +} + +float CameraAttributes::get_exposure_sensitivity() const { + return exposure_sensitivity; +} + +void CameraAttributes::_update_exposure() { + float exposure_normalization = 1.0; + // Ignore physical properties if not using physical light units. + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + exposure_normalization = calculate_exposure_normalization(); + } + + RS::get_singleton()->camera_attributes_set_exposure(camera_attributes, exposure_multiplier, exposure_normalization); +} + +void CameraAttributes::set_auto_exposure_enabled(bool p_enabled) { + auto_exposure_enabled = p_enabled; + _update_auto_exposure(); + notify_property_list_changed(); +} + +bool CameraAttributes::is_auto_exposure_enabled() const { + return auto_exposure_enabled; +} + +void CameraAttributes::set_auto_exposure_speed(float p_auto_exposure_speed) { + auto_exposure_speed = p_auto_exposure_speed; + _update_auto_exposure(); +} + +float CameraAttributes::get_auto_exposure_speed() const { + return auto_exposure_speed; +} + +void CameraAttributes::set_auto_exposure_scale(float p_auto_exposure_scale) { + auto_exposure_scale = p_auto_exposure_scale; + _update_auto_exposure(); +} + +float CameraAttributes::get_auto_exposure_scale() const { + return auto_exposure_scale; +} + +RID CameraAttributes::get_rid() const { + return camera_attributes; +} + +void CameraAttributes::_validate_property(PropertyInfo &p_property) const { + if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units") && p_property.name == "exposure_sensitivity") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + return; + } + + if (p_property.name.begins_with("auto_exposure_") && p_property.name != "auto_exposure_enabled" && !auto_exposure_enabled) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + return; + } +} + +void CameraAttributes::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_exposure_multiplier", "multiplier"), &CameraAttributes::set_exposure_multiplier); + ClassDB::bind_method(D_METHOD("get_exposure_multiplier"), &CameraAttributes::get_exposure_multiplier); + ClassDB::bind_method(D_METHOD("set_exposure_sensitivity", "sensitivity"), &CameraAttributes::set_exposure_sensitivity); + ClassDB::bind_method(D_METHOD("get_exposure_sensitivity"), &CameraAttributes::get_exposure_sensitivity); + + ClassDB::bind_method(D_METHOD("set_auto_exposure_enabled", "enabled"), &CameraAttributes::set_auto_exposure_enabled); + ClassDB::bind_method(D_METHOD("is_auto_exposure_enabled"), &CameraAttributes::is_auto_exposure_enabled); + ClassDB::bind_method(D_METHOD("set_auto_exposure_speed", "exposure_speed"), &CameraAttributes::set_auto_exposure_speed); + ClassDB::bind_method(D_METHOD("get_auto_exposure_speed"), &CameraAttributes::get_auto_exposure_speed); + ClassDB::bind_method(D_METHOD("set_auto_exposure_scale", "exposure_grey"), &CameraAttributes::set_auto_exposure_scale); + ClassDB::bind_method(D_METHOD("get_auto_exposure_scale"), &CameraAttributes::get_auto_exposure_scale); + + ADD_GROUP("Exposure", "exposure"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_sensitivity", PROPERTY_HINT_RANGE, "0.1,32000.0,0.1,suffix:ISO"), "set_exposure_sensitivity", "get_exposure_sensitivity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_multiplier", PROPERTY_HINT_RANGE, "0.0,2048.0,0.001"), "set_exposure_multiplier", "get_exposure_multiplier"); + + ADD_GROUP("Auto Exposure", "auto_exposure_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_auto_exposure_enabled", "is_auto_exposure_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_auto_exposure_scale", "get_auto_exposure_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_speed", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_auto_exposure_speed", "get_auto_exposure_speed"); +} + +CameraAttributes::CameraAttributes() { + camera_attributes = RS::get_singleton()->camera_attributes_create(); +} + +CameraAttributes::~CameraAttributes() { + RS::get_singleton()->free(camera_attributes); +} + +////////////////////////////////////////////////////// +/* CameraAttributesPractical */ + +void CameraAttributesPractical::set_dof_blur_far_enabled(bool p_enabled) { + dof_blur_far_enabled = p_enabled; + _update_dof_blur(); + notify_property_list_changed(); +} + +bool CameraAttributesPractical::is_dof_blur_far_enabled() const { + return dof_blur_far_enabled; +} + +void CameraAttributesPractical::set_dof_blur_far_distance(float p_distance) { + dof_blur_far_distance = p_distance; + _update_dof_blur(); +} + +float CameraAttributesPractical::get_dof_blur_far_distance() const { + return dof_blur_far_distance; +} + +void CameraAttributesPractical::set_dof_blur_far_transition(float p_distance) { + dof_blur_far_transition = p_distance; + _update_dof_blur(); +} + +float CameraAttributesPractical::get_dof_blur_far_transition() const { + return dof_blur_far_transition; +} + +void CameraAttributesPractical::set_dof_blur_near_enabled(bool p_enabled) { + dof_blur_near_enabled = p_enabled; + _update_dof_blur(); + notify_property_list_changed(); +} + +bool CameraAttributesPractical::is_dof_blur_near_enabled() const { + return dof_blur_near_enabled; +} + +void CameraAttributesPractical::set_dof_blur_near_distance(float p_distance) { + dof_blur_near_distance = p_distance; + _update_dof_blur(); +} + +float CameraAttributesPractical::get_dof_blur_near_distance() const { + return dof_blur_near_distance; +} + +void CameraAttributesPractical::set_dof_blur_near_transition(float p_distance) { + dof_blur_near_transition = p_distance; + _update_dof_blur(); +} + +float CameraAttributesPractical::get_dof_blur_near_transition() const { + return dof_blur_near_transition; +} + +void CameraAttributesPractical::set_dof_blur_amount(float p_amount) { + dof_blur_amount = p_amount; + _update_dof_blur(); +} + +float CameraAttributesPractical::get_dof_blur_amount() const { + return dof_blur_amount; +} + +void CameraAttributesPractical::_update_dof_blur() { + RS::get_singleton()->camera_attributes_set_dof_blur( + get_rid(), + dof_blur_far_enabled, + dof_blur_far_distance, + dof_blur_far_transition, + dof_blur_near_enabled, + dof_blur_near_distance, + dof_blur_near_transition, + dof_blur_amount); +} + +float CameraAttributesPractical::calculate_exposure_normalization() const { + return exposure_sensitivity / 3072007.0; // Matches exposure normalization for default CameraAttributesPhysical at ISO 100. +} + +void CameraAttributesPractical::set_auto_exposure_min_sensitivity(float p_min) { + auto_exposure_min = p_min; + _update_auto_exposure(); +} + +float CameraAttributesPractical::get_auto_exposure_min_sensitivity() const { + return auto_exposure_min; +} + +void CameraAttributesPractical::set_auto_exposure_max_sensitivity(float p_max) { + auto_exposure_max = p_max; + _update_auto_exposure(); +} + +float CameraAttributesPractical::get_auto_exposure_max_sensitivity() const { + return auto_exposure_max; +} + +void CameraAttributesPractical::_update_auto_exposure() { + RS::get_singleton()->camera_attributes_set_auto_exposure( + get_rid(), + auto_exposure_enabled, + auto_exposure_min * ((12.5 / 100.0) / exposure_sensitivity), // Convert from Sensitivity to Luminance + auto_exposure_max * ((12.5 / 100.0) / exposure_sensitivity), // Convert from Sensitivity to Luminance + auto_exposure_speed, + auto_exposure_scale); + emit_changed(); +} + +void CameraAttributesPractical::_validate_property(PropertyInfo &p_property) const { + if ((!dof_blur_far_enabled && (p_property.name == "dof_blur_far_distance" || p_property.name == "dof_blur_far_transition")) || + (!dof_blur_near_enabled && (p_property.name == "dof_blur_near_distance" || p_property.name == "dof_blur_near_transition"))) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + } +} + +void CameraAttributesPractical::_bind_methods() { + // DOF blur + + ClassDB::bind_method(D_METHOD("set_dof_blur_far_enabled", "enabled"), &CameraAttributesPractical::set_dof_blur_far_enabled); + ClassDB::bind_method(D_METHOD("is_dof_blur_far_enabled"), &CameraAttributesPractical::is_dof_blur_far_enabled); + ClassDB::bind_method(D_METHOD("set_dof_blur_far_distance", "distance"), &CameraAttributesPractical::set_dof_blur_far_distance); + ClassDB::bind_method(D_METHOD("get_dof_blur_far_distance"), &CameraAttributesPractical::get_dof_blur_far_distance); + ClassDB::bind_method(D_METHOD("set_dof_blur_far_transition", "distance"), &CameraAttributesPractical::set_dof_blur_far_transition); + ClassDB::bind_method(D_METHOD("get_dof_blur_far_transition"), &CameraAttributesPractical::get_dof_blur_far_transition); + + ClassDB::bind_method(D_METHOD("set_dof_blur_near_enabled", "enabled"), &CameraAttributesPractical::set_dof_blur_near_enabled); + ClassDB::bind_method(D_METHOD("is_dof_blur_near_enabled"), &CameraAttributesPractical::is_dof_blur_near_enabled); + ClassDB::bind_method(D_METHOD("set_dof_blur_near_distance", "distance"), &CameraAttributesPractical::set_dof_blur_near_distance); + ClassDB::bind_method(D_METHOD("get_dof_blur_near_distance"), &CameraAttributesPractical::get_dof_blur_near_distance); + ClassDB::bind_method(D_METHOD("set_dof_blur_near_transition", "distance"), &CameraAttributesPractical::set_dof_blur_near_transition); + ClassDB::bind_method(D_METHOD("get_dof_blur_near_transition"), &CameraAttributesPractical::get_dof_blur_near_transition); + ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "amount"), &CameraAttributesPractical::set_dof_blur_amount); + ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraAttributesPractical::get_dof_blur_amount); + + ClassDB::bind_method(D_METHOD("set_auto_exposure_max_sensitivity", "max_sensitivity"), &CameraAttributesPractical::set_auto_exposure_max_sensitivity); + ClassDB::bind_method(D_METHOD("get_auto_exposure_max_sensitivity"), &CameraAttributesPractical::get_auto_exposure_max_sensitivity); + ClassDB::bind_method(D_METHOD("set_auto_exposure_min_sensitivity", "min_sensitivity"), &CameraAttributesPractical::set_auto_exposure_min_sensitivity); + ClassDB::bind_method(D_METHOD("get_auto_exposure_min_sensitivity"), &CameraAttributesPractical::get_auto_exposure_min_sensitivity); + + ADD_GROUP("DOF Blur", "dof_blur_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_far_distance", "get_dof_blur_far_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount"); + + ADD_GROUP("Auto Exposure", "auto_exposure_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_sensitivity", PROPERTY_HINT_RANGE, "0,1600,0.01,or_greater,suffic:ISO"), "set_auto_exposure_min_sensitivity", "get_auto_exposure_min_sensitivity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_sensitivity", PROPERTY_HINT_RANGE, "0,64000,0.1,or_greater,suffic:ISO"), "set_auto_exposure_max_sensitivity", "get_auto_exposure_max_sensitivity"); +} + +CameraAttributesPractical::CameraAttributesPractical() { + _update_dof_blur(); + _update_exposure(); + set_auto_exposure_min_sensitivity(0.0); + set_auto_exposure_max_sensitivity(800.0); + notify_property_list_changed(); +} + +CameraAttributesPractical::~CameraAttributesPractical() { +} + +////////////////////////////////////////////////////// +/* CameraAttributesPhysical */ + +void CameraAttributesPhysical::set_aperture(float p_aperture) { + exposure_aperture = p_aperture; + _update_exposure(); + _update_frustum(); +} + +float CameraAttributesPhysical::get_aperture() const { + return exposure_aperture; +} + +void CameraAttributesPhysical::set_shutter_speed(float p_shutter_speed) { + exposure_shutter_speed = p_shutter_speed; + _update_exposure(); +} + +float CameraAttributesPhysical::get_shutter_speed() const { + return exposure_shutter_speed; +} + +void CameraAttributesPhysical::set_focal_length(float p_focal_length) { + frustum_focal_length = p_focal_length; + _update_frustum(); + emit_changed(); +} + +float CameraAttributesPhysical::get_focal_length() const { + return frustum_focal_length; +} + +void CameraAttributesPhysical::set_focus_distance(float p_focus_distance) { + frustum_focus_distance = p_focus_distance; + _update_frustum(); +} + +float CameraAttributesPhysical::get_focus_distance() const { + return frustum_focus_distance; +} + +void CameraAttributesPhysical::set_near(real_t p_near) { + frustum_near = p_near; + _update_frustum(); + emit_changed(); +} + +real_t CameraAttributesPhysical::get_near() const { + return frustum_near; +} + +void CameraAttributesPhysical::set_far(real_t p_far) { + frustum_far = p_far; + _update_frustum(); + emit_changed(); +} + +real_t CameraAttributesPhysical::get_far() const { + return frustum_far; +} + +real_t CameraAttributesPhysical::get_fov() const { + return frustum_fov; +} + +void CameraAttributesPhysical::_update_frustum() { + //https://en.wikipedia.org/wiki/Circle_of_confusion#Circle_of_confusion_diameter_limit_based_on_d/1500 + Vector2i sensor_size = Vector2i(36, 24); // Matches high-end DSLR, could be made variable if there is demand. + float CoC = sensor_size.length() / 1500.0; + + frustum_fov = Math::rad_to_deg(2 * atan(sensor_size.height / (2 * frustum_focal_length))); + + // Based on https://en.wikipedia.org/wiki/Depth_of_field. + float u = MAX(frustum_focus_distance * 1000.0, frustum_focal_length + 1.0); // Focus distance expressed in mm and clamped to at least 1 mm away from lens. + float hyperfocal_length = frustum_focal_length + ((frustum_focal_length * frustum_focal_length) / (exposure_aperture * CoC)); + + // This computes the start and end of the depth of field. Anything between these two points has a Circle of Confusino so small + // that it is not picked up by the camera sensors. + // To be properly physically-based, we would run the DoF shader at all depths. To be efficient, we are only running it where the CoC + // will be visible, this introduces some value shifts in the near field that we have to compensate for below. + float near = ((hyperfocal_length * u) / (hyperfocal_length + (u - frustum_focal_length))) / 1000.0; // In meters. + float far = ((hyperfocal_length * u) / (hyperfocal_length - (u - frustum_focal_length))) / 1000.0; // In meters. + float scale = (frustum_focal_length / (u - frustum_focal_length)) * (frustum_focal_length / exposure_aperture); + + bool use_far = (far < frustum_far) && (far > 0.0); + bool use_near = near > frustum_near; + RS::get_singleton()->camera_attributes_set_dof_blur( + get_rid(), + use_far, + u / 1000.0, // Focus distance clampd to focal length expressed in meters. + -1.0, // Negative to tell Bokeh effect to use physically-based scaling. + use_near, + u / 1000.0, + -1.0, + scale / 5.0); // Arbitrary scaling to get close to how much blur there should be. +} + +float CameraAttributesPhysical::calculate_exposure_normalization() const { + const float e = (exposure_aperture * exposure_aperture) * exposure_shutter_speed * (100.0 / exposure_sensitivity); + return 1.0 / (e * 1.2); +} + +void CameraAttributesPhysical::set_auto_exposure_min_exposure_value(float p_min) { + auto_exposure_min = p_min; + _update_auto_exposure(); +} + +float CameraAttributesPhysical::get_auto_exposure_min_exposure_value() const { + return auto_exposure_min; +} + +void CameraAttributesPhysical::set_auto_exposure_max_exposure_value(float p_max) { + auto_exposure_max = p_max; + _update_auto_exposure(); +} + +float CameraAttributesPhysical::get_auto_exposure_max_exposure_value() const { + return auto_exposure_max; +} + +void CameraAttributesPhysical::_update_auto_exposure() { + RS::get_singleton()->camera_attributes_set_auto_exposure( + get_rid(), + auto_exposure_enabled, + pow(2.0, auto_exposure_min) * (12.5 / exposure_sensitivity), // Convert from EV100 to Luminance + pow(2.0, auto_exposure_max) * (12.5 / exposure_sensitivity), // Convert from EV100 to Luminance + auto_exposure_speed, + auto_exposure_scale); + emit_changed(); +} + +void CameraAttributesPhysical::_validate_property(PropertyInfo &property) const { + if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units") && (property.name == "exposure_aperture" || property.name == "exposure_shutter_speed")) { + property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + return; + } +} + +void CameraAttributesPhysical::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_aperture", "aperture"), &CameraAttributesPhysical::set_aperture); + ClassDB::bind_method(D_METHOD("get_aperture"), &CameraAttributesPhysical::get_aperture); + ClassDB::bind_method(D_METHOD("set_shutter_speed", "shutter_speed"), &CameraAttributesPhysical::set_shutter_speed); + ClassDB::bind_method(D_METHOD("get_shutter_speed"), &CameraAttributesPhysical::get_shutter_speed); + + ClassDB::bind_method(D_METHOD("set_focal_length", "focal_length"), &CameraAttributesPhysical::set_focal_length); + ClassDB::bind_method(D_METHOD("get_focal_length"), &CameraAttributesPhysical::get_focal_length); + ClassDB::bind_method(D_METHOD("set_focus_distance", "focus_distance"), &CameraAttributesPhysical::set_focus_distance); + ClassDB::bind_method(D_METHOD("get_focus_distance"), &CameraAttributesPhysical::get_focus_distance); + ClassDB::bind_method(D_METHOD("set_near", "near"), &CameraAttributesPhysical::set_near); + ClassDB::bind_method(D_METHOD("get_near"), &CameraAttributesPhysical::get_near); + ClassDB::bind_method(D_METHOD("set_far", "far"), &CameraAttributesPhysical::set_far); + ClassDB::bind_method(D_METHOD("get_far"), &CameraAttributesPhysical::get_far); + ClassDB::bind_method(D_METHOD("get_fov"), &CameraAttributesPhysical::get_fov); + + ClassDB::bind_method(D_METHOD("set_auto_exposure_max_exposure_value", "exposure_value_max"), &CameraAttributesPhysical::set_auto_exposure_max_exposure_value); + ClassDB::bind_method(D_METHOD("get_auto_exposure_max_exposure_value"), &CameraAttributesPhysical::get_auto_exposure_max_exposure_value); + ClassDB::bind_method(D_METHOD("set_auto_exposure_min_exposure_value", "exposure_value_min"), &CameraAttributesPhysical::set_auto_exposure_min_exposure_value); + ClassDB::bind_method(D_METHOD("get_auto_exposure_min_exposure_value"), &CameraAttributesPhysical::get_auto_exposure_min_exposure_value); + + ADD_GROUP("Frustum", "frustum_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_focus_distance", PROPERTY_HINT_RANGE, "0.01,4000.0,0.01,suffix:m"), "set_focus_distance", "get_focus_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_focal_length", PROPERTY_HINT_RANGE, "1.0,800.0,0.01,exp,suffix:mm"), "set_focal_length", "get_focal_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp,suffix:m"), "set_near", "get_near"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp,suffix:m"), "set_far", "get_far"); + + ADD_GROUP("Exposure", "exposure"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_aperture", PROPERTY_HINT_RANGE, "0.5,64.0,0.01,exp,suffix:f-stop"), "set_aperture", "get_aperture"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_shutter_speed", PROPERTY_HINT_RANGE, "0.1,8000.0,0.001,suffix:1/s"), "set_shutter_speed", "get_shutter_speed"); + + ADD_GROUP("Auto Exposure", "auto_exposure_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_min_exposure_value", "get_auto_exposure_min_exposure_value"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_max_exposure_value", "get_auto_exposure_max_exposure_value"); +}; + +CameraAttributesPhysical::CameraAttributesPhysical() { + _update_exposure(); + _update_frustum(); + set_auto_exposure_min_exposure_value(-8); + set_auto_exposure_max_exposure_value(10); // Use a wide range by default to feel more like a real camera. + notify_property_list_changed(); +} + +CameraAttributesPhysical::~CameraAttributesPhysical() { +} diff --git a/scene/resources/camera_effects.h b/scene/resources/camera_attributes.h index 7353931d16..c4c783af29 100644 --- a/scene/resources/camera_effects.h +++ b/scene/resources/camera_attributes.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* camera_effects.h */ +/* camera_attributes.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,18 +28,57 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CAMERA_EFFECTS_H -#define CAMERA_EFFECTS_H +#ifndef CAMERA_ATTRIBUTES_H +#define CAMERA_ATTRIBUTES_H #include "core/io/resource.h" #include "core/templates/rid.h" -class CameraEffects : public Resource { - GDCLASS(CameraEffects, Resource); +class CameraAttributes : public Resource { + GDCLASS(CameraAttributes, Resource); private: - RID camera_effects; + RID camera_attributes; +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &p_property) const; + + float exposure_multiplier = 1.0; + float exposure_sensitivity = 100.0; // In ISO. + void _update_exposure(); + + bool auto_exposure_enabled = false; + float auto_exposure_min = 0.01; + float auto_exposure_max = 64.0; + float auto_exposure_speed = 0.5; + float auto_exposure_scale = 0.4; + virtual void _update_auto_exposure(){}; + +public: + virtual RID get_rid() const override; + virtual float calculate_exposure_normalization() const { return 1.0; } + + void set_exposure_multiplier(float p_multiplier); + float get_exposure_multiplier() const; + void set_exposure_sensitivity(float p_sensitivity); + float get_exposure_sensitivity() const; + + void set_auto_exposure_enabled(bool p_enabled); + bool is_auto_exposure_enabled() const; + void set_auto_exposure_speed(float p_auto_exposure_speed); + float get_auto_exposure_speed() const; + void set_auto_exposure_scale(float p_auto_exposure_scale); + float get_auto_exposure_scale() const; + + CameraAttributes(); + ~CameraAttributes(); +}; + +class CameraAttributesPractical : public CameraAttributes { + GDCLASS(CameraAttributesPractical, CameraAttributes); + +private: // DOF blur bool dof_blur_far_enabled = false; float dof_blur_far_distance = 10.0; @@ -52,18 +91,13 @@ private: float dof_blur_amount = 0.1; void _update_dof_blur(); - // Override exposure - bool override_exposure_enabled = false; - float override_exposure = 1.0; - void _update_override_exposure(); + virtual void _update_auto_exposure() override; protected: static void _bind_methods(); void _validate_property(PropertyInfo &p_property) const; public: - virtual RID get_rid() const override; - // DOF blur void set_dof_blur_far_enabled(bool p_enabled); bool is_dof_blur_far_enabled() const; @@ -78,18 +112,72 @@ public: float get_dof_blur_near_distance() const; void set_dof_blur_near_transition(float p_distance); float get_dof_blur_near_transition() const; - void set_dof_blur_amount(float p_amount); float get_dof_blur_amount() const; - // Override exposure - void set_override_exposure_enabled(bool p_enabled); - bool is_override_exposure_enabled() const; - void set_override_exposure(float p_exposure); - float get_override_exposure() const; + void set_auto_exposure_min_sensitivity(float p_min); + float get_auto_exposure_min_sensitivity() const; + void set_auto_exposure_max_sensitivity(float p_max); + float get_auto_exposure_max_sensitivity() const; + + virtual float calculate_exposure_normalization() const override; + + CameraAttributesPractical(); + ~CameraAttributesPractical(); +}; + +class CameraAttributesPhysical : public CameraAttributes { + GDCLASS(CameraAttributesPhysical, CameraAttributes); + +private: + // Exposure + float exposure_aperture = 16.0; // In f-stops; + float exposure_shutter_speed = 100.0; // In 1 / seconds; + + // Camera properties. + float frustum_focal_length = 35.0; // In millimeters. + float frustum_focus_distance = 10.0; // In Meters. + real_t frustum_near = 0.05; + real_t frustum_far = 4000.0; + real_t frustum_fov = 75.0; + void _update_frustum(); + + virtual void _update_auto_exposure() override; + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; + +public: + void set_aperture(float p_aperture); + float get_aperture() const; + + void set_shutter_speed(float p_shutter_speed); + float get_shutter_speed() const; + + void set_focal_length(float p_focal_length); + float get_focal_length() const; + + void set_focus_distance(float p_focus_distance); + float get_focus_distance() const; + + void set_near(real_t p_near); + real_t get_near() const; + + void set_far(real_t p_far); + real_t get_far() const; + + real_t get_fov() const; + + void set_auto_exposure_min_exposure_value(float p_min); + float get_auto_exposure_min_exposure_value() const; + void set_auto_exposure_max_exposure_value(float p_max); + float get_auto_exposure_max_exposure_value() const; + + virtual float calculate_exposure_normalization() const override; - CameraEffects(); - ~CameraEffects(); + CameraAttributesPhysical(); + ~CameraAttributesPhysical(); }; -#endif // CAMERA_EFFECTS_H +#endif // CAMERA_ATTRIBUTES_H diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp deleted file mode 100644 index 0b11366591..0000000000 --- a/scene/resources/camera_effects.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/*************************************************************************/ -/* camera_effects.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "camera_effects.h" - -#include "servers/rendering_server.h" - -RID CameraEffects::get_rid() const { - return camera_effects; -} - -// DOF blur - -void CameraEffects::set_dof_blur_far_enabled(bool p_enabled) { - dof_blur_far_enabled = p_enabled; - _update_dof_blur(); - notify_property_list_changed(); -} - -bool CameraEffects::is_dof_blur_far_enabled() const { - return dof_blur_far_enabled; -} - -void CameraEffects::set_dof_blur_far_distance(float p_distance) { - dof_blur_far_distance = p_distance; - _update_dof_blur(); -} - -float CameraEffects::get_dof_blur_far_distance() const { - return dof_blur_far_distance; -} - -void CameraEffects::set_dof_blur_far_transition(float p_distance) { - dof_blur_far_transition = p_distance; - _update_dof_blur(); -} - -float CameraEffects::get_dof_blur_far_transition() const { - return dof_blur_far_transition; -} - -void CameraEffects::set_dof_blur_near_enabled(bool p_enabled) { - dof_blur_near_enabled = p_enabled; - _update_dof_blur(); - notify_property_list_changed(); -} - -bool CameraEffects::is_dof_blur_near_enabled() const { - return dof_blur_near_enabled; -} - -void CameraEffects::set_dof_blur_near_distance(float p_distance) { - dof_blur_near_distance = p_distance; - _update_dof_blur(); -} - -float CameraEffects::get_dof_blur_near_distance() const { - return dof_blur_near_distance; -} - -void CameraEffects::set_dof_blur_near_transition(float p_distance) { - dof_blur_near_transition = p_distance; - _update_dof_blur(); -} - -float CameraEffects::get_dof_blur_near_transition() const { - return dof_blur_near_transition; -} - -void CameraEffects::set_dof_blur_amount(float p_amount) { - dof_blur_amount = p_amount; - _update_dof_blur(); -} - -float CameraEffects::get_dof_blur_amount() const { - return dof_blur_amount; -} - -void CameraEffects::_update_dof_blur() { - RS::get_singleton()->camera_effects_set_dof_blur( - camera_effects, - dof_blur_far_enabled, - dof_blur_far_distance, - dof_blur_far_transition, - dof_blur_near_enabled, - dof_blur_near_distance, - dof_blur_near_transition, - dof_blur_amount); -} - -// Custom exposure - -void CameraEffects::set_override_exposure_enabled(bool p_enabled) { - override_exposure_enabled = p_enabled; - _update_override_exposure(); - notify_property_list_changed(); -} - -bool CameraEffects::is_override_exposure_enabled() const { - return override_exposure_enabled; -} - -void CameraEffects::set_override_exposure(float p_exposure) { - override_exposure = p_exposure; - _update_override_exposure(); -} - -float CameraEffects::get_override_exposure() const { - return override_exposure; -} - -void CameraEffects::_update_override_exposure() { - RS::get_singleton()->camera_effects_set_custom_exposure( - camera_effects, - override_exposure_enabled, - override_exposure); -} - -// Private methods, constructor and destructor - -void CameraEffects::_validate_property(PropertyInfo &p_property) const { - if ((!dof_blur_far_enabled && (p_property.name == "dof_blur_far_distance" || p_property.name == "dof_blur_far_transition")) || - (!dof_blur_near_enabled && (p_property.name == "dof_blur_near_distance" || p_property.name == "dof_blur_near_transition")) || - (!override_exposure_enabled && p_property.name == "override_exposure")) { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } -} - -void CameraEffects::_bind_methods() { - // DOF blur - - ClassDB::bind_method(D_METHOD("set_dof_blur_far_enabled", "enabled"), &CameraEffects::set_dof_blur_far_enabled); - ClassDB::bind_method(D_METHOD("is_dof_blur_far_enabled"), &CameraEffects::is_dof_blur_far_enabled); - ClassDB::bind_method(D_METHOD("set_dof_blur_far_distance", "distance"), &CameraEffects::set_dof_blur_far_distance); - ClassDB::bind_method(D_METHOD("get_dof_blur_far_distance"), &CameraEffects::get_dof_blur_far_distance); - ClassDB::bind_method(D_METHOD("set_dof_blur_far_transition", "distance"), &CameraEffects::set_dof_blur_far_transition); - ClassDB::bind_method(D_METHOD("get_dof_blur_far_transition"), &CameraEffects::get_dof_blur_far_transition); - - ClassDB::bind_method(D_METHOD("set_dof_blur_near_enabled", "enabled"), &CameraEffects::set_dof_blur_near_enabled); - ClassDB::bind_method(D_METHOD("is_dof_blur_near_enabled"), &CameraEffects::is_dof_blur_near_enabled); - ClassDB::bind_method(D_METHOD("set_dof_blur_near_distance", "distance"), &CameraEffects::set_dof_blur_near_distance); - ClassDB::bind_method(D_METHOD("get_dof_blur_near_distance"), &CameraEffects::get_dof_blur_near_distance); - ClassDB::bind_method(D_METHOD("set_dof_blur_near_transition", "distance"), &CameraEffects::set_dof_blur_near_transition); - ClassDB::bind_method(D_METHOD("get_dof_blur_near_transition"), &CameraEffects::get_dof_blur_near_transition); - - ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "amount"), &CameraEffects::set_dof_blur_amount); - ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraEffects::get_dof_blur_amount); - - ADD_GROUP("DOF Blur", "dof_blur_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_far_distance", "get_dof_blur_far_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount"); - - // Override exposure - - ClassDB::bind_method(D_METHOD("set_override_exposure_enabled", "enabled"), &CameraEffects::set_override_exposure_enabled); - ClassDB::bind_method(D_METHOD("is_override_exposure_enabled"), &CameraEffects::is_override_exposure_enabled); - ClassDB::bind_method(D_METHOD("set_override_exposure", "exposure"), &CameraEffects::set_override_exposure); - ClassDB::bind_method(D_METHOD("get_override_exposure"), &CameraEffects::get_override_exposure); - - ADD_GROUP("Override Exposure", "override_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_exposure_enabled"), "set_override_exposure_enabled", "is_override_exposure_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "override_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_override_exposure", "get_override_exposure"); -} - -CameraEffects::CameraEffects() { - camera_effects = RS::get_singleton()->camera_effects_create(); - - _update_dof_blur(); - _update_override_exposure(); -} - -CameraEffects::~CameraEffects() { - RS::get_singleton()->free(camera_effects); -} diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index f7a7818b3b..8c23471e73 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -94,13 +94,30 @@ Color Environment::get_bg_color() const { return bg_color; } -void Environment::set_bg_energy(float p_energy) { - bg_energy = p_energy; - RS::get_singleton()->environment_set_bg_energy(environment, p_energy); +void Environment::set_bg_energy_multiplier(float p_multiplier) { + bg_energy_multiplier = p_multiplier; + _update_bg_energy(); } -float Environment::get_bg_energy() const { - return bg_energy; +float Environment::get_bg_energy_multiplier() const { + return bg_energy_multiplier; +} + +void Environment::set_bg_intensity(float p_exposure_value) { + bg_intensity = p_exposure_value; + _update_bg_energy(); +} + +float Environment::get_bg_intensity() const { + return bg_intensity; +} + +void Environment::_update_bg_energy() { + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + RS::get_singleton()->environment_set_bg_energy(environment, bg_energy_multiplier, bg_intensity); + } else { + RS::get_singleton()->environment_set_bg_energy(environment, bg_energy_multiplier, 1.0); + } } void Environment::set_canvas_max_layer(int p_max_layer) { @@ -214,63 +231,12 @@ float Environment::get_tonemap_white() const { return tonemap_white; } -void Environment::set_tonemap_auto_exposure_enabled(bool p_enabled) { - tonemap_auto_exposure_enabled = p_enabled; - _update_tonemap(); - notify_property_list_changed(); -} - -bool Environment::is_tonemap_auto_exposure_enabled() const { - return tonemap_auto_exposure_enabled; -} - -void Environment::set_tonemap_auto_exposure_min(float p_auto_exposure_min) { - tonemap_auto_exposure_min = p_auto_exposure_min; - _update_tonemap(); -} - -float Environment::get_tonemap_auto_exposure_min() const { - return tonemap_auto_exposure_min; -} - -void Environment::set_tonemap_auto_exposure_max(float p_auto_exposure_max) { - tonemap_auto_exposure_max = p_auto_exposure_max; - _update_tonemap(); -} - -float Environment::get_tonemap_auto_exposure_max() const { - return tonemap_auto_exposure_max; -} - -void Environment::set_tonemap_auto_exposure_speed(float p_auto_exposure_speed) { - tonemap_auto_exposure_speed = p_auto_exposure_speed; - _update_tonemap(); -} - -float Environment::get_tonemap_auto_exposure_speed() const { - return tonemap_auto_exposure_speed; -} - -void Environment::set_tonemap_auto_exposure_grey(float p_auto_exposure_grey) { - tonemap_auto_exposure_grey = p_auto_exposure_grey; - _update_tonemap(); -} - -float Environment::get_tonemap_auto_exposure_grey() const { - return tonemap_auto_exposure_grey; -} - void Environment::_update_tonemap() { RS::get_singleton()->environment_set_tonemap( environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, - tonemap_white, - tonemap_auto_exposure_enabled, - tonemap_auto_exposure_min, - tonemap_auto_exposure_max, - tonemap_auto_exposure_speed, - tonemap_auto_exposure_grey); + tonemap_white); } // SSR @@ -1080,10 +1046,13 @@ void Environment::_validate_property(PropertyInfo &p_property) const { } } + if (p_property.name == "background_intensity" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } + static const char *hide_prefixes[] = { "fog_", "volumetric_fog_", - "auto_exposure_", "ssr_", "ssao_", "ssil_", @@ -1095,7 +1064,6 @@ void Environment::_validate_property(PropertyInfo &p_property) const { }; static const char *high_end_prefixes[] = { - "auto_exposure_", "ssr_", "ssao_", nullptr @@ -1162,8 +1130,10 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("get_sky_rotation"), &Environment::get_sky_rotation); ClassDB::bind_method(D_METHOD("set_bg_color", "color"), &Environment::set_bg_color); ClassDB::bind_method(D_METHOD("get_bg_color"), &Environment::get_bg_color); - ClassDB::bind_method(D_METHOD("set_bg_energy", "energy"), &Environment::set_bg_energy); - ClassDB::bind_method(D_METHOD("get_bg_energy"), &Environment::get_bg_energy); + ClassDB::bind_method(D_METHOD("set_bg_energy_multiplier", "energy"), &Environment::set_bg_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_bg_energy_multiplier"), &Environment::get_bg_energy_multiplier); + ClassDB::bind_method(D_METHOD("set_bg_intensity", "energy"), &Environment::set_bg_intensity); + ClassDB::bind_method(D_METHOD("get_bg_intensity"), &Environment::get_bg_intensity); ClassDB::bind_method(D_METHOD("set_canvas_max_layer", "layer"), &Environment::set_canvas_max_layer); ClassDB::bind_method(D_METHOD("get_canvas_max_layer"), &Environment::get_canvas_max_layer); ClassDB::bind_method(D_METHOD("set_camera_feed_id", "id"), &Environment::set_camera_feed_id); @@ -1172,7 +1142,9 @@ void Environment::_bind_methods() { ADD_GROUP("Background", "background_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "background_mode", PROPERTY_HINT_ENUM, "Clear Color,Custom Color,Sky,Canvas,Keep,Camera Feed"), "set_background", "get_background"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "background_color"), "set_bg_color", "get_bg_color"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_bg_energy", "get_bg_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_energy_multiplier", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_bg_energy_multiplier", "get_bg_energy_multiplier"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_intensity", PROPERTY_HINT_RANGE, "0,100000,0.01,suffix:nt"), "set_bg_intensity", "get_bg_intensity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "background_canvas_max_layer", PROPERTY_HINT_RANGE, "-1000,1000,1"), "set_canvas_max_layer", "get_canvas_max_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "background_camera_feed_id", PROPERTY_HINT_RANGE, "1,10,1"), "set_camera_feed_id", "get_camera_feed_id"); @@ -1211,27 +1183,11 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tonemap_exposure"), &Environment::get_tonemap_exposure); ClassDB::bind_method(D_METHOD("set_tonemap_white", "white"), &Environment::set_tonemap_white); ClassDB::bind_method(D_METHOD("get_tonemap_white"), &Environment::get_tonemap_white); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_enabled", "enabled"), &Environment::set_tonemap_auto_exposure_enabled); - ClassDB::bind_method(D_METHOD("is_tonemap_auto_exposure_enabled"), &Environment::is_tonemap_auto_exposure_enabled); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_max", "exposure_max"), &Environment::set_tonemap_auto_exposure_max); - ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_max"), &Environment::get_tonemap_auto_exposure_max); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_min", "exposure_min"), &Environment::set_tonemap_auto_exposure_min); - ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_min"), &Environment::get_tonemap_auto_exposure_min); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_speed", "exposure_speed"), &Environment::set_tonemap_auto_exposure_speed); - ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_speed"), &Environment::get_tonemap_auto_exposure_speed); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_grey", "exposure_grey"), &Environment::set_tonemap_auto_exposure_grey); - ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_grey"), &Environment::get_tonemap_auto_exposure_grey); ADD_GROUP("Tonemap", "tonemap_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reinhard,Filmic,ACES"), "set_tonemapper", "get_tonemapper"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_exposure", "get_tonemap_exposure"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_white", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_white", "get_tonemap_white"); - ADD_GROUP("Auto Exposure", "auto_exposure_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_tonemap_auto_exposure_enabled", "is_tonemap_auto_exposure_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_grey", "get_tonemap_auto_exposure_grey"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_min", "get_tonemap_auto_exposure_min"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_max", "get_tonemap_auto_exposure_max"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_speed", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_speed", "get_tonemap_auto_exposure_speed"); // SSR @@ -1549,6 +1505,7 @@ Environment::Environment() { _update_fog(); _update_adjustment(); _update_volumetric_fog(); + _update_bg_energy(); notify_property_list_changed(); } diff --git a/scene/resources/environment.h b/scene/resources/environment.h index d39cb1acd8..6d8330f74b 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -92,9 +92,11 @@ private: float bg_sky_custom_fov = 0.0; Vector3 bg_sky_rotation; Color bg_color; - float bg_energy = 1.0; int bg_canvas_max_layer = 0; int bg_camera_feed_id = 1; + float bg_energy_multiplier = 1.0; + float bg_intensity = 30000.0; // Measured in nits or candela/m^2 + void _update_bg_energy(); // Ambient light Color ambient_color; @@ -108,11 +110,6 @@ private: ToneMapper tone_mapper = TONE_MAPPER_LINEAR; float tonemap_exposure = 1.0; float tonemap_white = 1.0; - bool tonemap_auto_exposure_enabled = false; - float tonemap_auto_exposure_min = 0.05; - float tonemap_auto_exposure_max = 8.0; - float tonemap_auto_exposure_speed = 0.5; - float tonemap_auto_exposure_grey = 0.4; void _update_tonemap(); // SSR @@ -231,8 +228,10 @@ public: Vector3 get_sky_rotation() const; void set_bg_color(const Color &p_color); Color get_bg_color() const; - void set_bg_energy(float p_energy); - float get_bg_energy() const; + void set_bg_energy_multiplier(float p_energy); + float get_bg_energy_multiplier() const; + void set_bg_intensity(float p_energy); + float get_bg_intensity() const; void set_canvas_max_layer(int p_max_layer); int get_canvas_max_layer() const; void set_camera_feed_id(int p_id); @@ -257,16 +256,6 @@ public: float get_tonemap_exposure() const; void set_tonemap_white(float p_white); float get_tonemap_white() const; - void set_tonemap_auto_exposure_enabled(bool p_enabled); - bool is_tonemap_auto_exposure_enabled() const; - void set_tonemap_auto_exposure_min(float p_auto_exposure_min); - float get_tonemap_auto_exposure_min() const; - void set_tonemap_auto_exposure_max(float p_auto_exposure_max); - float get_tonemap_auto_exposure_max() const; - void set_tonemap_auto_exposure_speed(float p_auto_exposure_speed); - float get_tonemap_auto_exposure_speed() const; - void set_tonemap_auto_exposure_grey(float p_auto_exposure_grey); - float get_tonemap_auto_exposure_grey() const; // SSR void set_ssr_enabled(bool p_enabled); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 32ddef1693..9a1b784ec4 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -31,6 +31,8 @@ #include "material.h" #include "core/config/engine.h" +#include "core/config/project_settings.h" +#include "core/error/error_macros.h" #include "core/version.h" #include "scene/main/scene_tree.h" #include "scene/scene_string_names.h" @@ -1504,13 +1506,27 @@ Color BaseMaterial3D::get_emission() const { return emission; } -void BaseMaterial3D::set_emission_energy(float p_emission_energy) { - emission_energy = p_emission_energy; - RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy); +void BaseMaterial3D::set_emission_energy_multiplier(float p_emission_energy_multiplier) { + emission_energy_multiplier = p_emission_energy_multiplier; + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier * emission_intensity); + } else { + RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier); + } +} + +float BaseMaterial3D::get_emission_energy_multiplier() const { + return emission_energy_multiplier; +} + +void BaseMaterial3D::set_emission_intensity(float p_emission_intensity) { + ERR_FAIL_COND_EDMSG(!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units"), "Cannot set material emission intensity when Physical Light Units disabled."); + emission_intensity = p_emission_intensity; + RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, emission_energy_multiplier * emission_intensity); } -float BaseMaterial3D::get_emission_energy() const { - return emission_energy; +float BaseMaterial3D::get_emission_intensity() const { + return emission_intensity; } void BaseMaterial3D::set_normal_scale(float p_normal_scale) { @@ -1884,6 +1900,10 @@ void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const { _validate_high_end("subsurf_scatter", p_property); _validate_high_end("heightmap", p_property); + if (p_property.name == "emission_intensity" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + p_property.usage = PROPERTY_USAGE_NONE; + } + if (p_property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) { p_property.usage = PROPERTY_USAGE_NONE; } @@ -2463,8 +2483,11 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_emission", "emission"), &BaseMaterial3D::set_emission); ClassDB::bind_method(D_METHOD("get_emission"), &BaseMaterial3D::get_emission); - ClassDB::bind_method(D_METHOD("set_emission_energy", "emission_energy"), &BaseMaterial3D::set_emission_energy); - ClassDB::bind_method(D_METHOD("get_emission_energy"), &BaseMaterial3D::get_emission_energy); + ClassDB::bind_method(D_METHOD("set_emission_energy_multiplier", "emission_energy_multiplier"), &BaseMaterial3D::set_emission_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_emission_energy_multiplier"), &BaseMaterial3D::get_emission_energy_multiplier); + + ClassDB::bind_method(D_METHOD("set_emission_intensity", "emission_energy_multiplier"), &BaseMaterial3D::set_emission_intensity); + ClassDB::bind_method(D_METHOD("get_emission_intensity"), &BaseMaterial3D::get_emission_intensity); ClassDB::bind_method(D_METHOD("set_normal_scale", "normal_scale"), &BaseMaterial3D::set_normal_scale); ClassDB::bind_method(D_METHOD("get_normal_scale"), &BaseMaterial3D::get_normal_scale); @@ -2681,7 +2704,9 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Emission", "emission_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_enabled"), "set_feature", "get_feature", FEATURE_EMISSION); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy", "get_emission_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy_multiplier", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy_multiplier", "get_emission_energy_multiplier"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_intensity", PROPERTY_HINT_RANGE, "0,100000.0,0.01,or_greater,suffix:nt"), "set_emission_intensity", "get_emission_intensity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_operator", PROPERTY_HINT_ENUM, "Add,Multiply"), "set_emission_operator", "get_emission_operator"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_on_uv2"), "set_flag", "get_flag", FLAG_EMISSION_ON_UV2); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "emission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_EMISSION); @@ -2943,7 +2968,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_roughness(1.0); set_metallic(0.0); set_emission(Color(0, 0, 0)); - set_emission_energy(1.0); + set_emission_energy_multiplier(1.0); set_normal_scale(1); set_rim(1.0); set_rim_tint(0.5); @@ -3096,6 +3121,8 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value) { "depth_flip_binormal", "heightmap_flip_binormal" }, { "depth_texture", "heightmap_texture" }, + { "emission_energy", "emission_energy_multiplier" }, + { nullptr, nullptr }, }; diff --git a/scene/resources/material.h b/scene/resources/material.h index c6be1b8766..9458e859f0 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -467,7 +467,8 @@ private: float metallic = 0.0f; float roughness = 0.0f; Color emission; - float emission_energy = 0.0f; + float emission_energy_multiplier = 1.0f; + float emission_intensity = 1000.0f; // In nits, equivalent to indoor lighting. float normal_scale = 0.0f; float rim = 0.0f; float rim_tint = 0.0f; @@ -573,8 +574,11 @@ public: void set_emission(const Color &p_emission); Color get_emission() const; - void set_emission_energy(float p_emission_energy); - float get_emission_energy() const; + void set_emission_energy_multiplier(float p_emission_energy_multiplier); + float get_emission_energy_multiplier() const; + + void set_emission_intensity(float p_emission_intensity); + float get_emission_intensity() const; void set_normal_scale(float p_normal_scale); float get_normal_scale() const; diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 737c50e570..fc999d5fcb 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -30,6 +30,7 @@ #include "sky_material.h" +#include "core/config/project_settings.h" #include "core/version.h" Mutex ProceduralSkyMaterial::shader_mutex; @@ -62,13 +63,13 @@ float ProceduralSkyMaterial::get_sky_curve() const { return sky_curve; } -void ProceduralSkyMaterial::set_sky_energy(float p_energy) { - sky_energy = p_energy; - RS::get_singleton()->material_set_param(_get_material(), "sky_energy", sky_energy); +void ProceduralSkyMaterial::set_sky_energy_multiplier(float p_multiplier) { + sky_energy_multiplier = p_multiplier; + RS::get_singleton()->material_set_param(_get_material(), "sky_energy", sky_energy_multiplier); } -float ProceduralSkyMaterial::get_sky_energy() const { - return sky_energy; +float ProceduralSkyMaterial::get_sky_energy_multiplier() const { + return sky_energy_multiplier; } void ProceduralSkyMaterial::set_sky_cover(const Ref<Texture2D> &p_sky_cover) { @@ -117,13 +118,13 @@ float ProceduralSkyMaterial::get_ground_curve() const { return ground_curve; } -void ProceduralSkyMaterial::set_ground_energy(float p_energy) { - ground_energy = p_energy; - RS::get_singleton()->material_set_param(_get_material(), "ground_energy", ground_energy); +void ProceduralSkyMaterial::set_ground_energy_multiplier(float p_multiplier) { + ground_energy_multiplier = p_multiplier; + RS::get_singleton()->material_set_param(_get_material(), "ground_energy", ground_energy_multiplier); } -float ProceduralSkyMaterial::get_ground_energy() const { - return ground_energy; +float ProceduralSkyMaterial::get_ground_energy_multiplier() const { + return ground_energy_multiplier; } void ProceduralSkyMaterial::set_sun_angle_max(float p_angle) { @@ -171,6 +172,12 @@ RID ProceduralSkyMaterial::get_shader_rid() const { return shader; } +void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const { + if ((p_property.name == "sky_luminance" || p_property.name == "ground_luminance") && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } +} + void ProceduralSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSkyMaterial::set_sky_top_color); ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSkyMaterial::get_sky_top_color); @@ -181,8 +188,8 @@ void ProceduralSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSkyMaterial::set_sky_curve); ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSkyMaterial::get_sky_curve); - ClassDB::bind_method(D_METHOD("set_sky_energy", "energy"), &ProceduralSkyMaterial::set_sky_energy); - ClassDB::bind_method(D_METHOD("get_sky_energy"), &ProceduralSkyMaterial::get_sky_energy); + ClassDB::bind_method(D_METHOD("set_sky_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_sky_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_sky_energy_multiplier"), &ProceduralSkyMaterial::get_sky_energy_multiplier); ClassDB::bind_method(D_METHOD("set_sky_cover", "sky_cover"), &ProceduralSkyMaterial::set_sky_cover); ClassDB::bind_method(D_METHOD("get_sky_cover"), &ProceduralSkyMaterial::get_sky_cover); @@ -199,8 +206,8 @@ void ProceduralSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSkyMaterial::set_ground_curve); ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSkyMaterial::get_ground_curve); - ClassDB::bind_method(D_METHOD("set_ground_energy", "energy"), &ProceduralSkyMaterial::set_ground_energy); - ClassDB::bind_method(D_METHOD("get_ground_energy"), &ProceduralSkyMaterial::get_ground_energy); + ClassDB::bind_method(D_METHOD("set_ground_energy_multiplier", "energy"), &ProceduralSkyMaterial::set_ground_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_ground_energy_multiplier"), &ProceduralSkyMaterial::get_ground_energy_multiplier); ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSkyMaterial::set_sun_angle_max); ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSkyMaterial::get_sun_angle_max); @@ -215,7 +222,7 @@ void ProceduralSkyMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_horizon_color", "get_sky_horizon_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy", "get_sky_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy_multiplier", "get_sky_energy_multiplier"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_cover", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_sky_cover", "get_sky_cover"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_cover_modulate"), "set_sky_cover_modulate", "get_sky_cover_modulate"); @@ -223,7 +230,7 @@ void ProceduralSkyMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_bottom_color", "get_ground_bottom_color"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_horizon_color", "get_ground_horizon_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy", "get_ground_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy_multiplier", "get_ground_energy_multiplier"); ADD_GROUP("Sun", "sun_"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01,degrees"), "set_sun_angle_max", "get_sun_angle_max"); @@ -253,7 +260,7 @@ shader_type sky; uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0); uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0); uniform float sky_curve : hint_range(0, 1) = 0.15; -uniform float sky_energy = 1.0; +uniform float sky_energy = 1.0; // In Lux. uniform sampler2D sky_cover : source_color, hint_default_black; uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0); uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0); @@ -338,13 +345,13 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() { set_sky_top_color(Color(0.385, 0.454, 0.55)); set_sky_horizon_color(Color(0.6463, 0.6558, 0.6708)); set_sky_curve(0.15); - set_sky_energy(1.0); + set_sky_energy_multiplier(1.0); set_sky_cover_modulate(Color(1, 1, 1)); set_ground_bottom_color(Color(0.2, 0.169, 0.133)); set_ground_horizon_color(Color(0.6463, 0.6558, 0.6708)); set_ground_curve(0.02); - set_ground_energy(1.0); + set_ground_energy_multiplier(1.0); set_sun_angle_max(30.0); set_sun_curve(0.15); @@ -528,13 +535,13 @@ Color PhysicalSkyMaterial::get_ground_color() const { return ground_color; } -void PhysicalSkyMaterial::set_exposure(float p_exposure) { - exposure = p_exposure; - RS::get_singleton()->material_set_param(_get_material(), "exposure", exposure); +void PhysicalSkyMaterial::set_energy_multiplier(float p_multiplier) { + energy_multiplier = p_multiplier; + RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier); } -float PhysicalSkyMaterial::get_exposure() const { - return exposure; +float PhysicalSkyMaterial::get_energy_multiplier() const { + return energy_multiplier; } void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) { @@ -574,6 +581,12 @@ RID PhysicalSkyMaterial::get_shader_rid() const { return shader; } +void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "exposure_value" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } +} + Mutex PhysicalSkyMaterial::shader_mutex; RID PhysicalSkyMaterial::shader; @@ -602,8 +615,8 @@ void PhysicalSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ground_color", "color"), &PhysicalSkyMaterial::set_ground_color); ClassDB::bind_method(D_METHOD("get_ground_color"), &PhysicalSkyMaterial::get_ground_color); - ClassDB::bind_method(D_METHOD("set_exposure", "exposure"), &PhysicalSkyMaterial::set_exposure); - ClassDB::bind_method(D_METHOD("get_exposure"), &PhysicalSkyMaterial::get_exposure); + ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PhysicalSkyMaterial::set_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PhysicalSkyMaterial::get_energy_multiplier); ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &PhysicalSkyMaterial::set_use_debanding); ClassDB::bind_method(D_METHOD("get_use_debanding"), &PhysicalSkyMaterial::get_use_debanding); @@ -623,7 +636,7 @@ void PhysicalSkyMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbidity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_turbidity", "get_turbidity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_color", "get_ground_color"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_exposure", "get_exposure"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "night_sky", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_night_sky", "get_night_sky"); } @@ -654,16 +667,13 @@ uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0); uniform float turbidity : hint_range(0, 1000) = 10.0; uniform float sun_disk_scale : hint_range(0, 360) = 1.0; uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0); -uniform float exposure : hint_range(0, 128) = 0.1; +uniform float exposure : hint_range(0, 128) = 1.0; uniform bool use_debanding = true; uniform sampler2D night_sky : source_color, hint_default_black; const vec3 UP = vec3( 0.0, 1.0, 0.0 ); -// Sun constants -const float SUN_ENERGY = 1000.0; - // Optical length at zenith for molecules. const float rayleigh_zenith_size = 8.4e3; const float mie_zenith_size = 1.25e3; @@ -683,7 +693,7 @@ vec3 interleaved_gradient_noise(vec2 pos) { void sky() { if (LIGHT0_ENABLED) { float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 ); - float sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY; + float sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * LIGHT0_ENERGY; float sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0); // Rayleigh coefficients. @@ -721,10 +731,10 @@ void sky() { float sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale); float sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale*0.5); float sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta); - vec3 L0 = (sun_energy * 1900.0 * extinction) * sundisk * LIGHT0_COLOR; + vec3 L0 = (sun_energy * extinction) * sundisk * LIGHT0_COLOR; L0 += texture(night_sky, SKY_COORDS).xyz * extinction; - vec3 color = (Lin + L0) * 0.04; + vec3 color = Lin + L0; COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade)))); COLOR *= exposure; if (use_debanding) { @@ -732,7 +742,7 @@ void sky() { } } else { // There is no sun, so display night_sky and nothing else. - COLOR = texture(night_sky, SKY_COORDS).xyz * 0.04; + COLOR = texture(night_sky, SKY_COORDS).xyz; COLOR *= exposure; } } @@ -751,7 +761,7 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() { set_turbidity(10.0); set_sun_disk_scale(1.0); set_ground_color(Color(0.1, 0.07, 0.034)); - set_exposure(0.1); + set_energy_multiplier(1.0); set_use_debanding(true); } diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h index 61999af3c4..b517fd806b 100644 --- a/scene/resources/sky_material.h +++ b/scene/resources/sky_material.h @@ -41,14 +41,14 @@ private: Color sky_top_color; Color sky_horizon_color; float sky_curve = 0.0f; - float sky_energy = 0.0f; + float sky_energy_multiplier = 0.0f; Ref<Texture2D> sky_cover; Color sky_cover_modulate; Color ground_bottom_color; Color ground_horizon_color; float ground_curve = 0.0f; - float ground_energy = 0.0f; + float ground_energy_multiplier = 0.0f; float sun_angle_max = 0.0f; float sun_curve = 0.0f; @@ -61,6 +61,7 @@ private: protected: static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; public: void set_sky_top_color(const Color &p_sky_top); @@ -72,8 +73,8 @@ public: void set_sky_curve(float p_curve); float get_sky_curve() const; - void set_sky_energy(float p_energy); - float get_sky_energy() const; + void set_sky_energy_multiplier(float p_multiplier); + float get_sky_energy_multiplier() const; void set_sky_cover(const Ref<Texture2D> &p_sky_cover); Ref<Texture2D> get_sky_cover() const; @@ -90,8 +91,8 @@ public: void set_ground_curve(float p_curve); float get_ground_curve() const; - void set_ground_energy(float p_energy); - float get_ground_energy() const; + void set_ground_energy_multiplier(float p_energy); + float get_ground_energy_multiplier() const; void set_sun_angle_max(float p_angle); float get_sun_angle_max() const; @@ -138,6 +139,9 @@ public: void set_filtering_enabled(bool p_enabled); bool is_filtering_enabled() const; + void set_energy_multiplier(float p_multiplier); + float get_energy_multiplier() const; + virtual Shader::Mode get_shader_mode() const override; virtual RID get_shader_rid() const override; virtual RID get_rid() const override; @@ -166,7 +170,7 @@ private: float turbidity = 0.0f; float sun_disk_scale = 0.0f; Color ground_color; - float exposure = 0.0f; + float energy_multiplier = 1.0f; bool use_debanding = true; Ref<Texture2D> night_sky; static void _update_shader(); @@ -174,6 +178,7 @@ private: protected: static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; public: void set_rayleigh_coefficient(float p_rayleigh); @@ -200,8 +205,11 @@ public: void set_ground_color(Color p_ground_color); Color get_ground_color() const; - void set_exposure(float p_exposure); - float get_exposure() const; + void set_energy_multiplier(float p_multiplier); + float get_energy_multiplier() const; + + void set_exposure_value(float p_exposure); + float get_exposure_value() const; void set_use_debanding(bool p_use_debanding); bool get_use_debanding() const; diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp index fb6dcd3d57..945b6af614 100644 --- a/scene/resources/world_3d.cpp +++ b/scene/resources/world_3d.cpp @@ -33,6 +33,8 @@ #include "core/config/project_settings.h" #include "scene/3d/camera_3d.h" #include "scene/3d/visible_on_screen_notifier_3d.h" +#include "scene/resources/camera_attributes.h" +#include "scene/resources/environment.h" #include "scene/scene_string_names.h" #include "servers/navigation_server_3d.h" @@ -98,17 +100,17 @@ Ref<Environment> World3D::get_fallback_environment() const { return fallback_environment; } -void World3D::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) { - camera_effects = p_camera_effects; - if (camera_effects.is_valid()) { - RS::get_singleton()->scenario_set_camera_effects(scenario, camera_effects->get_rid()); +void World3D::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) { + camera_attributes = p_camera_attributes; + if (camera_attributes.is_valid()) { + RS::get_singleton()->scenario_set_camera_attributes(scenario, camera_attributes->get_rid()); } else { - RS::get_singleton()->scenario_set_camera_effects(scenario, RID()); + RS::get_singleton()->scenario_set_camera_attributes(scenario, RID()); } } -Ref<CameraEffects> World3D::get_camera_effects() const { - return camera_effects; +Ref<CameraAttributes> World3D::get_camera_attributes() const { + return camera_attributes; } PhysicsDirectSpaceState3D *World3D::get_direct_space_state() { @@ -123,12 +125,12 @@ void World3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_environment"), &World3D::get_environment); ClassDB::bind_method(D_METHOD("set_fallback_environment", "env"), &World3D::set_fallback_environment); ClassDB::bind_method(D_METHOD("get_fallback_environment"), &World3D::get_fallback_environment); - ClassDB::bind_method(D_METHOD("set_camera_effects", "effects"), &World3D::set_camera_effects); - ClassDB::bind_method(D_METHOD("get_camera_effects"), &World3D::get_camera_effects); + ClassDB::bind_method(D_METHOD("set_camera_attributes", "attributes"), &World3D::set_camera_attributes); + ClassDB::bind_method(D_METHOD("get_camera_attributes"), &World3D::get_camera_attributes); ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World3D::get_direct_space_state); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_fallback_environment", "get_fallback_environment"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes"); ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_space"); ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_navigation_map"); ADD_PROPERTY(PropertyInfo(Variant::RID, "scenario", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_scenario"); diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h index 08bc050349..411b9aab37 100644 --- a/scene/resources/world_3d.h +++ b/scene/resources/world_3d.h @@ -32,11 +32,11 @@ #define WORLD_3D_H #include "core/io/resource.h" -#include "scene/resources/camera_effects.h" #include "scene/resources/environment.h" #include "servers/physics_server_3d.h" #include "servers/rendering_server.h" +class CameraAttributes; class Camera3D; class VisibleOnScreenNotifier3D; struct SpatialIndexer; @@ -51,7 +51,7 @@ private: Ref<Environment> environment; Ref<Environment> fallback_environment; - Ref<CameraEffects> camera_effects; + Ref<CameraAttributes> camera_attributes; HashSet<Camera3D *> cameras; @@ -74,8 +74,8 @@ public: void set_fallback_environment(const Ref<Environment> &p_environment); Ref<Environment> get_fallback_environment() const; - void set_camera_effects(const Ref<CameraEffects> &p_camera_effects); - Ref<CameraEffects> get_camera_effects() const; + void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes); + Ref<CameraAttributes> get_camera_attributes() const; _FORCE_INLINE_ const HashSet<Camera3D *> &get_cameras() const { return cameras; } |