mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-12-17 23:09:40 +01:00
a9d5e4dd22
- change how shadows for environment lights work: should cast light only when hitting SURF_SKY - add SBT_RECORD_SIZE to specialization; need this for sky/shadow closest hit shader fix #140
540 lines
20 KiB
Plaintext
540 lines
20 KiB
Plaintext
#version 460 core
|
|
#extension GL_GOOGLE_include_directive : require
|
|
#include "ray_common.glsl"
|
|
#include "ray_kusochki.glsl"
|
|
#include "noise.glsl"
|
|
#include "brdf.h"
|
|
|
|
//#define DEBUG_LIGHT_CULLING
|
|
|
|
// FIXME what should these be?
|
|
const float shadow_offset_fudge = .1;
|
|
const float pdf_culling_threshold = 100.;
|
|
const float color_factor = 600.;
|
|
const float color_culling_threshold = 600./color_factor;
|
|
const float throughput_threshold = 1e-3;
|
|
|
|
layout (constant_id = 4) const float LIGHT_GRID_CELL_SIZE = 256.;
|
|
layout (constant_id = 5) const uint MAX_LIGHT_CLUSTERS = 32768;
|
|
layout (constant_id = 7) const uint SBT_RECORD_SIZE = 64;
|
|
|
|
//const uint LIGHT_CLUSTER_SIZE = 2 + MAX_VISIBLE_POINT_LIGHTS + MAX_VISIBLE_SURFACE_LIGHTS;
|
|
//const uint LIGHT_CLUSTER_NUM_DLIGHTS_OFFSET = 0;
|
|
//const uint LIGHT_CLUSTER_NUM_EMISSIVE_SURFACES_OFFSET = 1;
|
|
//const uint LIGHT_CLUSTER_DLIGHTS_DATA_OFFSET = 2;
|
|
//const uint LIGHT_CLUSTER_EMISSIVE_SURFACES_DATA_OFFSET = 3 + MAX_VISIBLE_DLIGHTS;
|
|
|
|
layout(set = 0, binding = 0, rgba8) uniform image2D out_image_base_color;
|
|
layout(set = 0, binding = 9, rgba16f) uniform image2D out_image_diffuse_gi;
|
|
layout(set = 0, binding = 10, rgba16f) uniform image2D out_image_specular;
|
|
layout(set = 0, binding = 11, rgba16f) uniform image2D out_image_additive;
|
|
layout(set = 0, binding = 12, rgba16f) uniform image2D out_image_normals;
|
|
|
|
layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas;
|
|
layout(set = 0, binding = 2) uniform UBO {
|
|
mat4 inv_proj, inv_view;
|
|
} ubo;
|
|
|
|
layout (set = 0, binding = 7/*, align=4*/) uniform UBOLights { Lights lights; };
|
|
|
|
layout (set = 0, binding = 8, align = 1) readonly buffer UBOLightClusters {
|
|
ivec3 grid_min, grid_size;
|
|
//uint8_t clusters_data[MAX_LIGHT_CLUSTERS * LIGHT_CLUSTER_SIZE + HACK_OFFSET];
|
|
LightCluster clusters[MAX_LIGHT_CLUSTERS];
|
|
} light_grid;
|
|
|
|
layout (push_constant) uniform PC_ {
|
|
PushConstants push_constants;
|
|
};
|
|
|
|
layout(location = PAYLOAD_LOCATION_OPAQUE) rayPayloadEXT RayPayloadOpaque payload_opaque;
|
|
layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadEXT RayPayloadShadow payload_shadow;
|
|
layout(location = PAYLOAD_LOCATION_ADDITIVE) rayPayloadEXT RayPayloadAdditive payload_additive;
|
|
|
|
bool shadowed(vec3 pos, vec3 dir, float dist) {
|
|
payload_shadow.hit_type = SHADOW_HIT;
|
|
const uint flags = 0
|
|
//| gl_RayFlagsCullFrontFacingTrianglesEXT
|
|
//| gl_RayFlagsOpaqueEXT
|
|
| gl_RayFlagsTerminateOnFirstHitEXT
|
|
| gl_RayFlagsSkipClosestHitShaderEXT
|
|
;
|
|
traceRayEXT(tlas,
|
|
flags,
|
|
GEOMETRY_BIT_OPAQUE,
|
|
0, 0, SHADER_OFFSET_MISS_SHADOW,
|
|
pos, 0., dir, dist - shadow_offset_fudge, PAYLOAD_LOCATION_SHADOW);
|
|
return payload_shadow.hit_type == SHADOW_HIT;
|
|
}
|
|
|
|
// TODO join with just shadowed()
|
|
bool shadowedSky(vec3 pos, vec3 dir, float dist) {
|
|
payload_shadow.hit_type = SHADOW_HIT;
|
|
const uint flags = 0
|
|
//| gl_RayFlagsCullFrontFacingTrianglesEXT
|
|
//| gl_RayFlagsOpaqueEXT
|
|
//| gl_RayFlagsTerminateOnFirstHitEXT
|
|
//| gl_RayFlagsSkipClosestHitShaderEXT
|
|
;
|
|
traceRayEXT(tlas,
|
|
flags,
|
|
GEOMETRY_BIT_OPAQUE,
|
|
SHADER_OFFSET_HIT_SHADOW, SBT_RECORD_SIZE, SHADER_OFFSET_MISS_SHADOW,
|
|
pos, 0., dir, dist - shadow_offset_fudge, PAYLOAD_LOCATION_SHADOW);
|
|
return payload_shadow.hit_type != SHADOW_SKY;
|
|
}
|
|
|
|
// This is an entry point for evaluation of all other BRDFs based on selected configuration (for direct light)
|
|
void evalSplitBRDF(vec3 N, vec3 L, vec3 V, MaterialProperties material, out vec3 diffuse, out vec3 specular) {
|
|
// Prepare data needed for BRDF evaluation - unpack material properties and evaluate commonly used terms (e.g. Fresnel, NdotL, ...)
|
|
const BrdfData data = prepareBRDFData(N, L, V, material);
|
|
|
|
// Ignore V and L rays "below" the hemisphere
|
|
//if (data.Vbackfacing || data.Lbackfacing) return vec3(0.0f, 0.0f, 0.0f);
|
|
|
|
// Eval specular and diffuse BRDFs
|
|
specular = evalSpecular(data);
|
|
diffuse = evalDiffuse(data);
|
|
|
|
// Combine specular and diffuse layers
|
|
#if COMBINE_BRDFS_WITH_FRESNEL
|
|
// Specular is already multiplied by F, just attenuate diffuse
|
|
diffuse *= vec3(1.) - data.F;
|
|
#endif
|
|
}
|
|
|
|
void sampleSurfaceTriangle(
|
|
vec3 color, vec3 view_dir, MaterialProperties material /* TODO BrdfData instead is supposedly more efficient */,
|
|
mat4x3 emissive_transform, mat3 emissive_transform_normal,
|
|
uint triangle_index, uint index_offset, uint vertex_offset,
|
|
out vec3 diffuse, out vec3 specular)
|
|
{
|
|
diffuse = specular = vec3(0.);
|
|
const uint first_index_offset = index_offset + triangle_index * 3;
|
|
|
|
// TODO this is not entirely correct -- need to mix between all normals, or have this normal precomputed
|
|
const uint vi1 = uint(indices[first_index_offset+0]) + vertex_offset;
|
|
const uint vi2 = uint(indices[first_index_offset+1]) + vertex_offset;
|
|
const uint vi3 = uint(indices[first_index_offset+2]) + vertex_offset;
|
|
|
|
const vec3 v1 = (emissive_transform * vec4(vertices[vi1].pos, 1.)).xyz;
|
|
const vec3 v2 = (emissive_transform * vec4(vertices[vi2].pos, 1.)).xyz;
|
|
const vec3 v3 = (emissive_transform * vec4(vertices[vi3].pos, 1.)).xyz;
|
|
|
|
// TODO projected uniform sampling
|
|
const vec3 sample_pos = mix(mix(v1, v2, rand01()), v3, rand01());
|
|
|
|
vec3 light_dir = sample_pos - payload_opaque.hit_pos_t.xyz;
|
|
const float light_dir_normal_dot = dot(light_dir, payload_opaque.normal);
|
|
if (light_dir_normal_dot <= 0.)
|
|
#ifdef DEBUG_LIGHT_CULLING
|
|
return vec3(1., 0., 1.) * color_factor;
|
|
#else
|
|
return;
|
|
#endif
|
|
|
|
// Consider area light sources as planes, take the first normal
|
|
const vec3 normal = normalize(emissive_transform_normal * vertices[vi1].normal);
|
|
|
|
const float light_dot = -dot(light_dir, normal);
|
|
if (light_dot <= 0.)
|
|
#ifdef DEBUG_LIGHT_CULLING
|
|
return vec3(1., 0., 0.) * color_factor;
|
|
#else
|
|
return;
|
|
#endif
|
|
|
|
// TODO emissive normals and areas can be precomputed
|
|
const float area = .5 * length(cross(v1 - v2, v1 - v3));
|
|
const float light_dist2 = dot(light_dir, light_dir);
|
|
float pdf = light_dist2 / (area * light_dot);
|
|
|
|
if (pdf > pdf_culling_threshold)
|
|
#ifdef DEBUG_LIGHT_CULLING
|
|
return vec3(0., 1., 0.) * color_factor;
|
|
#else
|
|
return;
|
|
#endif
|
|
|
|
color /= pdf;
|
|
|
|
if (dot(color,color) < color_culling_threshold)
|
|
#ifdef DEBUG_LIGHT_CULLING
|
|
return vec3(0., 1., 0.) * color_factor;
|
|
#else
|
|
return;
|
|
#endif
|
|
|
|
light_dir = normalize(light_dir);
|
|
|
|
// TODO sample emissive texture
|
|
evalSplitBRDF(payload_opaque.normal, light_dir, view_dir, material, diffuse, specular);
|
|
diffuse *= color;
|
|
specular *= color;
|
|
|
|
vec3 combined = diffuse + specular;
|
|
|
|
if (dot(combined,combined) < color_culling_threshold)
|
|
#ifdef DEBUG_LIGHT_CULLING
|
|
return vec3(1., 1., 0.) * color_factor;
|
|
#else
|
|
return;
|
|
#endif
|
|
|
|
if (shadowed(payload_opaque.hit_pos_t.xyz, light_dir, sqrt(light_dist2))) {
|
|
diffuse = specular = vec3(0.);
|
|
}
|
|
}
|
|
|
|
void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, MaterialProperties material, out vec3 diffuse, out vec3 specular) {
|
|
diffuse = specular = vec3(0.);
|
|
const uint num_point_lights = uint(light_grid.clusters[cluster_index].num_point_lights);
|
|
for (uint j = 0; j < num_point_lights; ++j) {
|
|
const uint i = uint(light_grid.clusters[cluster_index].point_lights[j]);
|
|
|
|
vec3 color = lights.point_lights[i].color_stopdot.rgb * throughput;
|
|
if (dot(color,color) < color_culling_threshold)
|
|
continue;
|
|
|
|
const vec4 origin_r = lights.point_lights[i].origin_r;
|
|
const float stopdot = lights.point_lights[i].color_stopdot.a;
|
|
const vec3 dir = lights.point_lights[i].dir_stopdot2.xyz;
|
|
const float stopdot2 = lights.point_lights[i].dir_stopdot2.a;
|
|
const bool not_environment = (lights.point_lights[i].environment == 0);
|
|
|
|
const vec3 light_dir = not_environment ? (origin_r.xyz - payload_opaque.hit_pos_t.xyz) : -dir; // TODO need to randomize sampling direction for environment soft shadow
|
|
const vec3 light_dir_norm = normalize(light_dir);
|
|
const float light_dot = dot(light_dir_norm, payload_opaque.normal);
|
|
if (light_dot < 1e-5)
|
|
continue;
|
|
|
|
const float spot_dot = -dot(light_dir_norm, dir);
|
|
if (spot_dot < stopdot2)
|
|
continue;
|
|
|
|
float spot_attenuation = 1.f;
|
|
if (spot_dot < stopdot)
|
|
spot_attenuation = (spot_dot - stopdot2) / (stopdot - stopdot2);
|
|
|
|
float fdist = 1.f;
|
|
float light_dist = 1e4; // TODO this is supposedly not the right way to do shadows for environment lights. qrad checks for hitting SURF_SKY, and maybe we should too?
|
|
if (not_environment) {
|
|
#if 1
|
|
const float d2 = dot(light_dir, light_dir);
|
|
const float r2 = origin_r.w * origin_r.w;
|
|
light_dist = sqrt(d2);
|
|
fdist = 2.f / (r2 + d2 + light_dist * sqrt(d2 + r2));
|
|
#else
|
|
const float d2 = dot(light_dir, light_dir);
|
|
//const float r2 = origin_r.w * origin_r.w;
|
|
light_dist = sqrt(d2);
|
|
//const float fdist = 2.f / (r2 + d2 + light_dist * sqrt(d2 + r2));
|
|
//const float fdist = 2.f / (r2 + d2 + light_dist * sqrt(d2 + r2));
|
|
fdist = (light_dist > 1.) ? 1.f / d2 : 1.f; // qrad workaround
|
|
#endif
|
|
}
|
|
const float pdf = 1.f / (fdist * light_dot * spot_attenuation);
|
|
|
|
color /= pdf;
|
|
// if (dot(color,color) < color_culling_threshold)
|
|
// continue;
|
|
|
|
vec3 ldiffuse, lspecular;
|
|
evalSplitBRDF(payload_opaque.normal, light_dir_norm, view_dir, material, ldiffuse, lspecular);
|
|
ldiffuse *= color;
|
|
lspecular *= color;
|
|
|
|
vec3 combined = ldiffuse + lspecular;
|
|
|
|
if (dot(combined,combined) < color_culling_threshold)
|
|
continue;
|
|
|
|
if (not_environment) {
|
|
if (shadowed(payload_opaque.hit_pos_t.xyz, light_dir_norm, light_dist + shadow_offset_fudge))
|
|
continue;
|
|
} else {
|
|
// for environment light check that we've hit SURF_SKY
|
|
if (shadowedSky(payload_opaque.hit_pos_t.xyz, light_dir_norm, light_dist + shadow_offset_fudge))
|
|
continue;
|
|
}
|
|
|
|
diffuse += ldiffuse;
|
|
specular += lspecular;
|
|
} // for all lights
|
|
}
|
|
|
|
void computeLighting(vec3 throughput, vec3 view_dir, MaterialProperties material, out vec3 diffuse, out vec3 specular) {
|
|
diffuse = specular = vec3(0.);
|
|
const ivec3 light_cell = ivec3(floor(payload_opaque.hit_pos_t.xyz / LIGHT_GRID_CELL_SIZE)) - light_grid.grid_min;
|
|
const uint cluster_index = uint(dot(light_cell, ivec3(1, light_grid.grid_size.x, light_grid.grid_size.x * light_grid.grid_size.y)));
|
|
|
|
if (any(greaterThanEqual(light_cell, light_grid.grid_size)) || cluster_index >= MAX_LIGHT_CLUSTERS)
|
|
return; // throughput * vec3(1., 0., 0.);
|
|
|
|
// const uint cluster_offset = cluster_index * LIGHT_CLUSTER_SIZE + HACK_OFFSET;
|
|
// const int num_dlights = int(light_grid.clusters_data[cluster_offset + LIGHT_CLUSTER_NUM_DLIGHTS_OFFSET]);
|
|
// const int num_emissive_surfaces = int(light_grid.clusters_data[cluster_offset + LIGHT_CLUSTER_NUM_EMISSIVE_SURFACES_OFFSET]);
|
|
// const uint emissive_surfaces_offset = cluster_offset + LIGHT_CLUSTER_EMISSIVE_SURFACES_DATA_OFFSET;
|
|
//C = vec3(float(num_emissive_surfaces));
|
|
|
|
//C = vec3(float(int(light_grid.clusters[cluster_index].num_emissive_surfaces)));
|
|
//C += .3 * fract(vec3(light_cell) / 4.);
|
|
|
|
const uint num_emissive_kusochki = uint(light_grid.clusters[cluster_index].num_emissive_surfaces);
|
|
float sampling_light_scale = 1.;
|
|
#if 0
|
|
const uint max_lights_per_frame = 4;
|
|
uint begin_i = 0, end_i = num_emissive_kusochki;
|
|
if (end_i > max_lights_per_frame) {
|
|
begin_i = rand() % (num_emissive_kusochki - max_lights_per_frame);
|
|
end_i = begin_i + max_lights_per_frame;
|
|
sampling_light_scale = float(num_emissive_kusochki) / float(max_lights_per_frame);
|
|
}
|
|
for (uint i = begin_i; i < end_i; ++i) {
|
|
#else
|
|
|
|
for (uint i = 0; i < num_emissive_kusochki; ++i) {
|
|
#endif
|
|
const uint index_into_emissive_kusochki = uint(light_grid.clusters[cluster_index].emissive_surfaces[i]);
|
|
|
|
if (push_constants.debug_light_index_begin < push_constants.debug_light_index_end) {
|
|
if (index_into_emissive_kusochki < push_constants.debug_light_index_begin || index_into_emissive_kusochki >= push_constants.debug_light_index_end)
|
|
continue;
|
|
}
|
|
|
|
const EmissiveKusok ek = lights.kusochki[index_into_emissive_kusochki];
|
|
const uint emissive_kusok_index = lights.kusochki[index_into_emissive_kusochki].kusok_index;
|
|
const Kusok ekusok = kusochki[emissive_kusok_index];
|
|
|
|
// TODO streamline matrices layouts
|
|
const mat4x3 emissive_transform = mat4x3(
|
|
vec3(ek.tx_row_x.x, ek.tx_row_y.x, ek.tx_row_z.x),
|
|
vec3(ek.tx_row_x.y, ek.tx_row_y.y, ek.tx_row_z.y),
|
|
vec3(ek.tx_row_x.z, ek.tx_row_y.z, ek.tx_row_z.z),
|
|
vec3(ek.tx_row_x.w, ek.tx_row_y.w, ek.tx_row_z.w)
|
|
);
|
|
|
|
const mat3 emissive_transform_normal = transpose(inverse(mat3(emissive_transform)));
|
|
|
|
if (emissive_kusok_index == uint(payload_opaque.kusok_index))
|
|
continue;
|
|
|
|
const uint triangle_index = rand_range(ekusok.triangles);
|
|
vec3 ldiffuse, lspecular;
|
|
sampleSurfaceTriangle(throughput * ek.emissive, view_dir, material, emissive_transform, emissive_transform_normal, triangle_index, ekusok.index_offset, ekusok.vertex_offset, ldiffuse, lspecular);
|
|
diffuse += ldiffuse * sampling_light_scale;
|
|
specular += lspecular * sampling_light_scale;
|
|
} // for all emissive kusochki
|
|
|
|
vec3 ldiffuse, lspecular;
|
|
computePointLights(cluster_index, throughput, view_dir, material, ldiffuse, lspecular);
|
|
diffuse += ldiffuse;
|
|
specular += lspecular;
|
|
}
|
|
|
|
// Additive translucency
|
|
vec3 traceAdditive(vec3 origin, vec3 direction, float ray_distance) {
|
|
const uint flags = 0
|
|
/* TODO try without*/ | gl_RayFlagsCullFrontFacingTrianglesEXT
|
|
//| gl_RayFlagsOpaqueEXT
|
|
| gl_RayFlagsSkipClosestHitShaderEXT
|
|
;
|
|
const uint sbt_offset = 0;
|
|
const uint sbt_stride = 0;
|
|
|
|
payload_additive.color = vec3(0.);
|
|
payload_additive.ray_distance = ray_distance;
|
|
traceRayEXT(tlas, flags, GEOMETRY_BIT_ADDITIVE,
|
|
sbt_offset, sbt_stride, SHADER_OFFSET_MISS_EMPTY,
|
|
origin, 0., direction, ray_distance + additive_soft_overshoot,
|
|
PAYLOAD_LOCATION_ADDITIVE);
|
|
return payload_additive.color * color_factor;
|
|
}
|
|
|
|
void main() {
|
|
rand01_state = push_constants.random_seed + gl_LaunchIDEXT.x * 1833 + gl_LaunchIDEXT.y * 31337;
|
|
vec2 uv = (gl_LaunchIDEXT.xy + .5) / gl_LaunchSizeEXT.xy * 2. - 1.;
|
|
|
|
vec3 origin = (ubo.inv_view * vec4(0, 0, 0, 1)).xyz;
|
|
vec4 target = ubo.inv_proj * vec4(uv.x, uv.y, 1, 1);
|
|
vec3 direction = (ubo.inv_view * vec4(normalize(target.xyz), 0)).xyz;
|
|
|
|
payload_opaque.material_index = 0;
|
|
payload_opaque.t_offset = .0;
|
|
payload_opaque.pixel_cone_spread_angle = push_constants.pixel_cone_spread_angle;
|
|
|
|
float out_material_index = 0.;
|
|
vec3 out_additive = vec3(0.);
|
|
vec3 out_diffuse_gi = vec3(0.);
|
|
vec3 out_specular = vec3(0.);
|
|
|
|
// Can be specular or diffuse_gi based on first bounce
|
|
vec3 out_accumulated = vec3(0.);
|
|
|
|
int first_bounce_brdf_type = 0;
|
|
int brdfType = SPECULAR_TYPE;
|
|
vec3 throughput = vec3(1.);
|
|
for (int bounce = 0; bounce < push_constants.bounces; ++bounce) {
|
|
const uint flags = gl_RayFlagsCullFrontFacingTrianglesEXT;
|
|
const uint sbt_offset = 0;
|
|
const uint sbt_stride = 0;
|
|
const float L = 10000.; // Why 10k?
|
|
traceRayEXT(tlas, flags, GEOMETRY_BIT_OPAQUE | GEOMETRY_BIT_REFRACTIVE,
|
|
sbt_offset, sbt_stride, SHADER_OFFSET_MISS_REGULAR,
|
|
origin, 0., direction, L,
|
|
PAYLOAD_LOCATION_OPAQUE);
|
|
|
|
vec3 additive = traceAdditive(origin, direction, payload_opaque.hit_pos_t.w <= 0. ? L : payload_opaque.hit_pos_t.w);
|
|
|
|
// Sky/envmap
|
|
if (payload_opaque.kusok_index < 0) {
|
|
if (bounce == 0) {
|
|
out_additive += payload_opaque.emissive * color_factor + additive;
|
|
} else {
|
|
out_accumulated += throughput * (payload_opaque.emissive * color_factor + additive);
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG_LIGHT_CULLING
|
|
// light clusters debugging
|
|
{
|
|
const ivec3 light_cell = ivec3(floor(payload_opaque.hit_pos_t.xyz / LIGHT_GRID_CELL_SIZE)) - light_grid.grid_min;
|
|
const uint cluster_index = uint(dot(light_cell, ivec3(1, light_grid.grid_size.x, light_grid.grid_size.x * light_grid.grid_size.y)));
|
|
if (any(greaterThanEqual(light_cell, light_grid.grid_size)) || cluster_index >= MAX_LIGHT_CLUSTERS) {
|
|
C = vec3(1., 0., 0.) * color_factor;
|
|
break;
|
|
}
|
|
|
|
const uint num_emissive_kusochki = uint(light_grid.clusters[cluster_index].num_emissive_surfaces);
|
|
for (uint i = 0; i < num_emissive_kusochki; ++i) {
|
|
const uint index_into_emissive_kusochki = uint(light_grid.clusters[cluster_index].emissive_surfaces[i]);
|
|
|
|
if (push_constants.debug_light_index_begin < push_constants.debug_light_index_end) {
|
|
if (index_into_emissive_kusochki < push_constants.debug_light_index_begin || index_into_emissive_kusochki >= push_constants.debug_light_index_end)
|
|
continue;
|
|
}
|
|
|
|
C = vec3(0., 0., 1.) * color_factor;
|
|
}
|
|
|
|
/* const uvec3 cellrand = pcg3d(uvec3(light_cell)); */
|
|
/* C = .02 * color_factor * vec3( */
|
|
/* uintToFloat01(cellrand.r), */
|
|
/* uintToFloat01(cellrand.g), */
|
|
/* uintToFloat01(cellrand.b)); */
|
|
//break;
|
|
}
|
|
#endif
|
|
|
|
MaterialProperties material;
|
|
material.baseColor = payload_opaque.base_color;
|
|
material.metalness = payload_opaque.metalness;
|
|
material.emissive = payload_opaque.emissive;
|
|
material.roughness = payload_opaque.roughness;
|
|
|
|
// material.roughness = uintToFloat01(xxhash32(uvec3(abs(floor(payload_opaque.hit_pos_t.xyz/64.)))));
|
|
// material.metalness = step(.5, xxhash32(uvec3(abs(floor(payload_opaque.hit_pos_t.xyz/32.)))));
|
|
|
|
const vec3 shadingNormal = payload_opaque.normal;
|
|
const vec3 geometryNormal = payload_opaque.geometry_normal;
|
|
|
|
if (bounce == 0) { //brdfType == SPECULAR_TYPE)
|
|
out_additive = payload_opaque.emissive + additive;
|
|
additive = vec3(0.);
|
|
|
|
out_material_index = float(payload_opaque.material_index);
|
|
imageStore(out_image_base_color, ivec2(gl_LaunchIDEXT.xy), vec4(payload_opaque.base_color, 0.));
|
|
imageStore(out_image_normals, ivec2(gl_LaunchIDEXT.xy), vec4(geometryNormal.xy, shadingNormal.xy));
|
|
payload_opaque.base_color = vec3(1.);
|
|
|
|
//out_material_index = float(kusochki[payload_opaque.kusok_index].tex_roughness);
|
|
#if 0
|
|
//imageStore(out_image_base_color, ivec2(gl_LaunchIDEXT.xy), vec4(fract(payload_opaque.debug.xy), 0., 0.));
|
|
//imageStore(out_image_base_color, ivec2(gl_LaunchIDEXT.xy), vec4(payload_opaque.kusok_index));
|
|
imageStore(out_image_base_color, ivec2(gl_LaunchIDEXT.xy), vec4(payload_opaque.roughness));
|
|
imageStore(out_image_diffuse_gi, ivec2(gl_LaunchIDEXT.xy), vec4(0));
|
|
imageStore(out_image_specular, ivec2(gl_LaunchIDEXT.xy), vec4(0.));
|
|
imageStore(out_image_additive, ivec2(gl_LaunchIDEXT.xy), vec4(clamp(payload_opaque.normal, vec3(0.), vec3(1.)), 0.));
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
// TODO should we do this after reflect/transmit decision?
|
|
#define SKIP_TRASMITTED_LIGHT
|
|
#ifndef SKIP_TRASMITTED_LIGHT
|
|
C += computeLighting(throughput, -direction, material);
|
|
|
|
if (bounce == push_constants.bounces - 1)
|
|
break;
|
|
#else
|
|
vec3 prev_throughput = throughput;
|
|
#endif
|
|
|
|
const vec3 V = -direction;
|
|
if (material.metalness == 1.0f && material.roughness == 0.0f) {
|
|
// Fast path for mirrors
|
|
brdfType = SPECULAR_TYPE;
|
|
} else {
|
|
// Decide whether to sample diffuse or specular BRDF (based on Fresnel term)
|
|
float brdfProbability = getBrdfProbability(material, V, shadingNormal);
|
|
if (rand01() < brdfProbability) {
|
|
brdfType = SPECULAR_TYPE;
|
|
throughput /= brdfProbability;
|
|
} else {
|
|
// Refraction
|
|
if (rand01() < payload_opaque.transmissiveness) {
|
|
throughput *= material.baseColor;
|
|
direction = refract(direction, payload_opaque.geometry_normal, .8);
|
|
origin = payload_opaque.hit_pos_t.xyz - payload_opaque.geometry_normal * shadow_offset_fudge;
|
|
continue;
|
|
}
|
|
|
|
brdfType = DIFFUSE_TYPE;
|
|
throughput /= (1.0f - brdfProbability);
|
|
}
|
|
}
|
|
|
|
#ifdef SKIP_TRASMITTED_LIGHT
|
|
vec3 diffuse, specular;
|
|
computeLighting(prev_throughput, -direction, material, diffuse, specular);
|
|
|
|
if (bounce == 0) {
|
|
out_diffuse_gi += diffuse;
|
|
out_specular += specular;
|
|
} else {
|
|
out_accumulated += payload_opaque.base_color * (diffuse + specular);
|
|
out_accumulated += prev_throughput * additive;
|
|
}
|
|
|
|
if (bounce == push_constants.bounces - 1)
|
|
break;
|
|
#endif
|
|
|
|
vec2 u = vec2(rand01(), rand01());
|
|
vec3 brdfWeight;
|
|
if (!evalIndirectCombinedBRDF(u, shadingNormal, geometryNormal, V, material, brdfType, direction, brdfWeight)) {
|
|
break; // Ray was eaten by the surface :(
|
|
}
|
|
|
|
throughput *= brdfWeight;
|
|
if (dot(throughput, throughput) < throughput_threshold)
|
|
break;
|
|
|
|
origin = payload_opaque.hit_pos_t.xyz;
|
|
|
|
if (bounce == 0)
|
|
first_bounce_brdf_type = brdfType;
|
|
} // for all bounces
|
|
|
|
if (first_bounce_brdf_type == DIFFUSE_TYPE) {
|
|
out_diffuse_gi += out_accumulated;
|
|
} else {
|
|
out_specular += out_accumulated;
|
|
}
|
|
|
|
imageStore(out_image_diffuse_gi, ivec2(gl_LaunchIDEXT.xy), vec4(out_diffuse_gi / color_factor, out_material_index));
|
|
imageStore(out_image_specular, ivec2(gl_LaunchIDEXT.xy), vec4(out_specular / color_factor, 0.));
|
|
imageStore(out_image_additive, ivec2(gl_LaunchIDEXT.xy), vec4(out_additive / color_factor, 0.));
|
|
}
|