Permalink
Switch branches/tags
develop docs feature/add_atmospherics_ambient_to_deferred_shader feature/analytic_radiance_functions feature/ansiotropic_ggx feature/atmospherics_ambient feature/atmospherics_sky_scattering feature/atmospherics feature/basic_gui feature/better_diffuse_model_fitting_ggx feature/binary_voxelize feature/binding_set_pool_instances_deletion_queue feature/brdf_fitter feature/buffer_object_sparse_commitment_bitmap feature/bug_attributed_string_infinite_loop feature/camera_projection_model_update feature/cleanup_demo_scene feature/comments_doxygen feature/concurrent_gpu_data_structures feature/concurrent_vector feature/cone_tracing feature/correct_cpp_language_issues feature/correct_gbuffer_generation feature/cull_shadow_faces feature/depth_of_field feature/directional_lights feature/dof_bokeh_circle_of_confusion_handle_infinity feature/dual_quaternion_tranform feature/external_binding_sets_specialization_constants feature/fresnel_better_routines feature/fxaa feature/gbuffer_use_images feature/gcc_support feature/ggx_fittings_correct_integration feature/git_lfs feature/glsl_programs_pool feature/glsl_remove_nv_extensions feature/gpu_timer_query_and_performance_visualization feature/icc16_win_compilation feature/integrate_glsllang_spirv_compiler feature/integrate_graphics_modules_into_primary_renderer feature/inverted_depth_buffer feature/khr_dedicated_allocation feature/layered_surface_reflection feature/lights_merge_transformed_position feature/linearly_transformed_cosines feature/material_and_light_frameworks feature/material_correct_ior_probabilistic_approach feature/material_textures_storage feature/microfacet_energy_perservation_with_different_ior_layers feature/mipmap_depth_buffer feature/model_factory_support_displacement_and_normal_maps feature/more_info_on_debug_gui feature/multi_layered_materials feature/multiple_nonconsecutive_binding_sets feature/normalize_classes_and_objects_name_case feature/observable_resource_custom_resource_updater feature/octree_traversal feature/optimizations feature/optimizations2 feature/order_independant_trasnparency feature/organize_secondary_command_buffers feature/organize_shaders_function_parameters feature/pack_linked_light_list_element feature/pack_material_and_layer_descriptors feature/packed_gbuffer feature/pcf_shadow feature/per_pixel_linked_light_lists feature/polygonal_lights feature/projection_buffer_add_backbuffer_size feature/refactor_gpu_dispatchable feature/remove_oit_remove_gbuffer_ll feature/rendering_system feature/resource_loader feature/resource_storage feature/scene_and_objects feature/scene_frustum_cull feature/screen_space_soft_shadows feature/sequential_ordering_optimization_of_gpu_dispatch feature/shared_futex feature/signalling_storages_on_modification feature/small_allocator feature/ste_allocator feature/stohastic_light_culling_based_on_hdr_exposure feature/subsurface_scattering_multiple_scatters feature/subsurface_scattering feature/surface_block_readwrite_avx feature/surfaces feature/switch_models_and_materials_to_analytic_materials feature/task_dispatch_graph feature/task_future feature/task_scheduler_futures_execute_synchronously_when_applicable feature/tasks_cleanup feature/third_party feature/todo_hardware_destructive_interference_size feature/todo_pipeline_layout_exception_mention_variable_names feature/todo_strong_typed_common_types feature/translate_model_factory feature/uniform_distribution_light_integration feature/update_submodule_220916 feature/utility_buffer_image_host_read feature/volumetric_scattering_depth_aware_sampling feature/volumetric_scattering feature/volumetric_stratified_sampling feature/voxel_bricks_texture feature/voxels_data_and_interpolation feature/voxels_interpolate feature/vulkan_hdr_module feature/vulkan_objects_debug_name_markers feature/vulkan_primary_renderer feature/vulkan_sponza_gui_profiler feature/vulkan_text_engine feature/vulkan_translate_graphics_modules feature/vulkan master release/sponza_demo_022017 ssao_cone_trace
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
394 lines (339 sloc) 14.6 KB
#include <material.glsl>
#include <material_layer_unpack.glsl>
#include <subsurface_scattering.glsl>
#include <deferred_shading_common.glsl>
#include <common.glsl>
#include <light.glsl>
#include <light_transport.glsl>
#include <cosine_distribution_integration.glsl>
#include <clamped_cosine_distribution_integration.glsl>
#include <microfacet_ggx_fitting.glsl>
#include <cook_torrance.glsl>
#include <lambert_diffuse.glsl>
#include <disney_diffuse.glsl>
#include <fresnel.glsl>
const float air_ior = 1.0002772f;
vec3 material_evaluate_layer_radiance(material_layer_unpacked_descriptor descriptor,
light_descriptor ld,
sampler2D ltc_ggx_fit,
sampler2D ltc_ggx_amplitude,
float l_dist,
vec3 wp,
vec3 wn,
vec3 wv,
vec3 n, vec3 t, vec3 b,
vec3 v, vec3 l, vec3 h,
float cos_critical,
float refractive_ratio,
vec3 irradiance,
vec3 albedo,
vec3 diffused_light) {
// Specular color
vec3 specular_tint = vec3(1);
vec3 c_spec = mix(specular_tint, albedo, descriptor.metallic);
// Shading type
bool is_directional = light_type_is_directional(ld.type);
bool ltc_integration = light_type_is_shaped(ld.type) || is_directional;
if (ltc_integration) {
// Calculate polygonal light irradiance using linearly transformed cosines
vec2 ltccoords = ltc_lut_coords(ltc_ggx_fit, dot(n, v), descriptor.roughness);
mat3 ltc_M_inv = ltc_inv_matrix(ltc_ggx_fit, ltccoords);
float ltc_ampl = texture(ltc_ggx_amplitude, ltccoords).x;
// Read light shape
bool shape_sphere = light_shape_is_sphere(ld.type);
bool shape_quad = light_shape_is_quad(ld.type);
bool shape_polygon = light_shape_is_polygon(ld.type);
bool shape_polyhedron = light_shape_is_convex_polyhedron(ld.type);
// And properties
bool two_sided = light_type_is_two_sided(ld.type);
bool textured = light_type_is_textured(ld.type);
// Points count and offset into points buffer
uint points_count = light_get_polygon_point_counts(ld);
uint points_offset = light_get_polygon_point_offset(ld);
// Light position
vec3 L = is_directional ?
wp + l * light_directional_distance(ld) :
ld.position;
vec3 wl = (L - wp) / l_dist;
// The integration type depends on shape
vec3 specular_irradiance;
vec3 diffuse_irradiance;
if (shape_sphere || is_directional) {
// No points needed for spherical light
// Directional lights are (very far) sphere lights. Treat them identically.
float r = ld.radius;
specular_irradiance = ltc_evaluate_sphere(wn, wv, wp, ltc_M_inv, L, r) * ltc_ampl;
diffuse_irradiance = ltc_evaluate_sphere(wn, wv, wp, mat3(1), L, r);
}
else if (shape_quad) {
// Quad. Always 4 points.
specular_irradiance = ltc_evaluate_quad(wn, wv, wp, ltc_M_inv, L, points_offset, two_sided) * ltc_ampl;
diffuse_irradiance = ltc_evaluate_quad(wn, wv, wp, mat3(1), L, points_offset, two_sided);
}
else if (shape_polygon) {
specular_irradiance = ltc_evaluate_polygon(wn, wv, wp, ltc_M_inv, L, points_count, points_offset, two_sided) * ltc_ampl;
diffuse_irradiance = ltc_evaluate_polygon(wn, wv, wp, mat3(1), L, points_count, points_offset, two_sided);
}
else /*if (shape_polyhedron)*/ {
// Polyhedron light. Primitives are always triangles.
uint primitives = points_count / 3;
specular_irradiance = ltc_evaluate_convex_polyhedron(wn, wv, wp, ltc_M_inv, L, primitives, points_offset) * ltc_ampl;
diffuse_irradiance = ltc_evaluate_convex_polyhedron(wn, wv, wp, mat3(1), L, primitives, points_offset);
}
// Compute fresnel term
float F = fresnel(dot(l, h), cos_critical, refractive_ratio);
// And finalize
vec3 Specular = F * c_spec * specular_irradiance;
vec3 Diffuse = diffused_light * diffuse_irradiance;
return irradiance * (Specular + Diffuse);
}
else { // Virtual light
// For non-integrated lights we need to factor light attenuation manually.
float attenuation = virtual_light_attenuation(ld, l_dist);
// Anisotropic roughness
//float rx = descriptor.roughness * descriptor.anisotropy_ratio;
//float ry = descriptor.roughness / descriptor.anisotropy_ratio;
// Evaluate BRDFs
vec3 Specular = cook_torrance_iso_brdf(n,
v, l, h,
descriptor.roughness,
cos_critical,
refractive_ratio,
c_spec);
vec3 Diffuse = diffused_light * lambert_diffuse_brdf();
vec3 brdf = irradiance * dot(n, l) * (Specular + Diffuse);
return max(vec3(.0f), attenuation * brdf);
}
}
float material_attenuation_through_layer(float transmittance,
float metallic,
float masking) {
float passthrough = 1.f - metallic;
return transmittance * masking * passthrough;
}
/*
* Evaluate radiance of material at fragment. Simple single-layered materials without subsurface scattering.
*
* @param layer Material layer
* @param frag Fragment shading parameters
* @param light Light shading parameters
* @param material_microfacet_luts Microfacet GGX fitting LUTs
* @param occlusion Light occlusion
* @param external_medium_ior Index-of-refraction of source medium
*/
vec3 material_evaluate_radiance_simple(material_layer_unpacked_descriptor descriptor,
fragment_shading_parameters frag,
light_shading_parameters light,
sampler2D ltc_ggx_fit,
sampler2D ltc_ggx_amplitude,
sampler2D microfacet_refraction_fit_lut,
sampler2DArray microfacet_transmission_fit_lut,
float occlusion,
float external_medium_ior) {
// Compute sine and cosine of critical angle
float refractive_ratio = descriptor.ior / external_medium_ior;
float cos_critical = refractive_ratio < 1.f ?
sqrt(1.f - refractive_ratio * refractive_ratio) :
.0f;
// Evaluate refracted vectors
/*vec3 refracted_v = -ggx_refract(microfacet_refraction_fit_lut,
frag.v, frag.n,
descriptor.roughness,
refractive_ratio);
vec3 refracted_l = -ggx_refract(microfacet_refraction_fit_lut,
light.l, frag.n,
descriptor.roughness,
refractive_ratio);*/
// Evaluate total inner (downwards into material) and outer (upwards towards eye) transmission
float inner_transmission_ratio = ggx_transmission_ratio_v4(microfacet_transmission_fit_lut,
frag.v, frag.n,
descriptor.roughness,
refractive_ratio);
float outer_transmission_ratio = ggx_transmission_ratio_v4(microfacet_transmission_fit_lut,
/*refracted_l*/light.l, frag.n,
descriptor.roughness,
1.f / refractive_ratio);
vec3 scattering = inner_transmission_ratio * outer_transmission_ratio * descriptor.albedo.rgb;
vec3 diffused_light = descriptor.albedo.rgb * (1.f - descriptor.metallic);
// Half vector
vec3 h = normalize(frag.v + light.l);
// Evaluate layer BRDF
vec3 rgb = material_evaluate_layer_radiance(descriptor,
light.ld,
ltc_ggx_fit,
ltc_ggx_amplitude,
light.l_dist,
frag.world_position,
frag.world_normal,
frag.world_v,
frag.n, frag.t, frag.b,
frag.v, light.l, h,
cos_critical,
refractive_ratio,
light.cd_m2,
descriptor.albedo.rgb,
diffused_light);
return rgb * occlusion;
}
/*
* Evaluate radiance of material at fragment
*
* @param md Material descriptor
* @param layer Material layer
* @param frag Fragment shading parameters
* @param light Light shading parameters
* @param uv Material texture coordinates at sample point. Used for material layer unpacking.
* @param duvdx Material texture coordinates d/dx partial derivative at sample point. Used for material layer unpacking.
* @param duvdy Material texture coordinates d/dy partial derivative at sample point. Used for material layer unpacking.
* @param object_thickness Object thickness at shaded fragment
* @param material_microfacet_luts Microfacet GGX fitting LUTs
* @param shadow_maps Shadow maps
* @param occlusion Light occlusion
* @param external_medium_ior Index-of-refraction of source medium
*/
vec3 material_evaluate_radiance(material_descriptor md,
material_layer_descriptor layer,
fragment_shading_parameters frag,
light_shading_parameters light,
sampler2D ltc_ggx_fit,
sampler2D ltc_ggx_amplitude,
sampler2D microfacet_refraction_fit_lut,
sampler2DArray microfacet_transmission_fit_lut,
vec2 uv, vec2 duvdx, vec2 duvdy,
float object_thickness,
float occlusion,
float external_medium_ior) {
material_layer_unpacked_descriptor descriptor = material_layer_unpack(layer, uv, duvdx, duvdy);
// A simple material is a material without subsurface scattering and a single layer.
// Use a faster codepath in that case.
bool simple_material = material_is_simple(md, layer);
if (simple_material) {
return material_evaluate_radiance_simple(descriptor,
frag,
light,
ltc_ggx_fit,
ltc_ggx_amplitude,
microfacet_refraction_fit_lut,
microfacet_transmission_fit_lut,
occlusion,
external_medium_ior);
}
vec3 rgb = vec3(0);
vec3 n = frag.n;
vec3 t = frag.t;
vec3 b = frag.b;
vec3 position = frag.p;
ivec2 frag_coords = frag.coords;
vec3 l = light.l;
vec3 v = frag.v;
float top_medium_ior = external_medium_ior;
// Attenuation at current layer
vec3 attenuation = vec3(1.f);
// Attenuation of outgoing radiance, for sub-surface scattering
vec3 sss_attenuation = vec3(1.f);
while (true) {
// Read layer properties
vec3 albedo = descriptor.albedo.rgb;
float thickness = material_is_base_layer(descriptor) ? object_thickness : descriptor.thickness;
float metallic = descriptor.metallic;
float roughness = descriptor.roughness;
vec3 attenuation_coefficient = descriptor.attenuation_coefficient.rgb;
float bottom_medium_ior = descriptor.ior;
// Compute sine and cosine of critical angle
float refractive_ratio = bottom_medium_ior / top_medium_ior;
float cos_critical = refractive_ratio < 1.f ?
sqrt(1.f - refractive_ratio * refractive_ratio) :
.0f;
// Compute Fresnel reflection at parallel incidence
float F0 = fresnel_F0(refractive_ratio);
// Evaluate refracted vectors
/*vec3 refracted_v = -ggx_refract(microfacet_refraction_fit_lut,
v, n,
roughness,
refractive_ratio);
vec3 refracted_l = -ggx_refract(microfacet_refraction_fit_lut,
l, n,
roughness,
refractive_ratio);*/
// Evaluate total inner (downwards into material) and outer (upwards towards eye) transmission
float inner_transmission_ratio = ggx_transmission_ratio_v4(microfacet_transmission_fit_lut,
v, n,
roughness,
refractive_ratio);
float outer_transmission_ratio = ggx_transmission_ratio_v4(microfacet_transmission_fit_lut,
/*refracted_l*/l, n,
roughness,
1.f / refractive_ratio);
// Compute total and outer path lengths inside current layer
//float dotNV = max(epsilon, dot(n,refracted_v));
//float dotNL = max(epsilon, dot(n,refracted_l));
float dotNV = max(epsilon, dot(n,v));
float dotNL = max(epsilon, dot(n,l));
float path_length = thickness * (1.f / dotNV + 1.f / dotNL);
float outer_path_length = thickness / dotNL;
// Compute light attenuation in layer
vec3 k = beer_lambert(attenuation_coefficient, path_length);
// Compute light attenuation in layer on outgoing direction only
vec3 sss_outer_extinction = beer_lambert(attenuation_coefficient, outer_path_length);
// Diffused light is a portion of the energy scattered inside layer (based on albedo), unattenuated light doesn't contribute to diffuse
vec3 scattering = inner_transmission_ratio * outer_transmission_ratio * (vec3(1.f) - k) * albedo;
vec3 diffused_light = scattering * (1.f - metallic);
// Half vector
vec3 h = normalize(v + l);
// Evaluate layer BRDF
rgb += attenuation * material_evaluate_layer_radiance(descriptor,
light.ld,
ltc_ggx_fit,
ltc_ggx_amplitude,
light.l_dist,
frag.world_position,
frag.world_normal,
frag.world_v,
n, t, b,
v, l, h,
cos_critical,
refractive_ratio,
light.cd_m2,
albedo,
diffused_light);
// Update incident and outgoing vectors to refracted ones before continuing to next layer
//v = refracted_v;
//l = refracted_l;
// Compute attenuated light due to Fresnel transmittance, microfacet masking-shadowing and metallicity
float layer_surface_outer_attenuation = material_attenuation_through_layer(outer_transmission_ratio,
metallic,
1/*Gmask*/);
// For sub-surface scattering we assume normal incidence of light, and we attenuate based on (presumed) incident and outgoing sides
sss_attenuation *= layer_surface_outer_attenuation * material_attenuation_through_layer(1.f - F0, metallic, 1.f);
// If this is the base layer, stop
if (material_is_base_layer(descriptor))
break;
// Otherwise, update attenuation with attenuation at layer surface and with attenuated (absorbed and scattered) light
float layer_surface_inner_attenuation = material_attenuation_through_layer(inner_transmission_ratio,
metallic,
1/*Gshadow*/);
float total_layer_surface_attenuation = layer_surface_inner_attenuation * layer_surface_outer_attenuation;
attenuation *= total_layer_surface_attenuation * k;
// Update sss attenuation with attenuation on the way out and attenuation on the way in with parallel incident
sss_attenuation *= sss_outer_extinction * beer_lambert(attenuation_coefficient, thickness);
// Set ior and descriptor for next layer
top_medium_ior = bottom_medium_ior;
material_layer_descriptor next_layer_material_descriptor = mat_layer_descriptor[descriptor.next_layer_id];
descriptor = material_layer_unpack(next_layer_material_descriptor, uv, duvdx, duvdy);
}
// Apply occlusion
rgb *= occlusion;
// Sub-surface scattering
bool fully_attenuated = all(lessThan(sss_attenuation, vec3(epsilon)));
if (!fully_attenuated) {
rgb += sss_attenuation * subsurface_scattering(descriptor,
position,
n,
object_thickness,
light.ld,
light,
-v,
frag_coords);
}
return rgb;
}