Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Specular Blinn function #33836

Merged
merged 1 commit into from
Dec 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 93 additions & 106 deletions drivers/gles2/shaders/scene.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,10 @@ void light_compute(
//normalized blinn always unless disabled
vec3 H = normalize(V + L);
float cNdotH = max(dot(N, H), 0.0);
float cVdotH = max(dot(V, H), 0.0);
float cLdotH = max(dot(L, H), 0.0);
float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
float blinn = pow(cNdotH, shininess);
float blinn = pow(cNdotH, shininess) * cNdotL;
blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
specular_brdf_NL = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
specular_brdf_NL = blinn;
#endif

SRGB_APPROX(specular_brdf_NL)
Expand Down Expand Up @@ -1270,9 +1268,9 @@ LIGHT_SHADER_CODE

//normalized blinn
float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
float blinn = pow(cNdotH, shininess);
float blinn = pow(cNdotH, shininess) * cNdotL;
blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
specular_brdf_NL = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
specular_brdf_NL = blinn;

#elif defined(SPECULAR_PHONG)

Expand Down Expand Up @@ -1547,157 +1545,157 @@ FRAGMENT_SHADER_CODE
#endif // !USE_SHADOW_TO_OPACITY

#ifdef BASE_PASS
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't you add this extra scope a few commits ago in another PR? :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but it made the code messier, and it is unnecessary now that I removed the environment scaling from the vertex_lighting code path

// IBL precalculations
float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
vec3 f0 = F0(metallic, specular, albedo);
vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0);

// IBL precalculations
float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
vec3 f0 = F0(metallic, specular, albedo);
vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0);

#ifdef AMBIENT_LIGHT_DISABLED
ambient_light = vec3(0.0, 0.0, 0.0);
ambient_light = vec3(0.0, 0.0, 0.0);
#else

#ifdef USE_RADIANCE_MAP

vec3 ref_vec = reflect(-eye_position, N);
ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz);
vec3 ref_vec = reflect(-eye_position, N);
ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz);

ref_vec.z *= -1.0;
ref_vec.z *= -1.0;

specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy;
specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy;
#ifndef USE_LIGHTMAP
{
vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz);
vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, 4.0).xyz * bg_energy;
env_ambient *= 1.0 - F;
{
vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz);
vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, 4.0).xyz * bg_energy;
env_ambient *= 1.0 - F;

ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution);
}
ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution);
}
#endif

#else

ambient_light = ambient_color.rgb;
specular_light = bg_color.rgb * bg_energy;
ambient_light = ambient_color.rgb;
specular_light = bg_color.rgb * bg_energy;

#endif
#endif // AMBIENT_LIGHT_DISABLED
ambient_light *= ambient_energy;
ambient_light *= ambient_energy;

#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2)

vec4 ambient_accum = vec4(0.0);
vec4 reflection_accum = vec4(0.0);
vec4 ambient_accum = vec4(0.0);
vec4 reflection_accum = vec4(0.0);

#ifdef USE_REFLECTION_PROBE1

reflection_process(reflection_probe1,
reflection_process(reflection_probe1,
#ifdef USE_VERTEX_LIGHTING
refprobe1_reflection_normal_blend.rgb,
refprobe1_reflection_normal_blend.rgb,
#ifndef USE_LIGHTMAP
refprobe1_ambient_normal,
refprobe1_ambient_normal,
#endif
refprobe1_reflection_normal_blend.a,
refprobe1_reflection_normal_blend.a,
#else
normal_interp, vertex_interp, refprobe1_local_matrix,
refprobe1_use_box_project, refprobe1_box_extents, refprobe1_box_offset,
normal_interp, vertex_interp, refprobe1_local_matrix,
refprobe1_use_box_project, refprobe1_box_extents, refprobe1_box_offset,
#endif
refprobe1_exterior, refprobe1_intensity, refprobe1_ambient, roughness,
ambient_light, specular_light, reflection_accum, ambient_accum);
refprobe1_exterior, refprobe1_intensity, refprobe1_ambient, roughness,
ambient_light, specular_light, reflection_accum, ambient_accum);

#endif // USE_REFLECTION_PROBE1

#ifdef USE_REFLECTION_PROBE2

reflection_process(reflection_probe2,
reflection_process(reflection_probe2,
#ifdef USE_VERTEX_LIGHTING
refprobe2_reflection_normal_blend.rgb,
refprobe2_reflection_normal_blend.rgb,
#ifndef USE_LIGHTMAP
refprobe2_ambient_normal,
refprobe2_ambient_normal,
#endif
refprobe2_reflection_normal_blend.a,
refprobe2_reflection_normal_blend.a,
#else
normal_interp, vertex_interp, refprobe2_local_matrix,
refprobe2_use_box_project, refprobe2_box_extents, refprobe2_box_offset,
normal_interp, vertex_interp, refprobe2_local_matrix,
refprobe2_use_box_project, refprobe2_box_extents, refprobe2_box_offset,
#endif
refprobe2_exterior, refprobe2_intensity, refprobe2_ambient, roughness,
ambient_light, specular_light, reflection_accum, ambient_accum);
refprobe2_exterior, refprobe2_intensity, refprobe2_ambient, roughness,
ambient_light, specular_light, reflection_accum, ambient_accum);

#endif // USE_REFLECTION_PROBE2

if (reflection_accum.a > 0.0) {
specular_light = reflection_accum.rgb / reflection_accum.a;
}
if (reflection_accum.a > 0.0) {
specular_light = reflection_accum.rgb / reflection_accum.a;
}

#ifndef USE_LIGHTMAP
if (ambient_accum.a > 0.0) {
ambient_light = ambient_accum.rgb / ambient_accum.a;
}
if (ambient_accum.a > 0.0) {
ambient_light = ambient_accum.rgb / ambient_accum.a;
}
#endif

#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2)

// environment BRDF approximation
{
// environment BRDF approximation
{

#if defined(DIFFUSE_TOON)
//simplify for toon, as
specular_light *= specular * metallic * albedo * 2.0;
//simplify for toon, as
specular_light *= specular * metallic * albedo * 2.0;
#else

// scales the specular reflections, needs to be be computed before lighting happens,
// but after environment and reflection probes are added
//TODO: this curve is not really designed for gammaspace, should be adjusted
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
vec4 r = roughness * c0 + c1;
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 * F + env.y;
// scales the specular reflections, needs to be be computed before lighting happens,
// but after environment and reflection probes are added
//TODO: this curve is not really designed for gammaspace, should be adjusted
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
vec4 r = roughness * c0 + c1;
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 * F + env.y;

#endif
}
}

#ifdef USE_LIGHTMAP
//ambient light will come entirely from lightmap is lightmap is used
ambient_light = texture2D(lightmap, uv2_interp).rgb * lightmap_energy;
//ambient light will come entirely from lightmap is lightmap is used
ambient_light = texture2D(lightmap, uv2_interp).rgb * lightmap_energy;
#endif

#ifdef USE_LIGHTMAP_CAPTURE
{
vec3 cone_dirs[12] = vec3[](
vec3(0.0, 0.0, 1.0),
vec3(0.866025, 0.0, 0.5),
vec3(0.267617, 0.823639, 0.5),
vec3(-0.700629, 0.509037, 0.5),
vec3(-0.700629, -0.509037, 0.5),
vec3(0.267617, -0.823639, 0.5),
vec3(0.0, 0.0, -1.0),
vec3(0.866025, 0.0, -0.5),
vec3(0.267617, 0.823639, -0.5),
vec3(-0.700629, 0.509037, -0.5),
vec3(-0.700629, -0.509037, -0.5),
vec3(0.267617, -0.823639, -0.5));

vec3 local_normal = normalize(camera_matrix * vec4(normal, 0.0)).xyz;
vec4 captured = vec4(0.0);
float sum = 0.0;
for (int i = 0; i < 12; i++) {
float amount = max(0.0, dot(local_normal, cone_dirs[i])); //not correct, but creates a nice wrap around effect
captured += lightmap_captures[i] * amount;
sum += amount;
}
{
vec3 cone_dirs[12] = vec3[](
vec3(0.0, 0.0, 1.0),
vec3(0.866025, 0.0, 0.5),
vec3(0.267617, 0.823639, 0.5),
vec3(-0.700629, 0.509037, 0.5),
vec3(-0.700629, -0.509037, 0.5),
vec3(0.267617, -0.823639, 0.5),
vec3(0.0, 0.0, -1.0),
vec3(0.866025, 0.0, -0.5),
vec3(0.267617, 0.823639, -0.5),
vec3(-0.700629, 0.509037, -0.5),
vec3(-0.700629, -0.509037, -0.5),
vec3(0.267617, -0.823639, -0.5));

vec3 local_normal = normalize(camera_matrix * vec4(normal, 0.0)).xyz;
vec4 captured = vec4(0.0);
float sum = 0.0;
for (int i = 0; i < 12; i++) {
float amount = max(0.0, dot(local_normal, cone_dirs[i])); //not correct, but creates a nice wrap around effect
captured += lightmap_captures[i] * amount;
sum += amount;
}

captured /= sum;
captured /= sum;

if (lightmap_capture_sky) {
ambient_light = mix(ambient_light, captured.rgb, captured.a);
} else {
ambient_light = captured.rgb;
}
if (lightmap_capture_sky) {
ambient_light = mix(ambient_light, captured.rgb, captured.a);
} else {
ambient_light = captured.rgb;
}
#endif
}
#endif

#endif //BASE PASS

//
Expand Down Expand Up @@ -2052,17 +2050,6 @@ FRAGMENT_SHADER_CODE
specular_light += specular_interp * specular_blob_intensity * light_att;
diffuse_light += diffuse_interp * albedo * light_att;

// Same as above, needed for VERTEX_LIGHTING or else lights are too bright
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
vec4 r = roughness * c0 + c1;
float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
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;

vec3 f0 = F0(metallic, specular, albedo);
specular_light *= env.x * f0 + env.y;

#else
//fragment lighting
light_compute(
Expand Down
10 changes: 4 additions & 6 deletions drivers/gles3/shaders/scene.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,10 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float roughness, in
//normalized blinn always unless disabled
vec3 H = normalize(V + L);
float cNdotH = max(dot(N, H), 0.0);
float cVdotH = max(dot(V, H), 0.0);
float cLdotH = max(dot(L, H), 0.0);
float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
float blinn = pow(cNdotH, shininess);
float blinn = pow(cNdotH, shininess) * cNdotL;
blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
specular_brdf_NL = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
specular_brdf_NL = blinn;
#endif

specular += specular_brdf_NL * light_color * (1.0 / M_PI);
Expand Down Expand Up @@ -1094,9 +1092,9 @@ LIGHT_SHADER_CODE

//normalized blinn
float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
float blinn = pow(cNdotH, shininess);
float blinn = pow(cNdotH, shininess) * cNdotL;
blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
float intensity = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
float intensity = blinn;

specular_light += light_color * intensity * specular_blob_intensity * attenuation;

Expand Down