summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/CollisionShape2D.xml2
-rw-r--r--doc/classes/Line2D.xml2
-rw-r--r--methods.py9
-rwxr-xr-xmisc/dist/osx_tools.app/Contents/Info.plist2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp44
-rw-r--r--modules/gdscript/gdscript_parser.cpp54
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp46
-rw-r--r--modules/gdscript/gdscript_tokenizer.h1
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs1
-rw-r--r--scene/resources/environment.cpp3
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp4
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.h2
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp68
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp402
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.h37
-rw-r--r--servers/rendering/rasterizer_rd/shaders/sky.glsl81
-rw-r--r--servers/rendering/shader_types.cpp1
-rw-r--r--tests/test_gradient.h152
-rw-r--r--tests/test_main.cpp1
23 files changed, 720 insertions, 210 deletions
diff --git a/doc/classes/CollisionShape2D.xml b/doc/classes/CollisionShape2D.xml
index e32ce9c9f9..d2676e55d0 100644
--- a/doc/classes/CollisionShape2D.xml
+++ b/doc/classes/CollisionShape2D.xml
@@ -13,7 +13,7 @@
</methods>
<members>
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false">
- A disabled collision shape has no effect in the world.
+ A disabled collision shape has no effect in the world. This property should be changed with [method Object.set_deferred].
</member>
<member name="one_way_collision" type="bool" setter="set_one_way_collision" getter="is_one_way_collision_enabled" default="false">
Sets whether this collision shape should only detect collision on one side (top or bottom).
diff --git a/doc/classes/Line2D.xml b/doc/classes/Line2D.xml
index cfd23b28bd..22fe4f6194 100644
--- a/doc/classes/Line2D.xml
+++ b/doc/classes/Line2D.xml
@@ -85,7 +85,7 @@
The style for the points between the start and the end.
</member>
<member name="points" type="PackedVector2Array" setter="set_points" getter="get_points" default="PackedVector2Array( )">
- The points that form the lines. The line is drawn between every point set in this array.
+ The points that form the lines. The line is drawn between every point set in this array. Points are interpreted as local vectors.
</member>
<member name="round_precision" type="int" setter="set_round_precision" getter="get_round_precision" default="8">
The smoothness of the rounded joints and caps. This is only used if a cap or joint is set as round.
diff --git a/methods.py b/methods.py
index 65b0e2dd6b..44e381014d 100644
--- a/methods.py
+++ b/methods.py
@@ -555,18 +555,15 @@ def generate_vs_project(env, num_jobs):
# last double quote off, confusing MSBuild
env["MSVSBUILDCOM"] = build_commandline(
"scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" platform=windows progress=no target=$(Configuration)"
- " tools=!tools! -j"
- + str(num_jobs)
+ " tools=!tools! -j" + str(num_jobs)
)
env["MSVSREBUILDCOM"] = build_commandline(
"scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" platform=windows progress=no target=$(Configuration)"
- " tools=!tools! vsproj=yes -j"
- + str(num_jobs)
+ " tools=!tools! vsproj=yes -j" + str(num_jobs)
)
env["MSVSCLEANCOM"] = build_commandline(
"scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" --clean platform=windows progress=no"
- " target=$(Configuration) tools=!tools! -j"
- + str(num_jobs)
+ " target=$(Configuration) tools=!tools! -j" + str(num_jobs)
)
# This version information (Win32, x64, Debug, Release, Release_Debug seems to be
diff --git a/misc/dist/osx_tools.app/Contents/Info.plist b/misc/dist/osx_tools.app/Contents/Info.plist
index fd62bc0ef5..508586904c 100755
--- a/misc/dist/osx_tools.app/Contents/Info.plist
+++ b/misc/dist/osx_tools.app/Contents/Info.plist
@@ -111,7 +111,7 @@
<string>GDScript.icns</string>
<key>UTTypeConformsTo</key>
<array>
- <string>public.data</string>
+ <string>public.script</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 2082339ba7..7b07cce8bd 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -33,6 +33,7 @@
#include "core/class_db.h"
#include "core/hash_map.h"
#include "core/io/resource_loader.h"
+#include "core/os/file_access.h"
#include "core/project_settings.h"
#include "core/script_language.h"
#include "gdscript.h"
@@ -1960,6 +1961,8 @@ void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) {
void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dictionary) {
bool all_is_constant = true;
+ HashMap<Variant, GDScriptParser::ExpressionNode *, VariantHasher, VariantComparator> elements;
+
for (int i = 0; i < p_dictionary->elements.size(); i++) {
const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];
if (p_dictionary->style == GDScriptParser::DictionaryNode::PYTHON_DICT) {
@@ -1967,6 +1970,14 @@ void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dicti
}
reduce_expression(element.value);
all_is_constant = all_is_constant && element.key->is_constant && element.value->is_constant;
+
+ if (element.key->is_constant) {
+ if (elements.has(element.key->reduced_value)) {
+ push_error(vformat(R"(Key "%s" was already used in this dictionary (at line %d).)", element.key->reduced_value, elements[element.key->reduced_value]->start_line), element.key);
+ } else {
+ elements[element.key->reduced_value] = element.value;
+ }
+ }
}
if (all_is_constant) {
@@ -2301,6 +2312,37 @@ void GDScriptAnalyzer::reduce_literal(GDScriptParser::LiteralNode *p_literal) {
}
void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
+ if (!p_preload->path) {
+ return;
+ }
+
+ reduce_expression(p_preload->path);
+
+ if (!p_preload->path->is_constant) {
+ push_error("Preloaded path must be a constant string.", p_preload->path);
+ return;
+ }
+
+ if (p_preload->path->reduced_value.get_type() != Variant::STRING) {
+ push_error("Preloaded path must be a constant string.", p_preload->path);
+ } else {
+ p_preload->resolved_path = p_preload->path->reduced_value;
+ // TODO: Save this as script dependency.
+ if (p_preload->resolved_path.is_rel_path()) {
+ p_preload->resolved_path = parser->script_path.get_base_dir().plus_file(p_preload->resolved_path);
+ }
+ p_preload->resolved_path = p_preload->resolved_path.simplify_path();
+ if (!FileAccess::exists(p_preload->resolved_path)) {
+ push_error(vformat(R"(Preload file "%s" does not exist.)", p_preload->resolved_path), p_preload->path);
+ } else {
+ // TODO: Don't load if validating: use completion cache.
+ p_preload->resource = ResourceLoader::load(p_preload->resolved_path);
+ if (p_preload->resource.is_null()) {
+ push_error(vformat(R"(Could not p_preload resource file "%s".)", p_preload->resolved_path), p_preload->path);
+ }
+ }
+ }
+
p_preload->is_constant = true;
p_preload->reduced_value = p_preload->resource;
p_preload->set_datatype(type_from_variant(p_preload->reduced_value));
@@ -2476,7 +2518,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
// Check resulting type if possible.
result_type.builtin_type = Variant::NIL;
result_type.kind = GDScriptParser::DataType::BUILTIN;
- result_type.type_source = GDScriptParser::DataType::INFERRED;
+ result_type.type_source = base_type.is_hard_type() ? GDScriptParser::DataType::ANNOTATED_INFERRED : GDScriptParser::DataType::INFERRED;
switch (base_type.builtin_type) {
// Can't index at all.
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index e53a1090fe..aeec1c0379 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -986,9 +986,15 @@ GDScriptParser::SignalNode *GDScriptParser::parse_signal() {
signal->identifier = parse_identifier();
if (match(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) {
- while (!check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE) && !is_at_end()) {
+ do {
+ if (check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE)) {
+ // Allow for trailing comma.
+ break;
+ }
+
ParameterNode *parameter = parse_parameter();
if (parameter == nullptr) {
+ push_error("Expected signal parameter name.");
break;
}
if (parameter->default_value != nullptr) {
@@ -1000,7 +1006,8 @@ GDScriptParser::SignalNode *GDScriptParser::parse_signal() {
signal->parameters_indices[parameter->identifier->name] = signal->parameters.size();
signal->parameters.push_back(parameter);
}
- }
+ } while (match(GDScriptTokenizer::Token::COMMA) && !is_at_end());
+
consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after signal parameters.)*");
}
@@ -1022,6 +1029,8 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
push_multiline(true);
consume(GDScriptTokenizer::Token::BRACE_OPEN, vformat(R"(Expected "{" after %s.)", named ? "enum name" : R"("enum")"));
+ HashMap<StringName, int> elements;
+
do {
if (check(GDScriptTokenizer::Token::BRACE_CLOSE)) {
break; // Allow trailing comma.
@@ -1033,7 +1042,9 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
item.line = previous.start_line;
item.leftmost_column = previous.leftmost_column;
- if (!named) {
+ if (elements.has(item.identifier->name)) {
+ push_error(vformat(R"(Name "%s" was already in this enum (at line %d).)", item.identifier->name, elements[item.identifier->name]), item.identifier);
+ } else if (!named) {
// TODO: Abstract this recursive member check.
ClassNode *parent = current_class;
while (parent != nullptr) {
@@ -1045,6 +1056,8 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
}
}
+ elements[item.identifier->name] = item.line;
+
if (match(GDScriptTokenizer::Token::EQUAL)) {
ExpressionNode *value = parse_expression(false);
if (value == nullptr) {
@@ -1136,6 +1149,9 @@ GDScriptParser::FunctionNode *GDScriptParser::parse_function() {
if (match(GDScriptTokenizer::Token::FORWARD_ARROW)) {
make_completion_context(COMPLETION_TYPE_NAME_OR_VOID, function);
function->return_type = parse_type(true);
+ if (function->return_type == nullptr) {
+ push_error(R"(Expected return type or "void" after "->".)");
+ }
}
// TODO: Improve token consumption so it synchronizes to a statement boundary. This way we can get into the function body with unrecognized tokens.
@@ -2489,15 +2505,18 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p
make_completion_context(COMPLETION_GET_NODE, get_node);
get_node->string = parse_literal();
return get_node;
- } else if (check(GDScriptTokenizer::Token::IDENTIFIER)) {
+ } else if (current.is_node_name()) {
GetNodeNode *get_node = alloc_node<GetNodeNode>();
int chain_position = 0;
do {
make_completion_context(COMPLETION_GET_NODE, get_node, chain_position++);
- if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expect node identifer after "/".)")) {
+ if (!current.is_node_name()) {
+ push_error(R"(Expect node path after "/".)");
return nullptr;
}
- IdentifierNode *identifier = parse_identifier();
+ advance();
+ IdentifierNode *identifier = alloc_node<IdentifierNode>();
+ identifier->name = previous.get_identifier();
get_node->chain.push_back(identifier);
} while (match(GDScriptTokenizer::Token::SLASH));
return get_node;
@@ -2521,29 +2540,6 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_preload(ExpressionNode *p_
if (preload->path == nullptr) {
push_error(R"(Expected resource path after "(".)");
- } else if (preload->path->type != Node::LITERAL) {
- push_error("Preloaded path must be a constant string.");
- } else {
- LiteralNode *path = static_cast<LiteralNode *>(preload->path);
- if (path->value.get_type() != Variant::STRING) {
- push_error("Preloaded path must be a constant string.");
- } else {
- preload->resolved_path = path->value;
- // TODO: Save this as script dependency.
- if (preload->resolved_path.is_rel_path()) {
- preload->resolved_path = script_path.get_base_dir().plus_file(preload->resolved_path);
- }
- preload->resolved_path = preload->resolved_path.simplify_path();
- if (!FileAccess::exists(preload->resolved_path)) {
- push_error(vformat(R"(Preload file "%s" does not exist.)", preload->resolved_path));
- } else {
- // TODO: Don't load if validating: use completion cache.
- preload->resource = ResourceLoader::load(preload->resolved_path);
- if (preload->resource.is_null()) {
- push_error(vformat(R"(Could not preload resource file "%s".)", preload->resolved_path));
- }
- }
- }
}
pop_completion_call();
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 8ced06e2fd..737e920693 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -168,6 +168,52 @@ bool GDScriptTokenizer::Token::is_identifier() const {
}
}
+bool GDScriptTokenizer::Token::is_node_name() const {
+ // This is meant to allow keywords with the $ notation, but not as general identifiers.
+ switch (type) {
+ case IDENTIFIER:
+ case AND:
+ case AS:
+ case ASSERT:
+ case AWAIT:
+ case BREAK:
+ case BREAKPOINT:
+ case CLASS_NAME:
+ case CLASS:
+ case CONST:
+ case CONTINUE:
+ case ELIF:
+ case ELSE:
+ case ENUM:
+ case EXTENDS:
+ case FOR:
+ case FUNC:
+ case IF:
+ case IN:
+ case IS:
+ case MATCH:
+ case NAMESPACE:
+ case NOT:
+ case OR:
+ case PASS:
+ case PRELOAD:
+ case RETURN:
+ case SELF:
+ case SIGNAL:
+ case STATIC:
+ case SUPER:
+ case TRAIT:
+ case UNDERSCORE:
+ case VAR:
+ case VOID:
+ case WHILE:
+ case YIELD:
+ return true;
+ default:
+ return false;
+ }
+}
+
String GDScriptTokenizer::get_token_name(Token::Type p_token_type) {
ERR_FAIL_INDEX_V_MSG(p_token_type, Token::TK_MAX, "<error>", "Using token type out of the enum.");
return token_names[p_token_type];
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 956530341c..100ed3f132 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -169,6 +169,7 @@ public:
const char *get_name() const;
bool is_identifier() const;
+ bool is_node_name() const;
StringName get_identifier() const { return source; }
Token(Type p_type) {
diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
index c2549b4ad5..5edf72d63e 100644
--- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
@@ -70,13 +70,14 @@ namespace GodotTools.BuildLogger
{
string line = $"{e.File}({e.LineNumber},{e.ColumnNumber}): error {e.Code}: {e.Message}";
- if (e.ProjectFile.Length > 0)
+ if (!string.IsNullOrEmpty(e.ProjectFile))
line += $" [{e.ProjectFile}]";
WriteLine(line);
string errorLine = $@"error,{e.File.CsvEscape()},{e.LineNumber},{e.ColumnNumber}," +
- $@"{e.Code.CsvEscape()},{e.Message.CsvEscape()},{e.ProjectFile.CsvEscape()}";
+ $"{e.Code?.CsvEscape() ?? string.Empty},{e.Message.CsvEscape()}," +
+ $"{e.ProjectFile?.CsvEscape() ?? string.Empty}";
issuesStreamWriter.WriteLine(errorLine);
}
@@ -89,8 +90,9 @@ namespace GodotTools.BuildLogger
WriteLine(line);
- string warningLine = $@"warning,{e.File.CsvEscape()},{e.LineNumber},{e.ColumnNumber},{e.Code.CsvEscape()}," +
- $@"{e.Message.CsvEscape()},{(e.ProjectFile != null ? e.ProjectFile.CsvEscape() : string.Empty)}";
+ string warningLine = $@"warning,{e.File.CsvEscape()},{e.LineNumber},{e.ColumnNumber}," +
+ $"{e.Code?.CsvEscape() ?? string.Empty},{e.Message.CsvEscape()}," +
+ $"{e.ProjectFile?.CsvEscape() ?? string.Empty}";
issuesStreamWriter.WriteLine(warningLine);
}
diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
index 012b69032e..e6b0e8f1df 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
@@ -43,7 +43,7 @@ namespace GodotTools.Core
path.StartsWith(DriveRoot, StringComparison.Ordinal);
}
- public static string ToSafeDirName(this string dirName, bool allowDirSeparator)
+ public static string ToSafeDirName(this string dirName, bool allowDirSeparator = false)
{
var invalidChars = new List<string> { ":", "*", "?", "\"", "<", ">", "|" };
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
index 5541876f9e..01d7c99662 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using System.Text;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
@@ -41,7 +42,8 @@ namespace GodotTools.ProjectEditor
var root = GenGameProject(name);
- root.Save(path);
+ // Save (without BOM)
+ root.Save(path, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
return Guid.NewGuid().ToString().ToUpper();
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index 554763eecb..e819848212 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -430,7 +430,7 @@ namespace GodotTools.Export
private static string DetermineDataDirNameForProject()
{
var appName = (string)ProjectSettings.GetSetting("application/config/name");
- string appNameSafe = appName.ToSafeDirName(allowDirSeparator: false);
+ string appNameSafe = appName.ToSafeDirName();
return $"data_{appNameSafe}";
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index e2f7e87388..3148458d7e 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -45,6 +45,7 @@ namespace GodotTools
get
{
var projectAssemblyName = (string)ProjectSettings.GetSetting("application/config/name");
+ projectAssemblyName = projectAssemblyName.ToSafeDirName();
if (string.IsNullOrEmpty(projectAssemblyName))
projectAssemblyName = "UnnamedProject";
return projectAssemblyName;
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index a174c3eebe..ee8e63266d 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -134,6 +134,7 @@ Color Environment::get_ambient_light_color() const {
void Environment::set_ambient_source(AmbientSource p_source) {
ambient_source = p_source;
_update_ambient_light();
+ _change_notify();
}
Environment::AmbientSource Environment::get_ambient_source() const {
@@ -161,6 +162,7 @@ float Environment::get_ambient_light_sky_contribution() const {
void Environment::set_reflection_source(ReflectionSource p_source) {
reflection_source = p_source;
_update_ambient_light();
+ _change_notify();
}
Environment::ReflectionSource Environment::get_reflection_source() const {
@@ -758,6 +760,7 @@ void Environment::_update_volumetric_fog() {
void Environment::set_volumetric_fog_enabled(bool p_enable) {
volumetric_fog_enabled = p_enable;
_update_volumetric_fog();
+ _change_notify();
}
bool Environment::is_volumetric_fog_enabled() const {
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
index 390272b4b8..b3279f041f 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
@@ -1171,7 +1171,7 @@ void RasterizerEffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_des
RD::get_singleton()->compute_list_end();
}
-void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_lights, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) {
+void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) {
SkyPushConstant sky_push_constant;
zeromem(&sky_push_constant, sizeof(SkyPushConstant));
@@ -1198,7 +1198,7 @@ void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);
}
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_lights, 3);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_fog, 3);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
index 2ba9610498..b0964f23e7 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
@@ -638,7 +638,7 @@ public:
void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
- void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_lights, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position);
+ void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position);
void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera);
void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
index f65c5d5de3..11abb8f4a8 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
@@ -1156,8 +1156,19 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende
if (render_buffers_has_volumetric_fog(p_render_buffers)) {
scene_state.ubo.volumetric_fog_enabled = true;
- scene_state.ubo.volumetric_fog_inv_length = 1.0 / render_buffers_get_volumetric_fog_end(p_render_buffers);
- scene_state.ubo.volumetric_fog_detail_spread = 1.0 / render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+ float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers);
+ if (fog_end > 0.0) {
+ scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
+ } else {
+ scene_state.ubo.volumetric_fog_inv_length = 1.0;
+ }
+
+ float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+ if (fog_detail_spread > 0.0) {
+ scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
+ } else {
+ scene_state.ubo.volumetric_fog_detail_spread = 1.0;
+ }
}
}
#if 0
@@ -1696,6 +1707,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
}
RID radiance_uniform_set;
bool draw_sky = false;
+ bool draw_sky_fog_only = false;
Color clear_color;
bool keep_color = false;
@@ -1711,12 +1723,20 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
clear_color.r *= bg_energy;
clear_color.g *= bg_energy;
clear_color.b *= bg_energy;
+ if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
+ draw_sky_fog_only = true;
+ storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ }
} break;
case RS::ENV_BG_COLOR: {
clear_color = environment_get_bg_color(p_environment);
clear_color.r *= bg_energy;
clear_color.g *= bg_energy;
clear_color.b *= bg_energy;
+ if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
+ draw_sky_fog_only = true;
+ storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ }
} break;
case RS::ENV_BG_SKY: {
draw_sky = true;
@@ -1733,18 +1753,19 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
}
}
// setup sky if used for ambient, reflections, or background
- if (draw_sky || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+ if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+ RENDER_TIMESTAMP("Setup Sky");
+ CameraMatrix projection = p_cam_projection;
+ if (p_reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ projection = correction * p_cam_projection;
+ }
+
+ _setup_sky(p_environment, p_render_buffer, projection, p_cam_transform, screen_size);
+
RID sky = environment_get_sky(p_environment);
if (sky.is_valid()) {
- RENDER_TIMESTAMP("Setup Sky");
- CameraMatrix projection = p_cam_projection;
- if (p_reflection_probe.is_valid()) {
- CameraMatrix correction;
- correction.set_depth_correction(true);
- projection = correction * p_cam_projection;
- }
-
- _setup_sky(p_environment, p_cam_transform.origin, screen_size);
_update_sky(p_environment, projection, p_cam_transform);
radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET);
} else {
@@ -1813,8 +1834,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
{
- bool will_continue_color = (can_continue_color || draw_sky || debug_giprobes || debug_sdfgi_probes);
- bool will_continue_depth = (can_continue_depth || draw_sky || debug_giprobes || debug_sdfgi_probes);
+ bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes);
+ bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes);
//regular forward for now
Vector<Color> c;
@@ -1841,8 +1862,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
if (debug_giprobes) {
//debug giprobes
- bool will_continue_color = (can_continue_color || draw_sky);
- bool will_continue_depth = (can_continue_depth || draw_sky);
+ bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
+ bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
CameraMatrix dc;
dc.set_depth_correction(true);
@@ -1856,8 +1877,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
if (debug_sdfgi_probes) {
//debug giprobes
- bool will_continue_color = (can_continue_color || draw_sky);
- bool will_continue_depth = (can_continue_depth || draw_sky);
+ bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
+ bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
CameraMatrix dc;
dc.set_depth_correction(true);
@@ -1867,7 +1888,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
RD::get_singleton()->draw_list_end();
}
- if (draw_sky) {
+ if (draw_sky || draw_sky_fog_only) {
RENDER_TIMESTAMP("Render Sky");
CameraMatrix projection = p_cam_projection;
@@ -2532,8 +2553,13 @@ void RasterizerSceneHighEndRD::_update_render_buffers_uniform_set(RID p_render_b
RD::Uniform u;
u.binding = 10;
u.type = RD::UNIFORM_TYPE_TEXTURE;
- RID vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers);
- if (vfog.is_null()) {
+ RID vfog = RID();
+ if (p_render_buffers.is_valid() && render_buffers_has_volumetric_fog(p_render_buffers)) {
+ vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers);
+ if (vfog.is_null()) {
+ vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ }
+ } else {
vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
}
u.ids.push_back(vfog);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
index 5e39455c29..34818d2683 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -2066,22 +2066,33 @@ RID RasterizerSceneRD::sky_get_material(RID p_sky) const {
void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) {
ERR_FAIL_COND(!is_environment(p_environment));
+ SkyMaterialData *material = nullptr;
+
Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
- ERR_FAIL_COND(!sky);
- RID sky_material = sky_get_material(environment_get_sky(p_environment));
+ RID sky_material;
- SkyMaterialData *material = nullptr;
+ RS::EnvironmentBG background = environment_get_background(p_environment);
- if (sky_material.is_valid()) {
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
- if (!material || !material->shader_data->valid) {
- material = nullptr;
+ if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky_get_material(environment_get_sky(p_environment));
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
}
}
- if (!material) {
- sky_material = sky_shader.default_material;
+ if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+ sky_material = sky_scene_state.fog_material;
material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
}
@@ -2121,7 +2132,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, time, sky->quarter_res_framebuffer, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(draw_list, time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
@@ -2134,149 +2145,191 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, time, sky->half_res_framebuffer, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(draw_list, time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND];
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND);
+ RID texture_uniform_set;
+ if (sky) {
+ texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND);
+ } else {
+ texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
+ }
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
- storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
-void RasterizerSceneRD::_setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size) {
+void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size) {
ERR_FAIL_COND(!is_environment(p_environment));
+ SkyMaterialData *material = nullptr;
+
Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
- ERR_FAIL_COND(!sky);
- RID sky_material = sky_get_material(environment_get_sky(p_environment));
+ RID sky_material;
- SkyMaterialData *material = nullptr;
+ SkyShaderData *shader_data = nullptr;
- if (sky_material.is_valid()) {
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
- if (!material || !material->shader_data->valid) {
- material = nullptr;
+ RS::EnvironmentBG background = environment_get_background(p_environment);
+
+ if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky_get_material(environment_get_sky(p_environment));
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
}
- }
- if (!material) {
- sky_material = sky_shader.default_material;
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
- }
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
+ }
- ERR_FAIL_COND(!material);
+ ERR_FAIL_COND(!material);
- SkyShaderData *shader_data = material->shader_data;
+ shader_data = material->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_COND(!shader_data);
+ }
- // Invalidate supbass buffers if screen size changes
- if (sky->screen_size != p_screen_size) {
- sky->screen_size = p_screen_size;
- sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
- sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
- if (shader_data->uses_half_res) {
- if (sky->half_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->half_res_pass);
- sky->half_res_pass = RID();
+ if (sky) {
+ // Invalidate supbass buffers if screen size changes
+ if (sky->screen_size != p_screen_size) {
+ sky->screen_size = p_screen_size;
+ sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
+ sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
+ if (shader_data->uses_half_res) {
+ if (sky->half_res_pass.is_valid()) {
+ RD::get_singleton()->free(sky->half_res_pass);
+ sky->half_res_pass = RID();
+ }
+ _sky_invalidate(sky);
}
- _sky_invalidate(sky);
- }
- if (shader_data->uses_quarter_res) {
- if (sky->quarter_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->quarter_res_pass);
- sky->quarter_res_pass = RID();
+ if (shader_data->uses_quarter_res) {
+ if (sky->quarter_res_pass.is_valid()) {
+ RD::get_singleton()->free(sky->quarter_res_pass);
+ sky->quarter_res_pass = RID();
+ }
+ _sky_invalidate(sky);
}
+ }
+
+ // Create new subpass buffers if necessary
+ if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
+ (shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
+ sky->radiance.is_null()) {
_sky_invalidate(sky);
+ _update_dirty_skys();
}
- }
- // Create new subpass buffers if necessary
- if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
- (shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
- sky->radiance.is_null()) {
- _sky_invalidate(sky);
- _update_dirty_skys();
- }
+ if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
+ sky->prev_time = time;
+ sky->reflection.dirty = true;
+ RenderingServerRaster::redraw_request();
+ }
- if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
- sky->prev_time = time;
- sky->reflection.dirty = true;
- RenderingServerRaster::redraw_request();
- }
+ if (material != sky->prev_material) {
+ sky->prev_material = material;
+ sky->reflection.dirty = true;
+ }
- if (material != sky->prev_material) {
- sky->prev_material = material;
- sky->reflection.dirty = true;
- }
+ if (material->uniform_set_updated) {
+ material->uniform_set_updated = false;
+ sky->reflection.dirty = true;
+ }
- if (material->uniform_set_updated) {
- material->uniform_set_updated = false;
- sky->reflection.dirty = true;
- }
+ if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
+ sky->prev_position = p_transform.origin;
+ sky->reflection.dirty = true;
+ }
- if (!p_position.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
- sky->prev_position = p_position;
- sky->reflection.dirty = true;
- }
+ if (shader_data->uses_light) {
+ // Check whether the directional_light_buffer changes
+ bool light_data_dirty = false;
- if (shader_data->uses_light || sky_scene_state.light_uniform_set.is_null()) {
- // Check whether the directional_light_buffer changes
- bool light_data_dirty = false;
-
- if (sky_scene_state.directional_light_count != sky_scene_state.last_frame_directional_light_count) {
- light_data_dirty = true;
- for (uint32_t i = sky_scene_state.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
- sky_scene_state.directional_lights[i].enabled = false;
- }
- }
- if (!light_data_dirty) {
- for (uint32_t i = 0; i < sky_scene_state.directional_light_count; i++) {
- if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] ||
- sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] ||
- sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] ||
- sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy ||
- sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] ||
- sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] ||
- sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] ||
- sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled ||
- sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) {
- light_data_dirty = true;
- break;
+ if (sky_scene_state.ubo.directional_light_count != sky_scene_state.last_frame_directional_light_count) {
+ light_data_dirty = true;
+ for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
+ sky_scene_state.directional_lights[i].enabled = false;
+ }
+ }
+ if (!light_data_dirty) {
+ for (uint32_t i = 0; i < sky_scene_state.ubo.directional_light_count; i++) {
+ if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] ||
+ sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] ||
+ sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] ||
+ sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy ||
+ sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] ||
+ sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] ||
+ sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] ||
+ sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled ||
+ sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) {
+ light_data_dirty = true;
+ break;
+ }
}
}
+
+ if (light_data_dirty) {
+ RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights, true);
+
+ RasterizerSceneRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights;
+ sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights;
+ sky_scene_state.directional_lights = temp;
+ sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count;
+ sky->reflection.dirty = true;
+ }
}
+ }
- if (light_data_dirty || sky_scene_state.light_uniform_set.is_null()) {
- RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights, true);
+ //setup fog variables
+ sky_scene_state.ubo.volumetric_fog_enabled = false;
+ if (p_render_buffers.is_valid()) {
+ if (render_buffers_has_volumetric_fog(p_render_buffers)) {
+ sky_scene_state.ubo.volumetric_fog_enabled = true;
- if (sky_scene_state.light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.light_uniform_set)) {
- RD::get_singleton()->free(sky_scene_state.light_uniform_set);
+ float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers);
+ if (fog_end > 0.0) {
+ sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
+ } else {
+ sky_scene_state.ubo.volumetric_fog_inv_length = 1.0;
}
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 0;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(sky_scene_state.directional_light_buffer);
- uniforms.push_back(u);
+ float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+ if (fog_detail_spread > 0.0) {
+ sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
+ } else {
+ sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
}
+ }
- sky_scene_state.light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_LIGHTS);
+ RID fog_uniform_set = render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
- RasterizerSceneRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights;
- sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights;
- sky_scene_state.directional_lights = temp;
- sky_scene_state.last_frame_directional_light_count = sky_scene_state.directional_light_count;
- sky->reflection.dirty = true;
+ if (fog_uniform_set != RID()) {
+ sky_scene_state.fog_uniform_set = fog_uniform_set;
+ } else {
+ sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set;
}
}
+
+ sky_scene_state.ubo.z_far = p_projection.get_z_far();
+ sky_scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment);
+ sky_scene_state.ubo.fog_density = environment_get_fog_density(p_environment);
+ Color fog_color = environment_get_fog_light_color(p_environment).to_linear();
+ float fog_energy = environment_get_fog_light_energy(p_environment);
+ sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
+ sky_scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
+ sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
+ sky_scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment);
+
+ RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo, true);
}
void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) {
@@ -2371,7 +2424,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro
RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
}
@@ -2389,7 +2442,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro
RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_HALF_RES);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
}
@@ -2403,7 +2456,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro
RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
@@ -2965,7 +3018,7 @@ float RasterizerSceneRD::environment_get_fog_height_density(RID p_env) const {
return env->fog_height_density;
}
-void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, RenderingServer::EnvVolumetricFogShadowFilter p_shadow_filter) {
+void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RenderingServer::EnvVolumetricFogShadowFilter p_shadow_filter) {
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
@@ -2973,7 +3026,7 @@ void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable,
env->volumetric_fog_density = p_density;
env->volumetric_fog_light = p_light;
env->volumetric_fog_light_energy = p_light_energy;
- env->volumetric_fog_length = p_lenght;
+ env->volumetric_fog_length = p_length;
env->volumetric_fog_detail_spread = p_detail_spread;
env->volumetric_fog_shadow_filter = p_shadow_filter;
env->volumetric_fog_gi_inject = p_gi_inject;
@@ -5607,6 +5660,17 @@ RID RasterizerSceneRD::render_buffers_get_volumetric_fog_texture(RID p_render_bu
return rb->volumetric_fog->fog_map;
}
+RID RasterizerSceneRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers) {
+ const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND_V(!rb, RID());
+
+ if (!rb->volumetric_fog) {
+ return RID();
+ }
+
+ return rb->volumetric_fog->sky_uniform_set;
+}
+
float RasterizerSceneRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) {
const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0);
@@ -5838,7 +5902,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
uint32_t light_count = 0;
r_directional_light_count = 0;
r_positional_light_count = 0;
- sky_scene_state.directional_light_count = 0;
+ sky_scene_state.ubo.directional_light_count = 0;
for (int i = 0; i < p_light_cull_count; i++) {
RID li = p_light_cull_result[i];
@@ -6010,7 +6074,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
sky_light_data.enabled = true;
sky_light_data.size = angular_diameter;
- sky_scene_state.directional_light_count++;
+ sky_scene_state.ubo.directional_light_count++;
}
r_directional_light_count++;
@@ -6317,7 +6381,22 @@ void RasterizerSceneRD::_volumetric_fog_erase(RenderBuffers *rb) {
RD::get_singleton()->free(rb->volumetric_fog->light_density_map);
RD::get_singleton()->free(rb->volumetric_fog->fog_map);
+
+ if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
+ RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
+ }
+ if (rb->volumetric_fog->uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set2)) {
+ RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
+ }
+ if (rb->volumetric_fog->sdfgi_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sdfgi_uniform_set)) {
+ RD::get_singleton()->free(rb->volumetric_fog->sdfgi_uniform_set);
+ }
+ if (rb->volumetric_fog->sky_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sky_uniform_set)) {
+ RD::get_singleton()->free(rb->volumetric_fog->sky_uniform_set);
+ }
+
memdelete(rb->volumetric_fog);
+
rb->volumetric_fog = nullptr;
}
@@ -6407,6 +6486,17 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir
rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
_render_buffers_uniform_set_changed(p_render_buffers);
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(rb->volumetric_fog->fog_map);
+ uniforms.push_back(u);
+ }
+
+ rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
}
//update directional shadow
@@ -7907,6 +7997,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
actions.custom_samplers["RADIANCE"] = "material_samplers[3]";
actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
+ actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
@@ -7931,6 +8022,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY);
sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND);
+ sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO));
+
Vector<RD::Uniform> uniforms;
{
@@ -7962,7 +8055,70 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
uniforms.push_back(u);
}
- sky_scene_state.sampler_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_SAMPLERS);
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(sky_scene_state.uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(sky_scene_state.directional_light_buffer);
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS);
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ RID vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ u.ids.push_back(vfog);
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.default_fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
+ }
+
+ {
+ // Need defaults for using fog with clear color
+ sky_scene_state.fog_shader = storage->shader_create();
+ storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void fragment() { COLOR = clear_color.rgb; } \n");
+ sky_scene_state.fog_material = storage->material_create();
+ storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader);
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1;
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);
}
{
@@ -8179,11 +8335,8 @@ RasterizerSceneRD::~RasterizerSceneRD() {
RD::get_singleton()->free(E->get().cubemap);
}
- if (sky_scene_state.sampler_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.sampler_uniform_set)) {
- RD::get_singleton()->free(sky_scene_state.sampler_uniform_set);
- }
- if (sky_scene_state.light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.light_uniform_set)) {
- RD::get_singleton()->free(sky_scene_state.light_uniform_set);
+ if (sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.uniform_set)) {
+ RD::get_singleton()->free(sky_scene_state.uniform_set);
}
RD::get_singleton()->free(default_giprobe_buffer);
@@ -8199,14 +8352,19 @@ RasterizerSceneRD::~RasterizerSceneRD() {
sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader);
sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader);
+ volumetric_fog.shader.version_free(volumetric_fog.shader_version);
+
memdelete_arr(gi_probe_lights);
SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY);
sky_shader.shader.version_free(md->shader_data->version);
RD::get_singleton()->free(sky_scene_state.directional_light_buffer);
+ RD::get_singleton()->free(sky_scene_state.uniform_buffer);
memdelete_arr(sky_scene_state.directional_lights);
memdelete_arr(sky_scene_state.last_frame_directional_lights);
storage->free(sky_shader.default_shader);
storage->free(sky_shader.default_material);
+ storage->free(sky_scene_state.fog_shader);
+ storage->free(sky_scene_state.fog_material);
memdelete_arr(directional_penumbra_shadow_kernel);
memdelete_arr(directional_soft_shadow_kernel);
memdelete_arr(penumbra_shadow_kernel);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
index 4c48960587..f504240f50 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
@@ -63,14 +63,37 @@ protected:
};
struct SkySceneState {
+ struct UBO {
+ uint32_t volumetric_fog_enabled;
+ float volumetric_fog_inv_length;
+ float volumetric_fog_detail_spread;
+ uint32_t volumetric_fog_pad;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
+
+ uint32_t fog_enabled;
+ float fog_density;
+
+ float z_far;
+ uint32_t directional_light_count;
+ };
+
+ UBO ubo;
+
SkyDirectionalLightData *directional_lights;
SkyDirectionalLightData *last_frame_directional_lights;
uint32_t max_directional_lights;
- uint32_t directional_light_count;
uint32_t last_frame_directional_light_count;
RID directional_light_buffer;
- RID sampler_uniform_set;
- RID light_uniform_set;
+ RID uniform_set;
+ RID uniform_buffer;
+ RID fog_uniform_set;
+ RID default_fog_uniform_set;
+
+ RID fog_shader;
+ RID fog_material;
+ RID fog_only_texture_uniform_set;
} sky_scene_state;
struct RenderBufferData {
@@ -105,7 +128,7 @@ protected:
void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive);
void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera);
- void _setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size);
+ void _setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size);
void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);
void _draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);
void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count);
@@ -244,10 +267,10 @@ private:
};
enum SkySet {
- SKY_SET_SAMPLERS,
+ SKY_SET_UNIFORMS,
SKY_SET_MATERIAL,
SKY_SET_TEXTURES,
- SKY_SET_LIGHTS,
+ SKY_SET_FOG,
SKY_SET_MAX
};
@@ -1355,6 +1378,7 @@ private:
RID uniform_set;
RID uniform_set2;
RID sdfgi_uniform_set;
+ RID sky_uniform_set;
int last_shadow_filter = -1;
};
@@ -1837,6 +1861,7 @@ public:
bool render_buffers_has_volumetric_fog(RID p_render_buffers) const;
RID render_buffers_get_volumetric_fog_texture(RID p_render_buffers);
+ RID render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers);
float render_buffers_get_volumetric_fog_end(RID p_render_buffers);
float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers);
diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/rasterizer_rd/shaders/sky.glsl
index 9c59be6841..7b6de6a555 100644
--- a/servers/rendering/rasterizer_rd/shaders/sky.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/sky.glsl
@@ -58,6 +58,35 @@ layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalVariableData
}
global_variables;
+layout(set = 0, binding = 2, std140) uniform SceneData {
+ bool volumetric_fog_enabled;
+ float volumetric_fog_inv_length;
+ float volumetric_fog_detail_spread;
+ uint volumetric_fog_pad;
+
+ vec3 fog_light_color;
+ float fog_sun_scatter;
+
+ bool fog_enabled;
+ float fog_density;
+
+ float z_far;
+ uint directional_light_count;
+}
+scene_data;
+
+struct DirectionalLightData {
+ vec4 direction_energy;
+ vec4 color_size;
+ bool enabled;
+};
+
+layout(set = 0, binding = 3, std140) uniform DirectionalLights {
+ DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+}
+
+directional_lights;
+
#ifdef USE_MATERIAL_UNIFORMS
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
/* clang-format off */
@@ -77,6 +106,8 @@ layout(set = 2, binding = 1) uniform texture2D half_res;
layout(set = 2, binding = 2) uniform texture2D quarter_res;
#endif
+layout(set = 3, binding = 0) uniform texture3D volumetric_fog_texture;
+
#ifdef USE_CUBEMAP_PASS
#define AT_CUBEMAP_PASS true
#else
@@ -95,18 +126,6 @@ layout(set = 2, binding = 2) uniform texture2D quarter_res;
#define AT_QUARTER_RES_PASS false
#endif
-struct DirectionalLightData {
- vec4 direction_energy;
- vec4 color_size;
- bool enabled;
-};
-
-layout(set = 3, binding = 0, std140) uniform DirectionalLights {
- DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
-}
-
-directional_lights;
-
/* clang-format off */
FRAGMENT_SHADER_GLOBALS
@@ -115,6 +134,30 @@ FRAGMENT_SHADER_GLOBALS
layout(location = 0) out vec4 frag_color;
+vec4 volumetric_fog_process(vec2 screen_uv) {
+ vec3 fog_pos = vec3(screen_uv, 1.0);
+
+ return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos);
+}
+
+vec4 fog_process(vec3 view) {
+ vec3 fog_color = scene_data.fog_light_color;
+
+ if (scene_data.fog_sun_scatter > 0.001) {
+ vec4 sun_scatter = vec4(0.0);
+ float sun_total = 0.0;
+ for (uint i = 0; i < scene_data.directional_light_count; i++) {
+ vec3 light_color = directional_lights.data[i].color_size.xyz * directional_lights.data[i].direction_energy.w;
+ float light_amount = pow(max(dot(view, directional_lights.data[i].direction_energy.xyz), 0.0), 8.0);
+ fog_color += light_color * light_amount * scene_data.fog_sun_scatter;
+ }
+ }
+
+ float fog_amount = clamp(1.0 - exp(-scene_data.z_far * scene_data.fog_density), 0.0, 1.0);
+
+ return vec4(fog_color, fog_amount);
+}
+
void main() {
vec3 cube_normal;
cube_normal.z = -1.0;
@@ -178,6 +221,20 @@ FRAGMENT_SHADER_CODE
frag_color.rgb = color * params.position_multiplier.w;
frag_color.a = alpha;
+#if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS)
+
+ if (scene_data.volumetric_fog_enabled) {
+ vec4 fog = volumetric_fog_process(uv);
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+ }
+
+ if (scene_data.fog_enabled) {
+ vec4 fog = fog_process(cube_normal);
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+ }
+
+#endif // DISABLE_FOG
+
// Blending is disabled for Sky, so alpha doesn't blend
// alpha is used for subsurface scattering so make sure it doesn't get applied to Sky
if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) {
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 06cb6171a5..76aeb5989c 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -328,6 +328,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SKY].modes.push_back("use_half_res_pass");
shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass");
+ shader_modes[RS::SHADER_SKY].modes.push_back("disable_fog");
shader_types.insert("spatial");
shader_types.insert("canvas_item");
diff --git a/tests/test_gradient.h b/tests/test_gradient.h
new file mode 100644
index 0000000000..88fe06b3ec
--- /dev/null
+++ b/tests/test_gradient.h
@@ -0,0 +1,152 @@
+/*************************************************************************/
+/* test_gradient.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+#ifndef TEST_GRADIENT_H
+#define TEST_GRADIENT_H
+
+#include "core/class_db.h"
+#include "core/color.h"
+#include "scene/resources/gradient.h"
+
+#include "thirdparty/doctest/doctest.h"
+
+namespace TestGradient {
+
+TEST_CASE("[Gradient] Default gradient") {
+ // Black-white gradient.
+ Ref<Gradient> gradient = memnew(Gradient);
+
+ CHECK_MESSAGE(
+ gradient->get_points_count() == 2,
+ "Default gradient should contain the expected number of points.");
+
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.0).is_equal_approx(Color(0, 0, 0)),
+ "Default gradient should return the expected interpolated value at offset 0.0.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.4).is_equal_approx(Color(0.4, 0.4, 0.4)),
+ "Default gradient should return the expected interpolated value at offset 0.4.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.8).is_equal_approx(Color(0.8, 0.8, 0.8)),
+ "Default gradient should return the expected interpolated value at offset 0.8.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(1.0).is_equal_approx(Color(1, 1, 1)),
+ "Default gradient should return the expected interpolated value at offset 1.0.");
+
+ // Out of bounds checks.
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(-1.0).is_equal_approx(Color(0, 0, 0)),
+ "Default gradient should return the expected interpolated value at offset -1.0.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(1234.0).is_equal_approx(Color(1, 1, 1)),
+ "Default gradient should return the expected interpolated value at offset 1234.0.");
+}
+
+TEST_CASE("[Gradient] Custom gradient (points specified in order)") {
+ // Red-yellow-green gradient (with overbright green).
+ Ref<Gradient> gradient = memnew(Gradient);
+ Vector<Gradient::Point> points;
+ points.push_back({ 0.0, Color(1, 0, 0) });
+ points.push_back({ 0.5, Color(1, 1, 0) });
+ points.push_back({ 1.0, Color(0, 2, 0) });
+ gradient->set_points(points);
+
+ CHECK_MESSAGE(
+ gradient->get_points_count() == 3,
+ "Custom gradient should contain the expected number of points.");
+
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.0).is_equal_approx(Color(1, 0, 0)),
+ "Custom gradient should return the expected interpolated value at offset 0.0.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.25).is_equal_approx(Color(1, 0.5, 0)),
+ "Custom gradient should return the expected interpolated value at offset 0.25.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.5).is_equal_approx(Color(1, 1, 0)),
+ "Custom gradient should return the expected interpolated value at offset 0.5.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.75).is_equal_approx(Color(0.5, 1.5, 0)),
+ "Custom gradient should return the expected interpolated value at offset 0.75.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(1.0).is_equal_approx(Color(0, 2, 0)),
+ "Custom gradient should return the expected interpolated value at offset 1.0.");
+
+ gradient->remove_point(1);
+ CHECK_MESSAGE(
+ gradient->get_points_count() == 2,
+ "Custom gradient should contain the expected number of points after removing one point.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.5).is_equal_approx(Color(0.5, 1, 0)),
+ "Custom gradient should return the expected interpolated value at offset 0.5 after removing point at index 1.");
+}
+
+TEST_CASE("[Gradient] Custom gradient (points specified out-of-order)") {
+ // HSL rainbow with points specified out of order.
+ // These should be sorted automatically when adding points.
+ Ref<Gradient> gradient = memnew(Gradient);
+ Vector<Gradient::Point> points;
+ points.push_back({ 0.2, Color(1, 0, 0) });
+ points.push_back({ 0.0, Color(1, 1, 0) });
+ points.push_back({ 0.8, Color(0, 1, 0) });
+ points.push_back({ 0.4, Color(0, 1, 1) });
+ points.push_back({ 1.0, Color(0, 0, 1) });
+ points.push_back({ 0.6, Color(1, 0, 1) });
+ gradient->set_points(points);
+
+ CHECK_MESSAGE(
+ gradient->get_points_count() == 6,
+ "Custom out-of-order gradient should contain the expected number of points.");
+
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.0).is_equal_approx(Color(1, 1, 0)),
+ "Custom out-of-order gradient should return the expected interpolated value at offset 0.0.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.3).is_equal_approx(Color(0.5, 0.5, 0.5)),
+ "Custom out-of-order gradient should return the expected interpolated value at offset 0.3.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.6).is_equal_approx(Color(1, 0, 1)),
+ "Custom out-of-order gradient should return the expected interpolated value at offset 0.6.");
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(1.0).is_equal_approx(Color(0, 0, 1)),
+ "Custom out-of-order gradient should return the expected interpolated value at offset 1.0.");
+
+ gradient->remove_point(0);
+ CHECK_MESSAGE(
+ gradient->get_points_count() == 5,
+ "Custom out-of-order gradient should contain the expected number of points after removing one point.");
+ // The color will be clamped to the nearest point (which is at offset 0.2).
+ CHECK_MESSAGE(
+ gradient->get_color_at_offset(0.1).is_equal_approx(Color(1, 0, 0)),
+ "Custom out-of-order gradient should return the expected interpolated value at offset 0.1 after removing point at index 0.");
+}
+
+} // namespace TestGradient
+
+#endif // TEST_GRADIENT_H
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 137882841c..892cc26a51 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -37,6 +37,7 @@
#include "test_class_db.h"
#include "test_color.h"
#include "test_gdscript.h"
+#include "test_gradient.h"
#include "test_gui.h"
#include "test_math.h"
#include "test_oa_hash_map.h"