summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/CODEOWNERS5
-rw-r--r--doc/classes/ProjectSettings.xml5
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp3
-rw-r--r--drivers/gles3/shaders/scene.glsl289
-rw-r--r--drivers/gles3/storage/config.cpp2
-rw-r--r--drivers/gles3/storage/material_storage.cpp4
-rw-r--r--editor/renames_map_3_to_4.cpp2
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp5
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp9
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp5
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp7
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp164
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h43
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl10
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl190
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl326
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_vertex_lights_inc.glsl82
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp97
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h27
-rw-r--r--servers/rendering_server.cpp3
20 files changed, 875 insertions, 403 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 7cca1b6f2a..748d787b86 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -169,10 +169,12 @@
/modules/gridmap/icons/ @godotengine/3d-nodes @godotengine/usability
/modules/noise/ @godotengine/core
/modules/noise/doc_classes/ @godotengine/core @godotengine/documentation
+/modules/noise/icons/ @godotengine/core @godotengine/usability
/modules/noise/tests/ @godotengine/core @godotengine/tests
/modules/regex/ @godotengine/core
/modules/regex/doc_classes/ @godotengine/core @godotengine/documentation
-/modules/regex/test/ @godotengine/core @godotengine/tests
+/modules/regex/icons/ @godotengine/core @godotengine/usability
+/modules/regex/tests/ @godotengine/core @godotengine/tests
/modules/zip/ @godotengine/core
/modules/zip/doc_classes/ @godotengine/core @godotengine/documentation
@@ -207,6 +209,7 @@
/scene/resources/text_paragraph.* @godotengine/gui-nodes
/scene/resources/visual_shader*.* @godotengine/shaders
/scene/theme/ @godotengine/gui-nodes
+/scene/theme/icons/ @godotengine/gui-nodes @godotengine/usability
# Servers
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 7b6d8d0cd3..af5ec41b60 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -2863,11 +2863,6 @@
</member>
<member name="rendering/shading/overrides/force_vertex_shading" type="bool" setter="" getter="" default="false">
If [code]true[/code], forces vertex shading for all rendering. This can increase performance a lot, but also reduces quality immensely. Can be used to optimize performance on low-end mobile devices.
- [b]Note:[/b] This setting currently has no effect, as vertex shading is not implemented yet.
- </member>
- <member name="rendering/shading/overrides/force_vertex_shading.mobile" type="bool" setter="" getter="" default="true">
- Lower-end override for [member rendering/shading/overrides/force_vertex_shading] on mobile devices, due to performance concerns or driver support.
- [b]Note:[/b] This setting currently has no effect, as vertex shading is not implemented yet.
</member>
<member name="rendering/textures/canvas_textures/default_texture_filter" type="int" setter="" getter="" default="1">
The default texture filtering mode to use on [CanvasItem]s.
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 65749323fd..c2d1784958 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -4125,6 +4125,9 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
global_defines += "\n#define MAX_FORWARD_LIGHTS " + itos(config->max_lights_per_object) + "u\n";
global_defines += "\n#define MAX_ROUGHNESS_LOD " + itos(sky_globals.roughness_layers - 1) + ".0\n";
+ if (config->force_vertex_shading) {
+ global_defines += "\n#define USE_VERTEX_LIGHTING\n";
+ }
material_storage->shaders.scene_shader.initialize(global_defines);
scene_globals.shader_default_version = material_storage->shaders.scene_shader.version_create();
material_storage->shaders.scene_shader.version_bind_shader(scene_globals.shader_default_version, SceneShaderGLES3::MODE_COLOR);
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 393ba014c6..9ce10a4488 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -248,6 +248,175 @@ uniform lowp uint directional_shadow_index;
#endif // !(defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT))
#endif // USE_ADDITIVE_LIGHTING
+#ifdef USE_VERTEX_LIGHTING
+
+out vec3 diffuse_light_interp;
+out vec3 specular_light_interp;
+
+#ifdef USE_ADDITIVE_LIGHTING
+out vec3 additive_diffuse_light_interp;
+out vec3 additive_specular_light_interp;
+#endif // USE_ADDITIVE_LIGHTING
+
+// Directional light data.
+#if !defined(DISABLE_LIGHT_DIRECTIONAL) || (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT) && defined(USE_ADDITIVE_LIGHTING))
+
+struct DirectionalLightData {
+ mediump vec3 direction;
+ mediump float energy;
+ mediump vec3 color;
+ mediump float size;
+ lowp uint unused;
+ lowp uint bake_mode;
+ mediump float shadow_opacity;
+ mediump float specular;
+};
+
+layout(std140) uniform DirectionalLights { // ubo:7
+ DirectionalLightData directional_lights[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+};
+#endif // !DISABLE_LIGHT_DIRECTIONAL
+
+// Omni and spot light data.
+#if !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || (defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT) && defined(USE_ADDITIVE_LIGHTING))
+
+struct LightData { // This structure needs to be as packed as possible.
+ highp vec3 position;
+ highp float inv_radius;
+
+ mediump vec3 direction;
+ highp float size;
+
+ mediump vec3 color;
+ mediump float attenuation;
+
+ mediump float cone_attenuation;
+ mediump float cone_angle;
+ mediump float specular_amount;
+ mediump float shadow_opacity;
+
+ lowp vec3 pad;
+ lowp uint bake_mode;
+};
+
+#if !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI)
+layout(std140) uniform OmniLightData { // ubo:5
+ LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
+};
+#ifdef BASE_PASS
+uniform uint omni_light_indices[MAX_FORWARD_LIGHTS];
+uniform uint omni_light_count;
+#endif // BASE_PASS
+#endif // DISABLE_LIGHT_OMNI
+
+#if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
+layout(std140) uniform SpotLightData { // ubo:6
+ LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
+};
+#ifdef BASE_PASS
+uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
+uniform uint spot_light_count;
+#endif // BASE_PASS
+#endif // DISABLE_LIGHT_SPOT
+#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || (defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT) && defined(USE_ADDITIVE_LIGHTING))
+
+#ifdef USE_ADDITIVE_LIGHTING
+#ifdef ADDITIVE_OMNI
+uniform lowp uint omni_light_index;
+#endif
+#ifdef ADDITIVE_SPOT
+uniform lowp uint spot_light_index;
+#endif
+#endif // USE_ADDITIVE_LIGHTING
+
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
+
+// Eyeballed approximation of `exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25`.
+// Uses slightly more FMA instructions (2x rate) to avoid special instructions (0.25x rate).
+// Range is reduced to [0.64,4977] from [068,2,221,528] which makes mediump feasible for the rest of the shader.
+mediump float roughness_to_shininess(mediump float roughness) {
+ mediump float r = 1.2 - roughness;
+ mediump float r2 = r * r;
+ return r * r2 * r2 * 2000.0;
+}
+
+void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, bool is_directional, float roughness,
+ inout vec3 diffuse_light, inout vec3 specular_light) {
+ float NdotL = min(dot(N, L), 1.0);
+ float cNdotL = max(NdotL, 0.0); // clamped NdotL
+
+#if defined(DIFFUSE_LAMBERT_WRAP)
+ // Energy conserving lambert wrap shader.
+ // https://web.archive.org/web/20210228210901/http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/
+ float diffuse_brdf_NL = max(0.0, (cNdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))) * (1.0 / M_PI);
+#else
+ // lambert
+ float diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
+#endif
+
+ diffuse_light += light_color * diffuse_brdf_NL;
+
+#if !defined(SPECULAR_DISABLED)
+ float specular_brdf_NL = 0.0;
+ // Normalized blinn always unless disabled.
+ vec3 H = normalize(V + L);
+ float cNdotH = clamp(dot(N, H), 0.0, 1.0);
+ float shininess = roughness_to_shininess(roughness);
+ float blinn = pow(cNdotH, shininess);
+ blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI)) * cNdotL;
+ specular_brdf_NL = blinn;
+ specular_light += specular_brdf_NL * light_color;
+#endif
+}
+
+float get_omni_spot_attenuation(float distance, float inv_range, float decay) {
+ float nd = distance * inv_range;
+ nd *= nd;
+ nd *= nd; // nd^4
+ nd = max(1.0 - nd, 0.0);
+ nd *= nd; // nd^2
+ return nd * pow(max(distance, 0.0001), -decay);
+}
+
+#if !defined(DISABLE_LIGHT_OMNI) || (defined(ADDITIVE_OMNI) && defined(USE_ADDITIVE_LIGHTING))
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness,
+ inout vec3 diffuse_light, inout vec3 specular_light) {
+ vec3 light_rel_vec = omni_lights[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float omni_attenuation = get_omni_spot_attenuation(light_length, omni_lights[idx].inv_radius, omni_lights[idx].attenuation);
+ vec3 color = omni_lights[idx].color * omni_attenuation; // No light shaders here, so combine.
+
+ light_compute(normal, normalize(light_rel_vec), eye_vec, color, false, roughness,
+ diffuse_light,
+ specular_light);
+}
+#endif // !defined(DISABLE_LIGHT_OMNI) || (defined(ADDITIVE_OMNI) && defined(USE_ADDITIVE_LIGHTING))
+
+#if !defined(DISABLE_LIGHT_SPOT) || (defined(ADDITIVE_SPOT) && defined(USE_ADDITIVE_LIGHTING))
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness,
+ inout vec3 diffuse_light,
+ inout vec3 specular_light) {
+ vec3 light_rel_vec = spot_lights[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float spot_attenuation = get_omni_spot_attenuation(light_length, spot_lights[idx].inv_radius, spot_lights[idx].attenuation);
+ vec3 spot_dir = spot_lights[idx].direction;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights[idx].cone_angle);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights[idx].cone_angle));
+
+ mediump float cone_attenuation = spot_lights[idx].cone_attenuation;
+ spot_attenuation *= 1.0 - pow(spot_rim, cone_attenuation);
+
+ vec3 color = spot_lights[idx].color * spot_attenuation;
+
+ light_compute(normal, normalize(light_rel_vec), eye_vec, color, false, roughness,
+ diffuse_light, specular_light);
+}
+#endif // !defined(DISABLE_LIGHT_SPOT) || (defined(ADDITIVE_SPOT) && defined(USE_ADDITIVE_LIGHTING))
+
+#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
+
+#endif // USE_VERTEX_LIGHTING
+
#ifdef USE_MULTIVIEW
layout(std140) uniform MultiviewData { // ubo:8
highp mat4 projection_matrix_view[MAX_VIEWS];
@@ -540,8 +709,65 @@ void main() {
gl_Position.z = 0.00001;
gl_Position.w = 1.0;
#endif
-}
+#ifdef USE_VERTEX_LIGHTING
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+#ifdef USE_MULTIVIEW
+ vec3 view = -normalize(vertex_interp - eye_offset);
+#else
+ vec3 view = -normalize(vertex_interp);
+#endif
+ diffuse_light_interp = vec3(0.0);
+ specular_light_interp = vec3(0.0);
+#ifdef BASE_PASS
+#ifndef DISABLE_LIGHT_DIRECTIONAL
+ for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
+ light_compute(normal_interp, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].color * directional_lights[i].energy, true, roughness,
+ diffuse_light_interp.rgb,
+ specular_light_interp.rgb);
+ }
+#endif // !DISABLE_LIGHT_DIRECTIONAL
+
+#ifndef DISABLE_LIGHT_OMNI
+ for (uint i = 0u; i < omni_light_count; i++) {
+ light_process_omni(omni_light_indices[i], vertex_interp, view, normal_interp, roughness,
+ diffuse_light_interp.rgb, specular_light_interp.rgb);
+ }
+#endif // !DISABLE_LIGHT_OMNI
+
+#ifndef DISABLE_LIGHT_SPOT
+ for (uint i = 0u; i < spot_light_count; i++) {
+ light_process_spot(spot_light_indices[i], vertex_interp, view, normal_interp, roughness,
+ diffuse_light_interp.rgb, specular_light_interp.rgb);
+ }
+#endif // !DISABLE_LIGHT_SPOT
+#endif // BASE_PASS
+
+/* ADDITIVE LIGHTING PASS */
+#ifdef USE_ADDITIVE_LIGHTING
+ additive_diffuse_light_interp = vec3(0.0);
+ additive_specular_light_interp = vec3(0.0);
+#if !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
+
+ light_compute(normal_interp, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, roughness,
+ additive_diffuse_light_interp.rgb,
+ additive_specular_light_interp.rgb);
+#endif // !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
+
+#ifdef ADDITIVE_OMNI
+ light_process_omni(omni_light_index, vertex_interp, view, normal_interp, roughness,
+ additive_diffuse_light_interp.rgb, additive_specular_light_interp.rgb);
+#endif // ADDITIVE_OMNI
+
+#ifdef ADDITIVE_SPOT
+ light_process_spot(spot_light_index, vertex_interp, view, normal_interp, roughness,
+ additive_diffuse_light_interp.rgb, additive_specular_light_interp.rgb);
+#endif // ADDITIVE_SPOT
+
+#endif // USE_ADDITIVE_LIGHTING
+#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+#endif // USE_VERTEX_LIGHTING
+}
/* clang-format off */
#[fragment]
@@ -758,6 +984,16 @@ multiview_data;
#define LIGHT_BAKE_DYNAMIC 2u
#ifndef MODE_RENDER_DEPTH
+#ifdef USE_VERTEX_LIGHTING
+in vec3 diffuse_light_interp;
+in vec3 specular_light_interp;
+
+#ifdef USE_ADDITIVE_LIGHTING
+in vec3 additive_diffuse_light_interp;
+in vec3 additive_specular_light_interp;
+#endif // USE_ADDITIVE_LIGHTING
+#endif // USE_VERTEX_LIGHTING
+
// Directional light data.
#if !defined(DISABLE_LIGHT_DIRECTIONAL) || (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT))
@@ -809,22 +1045,22 @@ struct LightData { // This structure needs to be as packed as possible.
layout(std140) uniform OmniLightData { // ubo:5
LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
};
-#ifdef BASE_PASS
+#if defined(BASE_PASS) && !defined(USE_VERTEX_LIGHTING)
uniform uint omni_light_indices[MAX_FORWARD_LIGHTS];
uniform uint omni_light_count;
-#endif // BASE_PASS
-#endif // DISABLE_LIGHT_OMNI
+#endif // defined(BASE_PASS) && !defined(USE_VERTEX_LIGHTING)
+#endif // !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI)
#if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
layout(std140) uniform SpotLightData { // ubo:6
LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
};
-#ifdef BASE_PASS
+#if defined(BASE_PASS) && !defined(USE_VERTEX_LIGHTING)
uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
uniform uint spot_light_count;
-#endif // BASE_PASS
-#endif // DISABLE_LIGHT_SPOT
-#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
+#endif // defined(BASE_PASS) && !defined(USE_VERTEX_LIGHTING)
+#endif // !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
+#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
#ifdef USE_ADDITIVE_LIGHTING
#ifdef ADDITIVE_OMNI
@@ -985,6 +1221,8 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
return mix(vec3(dielectric), albedo, vec3(metallic));
}
#ifndef MODE_RENDER_DEPTH
+
+#ifndef USE_VERTEX_LIGHTING
#if !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || defined(USE_ADDITIVE_LIGHTING)
float D_GGX(float cos_theta_m, float alpha) {
@@ -1284,6 +1522,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
#endif // !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
+#endif // !USE_VERTEX_LIGHTING
vec4 fog_process(vec3 vertex) {
vec3 fog_color = scene_data.fog_light_color;
@@ -1859,9 +2098,13 @@ void main() {
specular_light *= env.x * f0 + env.y * clamp(50.0 * f0.g, metallic, 1.0);
#endif
}
-
#endif // !AMBIENT_LIGHT_DISABLED
+#ifdef USE_VERTEX_LIGHTING
+ specular_light += specular_light_interp * f0;
+ diffuse_light += diffuse_light_interp;
+#else
+
#ifndef DISABLE_LIGHT_DIRECTIONAL
for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
#if defined(USE_LIGHTMAP) && !defined(DISABLE_LIGHTMAP)
@@ -1944,6 +2187,7 @@ void main() {
diffuse_light, specular_light);
}
#endif // !DISABLE_LIGHT_SPOT
+#endif // !USE_VERTEX_LIGHTING
#endif // BASE_PASS
#endif // !MODE_UNSHADED
@@ -1993,7 +2237,6 @@ void main() {
#else
diffuse_light *= albedo;
-
diffuse_light *= 1.0 - metallic;
ambient_light *= 1.0 - metallic;
@@ -2024,6 +2267,11 @@ void main() {
diffuse_light = vec3(0.0);
specular_light = vec3(0.0);
+#ifdef USE_VERTEX_LIGHTING
+ diffuse_light = additive_diffuse_light_interp;
+ specular_light = additive_specular_light_interp * f0;
+#endif // USE_VERTEX_LIGHTING
+
#if !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
#ifndef SHADOWS_DISABLED
@@ -2137,6 +2385,8 @@ void main() {
#else
float directional_shadow = 1.0f;
#endif // SHADOWS_DISABLED
+
+#ifndef USE_VERTEX_LIGHTING
light_compute(normal, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].size, directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, directional_shadow, f0, roughness, metallic, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
@@ -2153,6 +2403,11 @@ void main() {
#endif
diffuse_light,
specular_light);
+#else
+ // Just apply shadows to vertex lighting.
+ diffuse_light *= directional_shadow;
+ specular_light *= directional_shadow;
+#endif // !USE_VERTEX_LIGHTING
#endif // !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
#ifdef ADDITIVE_OMNI
@@ -2162,6 +2417,8 @@ void main() {
omni_shadow = texture(omni_shadow_texture, vec4(light_ray, 1.0 - length(light_ray) * omni_lights[omni_light_index].inv_radius));
omni_shadow = mix(1.0, omni_shadow, omni_lights[omni_light_index].shadow_opacity);
#endif // SHADOWS_DISABLED
+
+#ifndef USE_VERTEX_LIGHTING
light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
@@ -2177,6 +2434,11 @@ void main() {
binormal, tangent, anisotropy,
#endif
diffuse_light, specular_light);
+#else
+ // Just apply shadows to vertex lighting.
+ diffuse_light *= omni_shadow;
+ specular_light *= omni_shadow;
+#endif // !USE_VERTEX_LIGHTING
#endif // ADDITIVE_OMNI
#ifdef ADDITIVE_SPOT
@@ -2185,6 +2447,8 @@ void main() {
spot_shadow = sample_shadow(spot_shadow_texture, positional_shadows[positional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
spot_shadow = mix(1.0, spot_shadow, spot_lights[spot_light_index].shadow_opacity);
#endif // SHADOWS_DISABLED
+
+#ifndef USE_VERTEX_LIGHTING
light_process_spot(spot_light_index, vertex, view, normal, f0, roughness, metallic, spot_shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
@@ -2201,6 +2465,11 @@ void main() {
binormal, anisotropy,
#endif
diffuse_light, specular_light);
+#else
+ // Just apply shadows to vertex lighting.
+ diffuse_light *= spot_shadow;
+ specular_light *= spot_shadow;
+#endif // !USE_VERTEX_LIGHTING
#endif // ADDITIVE_SPOT
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index 0100719151..209b7dd7d2 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -178,7 +178,7 @@ Config::Config() {
}
#endif
- force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading");
+ force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading");
use_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter");
use_depth_prepass = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index c29c741c2a..5dca149d99 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1368,6 +1368,10 @@ MaterialStorage::MaterialStorage() {
actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
+ if (!GLES3::Config::get_singleton()->force_vertex_shading) {
+ // If forcing vertex shading, this will be defined already.
+ actions.render_mode_defines["vertex_lighting"] = "#define USE_VERTEX_LIGHTING\n";
+ }
actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
diff --git a/editor/renames_map_3_to_4.cpp b/editor/renames_map_3_to_4.cpp
index ae7c86a5e5..ca5d3cbf2a 100644
--- a/editor/renames_map_3_to_4.cpp
+++ b/editor/renames_map_3_to_4.cpp
@@ -1354,7 +1354,6 @@ const char *RenamesMap3To4::project_settings_renames[][2] = {
{ "rendering/quality/shading/force_lambert_over_burley", "rendering/shading/overrides/force_lambert_over_burley" },
{ "rendering/quality/shading/force_lambert_over_burley.mobile", "rendering/shading/overrides/force_lambert_over_burley.mobile" },
{ "rendering/quality/shading/force_vertex_shading", "rendering/shading/overrides/force_vertex_shading" },
- { "rendering/quality/shading/force_vertex_shading.mobile", "rendering/shading/overrides/force_vertex_shading.mobile" },
{ "rendering/quality/shadow_atlas/quadrant_0_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_0_subdiv" },
{ "rendering/quality/shadow_atlas/quadrant_1_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_1_subdiv" },
{ "rendering/quality/shadow_atlas/quadrant_2_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_2_subdiv" },
@@ -1400,7 +1399,6 @@ const char *RenamesMap3To4::project_godot_renames[][2] = {
{ "quality/shading/force_lambert_over_burley", "shading/overrides/force_lambert_over_burley" },
{ "quality/shading/force_lambert_over_burley.mobile", "shading/overrides/force_lambert_over_burley.mobile" },
{ "quality/shading/force_vertex_shading", "shading/overrides/force_vertex_shading" },
- { "quality/shading/force_vertex_shading.mobile", "shading/overrides/force_vertex_shading.mobile" },
{ "quality/shadow_atlas/quadrant_0_subdiv", "lights_and_shadows/shadow_atlas/quadrant_0_subdiv" },
{ "quality/shadow_atlas/quadrant_1_subdiv", "lights_and_shadows/shadow_atlas/quadrant_1_subdiv" },
{ "quality/shadow_atlas/quadrant_2_subdiv", "lights_and_shadows/shadow_atlas/quadrant_2_subdiv" },
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 aca85ce497..307898232d 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -4261,6 +4261,11 @@ RenderForwardClustered::RenderForwardClustered() {
defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
+ bool force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading");
+ if (force_vertex_shading) {
+ defines += "\n#define USE_VERTEX_LIGHTING\n";
+ }
+
{
//lightmaps
scene_state.max_lightmaps = MAX_LIGHTMAPS;
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 6846c3f693..ee5b5ef1d8 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -730,13 +730,20 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
+
+ bool force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading");
+ if (!force_vertex_shading) {
+ // If forcing vertex shading, this will be defined already.
+ actions.render_mode_defines["vertex_lighting"] = "#define USE_VERTEX_LIGHTING\n";
+ }
+
actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n";
actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET;
actions.base_uniform_string = "material.";
- actions.base_varying_index = 12;
+ actions.base_varying_index = 14;
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
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 8a02ec0eb5..fa8796fae6 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -2800,6 +2800,11 @@ RenderForwardMobile::RenderForwardMobile() {
// defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
+ bool force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading");
+ if (force_vertex_shading) {
+ defines += "\n#define USE_VERTEX_LIGHTING\n";
+ }
+
{
//lightmaps
scene_state.max_lightmaps = 2;
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index 08982096c5..5dec4d8f21 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -633,6 +633,13 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
+
+ bool force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading");
+ if (!force_vertex_shading) {
+ // If forcing vertex shading, this will be defined already.
+ actions.render_mode_defines["vertex_lighting"] = "#define USE_VERTEX_LIGHTING\n";
+ }
+
actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n";
actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n";
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 57497eb207..5441e28be0 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1974,6 +1974,12 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
default_canvas_texture = texture_storage->canvas_texture_allocate();
texture_storage->canvas_texture_initialize(default_canvas_texture);
+ RendererRD::TextureStorage::CanvasTextureInfo info = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_info(default_canvas_texture, default_filter, default_repeat, false, false);
+ default_texture_info.diffuse = info.diffuse;
+ default_texture_info.normal = info.normal;
+ default_texture_info.specular = info.specular;
+ default_texture_info.sampler = info.sampler;
+
state.shadow_texture_size = GLOBAL_GET("rendering/2d/shadow_atlas/size");
//create functions for shader and material
@@ -2219,7 +2225,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET);
Item *current_clip = nullptr;
- state.current_tex_uniform_set = RID();
+ state.current_batch_uniform_set = RID();
for (uint32_t i = 0; i <= state.current_batch_index; i++) {
Batch *current_batch = &state.canvas_instance_batches[i];
@@ -2337,11 +2343,11 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->world[i] = world[i];
}
- instance_data->flags = base_flags | r_current_batch->tex_flags; // Reset on each command for safety, keep canvas texture binding config.
+ instance_data->flags = base_flags | r_current_batch->tex_info.flags; // Reset on each command for safety, keep canvas texture binding config.
- instance_data->color_texture_pixel_size[0] = r_current_batch->tex_texpixel_size.width;
- instance_data->color_texture_pixel_size[1] = r_current_batch->tex_texpixel_size.height;
- instance_data->specular_shininess = r_current_batch->tex_specular_shininess;
+ instance_data->color_texture_pixel_size[0] = r_current_batch->tex_info.texpixel_size.width;
+ instance_data->color_texture_pixel_size[1] = r_current_batch->tex_info.texpixel_size.height;
+ instance_data->specular_shininess = r_current_batch->tex_info.specular_shininess;
return instance_data;
};
@@ -2373,10 +2379,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
bool has_msdf = bool(rect->flags & CANVAS_RECT_MSDF);
TextureState tex_state(rect->texture, texture_filter, texture_repeat, has_msdf, use_linear_colors);
- if (tex_state != r_current_batch->tex_state) {
+ if (tex_state != r_current_batch->tex_info.state) {
r_current_batch = _new_batch(r_batch_broken);
- r_current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(r_current_batch, rect->texture);
+ r_current_batch->tex_info.state = tex_state;
+ _prepare_batch_texture_info(r_current_batch, rect->texture);
}
Color modulated = rect->modulate * base_color;
@@ -2399,7 +2405,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
Rect2 dst_rect;
if (rect->texture.is_valid()) {
- src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * r_current_batch->tex_texpixel_size, rect->source.size * r_current_batch->tex_texpixel_size) : Rect2(0, 0, 1, 1);
+ src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * r_current_batch->tex_info.texpixel_size, rect->source.size * r_current_batch->tex_info.texpixel_size) : Rect2(0, 0, 1, 1);
dst_rect = Rect2(rect->rect.position, rect->rect.size);
if (dst_rect.size.width < 0) {
@@ -2484,10 +2490,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
}
TextureState tex_state(np->texture, texture_filter, texture_repeat, false, use_linear_colors);
- if (tex_state != r_current_batch->tex_state) {
+ if (tex_state != r_current_batch->tex_info.state) {
r_current_batch = _new_batch(r_batch_broken);
- r_current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(r_current_batch, np->texture);
+ r_current_batch->tex_info.state = tex_state;
+ _prepare_batch_texture_info(r_current_batch, np->texture);
}
InstanceData *instance_data = new_instance_data();
@@ -2499,7 +2505,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
src_rect = Rect2(0, 0, 1, 1);
} else {
if (np->source != Rect2()) {
- src_rect = Rect2(np->source.position.x * r_current_batch->tex_texpixel_size.width, np->source.position.y * r_current_batch->tex_texpixel_size.height, np->source.size.x * r_current_batch->tex_texpixel_size.width, np->source.size.y * r_current_batch->tex_texpixel_size.height);
+ src_rect = Rect2(np->source.position.x * r_current_batch->tex_info.texpixel_size.width, np->source.position.y * r_current_batch->tex_info.texpixel_size.height, np->source.size.x * r_current_batch->tex_info.texpixel_size.width, np->source.size.y * r_current_batch->tex_info.texpixel_size.height);
instance_data->color_texture_pixel_size[0] = 1.0 / np->source.size.width;
instance_data->color_texture_pixel_size[1] = 1.0 / np->source.size.height;
} else {
@@ -2553,10 +2559,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->command = c;
TextureState tex_state(polygon->texture, texture_filter, texture_repeat, false, use_linear_colors);
- if (tex_state != r_current_batch->tex_state) {
+ if (tex_state != r_current_batch->tex_info.state) {
r_current_batch = _new_batch(r_batch_broken);
- r_current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(r_current_batch, polygon->texture);
+ r_current_batch->tex_info.state = tex_state;
+ _prepare_batch_texture_info(r_current_batch, polygon->texture);
}
// pipeline variant
@@ -2596,10 +2602,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->pipeline_variant = variant[primitive->point_count - 1];
TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors);
- if (tex_state != r_current_batch->tex_state) {
+ if (tex_state != r_current_batch->tex_info.state) {
r_current_batch = _new_batch(r_batch_broken);
- r_current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(r_current_batch, primitive->texture);
+ r_current_batch->tex_info.state = tex_state;
+ _prepare_batch_texture_info(r_current_batch, primitive->texture);
}
}
@@ -2657,8 +2663,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
TextureState tex_state(m->texture, texture_filter, texture_repeat, false, use_linear_colors);
- r_current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(r_current_batch, m->texture);
+ r_current_batch->tex_info.state = tex_state;
+ _prepare_batch_texture_info(r_current_batch, m->texture);
instance_data = new_instance_data();
r_current_batch->mesh_instance_count = 1;
@@ -2680,8 +2686,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
}
TextureState tex_state(mm->texture, texture_filter, texture_repeat, false, use_linear_colors);
- r_current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(r_current_batch, mm->texture);
+ r_current_batch->tex_info.state = tex_state;
+ _prepare_batch_texture_info(r_current_batch, mm->texture);
instance_data = new_instance_data();
instance_data->flags |= 1; // multimesh, trails disabled
@@ -2698,8 +2704,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
TextureState tex_state(pt->texture, texture_filter, texture_repeat, false, use_linear_colors);
- r_current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(r_current_batch, pt->texture);
+ r_current_batch->tex_info.state = tex_state;
+ _prepare_batch_texture_info(r_current_batch, pt->texture);
instance_data = new_instance_data();
@@ -2795,7 +2801,20 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
ERR_FAIL_NULL(p_batch->command);
- _bind_canvas_texture(p_draw_list, p_batch->tex_uniform_set);
+ {
+ RD::Uniform u_diffuse(RD::UNIFORM_TYPE_TEXTURE, 0, p_batch->tex_info.diffuse);
+ RD::Uniform u_normal(RD::UNIFORM_TYPE_TEXTURE, 1, p_batch->tex_info.normal);
+ RD::Uniform u_specular(RD::UNIFORM_TYPE_TEXTURE, 2, p_batch->tex_info.specular);
+ RD::Uniform u_sampler(RD::UNIFORM_TYPE_SAMPLER, 3, p_batch->tex_info.sampler);
+ RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 4, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
+
+ RID uniform_set = uniform_set_cache->get_cache(shader.default_version_rd_shader, BATCH_UNIFORM_SET, u_diffuse, u_normal, u_specular, u_sampler, u_instance_data);
+
+ if (state.current_batch_uniform_set != uniform_set) {
+ state.current_batch_uniform_set = uniform_set;
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, BATCH_UNIFORM_SET);
+ }
+ }
switch (p_batch->command_type) {
case Item::Command::TYPE_RECT:
@@ -2810,13 +2829,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
-
- RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
- RD::get_singleton()->draw_list_bind_uniform_set(
- p_draw_list,
- uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data),
- INSTANCE_DATA_UNIFORM_SET);
-
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
RD::get_singleton()->draw_list_draw(p_draw_list, true, p_batch->instance_count);
@@ -2839,13 +2851,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
-
- RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
- RD::get_singleton()->draw_list_bind_uniform_set(
- p_draw_list,
- uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data),
- INSTANCE_DATA_UNIFORM_SET);
-
RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array);
if (pb->indices.is_valid()) {
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, pb->indices);
@@ -2868,13 +2873,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
-
- RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
- RD::get_singleton()->draw_list_bind_uniform_set(
- p_draw_list,
- uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data),
- INSTANCE_DATA_UNIFORM_SET);
-
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[MIN(3u, primitive->point_count) - 1]);
uint32_t instance_count = p_batch->instance_count;
RD::get_singleton()->draw_list_draw(p_draw_list, true, instance_count);
@@ -2934,12 +2932,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
break;
}
- RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 0, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
- RD::get_singleton()->draw_list_bind_uniform_set(
- p_draw_list,
- uniform_set_cache->get_cache(shader.default_version_rd_shader, INSTANCE_DATA_UNIFORM_SET, u_instance_data),
- INSTANCE_DATA_UNIFORM_SET);
-
uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh);
static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
@@ -3046,60 +3038,46 @@ void RendererCanvasRenderRD::_allocate_instance_buffer() {
state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers.push_back(buf);
}
-void RendererCanvasRenderRD::_prepare_batch_texture(Batch *p_current_batch, RID p_texture) const {
+void RendererCanvasRenderRD::_prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const {
if (p_texture.is_null()) {
p_texture = default_canvas_texture;
}
- Color specular_shininess;
- bool use_normal;
- bool use_specular;
- Size2i size;
- bool success = RendererRD::TextureStorage::get_singleton()->canvas_texture_get_uniform_set(
- p_texture,
- p_current_batch->tex_state.texture_filter(),
- p_current_batch->tex_state.texture_repeat(),
- shader.default_version_rd_shader,
- CANVAS_TEXTURE_UNIFORM_SET,
- p_current_batch->tex_state.linear_colors(),
- p_current_batch->tex_uniform_set,
- size,
- specular_shininess,
- use_normal,
- use_specular,
- p_current_batch->tex_state.texture_is_data());
+ RendererRD::TextureStorage::CanvasTextureInfo info =
+ RendererRD::TextureStorage::get_singleton()->canvas_texture_get_info(
+ p_texture,
+ p_current_batch->tex_info.state.texture_filter(),
+ p_current_batch->tex_info.state.texture_repeat(),
+ p_current_batch->tex_info.state.linear_colors(),
+ p_current_batch->tex_info.state.texture_is_data());
+
// something odd happened
- if (!success) {
- _prepare_batch_texture(p_current_batch, default_canvas_texture);
+ if (info.is_null()) {
+ _prepare_batch_texture_info(p_current_batch, default_canvas_texture);
return;
}
- // cache values to be copied to instance data
- if (specular_shininess.a < 0.999) {
- p_current_batch->tex_flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
- }
+ p_current_batch->tex_info.diffuse = info.diffuse;
+ p_current_batch->tex_info.normal = info.normal;
+ p_current_batch->tex_info.specular = info.specular;
+ p_current_batch->tex_info.sampler = info.sampler;
- if (use_normal) {
- p_current_batch->tex_flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
+ // cache values to be copied to instance data
+ if (info.specular_color.a < 0.999) {
+ p_current_batch->tex_info.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
- uint8_t a = uint8_t(CLAMP(specular_shininess.a * 255.0, 0.0, 255.0));
- uint8_t b = uint8_t(CLAMP(specular_shininess.b * 255.0, 0.0, 255.0));
- uint8_t g = uint8_t(CLAMP(specular_shininess.g * 255.0, 0.0, 255.0));
- uint8_t r = uint8_t(CLAMP(specular_shininess.r * 255.0, 0.0, 255.0));
- p_current_batch->tex_specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r);
-
- p_current_batch->tex_texpixel_size = Vector2(1.0 / float(size.width), 1.0 / float(size.height));
-}
-
-void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_uniform_set) {
- if (state.current_tex_uniform_set == p_uniform_set) {
- return;
+ if (info.use_normal) {
+ p_current_batch->tex_info.flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
}
- state.current_tex_uniform_set = p_uniform_set;
+ uint8_t a = uint8_t(CLAMP(info.specular_color.a * 255.0, 0.0, 255.0));
+ uint8_t b = uint8_t(CLAMP(info.specular_color.b * 255.0, 0.0, 255.0));
+ uint8_t g = uint8_t(CLAMP(info.specular_color.g * 255.0, 0.0, 255.0));
+ uint8_t r = uint8_t(CLAMP(info.specular_color.r * 255.0, 0.0, 255.0));
+ p_current_batch->tex_info.specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r);
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, p_uniform_set, CANVAS_TEXTURE_UNIFORM_SET);
+ p_current_batch->tex_info.texpixel_size = Vector2(1.0 / float(info.size.width), 1.0 / float(info.size.height));
}
RendererCanvasRenderRD::~RendererCanvasRenderRD() {
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 8d90cd23ce..b0f4a4595a 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -45,8 +45,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
BASE_UNIFORM_SET = 0,
MATERIAL_UNIFORM_SET = 1,
TRANSFORMS_UNIFORM_SET = 2,
- CANVAS_TEXTURE_UNIFORM_SET = 3,
- INSTANCE_DATA_UNIFORM_SET = 4,
+ BATCH_UNIFORM_SET = 3,
};
const int SAMPLERS_BINDING_FIRST_INDEX = 10;
@@ -423,24 +422,25 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
}
};
+ struct TextureInfo {
+ TextureState state;
+ uint32_t specular_shininess = 0;
+ uint32_t flags = 0;
+ Vector2 texpixel_size;
+
+ RID diffuse;
+ RID normal;
+ RID specular;
+ RID sampler;
+ };
+
struct Batch {
// Position in the UBO measured in bytes
uint32_t start = 0;
uint32_t instance_count = 0;
uint32_t instance_buffer_index = 0;
- TextureState tex_state;
- RID tex_uniform_set;
-
- // The following tex_ prefixed fields are used to cache the texture data for the current batch.
- // These values are applied to new InstanceData for the batch
-
- // The cached specular shininess derived from the current texture.
- uint32_t tex_specular_shininess = 0;
- // The cached texture flags, such as FLAGS_DEFAULT_SPECULAR_MAP_USED and FLAGS_DEFAULT_NORMAL_MAP_USED
- uint32_t tex_flags = 0;
- // The cached texture pixel size.
- Vector2 tex_texpixel_size;
+ TextureInfo tex_info;
Color modulate = Color(1.0, 1.0, 1.0, 1.0);
@@ -462,14 +462,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t mesh_instance_count;
};
bool has_blend = false;
-
- void set_tex_state(TextureState &p_tex_state) {
- tex_state = p_tex_state;
- tex_uniform_set = RID();
- tex_texpixel_size = Size2();
- tex_specular_shininess = 0;
- tex_flags = 0;
- }
};
struct DataBuffer {
@@ -509,7 +501,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t max_instances_per_buffer = 16384;
uint32_t max_instance_buffer_size = 16384 * sizeof(InstanceData);
- RID current_tex_uniform_set;
+ RID current_batch_uniform_set;
LightUniform *light_uniforms = nullptr;
@@ -532,6 +524,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
Item *items[MAX_RENDER_ITEMS];
+ TextureInfo default_texture_info;
+
bool using_directional_lights = false;
RID default_canvas_texture;
@@ -561,8 +555,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
void _render_batch_items(RenderTarget p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr);
void _record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch);
void _render_batch(RD::DrawListID p_draw_list, PipelineVariants *p_pipeline_variants, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info = nullptr);
- void _prepare_batch_texture(Batch *p_current_batch, RID p_texture) const;
- void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_uniform_set);
+ void _prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const;
[[nodiscard]] Batch *_new_batch(bool &r_batch_broken);
void _add_to_batch(uint32_t &r_index, bool &r_batch_broken, Batch *&r_current_batch);
void _allocate_instance_buffer();
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index 7cf5b4576e..fc9b727581 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -54,11 +54,6 @@ struct InstanceData {
uint lights[4];
};
-layout(set = 4, binding = 0, std430) restrict readonly buffer DrawData {
- InstanceData data[];
-}
-instances;
-
layout(push_constant, std430) uniform Params {
uint base_instance_index; // base index to instance data
uint pad1;
@@ -163,3 +158,8 @@ layout(set = 3, binding = 0) uniform texture2D color_texture;
layout(set = 3, binding = 1) uniform texture2D normal_texture;
layout(set = 3, binding = 2) uniform texture2D specular_texture;
layout(set = 3, binding = 3) uniform sampler texture_sampler;
+
+layout(set = 3, binding = 4, std430) restrict readonly buffer DrawData {
+ InstanceData data[];
+}
+instances;
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 400451ec36..3cbe1427b6 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -156,8 +156,30 @@ vec2 multiview_uv(vec2 uv) {
ivec2 multiview_uv(ivec2 uv) {
return uv;
}
+
#endif //USE_MULTIVIEW
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
+layout(location = 12) highp out vec4 diffuse_light_interp;
+layout(location = 13) highp out vec4 specular_light_interp;
+
+#include "../scene_forward_vertex_lights_inc.glsl"
+
+void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) {
+ uint item_min_max = cluster_buffer.data[p_offset];
+ item_min = item_min_max & 0xFFFFu;
+ item_max = item_min_max >> 16;
+
+ item_from = item_min >> 5;
+ item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements
+}
+
+uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) {
+ int local_min = clamp(int(z_min) - int(i) * 32, 0, 31);
+ int mask_width = min(int(z_max) - int(z_min), 32 - local_min);
+ return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width);
+}
+#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
invariant gl_Position;
#GLOBALS
@@ -488,6 +510,145 @@ void vertex_shader(vec3 vertex_input,
screen_pos = gl_Position;
#endif
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
+ diffuse_light_interp = vec4(0.0);
+ specular_light_interp = vec4(0.0);
+
+#ifdef USE_MULTIVIEW
+ vec3 view = -normalize(vertex_interp - eye_offset);
+ vec2 clip_pos = clamp((combined_projected.xy / combined_projected.w) * 0.5 + 0.5, 0.0, 1.0);
+#else
+ vec3 view = -normalize(vertex_interp);
+ vec2 clip_pos = clamp((gl_Position.xy / gl_Position.w) * 0.5 + 0.5, 0.0, 1.0);
+#endif
+
+ uvec2 cluster_pos = uvec2(clip_pos / scene_data.screen_pixel_size) >> implementation_data.cluster_shift;
+ uint cluster_offset = (implementation_data.cluster_width * cluster_pos.y + cluster_pos.x) * (implementation_data.max_cluster_element_count_div_32 + 32);
+ uint cluster_z = uint(clamp((-vertex_interp.z / scene_data.z_far) * 32.0, 0.0, 31.0));
+
+ { //omni lights
+
+ uint cluster_omni_offset = cluster_offset;
+
+ uint item_min;
+ uint item_max;
+ uint item_from;
+ uint item_to;
+
+ cluster_get_item_range(cluster_omni_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+
+ for (uint i = item_from; i < item_to; i++) {
+ uint mask = cluster_buffer.data[cluster_omni_offset + i];
+ mask &= cluster_get_range_clip_mask(i, item_min, item_max);
+ uint merged_mask = mask;
+
+ while (merged_mask != 0) {
+ uint bit = findMSB(merged_mask);
+ merged_mask &= ~(1u << bit);
+ uint light_index = 32 * i + bit;
+
+ if (!bool(omni_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
+
+ if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
+
+ light_process_omni_vertex(light_index, vertex, view, normal, roughness,
+ diffuse_light_interp.rgb, specular_light_interp.rgb);
+ }
+ }
+ }
+
+ { //spot lights
+ uint cluster_spot_offset = cluster_offset + implementation_data.cluster_type_size;
+
+ uint item_min;
+ uint item_max;
+ uint item_from;
+ uint item_to;
+
+ cluster_get_item_range(cluster_spot_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+
+ for (uint i = item_from; i < item_to; i++) {
+ uint mask = cluster_buffer.data[cluster_spot_offset + i];
+ mask &= cluster_get_range_clip_mask(i, item_min, item_max);
+ uint merged_mask = mask;
+
+ while (merged_mask != 0) {
+ uint bit = findMSB(merged_mask);
+ merged_mask &= ~(1u << bit);
+
+ uint light_index = 32 * i + bit;
+
+ if (!bool(spot_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
+
+ if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
+
+ light_process_spot_vertex(light_index, vertex, view, normal, roughness,
+ diffuse_light_interp.rgb, specular_light_interp.rgb);
+ }
+ }
+ }
+
+ { // Directional light.
+
+ // We process the first directional light separately as it may have shadows.
+ vec3 directional_diffuse = vec3(0.0);
+ vec3 directional_specular = vec3(0.0);
+
+ for (uint i = 0; i < scene_data.directional_light_count; i++) {
+ if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
+ continue; // Not masked, skip.
+ }
+
+ if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip.
+ }
+ if (i == 0) {
+ light_compute_vertex(normal, directional_lights.data[0].direction, view,
+ directional_lights.data[0].color * directional_lights.data[0].energy,
+ true, roughness,
+ directional_diffuse,
+ directional_specular);
+ } else {
+ light_compute_vertex(normal, directional_lights.data[i].direction, view,
+ directional_lights.data[i].color * directional_lights.data[i].energy,
+ true, roughness,
+ diffuse_light_interp.rgb,
+ specular_light_interp.rgb);
+ }
+ }
+
+ // Calculate the contribution from the shadowed light so we can scale the shadows accordingly.
+ float diff_avg = dot(diffuse_light_interp.rgb, vec3(0.33333));
+ float diff_dir_avg = dot(directional_diffuse, vec3(0.33333));
+ if (diff_avg > 0.0) {
+ diffuse_light_interp.a = diff_dir_avg / (diff_avg + diff_dir_avg);
+ } else {
+ diffuse_light_interp.a = 1.0;
+ }
+
+ diffuse_light_interp.rgb += directional_diffuse;
+
+ float spec_avg = dot(specular_light_interp.rgb, vec3(0.33333));
+ float spec_dir_avg = dot(directional_specular, vec3(0.33333));
+ if (spec_avg > 0.0) {
+ specular_light_interp.a = spec_dir_avg / (spec_avg + spec_dir_avg);
+ } else {
+ specular_light_interp.a = 1.0;
+ }
+
+ specular_light_interp.rgb += directional_specular;
+ }
+
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
+
#ifdef MODE_RENDER_DEPTH
if (scene_data.pancake_shadows) {
if (gl_Position.z >= 0.9999) {
@@ -791,7 +952,10 @@ ivec2 multiview_uv(ivec2 uv) {
return uv;
}
#endif //USE_MULTIVIEW
-
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
+layout(location = 12) highp in vec4 diffuse_light_interp;
+layout(location = 13) highp in vec4 specular_light_interp;
+#endif
//defines to keep compatibility with vertex
#ifdef USE_MULTIVIEW
@@ -1375,7 +1539,6 @@ void fragment_shader(in SceneData scene_data) {
vec3 specular_light = vec3(0.0, 0.0, 0.0);
vec3 diffuse_light = vec3(0.0, 0.0, 0.0);
vec3 ambient_light = vec3(0.0, 0.0, 0.0);
-
#ifndef MODE_UNSHADED
// Used in regular draw pass and when drawing SDFs for SDFGI and materials for VoxelGI.
emission *= scene_data.emissive_exposure_normalization;
@@ -1836,6 +1999,11 @@ void fragment_shader(in SceneData scene_data) {
// LIGHTING
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+#ifdef USE_VERTEX_LIGHTING
+ diffuse_light += diffuse_light_interp.rgb;
+ specular_light += specular_light_interp.rgb * f0;
+#endif
+
{ // Directional light.
// Do shadow and lighting in two passes to reduce register pressure.
@@ -1843,10 +2011,15 @@ void fragment_shader(in SceneData scene_data) {
uint shadow0 = 0;
uint shadow1 = 0;
+#ifdef USE_VERTEX_LIGHTING
+ // Only process the first light's shadow for vertex lighting.
+ for (uint i = 0; i < 1; i++) {
+#else
for (uint i = 0; i < 8; i++) {
if (i >= scene_data.directional_light_count) {
break;
}
+#endif
if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) {
continue; //not masked
@@ -2044,6 +2217,11 @@ void fragment_shader(in SceneData scene_data) {
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
+#ifdef USE_VERTEX_LIGHTING
+ diffuse_light *= mix(1.0, shadow, diffuse_light_interp.a);
+ specular_light *= mix(1.0, shadow, specular_light_interp.a);
+#endif
+
#undef BIAS_FUNC
} // shadows
@@ -2055,6 +2233,8 @@ void fragment_shader(in SceneData scene_data) {
}
#endif // SHADOWS_DISABLED
+#ifndef USE_VERTEX_LIGHTING
+
for (uint i = 0; i < 8; i++) {
if (i >= scene_data.directional_light_count) {
break;
@@ -2175,8 +2355,10 @@ void fragment_shader(in SceneData scene_data) {
diffuse_light,
specular_light);
}
+#endif // USE_VERTEX_LIGHTING
}
+#ifndef USE_VERTEX_LIGHTING
{ //omni lights
uint cluster_omni_offset = cluster_offset;
@@ -2320,6 +2502,8 @@ void fragment_shader(in SceneData scene_data) {
}
}
}
+#endif // !USE_VERTEX_LIGHTING
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
#ifdef USE_SHADOW_TO_OPACITY
#ifndef MODE_RENDER_DEPTH
@@ -2334,8 +2518,6 @@ void fragment_shader(in SceneData scene_data) {
#endif // !MODE_RENDER_DEPTH
#endif // USE_SHADOW_TO_OPACITY
-#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
-
#ifdef MODE_RENDER_DEPTH
#ifdef MODE_RENDER_SDF
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 17c7b756c3..e7ce44bce2 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
@@ -105,7 +105,16 @@ layout(location = 4) mediump out vec2 uv2_interp;
layout(location = 5) mediump out vec3 tangent_interp;
layout(location = 6) mediump out vec3 binormal_interp;
#endif
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
+layout(location = 7) highp out vec4 diffuse_light_interp;
+layout(location = 8) highp out vec4 specular_light_interp;
+layout(constant_id = 9) const bool sc_disable_omni_lights = false;
+layout(constant_id = 10) const bool sc_disable_spot_lights = false;
+layout(constant_id = 12) const bool sc_disable_directional_lights = false;
+
+#include "../scene_forward_vertex_lights_inc.glsl"
+#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
#ifdef MATERIAL_UNIFORMS_USED
/* clang-format off */
layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms {
@@ -185,6 +194,7 @@ void main() {
mat4 model_matrix = instances.data[draw_call.instance_index].transform;
mat4 inv_view_matrix = scene_data.inv_view_matrix;
+
#ifdef USE_DOUBLE_PRECISION
vec3 model_precision = vec3(model_matrix[0][3], model_matrix[1][3], model_matrix[2][3]);
model_matrix[0][3] = 0.0;
@@ -448,6 +458,107 @@ void main() {
binormal_interp = binormal;
#endif
+// VERTEX LIGHTING
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
+#ifdef USE_MULTIVIEW
+ vec3 view = -normalize(vertex_interp - eye_offset);
+#else
+ vec3 view = -normalize(vertex_interp);
+#endif
+
+ diffuse_light_interp = vec4(0.0);
+ specular_light_interp = vec4(0.0);
+
+ if (!sc_disable_omni_lights) {
+ uint light_indices = instances.data[draw_call.instance_index].omni_lights.x;
+ for (uint i = 0; i < 8; i++) {
+ uint light_index = light_indices & 0xFF;
+ if (i == 3) {
+ light_indices = instances.data[draw_call.instance_index].omni_lights.y;
+ } else {
+ light_indices = light_indices >> 8;
+ }
+
+ if (light_index == 0xFF) {
+ break;
+ }
+
+ light_process_omni_vertex(light_index, vertex, view, normal, roughness,
+ diffuse_light_interp.rgb, specular_light_interp.rgb);
+ }
+ }
+
+ if (!sc_disable_spot_lights) {
+ uint light_indices = instances.data[draw_call.instance_index].spot_lights.x;
+ for (uint i = 0; i < 8; i++) {
+ uint light_index = light_indices & 0xFF;
+ if (i == 3) {
+ light_indices = instances.data[draw_call.instance_index].spot_lights.y;
+ } else {
+ light_indices = light_indices >> 8;
+ }
+
+ if (light_index == 0xFF) {
+ break;
+ }
+
+ light_process_spot_vertex(light_index, vertex, view, normal, roughness,
+ diffuse_light_interp.rgb, specular_light_interp.rgb);
+ }
+ }
+
+ if (!sc_disable_directional_lights) {
+ // We process the first directional light separately as it may have shadows.
+ vec3 directional_diffuse = vec3(0.0);
+ vec3 directional_specular = vec3(0.0);
+
+ for (uint i = 0; i < scene_data.directional_light_count; i++) {
+ if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
+ continue; // Not masked, skip.
+ }
+
+ if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip.
+ }
+ if (i == 0) {
+ light_compute_vertex(normal, directional_lights.data[0].direction, view,
+ directional_lights.data[0].color * directional_lights.data[0].energy,
+ true, roughness,
+ directional_diffuse,
+ directional_specular);
+ } else {
+ light_compute_vertex(normal, directional_lights.data[i].direction, view,
+ directional_lights.data[i].color * directional_lights.data[i].energy,
+ true, roughness,
+ diffuse_light_interp.rgb,
+ specular_light_interp.rgb);
+ }
+ }
+
+ // Calculate the contribution from the shadowed light so we can scale the shadows accordingly.
+ float diff_avg = dot(diffuse_light_interp.rgb, vec3(0.33333));
+ float diff_dir_avg = dot(directional_diffuse, vec3(0.33333));
+ if (diff_avg > 0.0) {
+ diffuse_light_interp.a = diff_dir_avg / (diff_avg + diff_dir_avg);
+ } else {
+ diffuse_light_interp.a = 1.0;
+ }
+
+ diffuse_light_interp.rgb += directional_diffuse;
+
+ float spec_avg = dot(specular_light_interp.rgb, vec3(0.33333));
+ float spec_dir_avg = dot(directional_specular, vec3(0.33333));
+ if (spec_avg > 0.0) {
+ specular_light_interp.a = spec_dir_avg / (spec_avg + spec_dir_avg);
+ } else {
+ specular_light_interp.a = 1.0;
+ }
+
+ specular_light_interp.rgb += directional_specular;
+ }
+
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
+
#ifdef MODE_RENDER_DEPTH
#ifdef MODE_DUAL_PARABOLOID
@@ -564,6 +675,11 @@ layout(location = 5) mediump in vec3 tangent_interp;
layout(location = 6) mediump in vec3 binormal_interp;
#endif
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
+layout(location = 7) highp in vec4 diffuse_light_interp;
+layout(location = 8) highp in vec4 specular_light_interp;
+#endif
+
#ifdef MODE_DUAL_PARABOLOID
layout(location = 9) highp in float dp_clip;
@@ -709,7 +825,7 @@ layout(location = 0) out mediump vec4 frag_color;
#include "../scene_forward_aa_inc.glsl"
-#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) // && !defined(USE_VERTEX_LIGHTING)
// Default to SPECULAR_SCHLICK_GGX.
#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON)
@@ -718,7 +834,7 @@ layout(location = 0) out mediump vec4 frag_color;
#include "../scene_forward_lights_inc.glsl"
-#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && !defined(USE_VERTEX_LIGHTING)
#ifndef MODE_RENDER_DEPTH
@@ -1401,6 +1517,10 @@ void main() {
// LIGHTING
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+#ifdef USE_VERTEX_LIGHTING
+ diffuse_light += diffuse_light_interp.rgb;
+ specular_light += specular_light_interp.rgb * f0;
+#endif
if (!sc_disable_directional_lights) { //directional light
#ifndef SHADOWS_DISABLED
@@ -1408,10 +1528,12 @@ void main() {
uint shadow0 = 0;
uint shadow1 = 0;
- for (uint i = 0; i < 8; i++) {
- if (i >= scene_data.directional_light_count) {
- break;
- }
+#ifdef USE_VERTEX_LIGHTING
+ // Only process the first light's shadow for vertex lighting.
+ for (uint i = 0; i < 1; i++) {
+#else
+ for (uint i = 0; i < scene_data.directional_light_count; i++) {
+#endif
if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
continue; //not masked
@@ -1419,164 +1541,6 @@ void main() {
float shadow = 1.0;
- // Directional light shadow code is basically the same as forward clustered at this point in time minus `LIGHT_TRANSMITTANCE_USED` support.
- // Not sure if there is a reason to change this seeing directional lights are part of our global data
- // Should think about whether we may want to move this code into an include file or function??
-
-#ifdef USE_SOFT_SHADOWS
- //version with soft shadows, more expensive
- if (directional_lights.data[i].shadow_opacity > 0.001) {
- float depth_z = -vertex.z;
-
- vec4 pssm_coord;
- vec3 light_dir = directional_lights.data[i].direction;
-
-#define BIAS_FUNC(m_var, m_idx) \
- m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
- vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))) * directional_lights.data[i].shadow_normal_bias[m_idx]; \
- normal_bias -= light_dir * dot(light_dir, normal_bias); \
- m_var.xyz += normal_bias;
-
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 0)
-
- pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
- pssm_coord /= pssm_coord.w;
-
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.x;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius;
- shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count);
- }
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 1)
-
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_coord /= pssm_coord.w;
-
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.y;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
- shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count);
- }
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 2)
-
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_coord /= pssm_coord.w;
-
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.z;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
- shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count);
- }
- } else {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 3)
-
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_coord /= pssm_coord.w;
-
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.w;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
- shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count);
- }
- }
-
- if (directional_lights.data[i].blend_splits) {
- float pssm_blend;
- float shadow2;
-
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 1)
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_coord /= pssm_coord.w;
-
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.y;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
- shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
- } else {
- shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count);
- }
-
- pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 2)
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_coord /= pssm_coord.w;
-
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.z;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
- shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
- } else {
- shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count);
- }
-
- pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 3)
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.w;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
- shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale, scene_data.taa_frame_count);
- } else {
- shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord, scene_data.taa_frame_count);
- }
-
- pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
- } else {
- pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
- }
-
- pssm_blend = sqrt(pssm_blend);
-
- shadow = mix(shadow, shadow2, pssm_blend);
- }
-
- shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
-
-#undef BIAS_FUNC
- }
-#else
- // Soft shadow disabled version
-
if (directional_lights.data[i].shadow_opacity > 0.001) {
float depth_z = -vertex.z;
@@ -1667,6 +1631,10 @@ void main() {
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
+#ifdef USE_VERTEX_LIGHTING
+ diffuse_light *= mix(1.0, shadow, diffuse_light_interp.a);
+ specular_light *= mix(1.0, shadow, specular_light_interp.a);
+#endif
#undef BIAS_FUNC
}
#endif
@@ -1678,13 +1646,8 @@ void main() {
}
}
-#endif // SHADOWS_DISABLED
-
- for (uint i = 0; i < 8; i++) {
- if (i >= scene_data.directional_light_count) {
- break;
- }
-
+#ifndef USE_VERTEX_LIGHTING
+ for (uint i = 0; i < scene_data.directional_light_count; i++) {
if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
continue; //not masked
}
@@ -1703,8 +1666,8 @@ void main() {
#endif
blur_shadow(shadow);
-#ifdef DEBUG_DRAW_PSSM_SPLITS
vec3 tint = vec3(1.0);
+#ifdef DEBUG_DRAW_PSSM_SPLITS
if (-vertex.z < directional_lights.data[i].shadow_split_offsets.x) {
tint = vec3(1.0, 0.0, 0.0);
} else if (-vertex.z < directional_lights.data[i].shadow_split_offsets.y) {
@@ -1718,12 +1681,10 @@ void main() {
shadow = 1.0;
#endif
- light_compute(normal, directional_lights.data[i].direction, normalize(view), 0.0,
-#ifndef DEBUG_DRAW_PSSM_SPLITS
- directional_lights.data[i].color * directional_lights.data[i].energy,
-#else
+ float size_A = sc_use_light_soft_shadows ? directional_lights.data[i].size : 0.0;
+
+ light_compute(normal, directional_lights.data[i].direction, view, size_A,
directional_lights.data[i].color * directional_lights.data[i].energy * tint,
-#endif
true, shadow, f0, orms, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
@@ -1745,14 +1706,13 @@ void main() {
#ifdef LIGHT_ANISOTROPY_USED
binormal, tangent, anisotropy,
#endif
-#ifdef USE_SOFT_SHADOW
- directional_lights.data[i].size,
-#endif
diffuse_light,
specular_light);
}
+#endif // USE_VERTEX_LIGHTING
} //directional light
+#ifndef USE_VERTEX_LIGHTING
if (!sc_disable_omni_lights) { //omni lights
uint light_indices = instances.data[draw_call.instance_index].omni_lights.x;
for (uint i = 0; i < 8; i++) {
@@ -1771,6 +1731,7 @@ void main() {
shadow = blur_shadow(shadow);
+ // Fragment lighting
light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
@@ -1841,6 +1802,9 @@ void main() {
diffuse_light, specular_light);
}
} //spot lights
+#endif // !VERTEX_LIGHTING
+
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
#ifdef USE_SHADOW_TO_OPACITY
#ifndef MODE_RENDER_DEPTH
@@ -1855,8 +1819,6 @@ void main() {
#endif // !MODE_RENDER_DEPTH
#endif // USE_SHADOW_TO_OPACITY
-#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
-
#ifdef MODE_RENDER_DEPTH
#ifdef MODE_RENDER_MATERIAL
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_vertex_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_vertex_lights_inc.glsl
new file mode 100644
index 0000000000..e962c8f7f3
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_vertex_lights_inc.glsl
@@ -0,0 +1,82 @@
+// Simplified versions of light functions intended for the vertex shader.
+
+// Eyeballed approximation of `exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25`.
+// Uses slightly more FMA instructions (2x rate) to avoid special instructions (0.25x rate).
+// Range is reduced to [0.64,4977] from [068,2,221,528] which makes mediump feasible for the rest of the shader.
+mediump float roughness_to_shininess(mediump float roughness) {
+ mediump float r = 1.2 - roughness;
+ mediump float r2 = r * r;
+ return r * r2 * r2 * 2000.0;
+}
+
+void light_compute_vertex(vec3 N, vec3 L, vec3 V, vec3 light_color, bool is_directional, float roughness,
+ inout vec3 diffuse_light, inout vec3 specular_light) {
+ float NdotL = min(dot(N, L), 1.0);
+ float cNdotL = max(NdotL, 0.0); // clamped NdotL
+
+#if defined(DIFFUSE_LAMBERT_WRAP)
+ // Energy conserving lambert wrap shader.
+ // https://web.archive.org/web/20210228210901/http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/
+ float diffuse_brdf_NL = max(0.0, (cNdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))) * (1.0 / M_PI);
+#else
+ // lambert
+ float diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
+#endif
+
+ diffuse_light += light_color * diffuse_brdf_NL;
+
+#if !defined(SPECULAR_DISABLED)
+ float specular_brdf_NL = 0.0;
+ // Normalized blinn always unless disabled.
+ vec3 H = normalize(V + L);
+ float cNdotH = clamp(dot(N, H), 0.0, 1.0);
+ float shininess = roughness_to_shininess(roughness);
+ float blinn = pow(cNdotH, shininess);
+ blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI)) * cNdotL;
+ specular_brdf_NL = blinn;
+ specular_light += specular_brdf_NL * light_color;
+#endif
+}
+
+float get_omni_attenuation(float distance, float inv_range, float decay) {
+ float nd = distance * inv_range;
+ nd *= nd;
+ nd *= nd; // nd^4
+ nd = max(1.0 - nd, 0.0);
+ nd *= nd; // nd^2
+ return nd * pow(max(distance, 0.0001), -decay);
+}
+
+void light_process_omni_vertex(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness,
+ inout vec3 diffuse_light, inout vec3 specular_light) {
+ vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation);
+ vec3 color = omni_lights.data[idx].color * omni_attenuation;
+
+ light_compute_vertex(normal, normalize(light_rel_vec), eye_vec, color, false, roughness,
+ diffuse_light,
+ specular_light);
+}
+
+void light_process_spot_vertex(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness,
+ inout vec3 diffuse_light,
+ inout vec3 specular_light) {
+ vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation);
+ vec3 spot_dir = spot_lights.data[idx].direction;
+
+ // This conversion to a highp float is crucial to prevent light leaking
+ // due to precision errors in the following calculations (cone angle is mediump).
+ highp float cone_angle = spot_lights.data[idx].cone_angle;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), cone_angle);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cone_angle));
+
+ spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation);
+ vec3 color = spot_lights.data[idx].color * spot_attenuation;
+ float specular_amount = spot_lights.data[idx].specular_amount;
+
+ light_compute_vertex(normal, normalize(light_rel_vec), eye_vec, color, false, roughness,
+ diffuse_light, specular_light);
+}
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index e5a8dbb9b2..84e8d1d671 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -40,25 +40,12 @@ using namespace RendererRD;
///////////////////////////////////////////////////////////////////////////
// TextureStorage::CanvasTexture
-void TextureStorage::CanvasTexture::clear_sets() {
- if (cleared_cache) {
- return;
- }
- for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
- for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
- for (int k = 0; k < 2; k++) {
- if (RD::get_singleton()->uniform_set_is_valid(uniform_sets[i][j][k])) {
- RD::get_singleton()->free(uniform_sets[i][j][k]);
- uniform_sets[i][j][k] = RID();
- }
- }
- }
- }
- cleared_cache = true;
+void TextureStorage::CanvasTexture::clear_cache() {
+ info_cache[0] = CanvasTextureCache();
+ info_cache[1] = CanvasTextureCache();
}
TextureStorage::CanvasTexture::~CanvasTexture() {
- clear_sets();
}
///////////////////////////////////////////////////////////////////////////
@@ -612,8 +599,7 @@ void TextureStorage::canvas_texture_set_channel(RID p_canvas_texture, RS::Canvas
ct->specular = p_texture;
} break;
}
-
- ct->clear_sets();
+ ct->clear_cache();
}
void TextureStorage::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) {
@@ -624,7 +610,6 @@ void TextureStorage::canvas_texture_set_shading_parameters(RID p_canvas_texture,
ct->specular_color.g = p_specular_color.g;
ct->specular_color.b = p_specular_color.b;
ct->specular_color.a = p_shininess;
- ct->clear_sets();
}
void TextureStorage::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) {
@@ -632,7 +617,6 @@ void TextureStorage::canvas_texture_set_texture_filter(RID p_canvas_texture, RS:
ERR_FAIL_NULL(ct);
ct->texture_filter = p_filter;
- ct->clear_sets();
}
void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) {
@@ -640,17 +624,14 @@ void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS:
ERR_FAIL_NULL(ct);
ct->texture_repeat = p_repeat;
- ct->clear_sets();
}
-bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular, bool p_texture_is_data) {
+TextureStorage::CanvasTextureInfo TextureStorage::canvas_texture_get_info(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, bool p_use_srgb, bool p_texture_is_data) {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
CanvasTexture *ct = nullptr;
Texture *t = get_texture(p_texture);
- // TODO once we have our texture storage split off we'll look into moving this code into canvas_texture
-
if (t) {
//regular texture
if (!t->canvas_texture) {
@@ -667,93 +648,71 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte
}
if (!ct) {
- return false; //invalid texture RID
+ return CanvasTextureInfo(); //invalid texture RID
}
RS::CanvasItemTextureFilter filter = ct->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? ct->texture_filter : p_base_filter;
- ERR_FAIL_COND_V(filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, false);
+ ERR_FAIL_COND_V(filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasTextureInfo());
RS::CanvasItemTextureRepeat repeat = ct->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? ct->texture_repeat : p_base_repeat;
- ERR_FAIL_COND_V(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, false);
+ ERR_FAIL_COND_V(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, CanvasTextureInfo());
- RID uniform_set = ct->uniform_sets[filter][repeat][int(p_use_srgb)];
- if (!RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- //create and update
- Vector<RD::Uniform> uniforms;
+ CanvasTextureCache &ctc = ct->info_cache[int(p_use_srgb)];
+ if (!RD::get_singleton()->texture_is_valid(ctc.diffuse) ||
+ !RD::get_singleton()->texture_is_valid(ctc.normal) ||
+ !RD::get_singleton()->texture_is_valid(ctc.specular)) {
{ //diffuse
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
-
t = get_texture(ct->diffuse);
if (!t) {
- u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE));
+ ctc.diffuse = texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
ct->size_cache = Size2i(1, 1);
} else {
- u.append_id(t->rd_texture_srgb.is_valid() && p_use_srgb && !p_texture_is_data ? t->rd_texture_srgb : t->rd_texture);
+ ctc.diffuse = t->rd_texture_srgb.is_valid() && p_use_srgb && !p_texture_is_data ? t->rd_texture_srgb : t->rd_texture;
ct->size_cache = Size2i(t->width_2d, t->height_2d);
if (t->render_target) {
t->render_target->was_used = true;
}
}
- uniforms.push_back(u);
}
{ //normal
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1;
-
t = get_texture(ct->normal_map);
if (!t) {
- u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL));
+ ctc.normal = texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
ct->use_normal_cache = false;
} else {
- u.append_id(t->rd_texture);
+ ctc.normal = t->rd_texture;
ct->use_normal_cache = true;
if (t->render_target) {
t->render_target->was_used = true;
}
}
- uniforms.push_back(u);
}
{ //specular
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 2;
-
t = get_texture(ct->specular);
if (!t) {
- u.append_id(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE));
+ ctc.specular = texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
ct->use_specular_cache = false;
} else {
- u.append_id(t->rd_texture);
+ ctc.specular = t->rd_texture;
ct->use_specular_cache = true;
if (t->render_target) {
t->render_target->was_used = true;
}
}
- uniforms.push_back(u);
}
- { //sampler
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 3;
- u.append_id(material_storage->sampler_rd_get_default(filter, repeat));
- uniforms.push_back(u);
- }
-
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, p_base_set);
- ct->uniform_sets[filter][repeat][int(p_use_srgb)] = uniform_set;
- ct->cleared_cache = false;
}
- r_uniform_set = uniform_set;
- r_size = ct->size_cache;
- r_specular_shininess = ct->specular_color;
- r_use_normal = ct->use_normal_cache;
- r_use_specular = ct->use_specular_cache;
+ CanvasTextureInfo res;
+ res.diffuse = ctc.diffuse;
+ res.normal = ctc.normal;
+ res.specular = ctc.specular;
+ res.sampler = material_storage->sampler_rd_get_default(filter, repeat);
+ res.size = ct->size_cache;
+ res.specular_color = ct->specular_color;
+ res.use_normal = ct->use_normal_cache;
+ res.use_specular = ct->use_specular_cache;
- return true;
+ return res;
}
/* Texture API */
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index 9de4ff7b6b..8aecc78f07 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -76,6 +76,21 @@ public:
TYPE_3D
};
+ struct CanvasTextureInfo {
+ RID diffuse;
+ RID normal;
+ RID specular;
+ RID sampler;
+ Size2i size;
+ Color specular_color;
+
+ bool use_normal = false;
+ bool use_specular = false;
+
+ _FORCE_INLINE_ bool is_valid() const { return diffuse.is_valid(); }
+ _FORCE_INLINE_ bool is_null() const { return diffuse.is_null(); }
+ };
+
private:
friend class LightStorage;
friend class MaterialStorage;
@@ -86,6 +101,12 @@ private:
/* Canvas Texture API */
+ struct CanvasTextureCache {
+ RID diffuse = RID();
+ RID normal = RID();
+ RID specular = RID();
+ };
+
class CanvasTexture {
public:
RID diffuse;
@@ -96,14 +117,14 @@ private:
RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
- RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX][2];
+ CanvasTextureCache info_cache[2];
Size2i size_cache = Size2i(1, 1);
bool use_normal_cache = false;
bool use_specular_cache = false;
bool cleared_cache = true;
- void clear_sets();
+ void clear_cache();
~CanvasTexture();
};
@@ -477,7 +498,7 @@ public:
virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override;
virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override;
- bool canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, bool p_use_srgb, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular, bool p_texture_is_data);
+ CanvasTextureInfo canvas_texture_get_info(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, bool p_use_srgb, bool p_texture_is_data);
/* Texture API */
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 0ad56961c0..5c85080298 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -3580,8 +3580,7 @@ void RenderingServer::init() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/global_illumination/voxel_gi/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)"), 0);
- GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading", false);
- GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading.mobile", true);
+ GLOBAL_DEF_RST("rendering/shading/overrides/force_vertex_shading", false);
GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley", false);
GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley.mobile", true);