diff options
author | ywmaa <ywmaa.personal@gmail.com> | 2023-10-15 03:48:52 +0300 |
---|---|---|
committer | Rémi Verschelde <rverschelde@gmail.com> | 2024-09-29 00:36:09 +0200 |
commit | 0a9ad8f9de825a14d112d9ebd0674a9c82f56e12 (patch) | |
tree | 38101f70d58a0f69b12b8c11eb068833fe4bc356 /drivers | |
parent | 76a135926aef1f02f27e4e09093787f2c670956d (diff) | |
download | redot-engine-0a9ad8f9de825a14d112d9ebd0674a9c82f56e12.tar.gz |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gles3/rasterizer_scene_gles3.cpp | 3 | ||||
-rw-r--r-- | drivers/gles3/shaders/scene.glsl | 289 | ||||
-rw-r--r-- | drivers/gles3/storage/config.cpp | 2 | ||||
-rw-r--r-- | drivers/gles3/storage/material_storage.cpp | 4 |
4 files changed, 287 insertions, 11 deletions
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; |