Implement vertex shading

This adds support in all backends, but the Compatibility renderer works the best.
Mobile and Forward+ can only support one directional light shader (the first in the tree)
While the Compatibility renderer supports any number of shadows.

Co-authored-by: Clay John <claynjohn@gmail.com>
This commit is contained in:
ywmaa 2023-10-15 03:48:52 +03:00 committed by Rémi Verschelde
parent 76a135926a
commit 0a9ad8f9de
No known key found for this signature in database
GPG Key ID: C3336907360768E1
14 changed files with 725 additions and 207 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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"));

View File

@ -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;

View File

@ -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" },

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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";

View File

@ -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

View File

@ -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,
@ -1744,15 +1705,14 @@ void main() {
#endif
#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

View File

@ -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);
}

View File

@ -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);