xash3d-fwgs/ref_vk/shaders/rtx.comp

552 lines
20 KiB
Plaintext

#version 460
#extension GL_EXT_ray_query : require
#extension GL_EXT_shader_16bit_storage : require
#extension GL_EXT_shader_8bit_storage : require
const float normal_offset_fudge = .01;
const float shadow_offset_fudge = .5;
const float
C_A = 434073., C_B = 497559., C_C = 397590., C_D = 498071.,
C_E = 988959., C_F = 988945., C_G = 400790., C_H = 630681.,
C_I = 467495., C_J = 467491., C_K = 611161., C_L = 69919.,
C_M = 653721., C_N = 638361., C_O = 432534., C_P = 497425.,
C_Q = 432606., C_R = 497497., C_S = 923271., C_T = 991778.,
C_U = 629142., C_V = 629075., C_W = 646615., C_X = 628377.,
C_Y = 628292., C_Z = 1016879., C_1 = 291919., C_2 = 493087.,
C_3 = 495239., C_4 = 630408., C_5 = 988807., C_6 = 272278.,
C_7 = 1016900., C_8 = 431766., C_9 = 433730., C_0 = 433590.,
C_dot = 1024.;
float gB(in float g, in vec2 gp){
return (gp.x<4.&&gp.y<5.) ? mod(floor(g / pow(2., gp.y*4. + gp.x)), 2.) : 0.;
}
#define PUTC(g) if(pc.x==lx){col=gB(g,pg);}lx+=1.
float diGlyph(in float di) {
if (di == 0.) return C_0;
if (di == 1.) return C_1;
if (di == 2.) return C_2;
if (di == 3.) return C_3;
if (di == 4.) return C_4;
if (di == 5.) return C_5;
if (di == 6.) return C_6;
if (di == 7.) return C_7;
if (di == 8.) return C_8;
if (di == 9.) return C_9;
return C_E;
}
void printInt(in float num, in vec2 pg, in vec2 pc, inout float lx, inout float col) {
/*if (num < 0.) {
PUTC(C_N);
num *= -1.;
} else {
PUTC(diGlyph(mod(floor(num/1000.),10.)));
}*/
if (num >= 100000.) { PUTC(diGlyph(mod(floor(num/100000.),10.))); }
if (num >= 10000.) { PUTC(diGlyph(mod(floor(num/10000.),10.))); }
if (num >= 1000.) { PUTC(diGlyph(mod(floor(num/1000.),10.))); }
if (num >= 100.) { PUTC(diGlyph(mod(floor(num/100.),10.))); }
if (num >= 10.) { PUTC(diGlyph(mod(floor(num/10.),10.))); }
PUTC(diGlyph(mod(floor(num),10.)));
}
// FIXME shader specialization
layout(local_size_x = 16, local_size_y = 8, local_size_z = 1) in;
layout(binding = 0, set = 0, rgba8) uniform image2D image;
layout(binding = 1, set = 0) uniform accelerationStructureEXT tlas;
layout(binding = 2, set = 0) uniform UBO {
mat4 inv_proj, inv_view;
// TODO combine
//int num_lights;
//Light lights[];
} ubo;
struct Kusok {
uint index_offset;
uint vertex_offset;
uint triangles;
uint is_emissive;
uint texture;
//vec4 emissive;
};
struct Vertex {
vec3 pos;
vec3 normal;
vec2 gl_tc;
vec2 lm_tc;
};
layout(std430, binding = 3, set = 0) readonly buffer Kusochki { Kusok kusochki[]; };
layout(std430, binding = 4, set = 0) readonly buffer Indices { uint16_t indices[]; };
layout(std430, binding = 5, set = 0) readonly buffer Vertices { Vertex vertices[]; };
// TODO #include, use from here and regular shader
struct Light {
vec4 pos_r;
vec4 color;
};
// FIXME what should this be?
const float dlight_attenuation_const = 20000.;
// TODO specialize in vk_rtx.c
layout (constant_id = 0) const uint max_dlights = 32;
layout(set=0,binding=6) uniform UBODLights {
uint num_lights;
Light lights[max_dlights];
};
struct EmissiveKusok {
uint kusok_index;
vec3 emissive_color;
vec4 tx_row_x, tx_row_y, tx_row_z;
};
layout (constant_id = 1) const uint MAX_EMISSIVE_KUSOCHKI = 256;
layout (set = 0, binding = 7/*, align=4*/) uniform UBOEmissiveKusochki {
uint num_kusochki;
EmissiveKusok kusochki[MAX_EMISSIVE_KUSOCHKI];
} emissive_kusochki;
layout(binding = 8, set = 0, rgba8) uniform readonly image2D previous_frame;
layout (constant_id = 2) const uint MAX_VISIBLE_DLIGHTS = 255;//15;
layout (constant_id = 3) const uint MAX_VISIBLE_SURFACE_LIGHTS = 255;//31;
const uint LIGHT_CLUSTER_SIZE = 2 + MAX_VISIBLE_DLIGHTS + 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;
struct LightCluster {
uint8_t num_dlights;
uint8_t num_emissive_surfaces;
uint8_t dlights[MAX_VISIBLE_DLIGHTS];
uint8_t emissive_surfaces[MAX_VISIBLE_SURFACE_LIGHTS];
};
// FIMXE specialize
layout (constant_id = 4) const float LIGHT_GRID_CELL_SIZE = 256.;
layout (constant_id = 5) const uint MAX_LIGHT_CLUSTERS = 32768;
const uint HACK_OFFSET = 0;
layout (set = 0, binding = 9, 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 (constant_id = 6) const uint MAX_TEXTURES = 4096;
layout (set = 0, binding = 10) uniform sampler2D textures[MAX_TEXTURES];
layout (push_constant) uniform PC {
float t;
int bounces;
float prev_frame_blend_factor;
} pc;
//uint picked_light = 76;//uint(mod(pc.t * 4., emissive_kusochki.num_kusochki));
int time_off = int(pc.t * 8.);
float hash(float f) { return fract(sin(f)*53478.4327); }
float printTiledNumber(vec2 p, int n) {
if (n == 0) return 0.;
float t = pc.t;
float x = floor(p.x / 5. / 2.);
//p.y += 12. * fract(pc.t * (4. + 3. * hash(x)));
p = floor(p / 2.);
vec2 pc = floor(p / vec2(5.,6.));
vec2 pg = mod(p, vec2(5.,6.));
float lx = 1.;
float col = 0.;
#define PUTN(n) printInt(n,pg,pc,lx,col)
// float ncol = floor(pc.x / 3.);
// float tlen = floor(16. + 32. * hash(ncol));
// pc.y = mod(pc.y + floor(t * (6. + 9. * hash(ncol))), tlen);
// if (pc.y > tlen * .6) return 0.;
pc.y = mod(pc.y, 2.);
pc.x = mod(pc.x, 5.);
PUTN(n);
return col;
}
float printText(in vec2 p) {
#define PIXSZ 4.
p = floor(p / PIXSZ);
vec2 pc = floor(p / vec2(5.,6.));
vec2 pg = mod(p, vec2(5.,6.));
float lx = 1.;
float col = 0.;
#define PUTN(n) printInt(n,pg,pc,lx,col)
// if (pc.y == 0.) {
// PUTC(C_N); PUTC(0.); PUTN(float(num_lighttextures));
// } else if (pc.y <= float(num_lighttextures)) {
// PUTN((pc.y-1.)); PUTC(0.); PUTN(float(lighttextures[int(pc.y-1.)]));
// }
if (pc.y < 0.)
return 0.;
const int idx = int(pc.y);
#define _ PUTC(0.);
if (false) {
const Kusok kusok = kusochki[idx];
PUTN(idx);
//PUTN(kusok.index_offset); PUTC(0.); PUTN(kusok.vertex_offset); PUTC(0.); PUTN(kusok.triangles);
} else if (false) {
if (idx == 0) {
PUTN(light_grid.grid_min.x); _
PUTN(light_grid.grid_min.y); _
PUTN(light_grid.grid_min.z); _
PUTN(light_grid.grid_size.x); _
PUTN(light_grid.grid_size.y); _
PUTN(light_grid.grid_size.z);
} else {
const int index = int(mod(idx - 1 /* + time_off*/, 500));
PUTN(index);
// const uint cluster_offset = 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;
// _ PUTC(C_D); PUTN(num_dlights);
// _ PUTC(C_S); PUTN(num_emissive_surfaces);
// _ PUTN(float(int(light_grid.clusters_data[emissive_surfaces_offset + 0])));
// _ PUTN(float(int(light_grid.clusters_data[emissive_surfaces_offset + 1])));
// _ PUTN(float(int(light_grid.clusters_data[emissive_surfaces_offset + 2])));
// _ PUTN(float(int(light_grid.clusters_data[emissive_surfaces_offset + 3])));
_ PUTC(C_D); PUTN(int(light_grid.clusters[index].num_dlights));
_ PUTC(C_S); PUTN(int(light_grid.clusters[index].num_emissive_surfaces));
_ PUTN(float(int(light_grid.clusters[index].emissive_surfaces[0])));
_ PUTN(float(int(light_grid.clusters[index].emissive_surfaces[1])));
_ PUTN(float(int(light_grid.clusters[index].emissive_surfaces[2])));
_ PUTN(float(int(light_grid.clusters[index].emissive_surfaces[3])));
}
} else if (false)
{
PUTN(emissive_kusochki.num_kusochki);
_ PUTN(idx);
_ PUTN(emissive_kusochki.kusochki[idx].kusok_index);
_ PUTN(emissive_kusochki.kusochki[idx].emissive_color.r*255.);
_ PUTN(emissive_kusochki.kusochki[idx].emissive_color.g*255.);
_ PUTN(emissive_kusochki.kusochki[idx].emissive_color.b*255.);
const uint kidx = emissive_kusochki.kusochki[idx].kusok_index;
_ PUTN(kusochki[kidx].triangles);
} else if (true) {
//PUTN(picked_light);
}
#undef _
return col;
}
// TODO find better random function
// float rand01_state;
// float rand01() {
// return rand01_state = fract(sin(rand01_state)*54873.35729);
// }
uint rand01_state = 0;
uint rand() {
//rand01_state = rand01_state * 1103515245 + 12345;
// xorshift32
rand01_state ^= rand01_state << 13;
rand01_state ^= rand01_state >> 17;
rand01_state ^= rand01_state << 5;
return rand01_state;
}
uint rand_range(uint rmax) {
return rand() % rmax;
}
float rand01() {
return uintBitsToFloat(0x3f800000 | (rand() & 0x007fffff)) - 1.;
}
bool shadowed(vec3 pos, vec3 dir, float dist) {
rayQueryEXT shadowRayQuery;
rayQueryInitializeEXT(shadowRayQuery, tlas,
gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT,
0xff,
pos, 0., dir, dist);
while(rayQueryProceedEXT(shadowRayQuery)) {
rayQueryConfirmIntersectionEXT(shadowRayQuery);
}
return rayQueryGetIntersectionTypeEXT(shadowRayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT;
}
void main() {
vec2 res = imageSize(image);
vec2 uv = (gl_GlobalInvocationID.xy + .5) / res * 2. - 1.;
vec4 origin = ubo.inv_view * vec4(0, 0, 0, 1);
vec4 target = ubo.inv_proj * vec4(uv.x, uv.y, 1, 1);
vec4 direction = ubo.inv_view * vec4(normalize(target.xyz), 0);
vec3 C = vec3(0.);
vec3 O = origin.xyz, D=direction.xyz;
vec3 kc = vec3(1.);
const float L = 10000.;
rand01_state = uint(mod(pc.t, 100.) * 1000.) + gl_GlobalInvocationID.x * 1823 + 31337 * gl_GlobalInvocationID.y;
for (int bounce = 0; bounce < pc.bounces; ++bounce) {
rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, tlas, gl_RayFlagsOpaqueEXT, 0xff, O, 0., D, L);
while(rayQueryProceedEXT(rayQuery)) {
rayQueryConfirmIntersectionEXT(rayQuery);
}
const float l = rayQueryGetIntersectionTEXT(rayQuery, true);
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionGeneratedEXT) {
C += kc * vec3(0., 1., 0.);
break;
}
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) {
C += kc * vec3(0., 0., 0.);
break;
}
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionTriangleEXT) {
C += kc * vec3(1., 0., 1.);
break;
}
vec3 pos = O+D*l;
const int instance_kusochki_offset = rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, true);
const int instance_index = rayQueryGetIntersectionInstanceIdEXT(rayQuery, true);
const int geom_index = rayQueryGetIntersectionGeometryIndexEXT(rayQuery, true);
const int kusok_index = instance_kusochki_offset + geom_index;
// vec2 pix = vec2(1.,-1.) * vec2(gl_GlobalInvocationID.xy) + vec2(0., imageSize(image).y);
// C = mix(C*.5, vec3(0., 1., 0.), printTiledNumber(pix*2., kusok_index));
// break;
const Kusok kusok = kusochki[kusok_index];
//const uint leaf = kusochki[kusok_index].leaf-1;
//C = fract(pos / LIGHT_GRID_CELL_SIZE); break;
//C = vec3(hash(float(geom_index)), hash(float(geom_index)+15.43), hash(float(geom_index)+34.)); break;
// C = vec3(hash(float(instance_index)), hash(float(instance_index)+15.43), hash(float(instance_index)+34.)) + .1 * fract(pos/LIGHT_GRID_CELL_SIZE);
// C = mix(C*.5, vec3(0., 1., 0.), printTiledNumber(pix, instance_index));
// break;
//C = vec3(hash(float(leaf)), hash(float(leaf)+15.43), hash(float(leaf)+34.));
//C = vec3(hash(float(leaf)), float(kusok.num_surface_lights) / 63., float(kusok.is_emissive));
//break;
// if (kusok.is_emissive != 0) {
// C = vec3(0., 1., 0.);
// break;
//}
const int prim_index = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true);
const mat4x3 transform = rayQueryGetIntersectionObjectToWorldEXT(rayQuery, true);
const uint first_index_offset = kusochki[kusok_index].index_offset + prim_index * 3;
const uint vi1 = uint(indices[first_index_offset+0]) + kusochki[kusok_index].vertex_offset;
const uint vi2 = uint(indices[first_index_offset+1]) + kusochki[kusok_index].vertex_offset;
const uint vi3 = uint(indices[first_index_offset+2]) + kusochki[kusok_index].vertex_offset;
const vec3 n1 = vertices[vi1].normal;
const vec3 n2 = vertices[vi2].normal;
const vec3 n3 = vertices[vi3].normal;
const vec2 bary = rayQueryGetIntersectionBarycentricsEXT(rayQuery, true);
const vec3 normal = normalize(transpose(inverse(mat3(transform))) * (n1 * (1. - bary.x - bary.y) + n2 * bary.x + n3 * bary.y));
pos += normal * normal_offset_fudge;
//C = normal * .5 + .5; break;
const vec2 texture_uv = vertices[vi1].gl_tc * (1. - bary.x - bary.y) + vertices[vi2].gl_tc * bary.x + vertices[vi3].gl_tc * bary.y;
const vec3 baseColor = pow(texture(textures[kusochki[kusok_index].texture], texture_uv).rgb, vec3(2.));
const ivec3 light_cell = ivec3(floor(pos / 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.);
break;
} else
#if 1
{
// 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.);
//break;
const uint num_emissive_kusochki = uint(light_grid.clusters[cluster_index].num_emissive_surfaces);
//const uint num_emissive_kusochki = emissive_kusochki.num_kusochki;
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]);
//const uint index_into_emissive_kusochki = i;
// if (index_into_emissive_kusochki < 45 || index_into_emissive_kusochki > 48)
// continue;
const EmissiveKusok ek = emissive_kusochki.kusochki[index_into_emissive_kusochki];
const uint emissive_kusok_index = emissive_kusochki.kusochki[index_into_emissive_kusochki].kusok_index;
const Kusok ekusok = kusochki[emissive_kusok_index];
const vec3 emissive = emissive_kusochki.kusochki[index_into_emissive_kusochki].emissive_color.rgb;
// 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 (i != picked_light) {
// continue;
// }
if (emissive_kusok_index == kusok_index) {
// TODO do we need to do this when we have textures?
//C += kc * vec3(hash(float(kusok_index)), hash(float(kusok_index)+15.43), hash(float(kusok_index)+34.));//kusok.emissive.rgb;
//C = vec3(1., 0., 1.);
if (bounce == 0)
C += kc * emissive * baseColor;
continue;
}
const uint picked_tri = rand_range(ekusok.triangles);
for (uint ti = 0; ti < ekusok.triangles; ++ti) {
const uint first_index_offset = ekusok.index_offset + ti * 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]) + ekusok.vertex_offset;
const vec3 n1 = normalize(emissive_transform_normal * vertices[vi1].normal);
// if (dot(n1, normal) >= 0. /* TODO epsilon */ )
// continue;
if (picked_tri > ti)
continue;
// TODO random sample point on the entire ekusok geometry
const uint vi2 = uint(indices[first_index_offset+1]) + ekusok.vertex_offset;
const uint vi3 = uint(indices[first_index_offset+2]) + ekusok.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;
const vec3 sample_pos = mix(mix(v1, v2, rand01()), v3, rand01());
//const vec3 sample_pos = vertices[vi1].pos;
// const vec3 n2 = vertices[vi2].normal;
// const vec3 n3 = vertices[vi3].normal;
vec3 light_dir = sample_pos - pos;
float light_dot = -dot(light_dir, n1);
if (light_dot <= 0.) {
//C = vec3(1., 0., 1.);
continue;
}
const float light_dist = length(light_dir);
light_dot /= light_dist;
light_dir /= light_dist;
if (shadowed(pos, light_dir, light_dist - shadow_offset_fudge)) {
//C = vec3(0., 1., 0.);
continue;
}
// TODO
const float brightness_fudge = 5.;
C += light_dot * sampling_light_scale * brightness_fudge * kc * baseColor * emissive * dot(light_dir, normal) / (light_dist * light_dist);
// Sample just one triangle
break;
}
}
}
#endif
//rand01_state = fract((pos.x + pos.y + pos.z)/100.) + uv.x + uv.y + pc.t;
for (uint i = 0; i < num_lights; ++i) {
const vec4 light_pos_r = lights[i].pos_r;
const vec3 light_color = lights[i].color.rgb;
//rand01_state = fract((pos.x + pos.y + pos.z)/100.) + uv.x + uv.y + fract(pc.t) + i;
//rand01_state += fract(fract(pc.t) + i + (light_pos_r.x + light_pos_r.y + light_pos_r.z)/1000.);
// Find random point on a sphere
// TODO proper BRDF importance sampling and correct random point distribution
vec3 rnd = normalize(vec3(rand01(), rand01(), rand01())*2.-1.);
if (dot(rnd, pos - light_pos_r.xyz) < 0.) rnd = -rnd;
// TODO fudge this
const float light_r_scaler = 2.;
const vec3 light_dir = light_pos_r.xyz - pos + rnd * light_pos_r.w / light_r_scaler;
const vec3 light_dir_norm = normalize(light_dir);
const float dot_ld_norm = dot(light_dir_norm, normal);
if (dot_ld_norm <= 0.)
continue;
const float d2 = dot(light_dir, light_dir);
const float light_dist = sqrt(d2);
if (shadowed(pos, light_dir_norm, light_dist + shadow_offset_fudge))
continue;
const float r2 = light_pos_r.w * light_pos_r.w;
// TODO this is a bad approximation
const float attenuation = dlight_attenuation_const / (d2 + r2 * .5);
C += kc * baseColor.rgb * light_color * dot_ld_norm * attenuation;
} // for all lights
//const Kusok kusok = kusochki[kusok_index];
// if (any(greaterThan(kusok.emissive.rgb, vec3(0.)))) {
// C += kc * vec3(hash(float(kusok_index)-102.3), hash(float(kusok_index)+15.43), hash(float(kusok_index)+34.));//kusok.emissive.rgb;
//}
kc *= .9 * baseColor;
//const float rough = .4;
const float rough = .3;// * hash(.01 * dot(floor((inverse(mat4(transform)) * vec4(pos, 1.))/10.).xyz, vec3(1.)));
O = pos;
// TODO this is totally not correct
D = normalize(mix(
reflect(D, normal),
vec3(rand01(), rand01(), rand01())*2.-1.,
rough
));
} // for all bounces
//C = mix(C, vec3(1.), printText(vec2(1.,-1.) * vec2(gl_GlobalInvocationID.xy) + vec2(0., imageSize(image).y)));
C = mix(C, vec3(1.), printText(vec2(1.,-1.) * vec2(gl_GlobalInvocationID.xy) + vec2(0., imageSize(image).y)));
//if (gl_GlobalInvocationID.x > imageSize(image).x / 2)
if (true)
{
vec3 prev_frame = imageLoad(previous_frame, ivec2(gl_GlobalInvocationID.xy)).rgb;
prev_frame *= prev_frame;
C = mix(C, prev_frame, pc.prev_frame_blend_factor);
}
imageStore(image, ivec2(gl_GlobalInvocationID.xy), vec4(sqrt(C), 1.));
}