diff options
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); |