diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index 16c378dcedd..77b6bb68173 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -120,6 +120,15 @@ Texture used to control the backlight effect per-pixel. Added to [member backlight]. + + If [code]true[/code], the bent normal map is enabled. This allows for more accurate indirect lighting and specular occlusion. + + + Texture that specifies the average direction of incoming ambient light at a given pixel. The [member bent_normal_texture] only uses the red and green channels; the blue and alpha channels are ignored. The normal read from [member bent_normal_texture] is oriented around the surface normal provided by the [Mesh]. + [b]Note:[/b] A bent normal map is different from a regular normal map. When baking a bent normal map make sure to use [b]a cosine distribution[/b] for the bent normal map to work correctly. + [b]Note:[/b] The mesh must have both normals and tangents defined in its vertex data. Otherwise, the shading produced by the bent normal map will not look correct. If creating geometry with [SurfaceTool], you can use [method SurfaceTool.generate_normals] and [method SurfaceTool.generate_tangents] to automatically generate normals and tangents respectively. + [b]Note:[/b] Godot expects the bent normal map to use X+, Y+, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines. + If [code]true[/code], the shader will keep the scale set for the mesh. Otherwise, the scale is lost when billboarding. Only applies when [member billboard_mode] is not [constant BILLBOARD_DISABLED]. @@ -461,6 +470,9 @@ Texture specifying per-pixel normal vector. + + Texture specifying per-pixel bent normal vector. + Texture specifying per-pixel rim value. @@ -500,7 +512,7 @@ Texture holding ambient occlusion, roughness, and metallic. - + Represents the size of the [enum TextureParam] enum. @@ -596,7 +608,10 @@ Constant for setting [member detail_enabled]. - + + Constant for setting [member bent_normal_enabled]. + + Represents the size of the [enum Feature] enum. diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index cde6f80735a..0ff75bf7640 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1842,6 +1842,10 @@ void main() { vec3 normal_map = vec3(0.5); #endif +#if defined(BENT_NORMAL_MAP_USED) + vec3 bent_normal_map = vec3(0.5); +#endif + float normal_map_depth = 1.0; vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size; diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index 75f1edb4a26..e8d38a41f74 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -1253,6 +1253,7 @@ MaterialStorage::MaterialStorage() { actions.renames["FRONT_FACING"] = "gl_FrontFacing"; actions.renames["NORMAL_MAP"] = "normal_map"; actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; + actions.renames["BENT_NORMAL_MAP"] = "bent_normal_map"; actions.renames["ALBEDO"] = "albedo"; actions.renames["ALPHA"] = "alpha"; actions.renames["PREMUL_ALPHA_FACTOR"] = "premul_alpha"; @@ -1330,6 +1331,7 @@ MaterialStorage::MaterialStorage() { actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n"; actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; + actions.usage_defines["BENT_NORMAL_MAP"] = "#define BENT_NORMAL_MAP_USED\n"; actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; @@ -2904,6 +2906,7 @@ void SceneShaderData::set_code(const String &p_code) { uses_screen_texture_mipmaps = false; uses_depth_texture = false; uses_normal_texture = false; + uses_bent_normal_texture = false; uses_time = false; uses_vertex_time = false; uses_fragment_time = false; @@ -2977,6 +2980,7 @@ void SceneShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; actions.usage_flag_pointers["NORMAL"] = &uses_normal; actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal; + actions.usage_flag_pointers["BENT_NORMAL_MAP"] = &uses_bent_normal_texture; actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h index 0d7fc215eb4..28097411d79 100644 --- a/drivers/gles3/storage/material_storage.h +++ b/drivers/gles3/storage/material_storage.h @@ -305,6 +305,7 @@ struct SceneShaderData : public ShaderData { bool uses_screen_texture_mipmaps; bool uses_depth_texture; bool uses_normal_texture; + bool uses_bent_normal_texture; bool uses_time; bool uses_vertex_time; bool uses_fragment_time; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 206cac213de..de5bee6b623 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -646,6 +646,7 @@ void BaseMaterial3D::init_shaders() { shader_names->texture_names[TEXTURE_ROUGHNESS] = "texture_roughness"; shader_names->texture_names[TEXTURE_EMISSION] = "texture_emission"; shader_names->texture_names[TEXTURE_NORMAL] = "texture_normal"; + shader_names->texture_names[TEXTURE_BENT_NORMAL] = "texture_bent_normal"; shader_names->texture_names[TEXTURE_RIM] = "texture_rim"; shader_names->texture_names[TEXTURE_CLEARCOAT] = "texture_clearcoat"; shader_names->texture_names[TEXTURE_FLOWMAP] = "texture_flowmap"; @@ -1022,6 +1023,12 @@ uniform vec4 refraction_texture_channel; code += vformat(R"( uniform sampler2D texture_normal : hint_roughness_normal, %s; uniform float normal_scale : hint_range(-16.0, 16.0); +)", + texfilter_str); + } + if (features[FEATURE_BENT_NORMAL_MAPPING]) { + code += vformat(R"( +uniform sampler2D texture_bent_normal : hint_roughness_normal, %s; )", texfilter_str); } @@ -1641,6 +1648,13 @@ void fragment() {)"; code += " NORMAL_MAP_DEPTH = normal_scale;\n"; } + if (features[FEATURE_BENT_NORMAL_MAPPING]) { + code += R"( + // Bent Normal Map: Enabled + BENT_NORMAL_MAP = texture(texture_bent_normal, base_uv).rgb; +)"; + } + if (features[FEATURE_EMISSION]) { code += R"( // Emission: Enabled @@ -2440,6 +2454,7 @@ void BaseMaterial3D::_validate_feature(const String &text, Feature feature, Prop void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const { _validate_feature("normal", FEATURE_NORMAL_MAPPING, p_property); + _validate_feature("bent_normal", FEATURE_BENT_NORMAL_MAPPING, p_property); _validate_feature("emission", FEATURE_EMISSION, p_property); _validate_feature("rim", FEATURE_RIM, p_property); _validate_feature("clearcoat", FEATURE_CLEARCOAT, p_property); @@ -2585,6 +2600,10 @@ void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const { p_property.usage = PROPERTY_USAGE_NONE; } + if (p_property.name.begins_with("bent_normal")) { + p_property.usage = PROPERTY_USAGE_NONE; + } + if (p_property.name.begins_with("backlight")) { p_property.usage = PROPERTY_USAGE_NONE; } @@ -3251,6 +3270,10 @@ void BaseMaterial3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_scale", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_normal_scale", "get_normal_scale"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_NORMAL); + ADD_GROUP("Bent Normal Map", "bent_normal_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "bent_normal_enabled", PROPERTY_HINT_GROUP_ENABLE), "set_feature", "get_feature", FEATURE_BENT_NORMAL_MAPPING); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "bent_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_BENT_NORMAL); + ADD_GROUP("Rim", "rim_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "rim_enabled", PROPERTY_HINT_GROUP_ENABLE), "set_feature", "get_feature", FEATURE_RIM); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rim", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_rim", "get_rim"); @@ -3377,6 +3400,7 @@ void BaseMaterial3D::_bind_methods() { BIND_ENUM_CONSTANT(TEXTURE_ROUGHNESS); BIND_ENUM_CONSTANT(TEXTURE_EMISSION); BIND_ENUM_CONSTANT(TEXTURE_NORMAL); + BIND_ENUM_CONSTANT(TEXTURE_BENT_NORMAL); BIND_ENUM_CONSTANT(TEXTURE_RIM); BIND_ENUM_CONSTANT(TEXTURE_CLEARCOAT); BIND_ENUM_CONSTANT(TEXTURE_FLOWMAP); @@ -3427,6 +3451,7 @@ void BaseMaterial3D::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_BACKLIGHT); BIND_ENUM_CONSTANT(FEATURE_REFRACTION); BIND_ENUM_CONSTANT(FEATURE_DETAIL); + BIND_ENUM_CONSTANT(FEATURE_BENT_NORMAL_MAPPING); BIND_ENUM_CONSTANT(FEATURE_MAX); BIND_ENUM_CONSTANT(BLEND_MODE_MIX); diff --git a/scene/resources/material.h b/scene/resources/material.h index d9487769502..17f14d51bea 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -162,8 +162,8 @@ public: TEXTURE_DETAIL_ALBEDO, TEXTURE_DETAIL_NORMAL, TEXTURE_ORM, + TEXTURE_BENT_NORMAL, TEXTURE_MAX - }; enum TextureFilter { @@ -218,6 +218,7 @@ public: FEATURE_BACKLIGHT, FEATURE_REFRACTION, FEATURE_DETAIL, + FEATURE_BENT_NORMAL_MAPPING, FEATURE_MAX }; diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 883b33efc3b..733771df29d 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -3977,6 +3977,8 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal Map", "NORMAL_MAP" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Normal Map Depth", "NORMAL_MAP_DEPTH" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Bent Normal Map", "BENT_NORMAL_MAP" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Rim", "RIM" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Rim Tint", "RIM_TINT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Clearcoat", "CLEARCOAT" }, 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 f13f364f3c1..cbd5bb9f09a 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 @@ -67,6 +67,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { uses_normal = false; uses_tangent = false; uses_normal_map = false; + uses_bent_normal_map = false; wireframe = false; unshaded = false; @@ -125,6 +126,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; actions.usage_flag_pointers["NORMAL"] = &uses_normal; actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal_map; + actions.usage_flag_pointers["BENT_NORMAL_MAP"] = &uses_bent_normal_map; actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; @@ -169,7 +171,9 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { uses_vertex_time = gen_code.uses_vertex_time; uses_fragment_time = gen_code.uses_fragment_time; uses_normal |= uses_normal_map; + uses_normal |= uses_bent_normal_map; uses_tangent |= uses_normal_map; + uses_tangent |= uses_bent_normal_map; #if 0 print_line("**compiling shader:"); @@ -630,6 +634,7 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.renames["FRONT_FACING"] = "gl_FrontFacing"; actions.renames["NORMAL_MAP"] = "normal_map"; actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; + actions.renames["BENT_NORMAL_MAP"] = "bent_normal_map"; actions.renames["ALBEDO"] = "albedo"; actions.renames["ALPHA"] = "alpha"; actions.renames["PREMUL_ALPHA_FACTOR"] = "premul_alpha"; @@ -707,6 +712,7 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n"; actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; + actions.usage_defines["BENT_NORMAL_MAP"] = "#define BENT_NORMAL_MAP_USED\n"; actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index cc120b133f6..49fe869da62 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -228,6 +228,7 @@ public: bool uses_tangent = false; bool uses_particle_trails = false; bool uses_normal_map = false; + bool uses_bent_normal_map = false; bool wireframe = false; bool unshaded = false; 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 47250fd6aec..deecf91a120 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 @@ -69,6 +69,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { uses_normal = false; uses_tangent = false; uses_normal_map = false; + uses_bent_normal_map = false; wireframe = false; unshaded = false; @@ -126,6 +127,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; actions.usage_flag_pointers["NORMAL"] = &uses_normal; actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal_map; + actions.usage_flag_pointers["BENT_NORMAL_MAP"] = &uses_bent_normal_map; actions.usage_flag_pointers["TANGENT"] = &uses_tangent; actions.usage_flag_pointers["BINORMAL"] = &uses_tangent; @@ -165,7 +167,9 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { uses_depth_texture = gen_code.uses_depth_texture; uses_normal_texture = gen_code.uses_normal_roughness_texture; uses_normal |= uses_normal_map; + uses_normal |= uses_bent_normal_map; uses_tangent |= uses_normal_map; + uses_tangent |= uses_bent_normal_map; #ifdef DEBUG_ENABLED if (uses_sss) { @@ -563,6 +567,7 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.renames["FRONT_FACING"] = "gl_FrontFacing"; actions.renames["NORMAL_MAP"] = "normal_map"; actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; + actions.renames["BENT_NORMAL_MAP"] = "bent_normal_map"; actions.renames["ALBEDO"] = "albedo"; actions.renames["ALPHA"] = "alpha"; actions.renames["PREMUL_ALPHA_FACTOR"] = "premul_alpha"; @@ -640,6 +645,7 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n"; actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; + actions.usage_defines["BENT_NORMAL_MAP"] = "#define BENT_NORMAL_MAP_USED\n"; actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 960c2872f51..a4dd35ba4b5 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -217,6 +217,7 @@ public: bool uses_tangent = false; bool uses_particle_trails = false; bool uses_normal_map = false; + bool uses_bent_normal_map = false; bool wireframe = false; bool unshaded = false; 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 dc762e43d9e..2dc86623eff 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 @@ -1201,6 +1201,11 @@ void fragment_shader(in SceneData scene_data) { vec3 normal_map = vec3(0.5); #endif +#if defined(BENT_NORMAL_MAP_USED) + vec3 bent_normal_vector = vec3(0.5); + vec3 bent_normal_map = vec3(0.5); +#endif + float normal_map_depth = 1.0; vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size; @@ -1331,6 +1336,13 @@ void fragment_shader(in SceneData scene_data) { normal = geo_normal; #endif // NORMAL_MAP_USED +#ifdef BENT_NORMAL_MAP_USED + bent_normal_map.xy = bent_normal_map.xy * 2.0 - 1.0; + bent_normal_map.z = sqrt(max(0.0, 1.0 - dot(bent_normal_map.xy, bent_normal_map.xy))); + + bent_normal_vector = normalize(tangent * bent_normal_map.x + binormal * bent_normal_map.y + normal * bent_normal_map.z); +#endif + #ifdef LIGHT_ANISOTROPY_USED if (anisotropy > 0.01) { @@ -1543,7 +1555,8 @@ void fragment_shader(in SceneData scene_data) { #endif //apply energy conservation - vec3 specular_light = vec3(0.0, 0.0, 0.0); + vec3 direct_specular_light = vec3(0.0, 0.0, 0.0); + vec3 indirect_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 @@ -1554,6 +1567,12 @@ void fragment_shader(in SceneData scene_data) { #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) #ifndef AMBIENT_LIGHT_DISABLED +// Use bent normal for indirect lighting where possible +#ifdef BENT_NORMAL_MAP_USED + vec3 indirect_normal = bent_normal_vector; +#else + vec3 indirect_normal = normal; +#endif if (scene_data.use_reflection_cubemap) { #ifdef LIGHT_ANISOTROPY_USED @@ -1571,25 +1590,26 @@ void fragment_shader(in SceneData scene_data) { float horizon = min(1.0 + dot(ref_vec, normal), 1.0); ref_vec = scene_data.radiance_inverse_xform * ref_vec; + #ifdef USE_RADIANCE_CUBEMAP_ARRAY float lod, blend; blend = modf(sqrt(roughness) * MAX_ROUGHNESS_LOD, lod); - specular_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb; - specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend); + indirect_specular_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb; + indirect_specular_light = mix(indirect_specular_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend); #else - specular_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb; + indirect_specular_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb; #endif //USE_RADIANCE_CUBEMAP_ARRAY - specular_light *= scene_data.IBL_exposure_normalization; - specular_light *= horizon * horizon; - specular_light *= scene_data.ambient_light_color_energy.a; + indirect_specular_light *= scene_data.IBL_exposure_normalization; + indirect_specular_light *= horizon * horizon; + indirect_specular_light *= scene_data.ambient_light_color_energy.a; } #if defined(CUSTOM_RADIANCE_USED) - specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a); + indirect_specular_light = mix(indirect_specular_light, custom_radiance.rgb, custom_radiance.a); #endif #ifndef USE_LIGHTMAP @@ -1598,7 +1618,7 @@ void fragment_shader(in SceneData scene_data) { ambient_light = scene_data.ambient_light_color_energy.rgb; if (scene_data.use_ambient_cubemap) { - vec3 ambient_dir = scene_data.radiance_inverse_xform * normal; + vec3 ambient_dir = scene_data.radiance_inverse_xform * indirect_normal; #ifdef USE_RADIANCE_CUBEMAP_ARRAY vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb; #else @@ -1623,9 +1643,9 @@ void fragment_shader(in SceneData scene_data) { float Fc = clearcoat * (0.04 + 0.96 * SchlickFresnel(NoV)); float attenuation = 1.0 - Fc; ambient_light *= attenuation; - specular_light *= attenuation; + indirect_specular_light *= attenuation; - float horizon = min(1.0 + dot(ref_vec, normal), 1.0); + float horizon = min(1.0 + dot(ref_vec, indirect_normal), 1.0); ref_vec = scene_data.radiance_inverse_xform * ref_vec; float roughness_lod = mix(0.001, 0.1, sqrt(clearcoat_roughness)) * MAX_ROUGHNESS_LOD; #ifdef USE_RADIANCE_CUBEMAP_ARRAY @@ -1639,7 +1659,7 @@ void fragment_shader(in SceneData scene_data) { vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, roughness_lod).rgb; #endif //USE_RADIANCE_CUBEMAP_ARRAY - specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a; + indirect_specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a; } #endif // LIGHT_CLEARCOAT_USED #endif // !AMBIENT_LIGHT_DISABLED @@ -1657,7 +1677,7 @@ void fragment_shader(in SceneData scene_data) { uint index = instances.data[instance_index].gi_offset; // The world normal. - vec3 wnormal = mat3(scene_data.inv_view_matrix) * normal; + vec3 wnormal = mat3(scene_data.inv_view_matrix) * indirect_normal; // The SH coefficients used for evaluating diffuse data from SH probes. const float c[5] = float[]( @@ -1706,7 +1726,7 @@ void fragment_shader(in SceneData scene_data) { lm_light_l1p1 = (textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb - vec3(0.5)) * 2.0; } - vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal); + vec3 n = normalize(lightmaps.data[ofs].normal_xform * indirect_normal); float en = lightmaps.data[ofs].exposure_normalization; ambient_light += lm_light_l0 * en; @@ -1728,8 +1748,8 @@ void fragment_shader(in SceneData scene_data) { //make vertex orientation the world one, but still align to camera vec3 cam_pos = mat3(scene_data.inv_view_matrix) * vertex; - vec3 cam_normal = mat3(scene_data.inv_view_matrix) * normal; - vec3 cam_reflection = mat3(scene_data.inv_view_matrix) * reflect(-view, normal); + vec3 cam_normal = mat3(scene_data.inv_view_matrix) * indirect_normal; + vec3 cam_reflection = mat3(scene_data.inv_view_matrix) * reflect(-view, indirect_normal); //apply y-mult cam_pos.y *= sdfgi.y_mult; @@ -1775,7 +1795,7 @@ void fragment_shader(in SceneData scene_data) { if (cascade == sdfgi.max_cascades - 1) { diffuse = mix(diffuse, ambient_light, blend); if (use_specular) { - specular = mix(specular, specular_light, blend); + indirect_specular_light = mix(specular, indirect_specular_light, blend); } } else { vec3 diffuse2, specular2; @@ -1791,7 +1811,7 @@ void fragment_shader(in SceneData scene_data) { ambient_light = diffuse; if (use_specular) { - specular_light = specular; + indirect_specular_light = specular; } } } @@ -1800,8 +1820,8 @@ void fragment_shader(in SceneData scene_data) { uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; // Make vertex orientation the world one, but still align to camera. vec3 cam_pos = mat3(scene_data.inv_view_matrix) * vertex; - vec3 cam_normal = mat3(scene_data.inv_view_matrix) * normal; - vec3 ref_vec = mat3(scene_data.inv_view_matrix) * normalize(reflect(-view, normal)); + vec3 cam_normal = mat3(scene_data.inv_view_matrix) * indirect_normal; + vec3 ref_vec = mat3(scene_data.inv_view_matrix) * normalize(reflect(-view, indirect_normal)); //find arbitrary tangent and bitangent, then build a matrix vec3 v0 = abs(cam_normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); @@ -1811,12 +1831,12 @@ void fragment_shader(in SceneData scene_data) { vec4 amb_accum = vec4(0.0); vec4 spec_accum = vec4(0.0); - voxel_gi_compute(index1, cam_pos, cam_normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); + voxel_gi_compute(index1, cam_pos, cam_normal, ref_vec, normal_mat, roughness * roughness, ambient_light, indirect_specular_light, spec_accum, amb_accum); uint index2 = instances.data[instance_index].gi_offset >> 16; if (index2 != 0xFFFF) { - voxel_gi_compute(index2, cam_pos, cam_normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); + voxel_gi_compute(index2, cam_pos, cam_normal, ref_vec, normal_mat, roughness * roughness, ambient_light, indirect_specular_light, spec_accum, amb_accum); } if (amb_accum.a > 0.0) { @@ -1827,7 +1847,7 @@ void fragment_shader(in SceneData scene_data) { spec_accum.rgb /= spec_accum.a; } - specular_light = spec_accum.rgb; + indirect_specular_light = spec_accum.rgb; ambient_light = amb_accum.rgb; } @@ -1839,18 +1859,18 @@ void fragment_shader(in SceneData scene_data) { vec2 base_coord = screen_uv; vec2 closest_coord = base_coord; #ifdef USE_MULTIVIEW - float closest_ang = dot(normal, normalize(textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(base_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0)); + float closest_ang = dot(indirect_normal, normalize(textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(base_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0)); #else // USE_MULTIVIEW - float closest_ang = dot(normal, normalize(textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), base_coord, 0.0).xyz * 2.0 - 1.0)); + float closest_ang = dot(indirect_normal, normalize(textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), base_coord, 0.0).xyz * 2.0 - 1.0)); #endif // USE_MULTIVIEW for (int i = 0; i < 4; i++) { const vec2 neighbors[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1)); vec2 neighbour_coord = base_coord + neighbors[i] * scene_data.screen_pixel_size; #ifdef USE_MULTIVIEW - float neighbour_ang = dot(normal, normalize(textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(neighbour_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0)); + float neighbour_ang = dot(indirect_normal, normalize(textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(neighbour_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0)); #else // USE_MULTIVIEW - float neighbour_ang = dot(normal, normalize(textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), neighbour_coord, 0.0).xyz * 2.0 - 1.0)); + float neighbour_ang = dot(indirect_normal, normalize(textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), neighbour_coord, 0.0).xyz * 2.0 - 1.0)); #endif // USE_MULTIVIEW if (neighbour_ang > closest_ang) { closest_ang = neighbour_ang; @@ -1873,7 +1893,7 @@ void fragment_shader(in SceneData scene_data) { #endif // USE_MULTIVIEW ambient_light = mix(ambient_light, buffer_ambient.rgb, buffer_ambient.a); - specular_light = mix(specular_light, buffer_reflection.rgb, buffer_reflection.a); + indirect_specular_light = mix(indirect_specular_light, buffer_reflection.rgb, buffer_reflection.a); } #endif // !USE_LIGHTMAP @@ -1945,7 +1965,7 @@ void fragment_shader(in SceneData scene_data) { break; } - reflection_process(reflection_index, vertex, ref_vec, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); + reflection_process(reflection_index, vertex, ref_vec, normal, roughness, ambient_light, indirect_specular_light, ambient_accum, reflection_accum); } } @@ -1954,11 +1974,11 @@ void fragment_shader(in SceneData scene_data) { } if (reflection_accum.a < 1.0) { - reflection_accum.rgb = specular_light * (1.0 - reflection_accum.a) + reflection_accum.rgb; + reflection_accum.rgb = indirect_specular_light * (1.0 - reflection_accum.a) + reflection_accum.rgb; } if (reflection_accum.a > 0.0) { - specular_light = reflection_accum.rgb; + indirect_specular_light = reflection_accum.rgb; } #if !defined(USE_LIGHTMAP) @@ -1972,6 +1992,38 @@ void fragment_shader(in SceneData scene_data) { { ambient_light *= ao; #ifndef SPECULAR_OCCLUSION_DISABLED +#ifdef BENT_NORMAL_MAP_USED + // Apply cone to cone intersection with cosine weighted assumption: + // https://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf + float cos_a_v = sqrt(1.0 - ao); + float limited_roughness = max(roughness, 0.01); // Avoid artifacts at really low roughness. + float cos_a_s = exp2((-log(10.0) / log(2.0)) * limited_roughness * limited_roughness); + float cos_b = dot(bent_normal_vector, reflect(-view, normal)); + + // Intersection between the spherical caps of the visibility and specular cone. + // Based on Christopher Oat and Pedro V. Sander's "Ambient aperture lighting": + // https://advances.realtimerendering.com/s2006/Chapter8-Ambient_Aperture_Lighting.pdf + float r1 = acos(cos_a_v); + float r2 = acos(cos_a_s); + float d = acos(cos_b); + float area = 0.0; + + if (d <= max(r1, r2) - min(r1, r2)) { + // One cap is enclosed in the other. + area = M_TAU - M_TAU * max(cos_a_v, cos_a_s); + } else if (d >= r1 + r2) { + // No intersection. + area = 0.0; + } else { + float delta = abs(r1 - r2); + float x = 1.0 - clamp((d - delta) / (r1 + r2 - delta), 0.0, 1.0); + area = smoothstep(0.0, 1.0, x); + area *= M_TAU - M_TAU * max(cos_a_v, cos_a_s); + } + + float specular_occlusion = area / (M_TAU * (1.0 - cos_a_s)); + indirect_specular_light *= specular_occlusion; +#else // BENT_NORMAL_MAP_USED float specular_occlusion = (ambient_light.r * 0.3 + ambient_light.g * 0.59 + ambient_light.b * 0.11) * 2.0; // Luminance of ambient light. specular_occlusion = min(specular_occlusion * 4.0, 1.0); // This multiplication preserves speculars on bright areas. @@ -1979,7 +2031,8 @@ void fragment_shader(in SceneData scene_data) { // 10.0 is a magic number, it gives the intended effect in most scenarios. // Low enough for occlusion, high enough for reaction to lights and shadows. specular_occlusion = max(min(reflective_f * specular_occlusion * 10.0, 1.0), specular_occlusion); - specular_light *= specular_occlusion; + indirect_specular_light *= specular_occlusion; +#endif // BENT_NORMAL_MAP_USED #endif // SPECULAR_OCCLUSION_DISABLED ambient_light *= albedo.rgb; @@ -1994,6 +2047,7 @@ void fragment_shader(in SceneData scene_data) { } } #endif // AMBIENT_LIGHT_DISABLED + // convert ao to direct light ao ao = mix(1.0, ao, ao_light_affect); @@ -2003,7 +2057,7 @@ void fragment_shader(in SceneData scene_data) { { #if defined(DIFFUSE_TOON) //simplify for toon, as - specular_light *= specular * metallic * albedo * 2.0; + indirect_specular_light *= specular * metallic * albedo * 2.0; #else // Base Layer float NdotV = clamp(dot(normal, view), 0.0001, 1.0); @@ -2013,7 +2067,7 @@ void fragment_shader(in SceneData scene_data) { // cheap luminance approximation float f90 = clamp(50.0 * f0.g, metallic, 1.0); - specular_light *= energy_compensation * (f90 * envBRDF.x + f0 * envBRDF.y); + indirect_specular_light *= energy_compensation * (f90 * envBRDF.x + f0 * envBRDF.y); #endif } @@ -2030,7 +2084,7 @@ void fragment_shader(in SceneData scene_data) { #ifdef USE_VERTEX_LIGHTING diffuse_light += diffuse_light_interp.rgb; - specular_light += specular_light_interp.rgb * f0; + direct_specular_light += specular_light_interp.rgb * f0; #endif { // Directional light. @@ -2283,7 +2337,7 @@ void fragment_shader(in SceneData scene_data) { #ifdef USE_VERTEX_LIGHTING diffuse_light *= mix(1.0, shadow, diffuse_light_interp.a); - specular_light *= mix(1.0, shadow, specular_light_interp.a); + direct_specular_light *= mix(1.0, shadow, specular_light_interp.a); #endif #undef BIAS_FUNC @@ -2301,7 +2355,7 @@ void fragment_shader(in SceneData scene_data) { #ifdef USE_VERTEX_LIGHTING diffuse_light *= mix(1.0, shadowmask, diffuse_light_interp.a); - specular_light *= mix(1.0, shadowmask, specular_light_interp.a); + direct_specular_light *= mix(1.0, shadowmask, specular_light_interp.a); #endif shadow0 |= uint(clamp(shadowmask * 255.0, 0.0, 255.0)); @@ -2433,7 +2487,7 @@ void fragment_shader(in SceneData scene_data) { tangent, anisotropy, #endif diffuse_light, - specular_light); + direct_specular_light); } #endif // USE_VERTEX_LIGHTING } @@ -2501,7 +2555,7 @@ void fragment_shader(in SceneData scene_data) { #ifdef LIGHT_ANISOTROPY_USED tangent, binormal, anisotropy, #endif - diffuse_light, specular_light); + diffuse_light, direct_specular_light); } } } @@ -2570,7 +2624,7 @@ void fragment_shader(in SceneData scene_data) { tangent, binormal, anisotropy, #endif - diffuse_light, specular_light); + diffuse_light, direct_specular_light); } } } @@ -2746,8 +2800,8 @@ void fragment_shader(in SceneData scene_data) { // apply direct light AO ao = unpackUnorm4x8(orms).x; - specular_light *= ao; diffuse_light *= ao; + direct_specular_light *= ao; // apply metallic metallic = unpackUnorm4x8(orms).z; @@ -2771,7 +2825,7 @@ void fragment_shader(in SceneData scene_data) { sss_strength = -sss_strength; #endif diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength); - specular_buffer = vec4(specular_light, metallic); + specular_buffer = vec4(direct_specular_light + indirect_specular_light, metallic); #endif #ifndef FOG_DISABLED @@ -2786,7 +2840,7 @@ void fragment_shader(in SceneData scene_data) { #ifdef MODE_UNSHADED frag_color = vec4(albedo, alpha); #else - frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha); + frag_color = vec4(emission + ambient_light + diffuse_light + direct_specular_light + indirect_specular_light, alpha); //frag_color = vec4(1.0); #endif //USE_NO_SHADING diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl index 32838e0a78c..a96a494bda2 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl @@ -1,4 +1,5 @@ #define M_PI 3.14159265359 +#define M_TAU 6.28318530718 #define ROUGHNESS_MAX_LOD 5 #define MAX_VOXEL_GI_INSTANCES 8 @@ -22,13 +23,13 @@ #include "../decal_data_inc.glsl" #include "../scene_data_inc.glsl" -#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) #ifndef NORMAL_USED #define NORMAL_USED #endif #endif -#if !defined(TANGENT_USED) && (defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)) +#if !defined(TANGENT_USED) && (defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)) #define TANGENT_USED #endif 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 00258efe38c..291ad82560d 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 @@ -97,7 +97,7 @@ layout(location = 3) mediump out vec2 uv_interp; layout(location = 4) mediump out vec2 uv2_interp; #endif -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) layout(location = 5) mediump out vec3 tangent_interp; layout(location = 6) mediump out vec3 binormal_interp; #endif @@ -305,7 +305,7 @@ void main() { vec3 normal = oct_to_vec3(axis_tangent_attrib.xy * 2.0 - 1.0); #endif -#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) vec3 binormal; float binormal_sign; @@ -369,7 +369,7 @@ void main() { normal = model_normal_matrix * normal; #endif -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) tangent = model_normal_matrix * tangent; binormal = model_normal_matrix * binormal; @@ -411,7 +411,7 @@ void main() { normal = modelview_normal * normal; #endif -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) binormal = modelview_normal * binormal; tangent = modelview_normal * tangent; @@ -426,7 +426,7 @@ void main() { normal = (scene_data.view_matrix * vec4(normal, 0.0)).xyz; #endif -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) binormal = (scene_data.view_matrix * vec4(binormal, 0.0)).xyz; tangent = (scene_data.view_matrix * vec4(tangent, 0.0)).xyz; #endif @@ -440,7 +440,7 @@ void main() { normal_interp = normalize(normal); #endif -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) || defined(BENT_NORMAL_MAP_USED) tangent_interp = normalize(tangent); binormal_interp = normalize(binormal); #endif @@ -603,7 +603,7 @@ layout(location = 3) mediump in vec2 uv_interp; layout(location = 4) mediump in vec2 uv2_interp; #endif -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) layout(location = 5) mediump in vec3 tangent_interp; layout(location = 6) mediump in vec3 binormal_interp; #endif @@ -891,10 +891,10 @@ void main() { float alpha = 1.0; -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) || defined(BENT_NORMAL_MAP_USED) vec3 binormal = binormal_interp; vec3 tangent = tangent_interp; -#else // TANGENT_USED || NORMAL_MAP_USED || LIGHT_ANISOTROPY_USED +#else // TANGENT_USED || NORMAL_MAP_USED || LIGHT_ANISOTROPY_USED || BENT_NORMAL_MAP_USED vec3 binormal = vec3(0.0); vec3 tangent = vec3(0.0); #endif @@ -925,6 +925,11 @@ void main() { vec3 normal_map = vec3(0.5); #endif +#if defined(BENT_NORMAL_MAP_USED) + vec3 bent_normal_vector; + vec3 bent_normal_map = vec3(0.5); +#endif + float normal_map_depth = 1.0; vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size; @@ -1060,6 +1065,13 @@ void main() { normal = geo_normal; #endif // NORMAL_MAP_USED +#ifdef BENT_NORMAL_MAP_USED + bent_normal_map.xy = bent_normal_map.xy * 2.0 - 1.0; + bent_normal_map.z = sqrt(max(0.0, 1.0 - dot(bent_normal_map.xy, bent_normal_map.xy))); + + bent_normal_vector = normalize(tangent * bent_normal_map.x + binormal * bent_normal_map.y + normal * bent_normal_map.z); +#endif + #ifdef LIGHT_ANISOTROPY_USED if (anisotropy > 0.01) { @@ -1202,7 +1214,8 @@ void main() { #endif // NORMAL_USED //apply energy conservation - vec3 specular_light = vec3(0.0, 0.0, 0.0); + vec3 indirect_specular_light = vec3(0.0, 0.0, 0.0); + vec3 direct_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); @@ -1214,6 +1227,11 @@ void main() { #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) #ifndef AMBIENT_LIGHT_DISABLED +#ifdef BENT_NORMAL_MAP_USED + vec3 indirect_normal = bent_normal_vector; +#else + vec3 indirect_normal = normal; +#endif if (sc_scene_use_reflection_cubemap()) { #ifdef LIGHT_ANISOTROPY_USED @@ -1221,34 +1239,34 @@ void main() { vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; vec3 anisotropic_tangent = cross(anisotropic_direction, view); vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction); - vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0))); + vec3 bent_normal = normalize(mix(indirect_normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0))); vec3 ref_vec = reflect(-view, bent_normal); ref_vec = mix(ref_vec, bent_normal, roughness * roughness); #else - vec3 ref_vec = reflect(-view, normal); - ref_vec = mix(ref_vec, normal, roughness * roughness); + vec3 ref_vec = reflect(-view, indirect_normal); + ref_vec = mix(ref_vec, indirect_normal, roughness * roughness); #endif - float horizon = min(1.0 + dot(ref_vec, normal), 1.0); + float horizon = min(1.0 + dot(ref_vec, indirect_normal), 1.0); ref_vec = scene_data.radiance_inverse_xform * ref_vec; #ifdef USE_RADIANCE_CUBEMAP_ARRAY float lod, blend; blend = modf(sqrt(roughness) * MAX_ROUGHNESS_LOD, lod); - specular_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb; - specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend); + indirect_specular_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb; + indirect_specular_light = mix(indirect_specular_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend); #else // USE_RADIANCE_CUBEMAP_ARRAY - specular_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb; + indirect_specular_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb; #endif //USE_RADIANCE_CUBEMAP_ARRAY - specular_light *= sc_luminance_multiplier(); - specular_light *= scene_data.IBL_exposure_normalization; - specular_light *= horizon * horizon; - specular_light *= scene_data.ambient_light_color_energy.a; + indirect_specular_light *= sc_luminance_multiplier(); + indirect_specular_light *= scene_data.IBL_exposure_normalization; + indirect_specular_light *= horizon * horizon; + indirect_specular_light *= scene_data.ambient_light_color_energy.a; } #if defined(CUSTOM_RADIANCE_USED) - specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a); + indirect_specular_light = mix(indirect_specular_light, custom_radiance.rgb, custom_radiance.a); #endif // CUSTOM_RADIANCE_USED #ifndef USE_LIGHTMAP @@ -1257,7 +1275,7 @@ void main() { ambient_light = scene_data.ambient_light_color_energy.rgb; if (sc_scene_use_ambient_cubemap()) { - vec3 ambient_dir = scene_data.radiance_inverse_xform * normal; + vec3 ambient_dir = scene_data.radiance_inverse_xform * indirect_normal; #ifdef USE_RADIANCE_CUBEMAP_ARRAY vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb; #else @@ -1283,9 +1301,9 @@ void main() { float Fc = clearcoat * (0.04 + 0.96 * SchlickFresnel(NoV)); float attenuation = 1.0 - Fc; ambient_light *= attenuation; - specular_light *= attenuation; + indirect_specular_light *= attenuation; - float horizon = min(1.0 + dot(ref_vec, normal), 1.0); + float horizon = min(1.0 + dot(ref_vec, indirect_normal), 1.0); ref_vec = scene_data.radiance_inverse_xform * ref_vec; float roughness_lod = mix(0.001, 0.1, sqrt(clearcoat_roughness)) * MAX_ROUGHNESS_LOD; #ifdef USE_RADIANCE_CUBEMAP_ARRAY @@ -1299,7 +1317,7 @@ void main() { vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, roughness_lod).rgb; #endif //USE_RADIANCE_CUBEMAP_ARRAY - specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a; + indirect_specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a; } #endif // LIGHT_CLEARCOAT_USED #endif // !AMBIENT_LIGHT_DISABLED @@ -1316,7 +1334,7 @@ void main() { uint index = instances.data[draw_call.instance_index].gi_offset; // The world normal. - vec3 wnormal = mat3(scene_data.inv_view_matrix) * normal; + vec3 wnormal = mat3(scene_data.inv_view_matrix) * indirect_normal; // The SH coefficients used for evaluating diffuse data from SH probes. const float c[5] = float[]( @@ -1365,7 +1383,7 @@ void main() { lm_light_l1p1 = (textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb - vec3(0.5)) * 2.0; } - vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal); + vec3 n = normalize(lightmaps.data[ofs].normal_xform * indirect_normal); float exposure_normalization = lightmaps.data[ofs].exposure_normalization; ambient_light += lm_light_l0 * exposure_normalization; @@ -1411,7 +1429,7 @@ void main() { break; } - reflection_process(reflection_index, vertex, ref_vec, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); + reflection_process(reflection_index, vertex, ref_vec, normal, roughness, ambient_light, indirect_specular_light, ambient_accum, reflection_accum); } if (ambient_accum.a < 1.0) { @@ -1419,11 +1437,11 @@ void main() { } if (reflection_accum.a < 1.0) { - reflection_accum.rgb = specular_light * (1.0 - reflection_accum.a) + reflection_accum.rgb; + reflection_accum.rgb = indirect_specular_light * (1.0 - reflection_accum.a) + reflection_accum.rgb; } if (reflection_accum.a > 0.0) { - specular_light = reflection_accum.rgb; + indirect_specular_light = reflection_accum.rgb; } #if !defined(USE_LIGHTMAP) @@ -1436,6 +1454,13 @@ void main() { // finalize ambient light here ambient_light *= ao; #ifndef SPECULAR_OCCLUSION_DISABLED +#ifdef BENT_NORMAL_MAP_USED + // Simplified bent normal occlusion. + float cos_b = max(dot(reflect(-view, normal), bent_normal_vector), 0.0); + float specular_occlusion = clamp((ao - (1.0 - cos_b)) / roughness, 0.0, 1.0); + specular_occlusion = mix(specular_occlusion, cos_b * (1.0 - ao), roughness); + indirect_specular_light *= specular_occlusion; +#else // BENT_NORMAL_MAP_USED float specular_occlusion = (ambient_light.r * 0.3 + ambient_light.g * 0.59 + ambient_light.b * 0.11) * 2.0; // Luminance of ambient light. specular_occlusion = min(specular_occlusion * 4.0, 1.0); // This multiplication preserves speculars on bright areas. @@ -1443,7 +1468,8 @@ void main() { // 10.0 is a magic number, it gives the intended effect in most scenarios. // Low enough for occlusion, high enough for reaction to lights and shadows. specular_occlusion = max(min(reflective_f * specular_occlusion * 10.0, 1.0), specular_occlusion); - specular_light *= specular_occlusion; + indirect_specular_light *= specular_occlusion; +#endif // BENT_NORMAL_MAP_USED #endif // USE_SPECULAR_OCCLUSION ambient_light *= albedo.rgb; @@ -1459,7 +1485,7 @@ void main() { { #if defined(DIFFUSE_TOON) //simplify for toon, as - specular_light *= specular * metallic * albedo * 2.0; + indirect_specular_light *= specular * metallic * albedo * 2.0; #else // scales the specular reflections, needs to be computed before lighting happens, @@ -1473,7 +1499,7 @@ void main() { float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; - specular_light *= env.x * f0 + env.y * clamp(50.0 * f0.g, metallic, 1.0); + indirect_specular_light *= env.x * f0 + env.y * clamp(50.0 * f0.g, metallic, 1.0); #endif } @@ -1489,7 +1515,7 @@ void main() { #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; + direct_specular_light += specular_light_interp.rgb * f0; #endif if (sc_directional_lights() > 0) { @@ -1642,7 +1668,7 @@ void main() { #ifdef USE_VERTEX_LIGHTING diffuse_light *= mix(1.0, shadow, diffuse_light_interp.a); - specular_light *= mix(1.0, shadow, specular_light_interp.a); + direct_specular_light *= mix(1.0, shadow, specular_light_interp.a); #endif #undef BIAS_FUNC } @@ -1659,7 +1685,7 @@ void main() { #ifdef USE_VERTEX_LIGHTING diffuse_light *= mix(1.0, shadowmask, diffuse_light_interp.a); - specular_light *= mix(1.0, shadowmask, specular_light_interp.a); + direct_specular_light *= mix(1.0, shadowmask, specular_light_interp.a); #endif shadow0 |= uint(clamp(shadowmask * 255.0, 0.0, 255.0)); @@ -1734,7 +1760,7 @@ void main() { binormal, tangent, anisotropy, #endif diffuse_light, - specular_light); + direct_specular_light); } #endif // USE_VERTEX_LIGHTING } //directional light @@ -1765,7 +1791,7 @@ void main() { tangent, binormal, anisotropy, #endif - diffuse_light, specular_light); + diffuse_light, direct_specular_light); } uvec2 spot_indices = instances.data[draw_call.instance_index].spot_lights; @@ -1793,7 +1819,7 @@ void main() { tangent, binormal, anisotropy, #endif - diffuse_light, specular_light); + diffuse_light, direct_specular_light); } #endif // !VERTEX_LIGHTING @@ -1847,8 +1873,8 @@ void main() { // apply direct light AO ao = unpackUnorm4x8(orms).x; - specular_light *= ao; diffuse_light *= ao; + direct_specular_light *= ao; // apply metallic metallic = unpackUnorm4x8(orms).z; @@ -1872,7 +1898,7 @@ void main() { sss_strength = -sss_strength; #endif // SSS_MODE_SKIN diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength); - specular_buffer = vec4(specular_light, metallic); + specular_buffer = vec4(direct_specular_light + indirect_specular_light, metallic); #endif // MODE_UNSHADED #ifndef FOG_DISABLED @@ -1885,7 +1911,7 @@ void main() { #ifdef MODE_UNSHADED frag_color = vec4(albedo, alpha); #else // MODE_UNSHADED - frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha); + frag_color = vec4(emission + ambient_light + diffuse_light + direct_specular_light + indirect_specular_light, alpha); #endif // MODE_UNSHADED #ifndef FOG_DISABLED diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl index 49c8905dbf1..f75d265fd55 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl @@ -8,7 +8,7 @@ #include "../decal_data_inc.glsl" #include "../scene_data_inc.glsl" -#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) #ifndef NORMAL_USED #define NORMAL_USED #endif diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index cf8c1bd6ca0..28be30e7338 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -133,6 +133,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_MAP"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_MAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["BENT_NORMAL_MAP"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["UV2"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4);