Skip to content

Commit

Permalink
first version of specular occlusion
Browse files Browse the repository at this point in the history
  • Loading branch information
guerro323 committed Dec 13, 2023
1 parent aa5b6ed commit fa18762
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 1 deletion.
13 changes: 13 additions & 0 deletions doc/classes/BaseMaterial3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,10 @@
The method for rendering the specular blob. See [enum SpecularMode].
[b]Note:[/b] [member specular_mode] only applies to the specular blob. It does not affect specular reflections from the sky, screen-space reflections, [VoxelGI], SDFGI or [ReflectionProbe]s. To disable reflections from these sources as well, set [member metallic_specular] to [code]0.0[/code] instead.
</member>
<member name="specular_occlusion_mode" type="int" setter="set_specular_occlusion_mode" getter="get_specular_occlusion_mode" enum="BaseMaterial3D.SpecularOcclusionMode" default="0">
The method for occluding specular light from [LightmapGI] data. See [enum SpecularOcclusionMode].
[b]Note:[/b] This only apply to materials under the influence of a [LightmapGI] node and reflective/metallic materials.
</member>
<member name="subsurf_scatter_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
If [code]true[/code], subsurface scattering is enabled. Emulates light that penetrates an object's surface, is scattered, and then emerges. Subsurface scattering quality is controlled by [member ProjectSettings.rendering/environment/subsurface_scattering/subsurface_scattering_quality].
</member>
Expand Down Expand Up @@ -727,6 +731,15 @@
<constant name="SPECULAR_DISABLED" value="2" enum="SpecularMode">
No specular blob. This is slightly faster to render than other specular modes.
</constant>
<constant name="SPECULAR_OCCLUSION" value="0" enum="SpecularOcclusionMode">
Default specular occlusion, reduce the specular intensity by current [LightmapGI] pixel brightness.
</constant>
<constant name="SPECULAR_OCCLUSION_CORRECT" value="1" enum="SpecularOcclusionMode">
Specular occlusion that gives a more realistic appearence by keeping more energy from mixing metallic and roughness values.
</constant>
<constant name="SPECULAR_OCCLUSION_DISABLED" value="2" enum="SpecularOcclusionMode">
No specular occlusion.
</constant>
<constant name="BILLBOARD_DISABLED" value="0" enum="BillboardMode">
Billboard mode is disabled.
</constant>
Expand Down
35 changes: 35 additions & 0 deletions scene/resources/material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,20 @@ void BaseMaterial3D::_update_shader() {
case SPECULAR_MAX:
break; // Internal value, skip.
}

switch (specular_occlusion_mode) {
case SPECULAR_OCCLUSION:
code += ",specular_occlusion";
break;
case SPECULAR_OCCLUSION_CORRECT:
code += ",specular_occlusion_correct";
break;
case SPECULAR_OCCLUSION_DISABLED:
break;
case SPECULAR_OCCLUSION_MAX:
break; // Internal value, skip.
}

if (features[FEATURE_SUBSURFACE_SCATTERING] && flags[FLAG_SUBSURFACE_MODE_SKIN]) {
code += ",sss_mode_skin";
}
Expand Down Expand Up @@ -1879,6 +1893,19 @@ BaseMaterial3D::SpecularMode BaseMaterial3D::get_specular_mode() const {
return specular_mode;
}

void BaseMaterial3D::set_specular_occlusion_mode(SpecularOcclusionMode p_mode) {
if (specular_occlusion_mode == p_mode) {
return;
}

specular_occlusion_mode = p_mode;
_queue_shader_change();
}

BaseMaterial3D::SpecularOcclusionMode BaseMaterial3D::get_specular_occlusion_mode() const {
return specular_occlusion_mode;
}

void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);

Expand Down Expand Up @@ -2614,6 +2641,9 @@ void BaseMaterial3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_specular_mode", "specular_mode"), &BaseMaterial3D::set_specular_mode);
ClassDB::bind_method(D_METHOD("get_specular_mode"), &BaseMaterial3D::get_specular_mode);

ClassDB::bind_method(D_METHOD("set_specular_occlusion_mode", "specular_occlusion_mode"), &BaseMaterial3D::set_specular_occlusion_mode);
ClassDB::bind_method(D_METHOD("get_specular_occlusion_mode"), &BaseMaterial3D::get_specular_occlusion_mode);

ClassDB::bind_method(D_METHOD("set_flag", "flag", "enable"), &BaseMaterial3D::set_flag);
ClassDB::bind_method(D_METHOD("get_flag", "flag"), &BaseMaterial3D::get_flag);

Expand Down Expand Up @@ -2740,6 +2770,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "shading_mode", PROPERTY_HINT_ENUM, "Unshaded,Per-Pixel,Per-Vertex"), "set_shading_mode", "get_shading_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "diffuse_mode", PROPERTY_HINT_ENUM, "Burley,Lambert,Lambert Wrap,Toon"), "set_diffuse_mode", "get_diffuse_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "specular_mode", PROPERTY_HINT_ENUM, "SchlickGGX,Toon,Disabled"), "set_specular_mode", "get_specular_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "specular_occlusion_mode", PROPERTY_HINT_ENUM, "Default,Correct,Disabled"), "set_specular_occlusion_mode", "get_specular_occlusion_mode");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "disable_ambient_light"), "set_flag", "get_flag", FLAG_DISABLE_AMBIENT_LIGHT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "disable_fog"), "set_flag", "get_flag", FLAG_DISABLE_FOG);

Expand Down Expand Up @@ -3006,6 +3037,10 @@ void BaseMaterial3D::_bind_methods() {
BIND_ENUM_CONSTANT(SPECULAR_TOON);
BIND_ENUM_CONSTANT(SPECULAR_DISABLED);

BIND_ENUM_CONSTANT(SPECULAR_OCCLUSION);
BIND_ENUM_CONSTANT(SPECULAR_OCCLUSION_CORRECT);
BIND_ENUM_CONSTANT(SPECULAR_OCCLUSION_DISABLED);

BIND_ENUM_CONSTANT(BILLBOARD_DISABLED);
BIND_ENUM_CONSTANT(BILLBOARD_ENABLED);
BIND_ENUM_CONSTANT(BILLBOARD_FIXED_Y);
Expand Down
14 changes: 14 additions & 0 deletions scene/resources/material.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ class BaseMaterial3D : public Material {
SPECULAR_MAX
};

enum SpecularOcclusionMode {
SPECULAR_OCCLUSION,
SPECULAR_OCCLUSION_CORRECT,
SPECULAR_OCCLUSION_DISABLED,
SPECULAR_OCCLUSION_MAX
};

enum BillboardMode {
BILLBOARD_DISABLED,
BILLBOARD_ENABLED,
Expand Down Expand Up @@ -319,6 +326,7 @@ class BaseMaterial3D : public Material {
uint64_t cull_mode : get_num_bits(CULL_MAX - 1);
uint64_t diffuse_mode : get_num_bits(DIFFUSE_MAX - 1);
uint64_t specular_mode : get_num_bits(SPECULAR_MAX - 1);
uint64_t specular_occlusion_mode : get_num_bits(SPECULAR_OCCLUSION_MAX - 1);
uint64_t billboard_mode : get_num_bits(BILLBOARD_MAX - 1);
uint64_t detail_blend_mode : get_num_bits(BLEND_MODE_MAX - 1);
uint64_t roughness_channel : get_num_bits(TEXTURE_CHANNEL_MAX - 1);
Expand Down Expand Up @@ -374,6 +382,7 @@ class BaseMaterial3D : public Material {
mk.detail_blend_mode = detail_blend_mode;
mk.diffuse_mode = diffuse_mode;
mk.specular_mode = specular_mode;
mk.specular_occlusion_mode = specular_occlusion_mode;
mk.billboard_mode = billboard_mode;
mk.deep_parallax = deep_parallax;
mk.grow = grow_enabled;
Expand Down Expand Up @@ -536,6 +545,7 @@ class BaseMaterial3D : public Material {
CullMode cull_mode = CULL_BACK;
bool flags[FLAG_MAX] = {};
SpecularMode specular_mode = SPECULAR_SCHLICK_GGX;
SpecularOcclusionMode specular_occlusion_mode = SPECULAR_OCCLUSION;
DiffuseMode diffuse_mode = DIFFUSE_BURLEY;
BillboardMode billboard_mode;
EmissionOperator emission_op = EMISSION_OP_ADD;
Expand Down Expand Up @@ -676,6 +686,9 @@ class BaseMaterial3D : public Material {
void set_specular_mode(SpecularMode p_mode);
SpecularMode get_specular_mode() const;

void set_specular_occlusion_mode(SpecularOcclusionMode p_mode);
SpecularOcclusionMode get_specular_occlusion_mode() const;

void set_flag(Flags p_flag, bool p_enabled);
bool get_flag(Flags p_flag) const;

Expand Down Expand Up @@ -793,6 +806,7 @@ VARIANT_ENUM_CAST(BaseMaterial3D::CullMode)
VARIANT_ENUM_CAST(BaseMaterial3D::Flags)
VARIANT_ENUM_CAST(BaseMaterial3D::DiffuseMode)
VARIANT_ENUM_CAST(BaseMaterial3D::SpecularMode)
VARIANT_ENUM_CAST(BaseMaterial3D::SpecularOcclusionMode)
VARIANT_ENUM_CAST(BaseMaterial3D::BillboardMode)
VARIANT_ENUM_CAST(BaseMaterial3D::TextureChannel)
VARIANT_ENUM_CAST(BaseMaterial3D::EmissionOperator)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,8 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\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.render_mode_defines["specular_occlusion_correct"] = "#define SPECULAR_OCCLUSION_CORRECT\n";
actions.render_mode_defines["specular_occlusion"] = "#define SPECULAR_OCCLUSION\n";

actions.base_texture_binding_index = 1;
actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1357,7 +1357,8 @@ void fragment_shader(in SceneData scene_data) {
const float c3 = 0.743125;
const float c4 = 0.886227;
const float c5 = 0.247708;
ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) +

vec3 c = (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) +
c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
c4 * lightmap_captures.data[index].sh[0].rgb -
c5 * lightmap_captures.data[index].sh[6].rgb +
Expand All @@ -1369,6 +1370,21 @@ void fragment_shader(in SceneData scene_data) {
2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z) *
scene_data.emissive_exposure_normalization;

#if defined(SPECULAR_OCCLUSION) || defined(SPECULAR_OCCLUSION_CORRECT)
float specular_occlusion = (c.r * 0.3 + c.g * 0.59 + c.b * 0.11) * 2.0; // brightness from lightmap color
specular_occlusion = min(1.0, specular_occlusion * scene_data.emissive_exposure_normalization);

#if defined(SPECULAR_OCCLUSION_CORRECT)
float reflective_f = (1.0 - roughness) * metallic;
// 10.0 is a number picked by hand, 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);
#endif // defined(SPECULAR_OCCLUSION_CORRECT)

specular_light *= specular_occlusion;
#endif // defined(SPECULAR_OCCLUSION) || defined(SPECULAR_OCCLUSION_CORRECT)
ambient_light += c;

} else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
uint ofs = instances.data[instance_index].gi_offset & 0xFFFF;
Expand Down Expand Up @@ -1399,7 +1415,24 @@ void fragment_shader(in SceneData scene_data) {
}

} else {
#if defined(SPECULAR_OCCLUSION) || defined(SPECULAR_OCCLUSION_CORRECT)
vec3 c = textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;

float specular_occlusion = (c.r * 0.3 + c.g * 0.59 + c.b * 0.11) * 2.0; // brightness from lightmap color
specular_occlusion = min(1.0, specular_occlusion * lightmaps.data[ofs].exposure_normalization);

#if defined(SPECULAR_OCCLUSION_CORRECT)
float reflective_f = (1.0 - roughness) * metallic;
// 10.0 is a number picked by hand, 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);
#endif // defined(SPECULAR_OCCLUSION_CORRECT)

specular_light *= specular_occlusion;
ambient_light += c;
#else // defined(SPECULAR_OCCLUSION) || defined(SPECULAR_OCCLUSION_CORRECT)
ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
#endif // defined(SPECULAR_OCCLUSION) || defined(SPECULAR_OCCLUSION_CORRECT)
}
}
#else
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/shader_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("alpha_to_coverage_and_one") });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("debug_shadow_splits") });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("fog_disabled") });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("specular_occlusion") });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("specular_occlusion_correct") });
}

/************ CANVAS ITEM **************************/
Expand Down

0 comments on commit fa18762

Please sign in to comment.