Remove kD term, improve fresnel reflections and fix scene capture
This commit is contained in:
parent
69eb4bea34
commit
92e04068fd
6 changed files with 58 additions and 57 deletions
|
@ -292,6 +292,18 @@ ShaderSource MaterialCompiler::compile_material_fragment(Material& material, boo
|
||||||
}\n";
|
}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(use_ibl) {
|
||||||
|
src += "vec3 ibl(const int probe, const ComputedSurfaceInfo surface_info, const float intensity) {\n \
|
||||||
|
const vec3 R = get_reflect(probe, surface_info.N);\n \
|
||||||
|
const vec2 brdf = texture(brdfSampler, vec2(surface_info.NdotV, surface_info.roughness)).rg; \n \
|
||||||
|
const vec3 sampledIrradiance = texture(irrandianceSampler, vec4(surface_info.N, probe)).xyz;\n \
|
||||||
|
const vec3 prefilteredColor = textureLod(prefilterSampler, vec4(R, probe), surface_info.roughness * 4).xyz;\n \
|
||||||
|
const vec3 diffuse = sampledIrradiance * surface_info.diffuse_color;\n \
|
||||||
|
const vec3 specular = prefilteredColor * (surface_info.F0 * brdf.x + 1.0 * brdf.y);\n \
|
||||||
|
return (diffuse + specular) * intensity;\n \
|
||||||
|
}\n";
|
||||||
|
}
|
||||||
|
|
||||||
src += "void main() {\n";
|
src += "void main() {\n";
|
||||||
|
|
||||||
bool has_output = false;
|
bool has_output = false;
|
||||||
|
@ -335,47 +347,33 @@ ShaderSource MaterialCompiler::compile_material_fragment(Material& material, boo
|
||||||
light_info = calculate_sun(scene.lights[i]);\n \
|
light_info = calculate_sun(scene.lights[i]);\n \
|
||||||
break;\n \
|
break;\n \
|
||||||
}\n \
|
}\n \
|
||||||
ComputedLightSurfaceInfo light_surface_info = compute_light_surface(light_info.direction, surface_info);\n";
|
SurfaceBRDF surface_brdf = brdf(light_info.direction, surface_info);\n";
|
||||||
|
|
||||||
if(render_options.enable_normal_mapping && has_normal_mapping && render_options.enable_normal_shadowing) {
|
if(render_options.enable_normal_mapping && has_normal_mapping && render_options.enable_normal_shadowing) {
|
||||||
src += std::string("light_info.radiance *= calculate_normal_lighting(") + normal_map_property_name + ", final_normal, light_info.direction);\n";
|
src += std::string("light_info.radiance *= calculate_normal_lighting(") + normal_map_property_name + ", final_normal, light_info.direction);\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
src += "Lo += (light_surface_info.kD * final_diffuse_color.rgb / PI + light_surface_info.specular) * light_surface_info.NdotL * scene.lights[i].colorSize.xyz * light_info.radiance;\n \
|
src += "Lo += ((surface_brdf.specular + surface_brdf.diffuse) * light_info.radiance * surface_brdf.NdotL) * scene.lights[i].colorSize.rgb;\n \
|
||||||
}\n";
|
}\n";
|
||||||
|
|
||||||
if(use_ibl) {
|
if(use_ibl) {
|
||||||
src +=
|
src +=
|
||||||
"const vec3 F = fresnel_schlick_roughness(surface_info.NdotV, surface_info.F0, surface_info.roughness); \n \
|
"vec3 ambient = vec3(0.0); \
|
||||||
const vec3 kD = (1.0 - F) * (1.0 - surface_info.metallic); \n \
|
|
||||||
vec3 ambient = vec3(0.0); \
|
|
||||||
float sum = 0.0;\n \
|
float sum = 0.0;\n \
|
||||||
for(int i = 0; i < max_probes; i++) { \
|
for(int i = 0; i < max_probes; i++) { \
|
||||||
if(scene.probes[i].position.w == 1) {\n \
|
if(scene.probes[i].position.w == 1) {\n \
|
||||||
vec3 position = scene.probes[i].position.xyz; \
|
const vec3 position = scene.probes[i].position.xyz; \
|
||||||
vec3 probe_min = position - (scene.probes[i].size.xyz / 2.0); \
|
const vec3 probe_min = position - (scene.probes[i].size.xyz / 2.0); \
|
||||||
vec3 probe_max = position + (scene.probes[i].size.xyz / 2.0); \
|
const vec3 probe_max = position + (scene.probes[i].size.xyz / 2.0); \
|
||||||
if(all(greaterThan(in_frag_pos, probe_min)) && all(lessThan(in_frag_pos, probe_max)) && scene.probes[i].position.w == 1) { \
|
if(all(greaterThan(in_frag_pos, probe_min)) && all(lessThan(in_frag_pos, probe_max))) { \
|
||||||
float intensity = 1.0 - length(abs(in_frag_pos - position) / (scene.probes[i].size.xyz / 2.0));\n \
|
float intensity = 1.0 - length(abs(in_frag_pos - position) / (scene.probes[i].size.xyz / 2.0));\n \
|
||||||
intensity = clamp(intensity, 0.0, 1.0) * scene.probes[i].size.w;\n \
|
intensity = clamp(intensity, 0.0, 1.0) * scene.probes[i].size.w;\n \
|
||||||
const vec3 R = get_reflect(i, surface_info.N);\n \
|
ambient += ibl(i, surface_info, intensity);\n \
|
||||||
const vec2 brdf = texture(brdfSampler, vec2(surface_info.NdotV, surface_info.roughness)).rg; \n \
|
|
||||||
const vec3 sampledIrradiance = texture(irrandianceSampler, vec4(surface_info.N, i)).xyz;\n \
|
|
||||||
const vec3 prefilteredColor = textureLod(prefilterSampler, vec4(R, i), surface_info.roughness * 4).xyz;\n \
|
|
||||||
const vec3 diffuse = sampledIrradiance * final_diffuse_color.rgb;\n \
|
|
||||||
const vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);\n \
|
|
||||||
ambient += (kD * diffuse + specular) * intensity;\n \
|
|
||||||
sum += intensity; \n \
|
sum += intensity; \n \
|
||||||
} \
|
} \
|
||||||
} else if(scene.probes[i].position.w == 2) {\n \
|
} else if(scene.probes[i].position.w == 2) {\n \
|
||||||
const vec3 R = reflect(-surface_info.V, surface_info.N);\n \
|
ambient += ibl(i, surface_info, scene.probes[i].size.w);\n \
|
||||||
const vec2 brdf = texture(brdfSampler, vec2(surface_info.NdotV, surface_info.roughness)).rg; \n \
|
sum += scene.probes[i].size.w; \n \
|
||||||
const vec3 sampledIrradiance = texture(irrandianceSampler, vec4(surface_info.N, i)).xyz;\n \
|
|
||||||
const vec3 prefilteredColor = textureLod(prefilterSampler, vec4(R, i), surface_info.roughness * 4).xyz;\n \
|
|
||||||
const vec3 diffuse = sampledIrradiance * final_diffuse_color.rgb;\n \
|
|
||||||
const vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);\n \
|
|
||||||
ambient += (kD * diffuse + specular) * scene.probes[i].size.w;\n \
|
|
||||||
sum += 1.0; \n \
|
|
||||||
}\n \
|
}\n \
|
||||||
}\n \
|
}\n \
|
||||||
ambient /= sum;\n";
|
ambient /= sum;\n";
|
||||||
|
|
|
@ -706,6 +706,8 @@ void Renderer::create_mesh_pipeline(Material& material) {
|
||||||
|
|
||||||
pipelineInfo.shaders.fragment_src = material_compiler.compile_material_fragment(material, false); // scene capture does not use IBL
|
pipelineInfo.shaders.fragment_src = material_compiler.compile_material_fragment(material, false); // scene capture does not use IBL
|
||||||
|
|
||||||
|
pipelineInfo.rasterization.culling_mode = GFXCullingMode::Frontface;
|
||||||
|
|
||||||
material.capture_pipeline = material_compiler.create_static_pipeline(pipelineInfo, false, true);
|
material.capture_pipeline = material_compiler.create_static_pipeline(pipelineInfo, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,8 @@ const int mipLevels = 5;
|
||||||
const std::array<Matrix4x4, 6> sceneTransforms = {
|
const std::array<Matrix4x4, 6> sceneTransforms = {
|
||||||
transform::look_at(Vector3(0), Vector3(1.0, 0.0, 0.0), Vector3(0.0, -1.0, 0.0)),
|
transform::look_at(Vector3(0), Vector3(1.0, 0.0, 0.0), Vector3(0.0, -1.0, 0.0)),
|
||||||
transform::look_at(Vector3(0), Vector3(-1.0, 0.0, 0.0), Vector3(0.0, -1.0, 0.0)),
|
transform::look_at(Vector3(0), Vector3(-1.0, 0.0, 0.0), Vector3(0.0, -1.0, 0.0)),
|
||||||
transform::look_at(Vector3(0), Vector3( 0.0, -1.0, 0.0), Vector3(0.0, 0.0,1.0)),
|
transform::look_at(Vector3(0), Vector3( 0.0, -1.0, 0.0), Vector3(0.0, 0.0,-1.0)),
|
||||||
transform::look_at(Vector3(0), Vector3( 0.0, 1.0, 0.0), Vector3(0.0, 0.0,-1.0)),
|
transform::look_at(Vector3(0), Vector3( 0.0, 1.0, 0.0), Vector3(0.0, 0.0,1.0)),
|
||||||
transform::look_at(Vector3(0), Vector3( 0.0, 0.0, 1.0), Vector3(0.0, -1.0, 0.0)),
|
transform::look_at(Vector3(0), Vector3( 0.0, 0.0, 1.0), Vector3(0.0, -1.0, 0.0)),
|
||||||
transform::look_at(Vector3(0), Vector3( 0.0, 0.0, -1.0), Vector3(0.0, -1.0, 0.0))
|
transform::look_at(Vector3(0), Vector3( 0.0, 0.0, -1.0), Vector3(0.0, -1.0, 0.0))
|
||||||
};
|
};
|
||||||
|
@ -165,8 +165,8 @@ void SceneCapture::render(GFXCommandBuffer* command_buffer, Scene* scene) {
|
||||||
Vector3 front = Vector3(0.0f, 0.0f, 1.0f) * scene->get<Transform>(obj).rotation;
|
Vector3 front = Vector3(0.0f, 0.0f, 1.0f) * scene->get<Transform>(obj).rotation;
|
||||||
|
|
||||||
sl.directionPower = Vector4(-front, light.power);
|
sl.directionPower = Vector4(-front, light.power);
|
||||||
sl.colorSize = Vector4(light.color, radians(light.size));
|
sl.colorSize = Vector4(light.color, radians(light.spot_size));
|
||||||
sl.shadowsEnable = Vector4(light.enable_shadows, 0, 0, 0);
|
sl.shadowsEnable = Vector4(light.enable_shadows, radians(light.size), 0, 0);
|
||||||
|
|
||||||
sceneInfo.lights[sceneInfo.numLights++] = sl;
|
sceneInfo.lights[sceneInfo.numLights++] = sl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ vec2 IntegrateBRDF(float NdotV, float roughness) {
|
||||||
// preferred alignment direction (importance sampling).
|
// preferred alignment direction (importance sampling).
|
||||||
const vec2 Xi = hammersley(i, SAMPLE_COUNT);
|
const vec2 Xi = hammersley(i, SAMPLE_COUNT);
|
||||||
const vec3 H = importance_sample_ggx(Xi, N, roughness);
|
const vec3 H = importance_sample_ggx(Xi, N, roughness);
|
||||||
const vec3 L = normalize(2.0 * dot(V, H) * H - V);
|
const vec3 L = 2.0 * dot(V, H) * H - V;
|
||||||
|
|
||||||
const float NdotL = max(L.z, 0.0);
|
const float NdotL = max(L.z, 0.0);
|
||||||
const float NdotH = max(H.z, 0.0);
|
const float NdotH = max(H.z, 0.0);
|
||||||
|
|
|
@ -88,10 +88,14 @@ float geometry_slick_direct(const vec3 N, const vec3 V, const float roughness) {
|
||||||
|
|
||||||
// GGX Smith Geometry, using GGX slick but combining both the view direction and the light direction
|
// GGX Smith Geometry, using GGX slick but combining both the view direction and the light direction
|
||||||
float geometry_smith(const vec3 N, const vec3 V, const vec3 L, float roughness) {
|
float geometry_smith(const vec3 N, const vec3 V, const vec3 L, float roughness) {
|
||||||
float ggx2 = geometry_slick_direct(N, V, roughness);
|
const float dotNV = max(dot(N, V), 0.0);
|
||||||
float ggx1 = geometry_slick_direct(N, L, roughness);
|
const float dotNL = max(dot(N, L), 0.0);
|
||||||
|
|
||||||
return ggx1 * ggx2;
|
const float k = (roughness * roughness) / 2.0;
|
||||||
|
const float GL = dotNL / (dotNL * (1.0 - k) + k);
|
||||||
|
const float GV = dotNV / (dotNV * (1.0 - k) + k);
|
||||||
|
|
||||||
|
return GL * GV;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fresnel Shlick
|
// Fresnel Shlick
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
struct ComputedSurfaceInfo {
|
struct ComputedSurfaceInfo {
|
||||||
vec3 N;
|
vec3 N;
|
||||||
vec3 V;
|
vec3 V;
|
||||||
vec3 F0;
|
vec3 F0, diffuse_color;
|
||||||
|
|
||||||
float NdotV;
|
float NdotV;
|
||||||
|
|
||||||
|
@ -16,47 +16,44 @@ ComputedSurfaceInfo compute_surface(const vec3 diffuse, const vec3 normal, const
|
||||||
info.NdotV = max(dot(info.N, info.V), 0.0);
|
info.NdotV = max(dot(info.N, info.V), 0.0);
|
||||||
|
|
||||||
info.metallic = metallic;
|
info.metallic = metallic;
|
||||||
info.roughness = max(0.0001, roughness * roughness);
|
info.roughness = max(0.0001, roughness);
|
||||||
|
|
||||||
info.F0 = mix(vec3(0.04), diffuse, info.metallic);
|
info.F0 = 0.16 * (1.0 - info.metallic) + diffuse * info.metallic;
|
||||||
|
info.diffuse_color = (1.0 - info.metallic) * diffuse;
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ComputedLightSurfaceInfo {
|
struct SurfaceBRDF {
|
||||||
vec3 kD;
|
vec3 diffuse, specular;
|
||||||
vec3 specular;
|
|
||||||
float NdotL;
|
float NdotL;
|
||||||
};
|
};
|
||||||
|
|
||||||
ComputedLightSurfaceInfo compute_light_surface(const vec3 L, const ComputedSurfaceInfo surface_info) {
|
SurfaceBRDF brdf(const vec3 L, const ComputedSurfaceInfo surface_info) {
|
||||||
ComputedLightSurfaceInfo info;
|
SurfaceBRDF info;
|
||||||
|
|
||||||
// half-vector
|
// half-vector
|
||||||
const vec3 H = normalize(surface_info.V + L);
|
const vec3 H = normalize(surface_info.V + L);
|
||||||
const float HdotV = clamp(dot(H, surface_info.V), 0.0, 1.0);
|
const float HdotV = clamp(dot(H, surface_info.V), 0.0, 1.0);
|
||||||
|
|
||||||
const vec3 F = fresnel_schlick(HdotV, surface_info.F0);
|
// fresnel reflectance function
|
||||||
|
const vec3 F = fresnel_schlick(surface_info.NdotV, surface_info.F0);
|
||||||
info.kD = (vec3(1.0) - F) * (1.0 - surface_info.metallic);
|
|
||||||
|
|
||||||
|
// geometry function
|
||||||
const float D = ggx_distribution(surface_info.N, H, surface_info.roughness);
|
const float D = ggx_distribution(surface_info.N, H, surface_info.roughness);
|
||||||
|
|
||||||
|
// normal distribution function
|
||||||
const float G = geometry_smith(surface_info.N, surface_info.V, L, surface_info.roughness);
|
const float G = geometry_smith(surface_info.N, surface_info.V, L, surface_info.roughness);
|
||||||
|
|
||||||
/*
|
|
||||||
F = fresnel reflectance function
|
|
||||||
G = geometry function
|
|
||||||
D = NDF (normal distribution function)
|
|
||||||
*/
|
|
||||||
const vec3 numerator = F * G * D;
|
const vec3 numerator = F * G * D;
|
||||||
|
|
||||||
/*
|
|
||||||
Correction factor
|
|
||||||
*/
|
|
||||||
const float denominator = 4.0 * surface_info.NdotV * clamp(dot(surface_info.N, L), 0.0, 1.0);
|
const float denominator = 4.0 * surface_info.NdotV * clamp(dot(surface_info.N, L), 0.0, 1.0);
|
||||||
|
|
||||||
|
// cook-torrance specular brdf
|
||||||
info.specular = numerator / (denominator + 0.001);
|
info.specular = numerator / (denominator + 0.001);
|
||||||
|
|
||||||
|
// lambertian diffuse
|
||||||
|
info.diffuse = surface_info.diffuse_color * (1.0 / PI);
|
||||||
|
|
||||||
info.NdotL = clamp(dot(surface_info.N, L), 0.0, 1.0);
|
info.NdotL = clamp(dot(surface_info.N, L), 0.0, 1.0);
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
|
Reference in a new issue