diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml
index 10ac4b0fccf..8867ca58e83 100644
--- a/doc/classes/Sprite2D.xml
+++ b/doc/classes/Sprite2D.xml
@@ -76,7 +76,7 @@
If [code]true[/code], texture is cut from a larger atlas texture. See [member region_rect].
- If [code]true[/code], the outermost pixels get blurred out. [member region_enabled] must be [code]true[/code].
+ If [code]true[/code], the area outside of the [member region_rect] is clipped to avoid bleeding of the surrounding texture pixels. [member region_enabled] must be [code]true[/code].
The region of the atlas texture to display. [member region_enabled] must be [code]true[/code].
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp
index 7f4988583b6..bc67e0fafcb 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.cpp
+++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp
@@ -2348,6 +2348,19 @@ RDD::CommandPoolID RenderingDeviceDriverD3D12::command_pool_create(CommandQueueF
void RenderingDeviceDriverD3D12::command_pool_free(CommandPoolID p_cmd_pool) {
CommandPoolInfo *command_pool = (CommandPoolInfo *)(p_cmd_pool.id);
+
+ // Destroy all command buffers associated with this command pool, mirroring Vulkan's behavior.
+ SelfList *cmd_buf_elem = command_pool->command_buffers.first();
+ while (cmd_buf_elem != nullptr) {
+ CommandBufferInfo *cmd_buf_info = cmd_buf_elem->self();
+ cmd_buf_elem = cmd_buf_elem->next();
+
+ cmd_buf_info->cmd_list.Reset();
+ cmd_buf_info->cmd_allocator.Reset();
+
+ VersatileResource::free(resources_allocator, cmd_buf_info);
+ }
+
memdelete(command_pool);
}
@@ -2356,7 +2369,7 @@ void RenderingDeviceDriverD3D12::command_pool_free(CommandPoolID p_cmd_pool) {
RDD::CommandBufferID RenderingDeviceDriverD3D12::command_buffer_create(CommandPoolID p_cmd_pool) {
DEV_ASSERT(p_cmd_pool);
- const CommandPoolInfo *command_pool = (CommandPoolInfo *)(p_cmd_pool.id);
+ CommandPoolInfo *command_pool = (CommandPoolInfo *)(p_cmd_pool.id);
D3D12_COMMAND_LIST_TYPE list_type;
if (command_pool->buffer_type == COMMAND_BUFFER_TYPE_SECONDARY) {
list_type = D3D12_COMMAND_LIST_TYPE_BUNDLE;
@@ -2392,6 +2405,9 @@ RDD::CommandBufferID RenderingDeviceDriverD3D12::command_buffer_create(CommandPo
cmd_buf_info->cmd_allocator = cmd_allocator;
cmd_buf_info->cmd_list = cmd_list;
+ // Add this command buffer to the command pool's list of command buffers.
+ command_pool->command_buffers.add(&cmd_buf_info->command_buffer_info_elem);
+
return CommandBufferID(cmd_buf_info);
}
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h
index e6833e0793b..e43cb322b51 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.h
+++ b/drivers/d3d12/rendering_device_driver_d3d12.h
@@ -451,6 +451,9 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
struct CommandPoolInfo {
CommandQueueFamilyID queue_family;
CommandBufferType buffer_type = COMMAND_BUFFER_TYPE_PRIMARY;
+ // Since there are no command pools in D3D12, we need to track the command buffers created by this pool
+ // so that we can free them when the pool is freed.
+ SelfList::List command_buffers;
};
public:
@@ -478,6 +481,9 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
// Leveraging knowledge of actual usage and D3D12 specifics (namely, command lists from the same allocator
// can't be freely begun and ended), an allocator per list works better.
struct CommandBufferInfo {
+ // Store a self list reference to be used by the command pool.
+ SelfList command_buffer_info_elem{ this };
+
ComPtr cmd_allocator;
ComPtr cmd_list;
diff --git a/drivers/gles3/effects/cubemap_filter.cpp b/drivers/gles3/effects/cubemap_filter.cpp
index 84528056dde..8415ce92d7d 100644
--- a/drivers/gles3/effects/cubemap_filter.cpp
+++ b/drivers/gles3/effects/cubemap_filter.cpp
@@ -43,7 +43,10 @@ CubemapFilter *CubemapFilter::singleton = nullptr;
CubemapFilter::CubemapFilter() {
singleton = this;
- ggx_samples = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples");
+ // Use a factor 4 larger for the compatibility renderer to make up for the fact
+ // That we don't use an array texture. We will reduce samples on low roughness
+ // to compensate.
+ ggx_samples = 4 * uint32_t(GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples"));
{
String defines;
@@ -59,10 +62,10 @@ CubemapFilter::CubemapFilter() {
const float qv[6] = {
-1.0f,
-1.0f,
- 3.0f,
- -1.0f,
-1.0f,
3.0f,
+ 3.0f,
+ -1.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW);
@@ -148,10 +151,11 @@ void CubemapFilter::filter_radiance(GLuint p_source_cubemap, GLuint p_dest_cubem
}
if (p_layer > 0) {
- const uint32_t sample_counts[4] = { 1, ggx_samples / 4, ggx_samples / 2, ggx_samples };
- uint32_t sample_count = sample_counts[MIN(3, p_layer)];
+ const uint32_t sample_counts[5] = { 1, ggx_samples / 16, ggx_samples / 8, ggx_samples / 4, ggx_samples };
+ uint32_t sample_count = sample_counts[MIN(4, p_layer)];
- float roughness = float(p_layer) / (p_mipmap_count);
+ float roughness = float(p_layer) / (p_mipmap_count - 1);
+ roughness *= roughness; // Convert to non-perceptual roughness.
float roughness4 = roughness * roughness;
roughness4 *= roughness4;
@@ -167,7 +171,7 @@ void CubemapFilter::filter_radiance(GLuint p_source_cubemap, GLuint p_dest_cubem
Vector3 dir = importance_sample_GGX(xi, roughness4);
Vector3 light_vec = (2.0 * dir.z * dir - Vector3(0.0, 0.0, 1.0));
- if (light_vec.z < 0.0) {
+ if (light_vec.z <= 0.0) {
continue;
}
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 10d580f5b7c..b45926cafee 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -2397,6 +2397,7 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_
bool draw_sky = false;
bool draw_sky_fog_only = false;
bool keep_color = false;
+ bool draw_canvas = false;
float sky_energy_multiplier = 1.0;
if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW)) {
@@ -2436,12 +2437,13 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_
draw_sky = !render_data.transparent_bg;
} break;
case RS::ENV_BG_CANVAS: {
- keep_color = true;
+ draw_canvas = true;
} break;
case RS::ENV_BG_KEEP: {
keep_color = true;
} break;
case RS::ENV_BG_CAMERA_FEED: {
+ keep_color = true;
} break;
default: {
}
@@ -2553,10 +2555,14 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_
glClear(GL_DEPTH_BUFFER_BIT);
}
- if (!keep_color) {
+ // Need to clear framebuffer unless:
+ // a) We explicitly request not to (i.e. ENV_BG_KEEP).
+ // b) We are rendering to a non-intermediate framebuffer with ENV_BG_CANVAS (shared between 2D and 3D).
+ if (!keep_color && (!draw_canvas || fbo != rt->fbo)) {
clear_color.a = render_data.transparent_bg ? 0.0f : 1.0f;
glClearBufferfv(GL_COLOR, 0, clear_color.components);
- } else if (fbo != rt->fbo) {
+ }
+ if ((keep_color || draw_canvas) && fbo != rt->fbo) {
// Need to copy our current contents to our intermediate/MSAA buffer
GLES3::CopyEffects *copy_effects = GLES3::CopyEffects::get_singleton();
@@ -2567,6 +2573,9 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_
glBindTexture(rt->view_count > 1 ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D, rt->color);
copy_effects->copy_screen(render_data.luminance_multiplier);
+
+ scene_state.enable_gl_depth_test(true);
+ scene_state.enable_gl_depth_draw(true);
}
RENDER_TIMESTAMP("Render Opaque Pass");
@@ -3287,10 +3296,6 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant, spec_constants);
-
- prev_shader = shader;
- prev_variant = instance_variant;
- prev_spec_constants = spec_constants;
}
// Pass in lighting uniforms.
@@ -3328,7 +3333,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
// Pass light count and array of light indices for base pass.
- if ((prev_inst != inst || prev_shader != shader || prev_variant != instance_variant) && pass == 0) {
+ if ((prev_inst != inst || prev_shader != shader || prev_variant != instance_variant || prev_spec_constants != spec_constants) && pass == 0) {
// Rebind the light indices.
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_gl_cache.size(), shader->version, instance_variant, spec_constants);
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_gl_cache.size(), shader->version, instance_variant, spec_constants);
@@ -3380,11 +3385,14 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
} else if (inst->lightmap_sh) {
glUniform4fv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::LIGHTMAP_CAPTURES, shader->version, instance_variant, spec_constants), 9, reinterpret_cast(inst->lightmap_sh->sh));
}
-
prev_inst = inst;
}
}
+ prev_shader = shader;
+ prev_variant = instance_variant;
+ prev_spec_constants = spec_constants;
+
// Pass in reflection probe data
if constexpr (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
if (pass == 0 && inst->reflection_probe_rid_cache.size() > 0) {
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 728d0d47f38..1ac289d5a24 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -578,7 +578,8 @@ void main() {
#endif
if (bool(read_draw_data_flags & FLAGS_CLIP_RECT_UV)) {
- uv = clamp(uv, read_draw_data_src_rect.xy, read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw));
+ vec2 half_texpixel = read_draw_data_color_texture_pixel_size * 0.5;
+ uv = clamp(uv, read_draw_data_src_rect.xy + half_texpixel, read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) - half_texpixel);
}
#endif
diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl
index 2591937a1da..bdc28e292e2 100644
--- a/drivers/gles3/shaders/particles.glsl
+++ b/drivers/gles3/shaders/particles.glsl
@@ -453,14 +453,14 @@ void main() {
vec3 uvw_pos = vec3(local_pos_bottom / colliders[i].extents.xyz) * 0.5 + 0.5;
- float y = 1.0 - texture(height_field_texture, uvw_pos.xz).r;
+ float y = texture(height_field_texture, uvw_pos.xz).r;
if (y + EPSILON > uvw_pos.y) {
//inside heightfield
vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
- vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
- vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * colliders[i].extents.xyz;
+ vec3 pos2 = (vec3(uvw_pos.x + DELTA, texture(height_field_texture, uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
+ vec3 pos3 = (vec3(uvw_pos.x, texture(height_field_texture, uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * colliders[i].extents.xyz;
normal = normalize(cross(pos1 - pos2, pos1 - pos3));
float local_y = (vec3(local_pos / colliders[i].extents.xyz) * 0.5 + 0.5).y;
diff --git a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp
index f6002a18d6e..2ed6156d26a 100644
--- a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp
@@ -167,13 +167,6 @@ void ReflectionProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
aabb.position = -size / 2;
aabb.size = size;
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
for (int i = 0; i < 8; i++) {
Vector3 ep = aabb.get_endpoint(i);
internal_lines.push_back(probe->get_origin_offset());
diff --git a/platform/web/doc_classes/EditorExportPlatformWeb.xml b/platform/web/doc_classes/EditorExportPlatformWeb.xml
index 6907bb1a256..dc7fc2c069a 100644
--- a/platform/web/doc_classes/EditorExportPlatformWeb.xml
+++ b/platform/web/doc_classes/EditorExportPlatformWeb.xml
@@ -87,10 +87,10 @@
If [code]false[/code], the exported game will not support threads. As a result, it is more prone to performance and audio issues, but will only require to be run on an HTTPS website.
- If [code]true[/code], allows textures to be optimized for desktop through the S3TC algorithm.
+ If [code]true[/code], allows textures to be optimized for desktop through the S3TC/BPTC algorithm.
- If [code]true[/code] allows textures to be optimized for mobile through the ETC2 algorithm.
+ If [code]true[/code] allows textures to be optimized for mobile through the ETC2/ASTC algorithm.
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index e52b1fdedb9..8aed2a18ef0 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -336,9 +336,11 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref &p_prese
void EditorExportPlatformWeb::get_preset_features(const Ref &p_preset, List *r_features) const {
if (p_preset->get("vram_texture_compression/for_desktop")) {
r_features->push_back("s3tc");
+ r_features->push_back("bptc");
}
if (p_preset->get("vram_texture_compression/for_mobile")) {
r_features->push_back("etc2");
+ r_features->push_back("astc");
}
if (p_preset->get("variant/thread_support").operator bool()) {
r_features->push_back("threads");
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index c8a15c814d4..c9116c04d6d 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -6292,7 +6292,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
}
WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution), false, INVALID_WINDOW_ID);
- ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window.");
+ if (main_window == INVALID_WINDOW_ID) {
+ r_error = ERR_UNAVAILABLE;
+ ERR_FAIL_MSG("Failed to create main window.");
+ }
joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd);
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index b9c843b1dc8..aa1f8c7cd67 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -187,8 +187,8 @@ ReflectionProbe::UpdateMode ReflectionProbe::get_update_mode() const {
AABB ReflectionProbe::get_aabb() const {
AABB aabb;
- aabb.position = -origin_offset;
- aabb.size = origin_offset + size / 2;
+ aabb.position = -size / 2;
+ aabb.size = size;
return aabb;
}
diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp
index 8084cace216..8d05c72c4d2 100644
--- a/scene/resources/multimesh.cpp
+++ b/scene/resources/multimesh.cpp
@@ -197,6 +197,9 @@ Vector MultiMesh::_get_custom_data_array() const {
#endif // DISABLE_DEPRECATED
void MultiMesh::set_buffer(const Vector &p_buffer) {
+ if (instance_count == 0) {
+ return;
+ }
RS::get_singleton()->multimesh_set_buffer(multimesh, p_buffer);
}
diff --git a/scene/resources/texture_rd.cpp b/scene/resources/texture_rd.cpp
index 65783f4d1c0..0882a3d349c 100644
--- a/scene/resources/texture_rd.cpp
+++ b/scene/resources/texture_rd.cpp
@@ -199,7 +199,7 @@ void TextureLayeredRD::_set_texture_rd_rid(RID p_texture_rd_rid) {
RS::TextureLayeredType rs_layer_type;
RD::TextureFormat tf = RD::get_singleton()->texture_get_format(p_texture_rd_rid);
- ERR_FAIL_COND(tf.texture_type != RD::TEXTURE_TYPE_2D_ARRAY);
+ ERR_FAIL_COND(tf.texture_type != RD::TEXTURE_TYPE_2D_ARRAY && tf.texture_type != RD::TEXTURE_TYPE_CUBE && tf.texture_type != RD::TEXTURE_TYPE_CUBE_ARRAY);
ERR_FAIL_COND(tf.depth > 1);
switch (layer_type) {
case LAYERED_TYPE_2D_ARRAY: {
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index 6cbd2479a32..4cdb38fd29c 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -624,6 +624,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
bool any_uses_time = false;
+ Vector3 cam_position = p_cam_transform.get_origin();
for (int i = 0; i < (int)p_fog_volumes.size(); i++) {
FogVolumeInstance *fog_volume_instance = fog_volume_instance_owner.get_or_null(p_fog_volumes[i]);
@@ -654,41 +655,68 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
any_uses_time |= shader_data->uses_time;
- Vector3i min;
- Vector3i max;
+ Vector3i froxel_min;
+ Vector3i froxel_max;
Vector3i kernel_size;
- Vector3 position = fog_volume_instance->transform.get_origin();
+ Vector3 fog_position = fog_volume_instance->transform.get_origin();
RS::FogVolumeShape volume_type = RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume);
Vector3 extents = RendererRD::Fog::get_singleton()->fog_volume_get_size(fog_volume) / 2;
if (volume_type != RS::FOG_VOLUME_SHAPE_WORLD) {
// Local fog volume.
- Vector3i points[8];
Vector3 fog_size = Vector3(fog->width, fog->height, fog->depth);
float volumetric_fog_detail_spread = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_detail_spread(p_settings.env);
- points[0] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[1] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[2] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[3] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[4] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[5] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[6] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[7] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
-
- min = Vector3i(int32_t(fog->width) - 1, int32_t(fog->height) - 1, int32_t(fog->depth) - 1);
- max = Vector3i(1, 1, 1);
-
+ Vector3 corners[8]{
+ fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)),
+ fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)),
+ fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)),
+ fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)),
+ fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)),
+ fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)),
+ fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)),
+ fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z))
+ };
+ Vector3i froxels[8];
+ Vector3 corner_min = corners[0];
+ Vector3 corner_max = corners[0];
for (int j = 0; j < 8; j++) {
- min = min.min(points[j]);
- max = max.max(points[j]);
+ froxels[j] = _point_get_position_in_froxel_volume(corners[j], fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
+ corner_min = corner_min.min(corners[j]);
+ corner_max = corner_max.max(corners[j]);
+ }
+
+ froxel_min = Vector3i(int32_t(fog->width) - 1, int32_t(fog->height) - 1, int32_t(fog->depth) - 1);
+ froxel_max = Vector3i(1, 1, 1);
+
+ // Tracking just the corners of the fog volume can result in missing some fog:
+ // when the camera's near plane is inside the fog, we must always consider the entire screen
+ Vector3 near_plane_corner(frustum_near_size.x, frustum_near_size.y, z_near);
+ float expand = near_plane_corner.length();
+ if (cam_position.x > (corner_min.x - expand) && cam_position.x < (corner_max.x + expand) &&
+ cam_position.y > (corner_min.y - expand) && cam_position.y < (corner_max.y + expand) &&
+ cam_position.z > (corner_min.z - expand) && cam_position.z < (corner_max.z + expand)) {
+ froxel_min.x = 0;
+ froxel_min.y = 0;
+ froxel_min.z = 0;
+ froxel_max.x = int32_t(fog->width);
+ froxel_max.y = int32_t(fog->height);
+ for (int j = 0; j < 8; j++) {
+ froxel_max.z = MAX(froxel_max.z, froxels[j].z);
+ }
+ } else {
+ // Camera is guaranteed to be outside the fog volume
+ for (int j = 0; j < 8; j++) {
+ froxel_min = froxel_min.min(froxels[j]);
+ froxel_max = froxel_max.max(froxels[j]);
+ }
}
- kernel_size = max - min;
+ kernel_size = froxel_max - froxel_min;
} else {
// Volume type global runs on all cells
extents = Vector3(fog->width, fog->height, fog->depth);
- min = Vector3i(0, 0, 0);
+ froxel_min = Vector3i(0, 0, 0);
kernel_size = Vector3i(int32_t(fog->width), int32_t(fog->height), int32_t(fog->depth));
}
@@ -697,15 +725,15 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
}
VolumetricFogShader::FogPushConstant push_constant;
- push_constant.position[0] = position.x;
- push_constant.position[1] = position.y;
- push_constant.position[2] = position.z;
+ push_constant.position[0] = fog_position.x;
+ push_constant.position[1] = fog_position.y;
+ push_constant.position[2] = fog_position.z;
push_constant.size[0] = extents.x * 2;
push_constant.size[1] = extents.y * 2;
push_constant.size[2] = extents.z * 2;
- push_constant.corner[0] = min.x;
- push_constant.corner[1] = min.y;
- push_constant.corner[2] = min.z;
+ push_constant.corner[0] = froxel_min.x;
+ push_constant.corner[1] = froxel_min.y;
+ push_constant.corner[2] = froxel_min.z;
push_constant.shape = uint32_t(RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume));
RendererRD::MaterialStorage::store_transform(fog_volume_instance->transform.affine_inverse(), push_constant.transform);
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 7bd30d4876a..44c5dd725b1 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -2276,7 +2276,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
real_t fov = p_render_data->scene_data->cam_projection.get_fov();
real_t aspect = p_render_data->scene_data->cam_projection.get_aspect();
- real_t fovy = p_render_data->scene_data->cam_projection.get_fovy(fov, aspect);
+ real_t fovy = p_render_data->scene_data->cam_projection.get_fovy(fov, 1.0 / aspect);
Vector2 jitter = p_render_data->scene_data->taa_jitter * Vector2(rb->get_internal_size()) * 0.5f;
RendererRD::FSR2Effect::Parameters params;
params.context = rb_data->get_fsr2_context();
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 23d8a598019..27a41c36def 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -1976,6 +1976,10 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
surf = surf->next;
}
}
+
+ if (p_render_list == RENDER_LIST_OPAQUE && lightmap_captures_used) {
+ RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures);
+ }
}
void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 3b86386fc95..7bd7d4448a4 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -479,7 +479,8 @@ void main() {
#endif
if (bool(draw_data.flags & FLAGS_CLIP_RECT_UV)) {
- uv = clamp(uv, draw_data.src_rect.xy, draw_data.src_rect.xy + abs(draw_data.src_rect.zw));
+ vec2 half_texpixel = draw_data.color_texture_pixel_size * 0.5;
+ uv = clamp(uv, draw_data.src_rect.xy + half_texpixel, draw_data.src_rect.xy + abs(draw_data.src_rect.zw) - half_texpixel);
}
#endif
diff --git a/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl b/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl
index fb35d3cde69..553637dc4fe 100644
--- a/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl
@@ -152,10 +152,10 @@ void main() {
float depth_scale;
if (params.orthogonal) {
- depth = ((depth + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0;
+ depth = -(depth * (params.camera_z_far - params.camera_z_near) - (params.camera_z_far + params.camera_z_near)) / 2.0;
depth_scale = params.unit_size; //remember depth is negative by default in OpenGL
} else {
- depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near));
+ depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near + depth * (params.camera_z_far - params.camera_z_near));
depth_scale = params.unit_size / depth; //remember depth is negative by default in OpenGL
}
diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
index d0cfe6a3b87..5a2ea19b2b6 100644
--- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
@@ -513,6 +513,7 @@ void main() {
shadow_sample.z = 1.0 + abs(shadow_sample.z);
vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - omni_lights.data[light_index].shadow_bias);
pos.z *= omni_lights.data[light_index].inv_radius;
+ pos.z = 1.0 - pos.z;
pos.xy = pos.xy * 0.5 + 0.5;
pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index 409a71dc782..205e5d20f7b 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -439,12 +439,12 @@ void main() {
vertex_interp = vertex;
#ifdef NORMAL_USED
- normal_interp = normal;
+ normal_interp = normalize(normal);
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
- tangent_interp = tangent;
- binormal_interp = binormal;
+ tangent_interp = normalize(tangent);
+ binormal_interp = normalize(binormal);
#endif
#ifdef MODE_RENDER_DEPTH
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
index 43befaf6c0d..7bc5257e828 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
@@ -130,7 +130,7 @@ class RenderSceneBuffersRD : public RenderSceneBuffers {
h = hash_murmur3_one_32(p_val.layers, h);
h = hash_murmur3_one_32(p_val.mipmap, h);
h = hash_murmur3_one_32(p_val.mipmaps, h);
- h = hash_murmur3_one_32(p_val.texture_view.format_override);
+ h = hash_murmur3_one_32(p_val.texture_view.format_override, h);
h = hash_murmur3_one_32(p_val.texture_view.swizzle_r, h);
h = hash_murmur3_one_32(p_val.texture_view.swizzle_g, h);
h = hash_murmur3_one_32(p_val.texture_view.swizzle_b, h);
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 2ce6c6c0a85..49558b13e3c 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -1505,7 +1505,9 @@ void TextureStorage::texture_rd_initialize(RID p_texture, const RID &p_rd_textur
ERR_FAIL_COND(tf.array_layers != 1);
texture.type = TextureStorage::TYPE_2D;
} break;
- case RD::TEXTURE_TYPE_2D_ARRAY: {
+ case RD::TEXTURE_TYPE_2D_ARRAY:
+ case RD::TEXTURE_TYPE_CUBE:
+ case RD::TEXTURE_TYPE_CUBE_ARRAY: {
// RenderingDevice doesn't distinguish between Array textures and Cube textures
// this condition covers TextureArrays, TextureCube, and TextureCubeArray.
ERR_FAIL_COND(tf.array_layers == 1);
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 83e149a97e4..1afbd3a1b0c 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -1845,6 +1845,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES];
}
pair.cull_mask = RSG::light_storage->light_get_cull_mask(p_instance->base);
+ } else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) {
+ pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK;
+ pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
} else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE)) {
pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK;
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
@@ -2878,6 +2881,10 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
for (const Instance *E : geom->lights) {
InstanceLightData *light = static_cast(E->base_data);
+ if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) {
+ continue;
+ }
+
instance_pair_buffer[idx++] = light->instance;
if (idx == MAX_INSTANCE_PAIRS) {
break;
@@ -3097,7 +3104,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
continue;
}
- if (directional_lights.size() > RendererSceneRender::MAX_DIRECTIONAL_LIGHTS) {
+ if (directional_lights.size() >= RendererSceneRender::MAX_DIRECTIONAL_LIGHTS) {
break;
}
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 4e2ca99ab51..1032403fb23 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -695,9 +695,10 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture
if (format.texture_type == TEXTURE_TYPE_1D_ARRAY || format.texture_type == TEXTURE_TYPE_2D_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE) {
ERR_FAIL_COND_V_MSG(format.array_layers < 1, RID(),
- "Amount of layers must be equal or greater than 1 for arrays and cubemaps.");
+ "Number of layers must be equal or greater than 1 for arrays and cubemaps.");
ERR_FAIL_COND_V_MSG((format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || format.texture_type == TEXTURE_TYPE_CUBE) && (format.array_layers % 6) != 0, RID(),
"Cubemap and cubemap array textures must provide a layer number that is multiple of 6");
+ ERR_FAIL_COND_V_MSG(format.array_layers > driver->limit_get(LIMIT_MAX_TEXTURE_ARRAY_LAYERS), RID(), "Number of layers exceeds device maximum.");
} else {
format.array_layers = 1;
}
@@ -709,6 +710,28 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture
format.height = format.texture_type != TEXTURE_TYPE_1D && format.texture_type != TEXTURE_TYPE_1D_ARRAY ? format.height : 1;
format.depth = format.texture_type == TEXTURE_TYPE_3D ? format.depth : 1;
+ uint64_t size_max = 0;
+ switch (format.texture_type) {
+ case TEXTURE_TYPE_1D:
+ case TEXTURE_TYPE_1D_ARRAY:
+ size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_1D);
+ break;
+ case TEXTURE_TYPE_2D:
+ case TEXTURE_TYPE_2D_ARRAY:
+ size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_2D);
+ break;
+ case TEXTURE_TYPE_CUBE:
+ case TEXTURE_TYPE_CUBE_ARRAY:
+ size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_CUBE);
+ break;
+ case TEXTURE_TYPE_3D:
+ size_max = driver->limit_get(LIMIT_MAX_TEXTURE_SIZE_3D);
+ break;
+ case TEXTURE_TYPE_MAX:
+ break;
+ }
+ ERR_FAIL_COND_V_MSG(format.width > size_max || format.height > size_max || format.depth > size_max, RID(), "Texture dimensions exceed device maximum.");
+
uint32_t required_mipmaps = get_image_required_mipmaps(format.width, format.height, format.depth);
ERR_FAIL_COND_V_MSG(required_mipmaps < format.mipmaps, RID(),
diff --git a/servers/rendering/rendering_device_driver.cpp b/servers/rendering/rendering_device_driver.cpp
index 6ed98b2d63e..bd40bfdb1bd 100644
--- a/servers/rendering/rendering_device_driver.cpp
+++ b/servers/rendering/rendering_device_driver.cpp
@@ -261,7 +261,7 @@ Error RenderingDeviceDriver::_reflect_spirv(VectorView p_s
}
}
- if (existing > 0) {
+ if (existing >= 0) {
r_reflection.specialization_constants.write[existing].stages.set_flag(stage_flag);
} else {
r_reflection.specialization_constants.push_back(sconst);