From 395d5c4fcb0d3779a50c992232835bd30a763ec6 Mon Sep 17 00:00:00 2001 From: Ivan 'provod' Avdeev Date: Thu, 2 Feb 2023 10:22:52 -0800 Subject: [PATCH 1/6] rt: add alpha test for primary ray and for shadows shadows are particularly slow --- ref_vk/shaders/light_common.glsl | 62 ++++++++++++++++++++++++++------ ref_vk/shaders/ray_primary.comp | 38 ++++++++++++++++++-- 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/ref_vk/shaders/light_common.glsl b/ref_vk/shaders/light_common.glsl index e4d9c883..d6d6e104 100644 --- a/ref_vk/shaders/light_common.glsl +++ b/ref_vk/shaders/light_common.glsl @@ -1,8 +1,11 @@ #ifndef LIGHT_COMMON_GLSL_INCLUDED #define LIGHT_COMMON_GLSL_INCLUDED +#extension GL_EXT_nonuniform_qualifier : enable #include "ray_kusochki.glsl" +layout(set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES]; + #ifdef RAY_TRACE2 #include "ray_shadow_interface.glsl" layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadEXT RayPayloadShadow payload_shadow; @@ -20,6 +23,49 @@ uint traceShadowRay(vec3 pos, vec3 dir, float dist, uint flags) { } #endif +#if defined(RAY_QUERY) +void shadowRayQuery(rayQueryEXT rq, vec3 pos, vec3 dir, float dist, uint flags) { + rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_OPAQUE, pos, 0., dir, dist - shadow_offset_fudge); + + while (rayQueryProceedEXT(rq)) { + if (0 != (rayQueryGetRayFlagsEXT(rq) & gl_RayFlagsOpaqueEXT)) + continue; + + // Alpha test, takes 10ms + // TODO check other possible ways of doing alpha test. They might be more efficient: + // 1. Do a separate ray query for alpha masked geometry. Reason: here we might accidentally do the expensive + // texture sampling for geometry that's ultimately invisible (i.e. behind walls). Also, shader threads congruence. + // Separate pass could be more efficient as it'd be doing the same thing for every invocation. + // 2. Same as the above, but also with a completely independent TLAS. Why: no need to mask-check geometry for opaque-vs-alpha +#if 1 + const uint instance_kusochki_offset = rayQueryGetIntersectionInstanceCustomIndexEXT(rq, false); + const uint geometry_index = rayQueryGetIntersectionGeometryIndexEXT(rq, false); + const uint kusok_index = instance_kusochki_offset + geometry_index; + const Kusok kusok = getKusok(kusok_index); + + const uint primitive_index = rayQueryGetIntersectionPrimitiveIndexEXT(rq, false); + const uint first_index_offset = kusok.index_offset + primitive_index * 3; + const uint vi1 = uint(getIndex(first_index_offset+0)) + kusok.vertex_offset; + const uint vi2 = uint(getIndex(first_index_offset+1)) + kusok.vertex_offset; + const uint vi3 = uint(getIndex(first_index_offset+2)) + kusok.vertex_offset; + const vec2 uvs[3] = { + getVertex(vi1).gl_tc, + getVertex(vi2).gl_tc, + getVertex(vi3).gl_tc, + }; + const vec2 bary = rayQueryGetIntersectionBarycentricsEXT(rq, false); + const vec2 uv = baryMix(uvs[0], uvs[1], uvs[2], bary); + const vec4 texture_color = texture(textures[nonuniformEXT(kusok.tex_base_color)], uv); + + const float alpha_mask_threshold = .1f; + if (texture_color.a >= alpha_mask_threshold) { + rayQueryConfirmIntersectionEXT(rq); + } +#endif + } +} +#endif + bool shadowed(vec3 pos, vec3 dir, float dist) { #ifdef RAY_TRACE const uint flags = 0 @@ -31,16 +77,14 @@ bool shadowed(vec3 pos, vec3 dir, float dist) { const uint hit_type = traceShadowRay(pos, dir, dist, flags); return payload_shadow.hit_type == SHADOW_HIT; #elif defined(RAY_QUERY) - rayQueryEXT rq; const uint flags = 0 //| gl_RayFlagsCullFrontFacingTrianglesEXT //| gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT //| gl_RayFlagsSkipClosestHitShaderEXT ; - rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_OPAQUE, pos, 0., dir, dist - shadow_offset_fudge); - // TODO alpha test - while (rayQueryProceedEXT(rq)) { } + rayQueryEXT rq; + shadowRayQuery(rq, pos, dir, dist, flags); return rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionTriangleEXT; #else #error RAY_TRACE or RAY_QUERY @@ -50,7 +94,7 @@ bool shadowed(vec3 pos, vec3 dir, float dist) { // TODO join with just shadowed() bool shadowedSky(vec3 pos, vec3 dir, float dist) { #ifdef RAY_TRACE - const uint flags = 0 + const uint flags = 0 //| gl_RayFlagsCullFrontFacingTrianglesEXT //| gl_RayFlagsOpaqueEXT //| gl_RayFlagsTerminateOnFirstHitEXT @@ -59,16 +103,14 @@ bool shadowedSky(vec3 pos, vec3 dir, float dist) { const uint hit_type = traceShadowRay(pos, dir, dist, flags); return payload_shadow.hit_type != SHADOW_SKY; #elif defined(RAY_QUERY) - rayQueryEXT rq; - const uint flags = 0 + const uint flags = 0 //| gl_RayFlagsCullFrontFacingTrianglesEXT //| gl_RayFlagsOpaqueEXT //| gl_RayFlagsTerminateOnFirstHitEXT //| gl_RayFlagsSkipClosestHitShaderEXT ; - rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_OPAQUE, pos, 0., dir, dist - shadow_offset_fudge); - // TODO alpha test - while (rayQueryProceedEXT(rq)) { } + rayQueryEXT rq; + shadowRayQuery(rq, pos, dir, dist, flags); if (rayQueryGetIntersectionTypeEXT(rq, true) != gl_RayQueryCommittedIntersectionTriangleEXT) return true; diff --git a/ref_vk/shaders/ray_primary.comp b/ref_vk/shaders/ray_primary.comp index 355d13a7..96eb77ac 100644 --- a/ref_vk/shaders/ray_primary.comp +++ b/ref_vk/shaders/ray_primary.comp @@ -52,8 +52,42 @@ void main() { ; const float L = 10000.; // TODO Why 10k? rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_OPAQUE, origin, 0., direction, L); - // TODO alpha test - while (rayQueryProceedEXT(rq)) { } + while (rayQueryProceedEXT(rq)) { + if (0 != (rayQueryGetRayFlagsEXT(rq) & gl_RayFlagsOpaqueEXT)) + continue; + + // alpha test + // TODO check other possible ways of doing alpha test. They might be more efficient + // (although in this particular primary ray case it's not taht important): + // 1. Do a separate ray query for alpha masked geometry. Reason: here we might accidentally do the expensive + // texture sampling for geometry that's ultimately invisible (i.e. behind walls). Also, shader threads congruence. + // Separate pass could be more efficient as it'd be doing the same thing for every invocation. + // 2. Same as the above, but also with a completely independent TLAS. Why: no need to mask-check geometry for opaque-vs-alpha + const uint instance_kusochki_offset = rayQueryGetIntersectionInstanceCustomIndexEXT(rq, false); + const uint geometry_index = rayQueryGetIntersectionGeometryIndexEXT(rq, false); + const uint kusok_index = instance_kusochki_offset + geometry_index; + const Kusok kusok = getKusok(kusok_index); + + const uint primitive_index = rayQueryGetIntersectionPrimitiveIndexEXT(rq, false); + const uint first_index_offset = kusok.index_offset + primitive_index * 3; + const uint vi1 = uint(getIndex(first_index_offset+0)) + kusok.vertex_offset; + const uint vi2 = uint(getIndex(first_index_offset+1)) + kusok.vertex_offset; + const uint vi3 = uint(getIndex(first_index_offset+2)) + kusok.vertex_offset; + const vec2 uvs[3] = { + getVertex(vi1).gl_tc, + getVertex(vi2).gl_tc, + getVertex(vi3).gl_tc, + }; + const vec2 bary = rayQueryGetIntersectionBarycentricsEXT(rq, false); + const vec2 uv = baryMix(uvs[0], uvs[1], uvs[2], bary); + const vec4 texture_color = texture(textures[nonuniformEXT(kusok.tex_base_color)], uv); + + const float alpha_mask_threshold = .1f; + if (texture_color.a >= alpha_mask_threshold) { + rayQueryConfirmIntersectionEXT(rq); + } + } + if (rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionTriangleEXT) { primaryRayHit(rq, payload); } From 3ebfb728191f71027e3a25e262ae2850f20b9357 Mon Sep 17 00:00:00 2001 From: Ivan Avdeev Date: Thu, 2 Feb 2023 11:07:41 -0800 Subject: [PATCH 2/6] fix linux linking --- ref_vk/vk_previous_frame.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ref_vk/vk_previous_frame.c b/ref_vk/vk_previous_frame.c index d5cc588d..003c35b6 100644 --- a/ref_vk/vk_previous_frame.c +++ b/ref_vk/vk_previous_frame.c @@ -39,7 +39,7 @@ typedef struct { prev_states_storage_t g_prev = { 0 }; -inline int clampIndex( int index, int array_length ) +static inline int clampIndex( int index, int array_length ) { if (index < 0) return 0; From 8ec8502a5376fffa1cc02cbe26ec49904b8e93ff Mon Sep 17 00:00:00 2001 From: Ivan 'provod' Avdeev Date: Fri, 3 Feb 2023 10:12:12 -0800 Subject: [PATCH 3/6] rt: unify shadowed with shadowedSky --- ref_vk/shaders/light.glsl | 20 +++++++------------ ref_vk/shaders/light_common.glsl | 33 +++++-------------------------- ref_vk/shaders/light_polygon.glsl | 6 +++--- 3 files changed, 15 insertions(+), 44 deletions(-) diff --git a/ref_vk/shaders/light.glsl b/ref_vk/shaders/light.glsl index 83fefa2c..d880e271 100644 --- a/ref_vk/shaders/light.glsl +++ b/ref_vk/shaders/light.glsl @@ -42,9 +42,9 @@ void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 throughput, vec const float stopdot = lights.m.point_lights[i].color_stopdot.a; const vec3 dir = lights.m.point_lights[i].dir_stopdot2.xyz; const float stopdot2 = lights.m.point_lights[i].dir_stopdot2.a; - const bool not_environment = (lights.m.point_lights[i].environment == 0); + const bool is_environment = (lights.m.point_lights[i].environment != 0); - const vec3 light_dir = not_environment ? (origin_r.xyz - P) : -dir; // TODO need to randomize sampling direction for environment soft shadow + const vec3 light_dir = is_environment ? -dir : (origin_r.xyz - P); // TODO need to randomize sampling direction for environment soft shadow const float radius = origin_r.w; const vec3 light_dir_norm = normalize(light_dir); @@ -64,7 +64,9 @@ void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 throughput, vec float light_dist = 1e5; // TODO this is supposedly not the right way to do shadows for environment lights.m. qrad checks for hitting SURF_SKY, and maybe we should too? const float d2 = dot(light_dir, light_dir); const float r2 = origin_r.w * origin_r.w; - if (not_environment) { + if (is_environment) { + color *= 2; // TODO WHY? + } else { if (radius < 1e-3) continue; @@ -86,8 +88,6 @@ void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 throughput, vec //const float pdf = TWO_PI / asin(radius / dist); const float pdf = 1. / ((1. - sqrt(d2 - r2) / dist) * spot_attenuation); color /= pdf; - } else { - color *= 2; } // if (dot(color,color) < color_culling_threshold) @@ -104,14 +104,8 @@ void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 throughput, vec continue; // FIXME split environment and other lights - if (not_environment) { - if (shadowed(P, light_dir_norm, light_dist + shadow_offset_fudge)) - continue; - } else { - // for environment light check that we've hit SURF_SKY - if (shadowedSky(P, light_dir_norm, light_dist + shadow_offset_fudge)) - continue; - } + if (shadowed(P, light_dir_norm, light_dist + shadow_offset_fudge, is_environment)) + continue; diffuse += ldiffuse; specular += lspecular; diff --git a/ref_vk/shaders/light_common.glsl b/ref_vk/shaders/light_common.glsl index d6d6e104..0a7b2054 100644 --- a/ref_vk/shaders/light_common.glsl +++ b/ref_vk/shaders/light_common.glsl @@ -66,7 +66,7 @@ void shadowRayQuery(rayQueryEXT rq, vec3 pos, vec3 dir, float dist, uint flags) } #endif -bool shadowed(vec3 pos, vec3 dir, float dist) { +bool shadowed(vec3 pos, vec3 dir, float dist, bool check_sky) { #ifdef RAY_TRACE const uint flags = 0 //| gl_RayFlagsCullFrontFacingTrianglesEXT @@ -75,42 +75,19 @@ bool shadowed(vec3 pos, vec3 dir, float dist) { | gl_RayFlagsSkipClosestHitShaderEXT ; const uint hit_type = traceShadowRay(pos, dir, dist, flags); - return payload_shadow.hit_type == SHADOW_HIT; + return check_sky ? payload_shadow.hit_type != SHADOW_SKY : payload_shadow.hit_type == SHADOW_HIT; #elif defined(RAY_QUERY) const uint flags = 0 //| gl_RayFlagsCullFrontFacingTrianglesEXT //| gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT - //| gl_RayFlagsSkipClosestHitShaderEXT ; rayQueryEXT rq; shadowRayQuery(rq, pos, dir, dist, flags); - return rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionTriangleEXT; -#else -#error RAY_TRACE or RAY_QUERY -#endif -} -// TODO join with just shadowed() -bool shadowedSky(vec3 pos, vec3 dir, float dist) { -#ifdef RAY_TRACE - const uint flags = 0 - //| gl_RayFlagsCullFrontFacingTrianglesEXT - //| gl_RayFlagsOpaqueEXT - //| gl_RayFlagsTerminateOnFirstHitEXT - //| gl_RayFlagsSkipClosestHitShaderEXT - ; - const uint hit_type = traceShadowRay(pos, dir, dist, flags); - return payload_shadow.hit_type != SHADOW_SKY; -#elif defined(RAY_QUERY) - const uint flags = 0 - //| gl_RayFlagsCullFrontFacingTrianglesEXT - //| gl_RayFlagsOpaqueEXT - //| gl_RayFlagsTerminateOnFirstHitEXT - //| gl_RayFlagsSkipClosestHitShaderEXT - ; - rayQueryEXT rq; - shadowRayQuery(rq, pos, dir, dist, flags); + if (!check_sky) { + return rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionTriangleEXT; + } if (rayQueryGetIntersectionTypeEXT(rq, true) != gl_RayQueryCommittedIntersectionTriangleEXT) return true; diff --git a/ref_vk/shaders/light_polygon.glsl b/ref_vk/shaders/light_polygon.glsl index 02dd56eb..2b2a986d 100644 --- a/ref_vk/shaders/light_polygon.glsl +++ b/ref_vk/shaders/light_polygon.glsl @@ -177,7 +177,7 @@ void sampleSinglePolygonLight(in vec3 P, in vec3 N, in vec3 view_dir, in SampleC const float dist = - dot(vec4(P, 1.f), poly.plane) / dot(light_sample_dir.xyz, poly.plane.xyz); - if (shadowed(P, light_sample_dir.xyz, dist)) + if (shadowed(P, light_sample_dir.xyz, dist, false)) return; vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.); @@ -244,7 +244,7 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, Mate const float dist = - plane_dist / dot(light_sample_dir.xyz, poly.plane.xyz); const vec3 emissive = poly.emissive; - if (!shadowed(P, light_sample_dir.xyz, dist)) { + if (!shadowed(P, light_sample_dir.xyz, dist, false)) { //const float estimate = total_contrib; const float estimate = light_sample_dir.w; vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.); @@ -320,7 +320,7 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, Mate const vec3 emissive = poly.emissive; //if (true) {//!shadowed(P, light_sample_dir.xyz, dist)) { - if (!shadowed(P, light_sample_dir.xyz, dist)) { + if (!shadowed(P, light_sample_dir.xyz, dist, false)) { //const float estimate = total_contrib; const float estimate = light_sample_dir.w; vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.); From c615b9355a934a87a4b701583218e8448b5ff57c Mon Sep 17 00:00:00 2001 From: Ivan 'provod' Avdeev Date: Fri, 3 Feb 2023 11:00:34 -0800 Subject: [PATCH 4/6] rt: only do alpha test shadows after opaque geometry this honestly barely helps ;_; --- ref_vk/shaders/light_common.glsl | 52 ++++++++++++++++++-------------- ref_vk/shaders/ray_interop.h | 5 +-- ref_vk/shaders/ray_primary.comp | 2 +- ref_vk/vk_ray_accel.c | 2 +- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/ref_vk/shaders/light_common.glsl b/ref_vk/shaders/light_common.glsl index 0a7b2054..5c3c2190 100644 --- a/ref_vk/shaders/light_common.glsl +++ b/ref_vk/shaders/light_common.glsl @@ -24,20 +24,22 @@ uint traceShadowRay(vec3 pos, vec3 dir, float dist, uint flags) { #endif #if defined(RAY_QUERY) -void shadowRayQuery(rayQueryEXT rq, vec3 pos, vec3 dir, float dist, uint flags) { - rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_OPAQUE, pos, 0., dir, dist - shadow_offset_fudge); +bool shadowTestAlphaMask(vec3 pos, vec3 dir, float dist) { + rayQueryEXT rq; + const uint flags = 0 + | gl_RayFlagsCullFrontFacingTrianglesEXT + //| gl_RayFlagsNoOpaqueEXT + | gl_RayFlagsTerminateOnFirstHitEXT + ; + rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_ALPHA_TEST, pos, 0., dir, dist); while (rayQueryProceedEXT(rq)) { - if (0 != (rayQueryGetRayFlagsEXT(rq) & gl_RayFlagsOpaqueEXT)) - continue; - // Alpha test, takes 10ms // TODO check other possible ways of doing alpha test. They might be more efficient: // 1. Do a separate ray query for alpha masked geometry. Reason: here we might accidentally do the expensive // texture sampling for geometry that's ultimately invisible (i.e. behind walls). Also, shader threads congruence. // Separate pass could be more efficient as it'd be doing the same thing for every invocation. // 2. Same as the above, but also with a completely independent TLAS. Why: no need to mask-check geometry for opaque-vs-alpha -#if 1 const uint instance_kusochki_offset = rayQueryGetIntersectionInstanceCustomIndexEXT(rq, false); const uint geometry_index = rayQueryGetIntersectionGeometryIndexEXT(rq, false); const uint kusok_index = instance_kusochki_offset + geometry_index; @@ -61,8 +63,9 @@ void shadowRayQuery(rayQueryEXT rq, vec3 pos, vec3 dir, float dist, uint flags) if (texture_color.a >= alpha_mask_threshold) { rayQueryConfirmIntersectionEXT(rq); } -#endif } + + return rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionTriangleEXT; } #endif @@ -77,25 +80,30 @@ bool shadowed(vec3 pos, vec3 dir, float dist, bool check_sky) { const uint hit_type = traceShadowRay(pos, dir, dist, flags); return check_sky ? payload_shadow.hit_type != SHADOW_SKY : payload_shadow.hit_type == SHADOW_HIT; #elif defined(RAY_QUERY) - const uint flags = 0 - //| gl_RayFlagsCullFrontFacingTrianglesEXT - //| gl_RayFlagsOpaqueEXT - | gl_RayFlagsTerminateOnFirstHitEXT - ; - rayQueryEXT rq; - shadowRayQuery(rq, pos, dir, dist, flags); + { + const uint flags = 0 + | gl_RayFlagsCullFrontFacingTrianglesEXT + | gl_RayFlagsOpaqueEXT + | gl_RayFlagsTerminateOnFirstHitEXT + ; + rayQueryEXT rq; + rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_OPAQUE, pos, 0., dir, dist - shadow_offset_fudge); + while (rayQueryProceedEXT(rq)) {} - if (!check_sky) { - return rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionTriangleEXT; + if (rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionTriangleEXT) { + if (!check_sky) + return true; + + const int instance_kusochki_offset = rayQueryGetIntersectionInstanceCustomIndexEXT(rq, true); + const int kusok_index = instance_kusochki_offset + rayQueryGetIntersectionGeometryIndexEXT(rq, true); + const uint tex_base_color = getKusok(kusok_index).tex_base_color; + if ((tex_base_color & KUSOK_MATERIAL_FLAG_SKYBOX) == 0) + return true; + } } - if (rayQueryGetIntersectionTypeEXT(rq, true) != gl_RayQueryCommittedIntersectionTriangleEXT) - return true; + return shadowTestAlphaMask(pos, dir, dist); - const int instance_kusochki_offset = rayQueryGetIntersectionInstanceCustomIndexEXT(rq, true); - const int kusok_index = instance_kusochki_offset + rayQueryGetIntersectionGeometryIndexEXT(rq, true); - const uint tex_base_color = getKusok(kusok_index).tex_base_color; - return (tex_base_color & KUSOK_MATERIAL_FLAG_SKYBOX) == 0; #else #error RAY_TRACE or RAY_QUERY #endif diff --git a/ref_vk/shaders/ray_interop.h b/ref_vk/shaders/ray_interop.h index f4307ad7..88ad0a4c 100644 --- a/ref_vk/shaders/ray_interop.h +++ b/ref_vk/shaders/ray_interop.h @@ -47,8 +47,9 @@ LIST_SPECIALIZATION_CONSTANTS(DECLARE_SPECIALIZATION_CONSTANT) #endif // not GLSL #define GEOMETRY_BIT_OPAQUE 0x01 -#define GEOMETRY_BIT_ADDITIVE 0x02 -#define GEOMETRY_BIT_REFRACTIVE 0x04 +#define GEOMETRY_BIT_ALPHA_TEST 0x02 +#define GEOMETRY_BIT_ADDITIVE 0x04 +#define GEOMETRY_BIT_REFRACTIVE 0x08 #define SHADER_OFFSET_MISS_REGULAR 0 #define SHADER_OFFSET_MISS_SHADOW 1 diff --git a/ref_vk/shaders/ray_primary.comp b/ref_vk/shaders/ray_primary.comp index 96eb77ac..6c9fc3e9 100644 --- a/ref_vk/shaders/ray_primary.comp +++ b/ref_vk/shaders/ray_primary.comp @@ -51,7 +51,7 @@ void main() { //| gl_RayFlagsSkipClosestHitShaderEXT ; const float L = 10000.; // TODO Why 10k? - rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_OPAQUE, origin, 0., direction, L); + rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_OPAQUE | GEOMETRY_BIT_ALPHA_TEST, origin, 0., direction, L); while (rayQueryProceedEXT(rq)) { if (0 != (rayQueryGetRayFlagsEXT(rq) & gl_RayFlagsOpaqueEXT)) continue; diff --git a/ref_vk/vk_ray_accel.c b/ref_vk/vk_ray_accel.c index da6638a9..efa00818 100644 --- a/ref_vk/vk_ray_accel.c +++ b/ref_vk/vk_ray_accel.c @@ -179,7 +179,7 @@ void RT_VkAccelPrepareTlas(VkCommandBuffer cmdbuf) { inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR; break; case MaterialMode_Opaque_AlphaTest: - inst[i].mask = GEOMETRY_BIT_OPAQUE; + inst[i].mask = GEOMETRY_BIT_ALPHA_TEST; inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_ALPHA_TEST, inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR; break; From de6da4f03f3ae002b04741e0388a7ac9d56af619 Mon Sep 17 00:00:00 2001 From: Ivan 'provod' Avdeev Date: Fri, 3 Feb 2023 11:52:39 -0800 Subject: [PATCH 5/6] rt: add additive transparency known issues: - colors are incorrect (probably because of kusok.color having the wrong value) - mixes weirdly with denoiser --- ref_vk/shaders/ray_primary.comp | 51 +++++++++++++++++++++------------ ref_vk/shaders/rt_geometry.glsl | 33 +++++++++++++++++++++ 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/ref_vk/shaders/ray_primary.comp b/ref_vk/shaders/ray_primary.comp index 6c9fc3e9..a0f20c77 100644 --- a/ref_vk/shaders/ray_primary.comp +++ b/ref_vk/shaders/ray_primary.comp @@ -23,6 +23,31 @@ RAY_PRIMARY_OUTPUTS(X) layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas; +vec3 traceAdditive(vec3 pos, vec3 dir, float L) { + const float additive_soft_overshoot = 16.; + vec3 ret = vec3(0., 0., 0.); + rayQueryEXT rq; + const uint flags = 0 + | gl_RayFlagsCullFrontFacingTrianglesEXT + //| gl_RayFlagsSkipClosestHitShaderEXT + | gl_RayFlagsNoOpaqueEXT // force all to be non-opaque + ; + rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_ADDITIVE, pos, 0., dir, L + additive_soft_overshoot); + while (rayQueryProceedEXT(rq)) { + const MiniGeometry geom = readCandidateMiniGeometry(rq); + const uint tex_base_color = getKusok(geom.kusok_index).tex_base_color; + const vec4 texture_color = texture(textures[nonuniformEXT(tex_base_color)], geom.uv); + const vec4 kusok_color = getKusok(geom.kusok_index).color; + const vec3 color = texture_color.rgb * kusok_color.rgb * texture_color.a; // * kusok_color.a; + //const vec3 color = texture_color.rgb * kusok_color.rgb * texture_color.a * kusok_color.a; + + const float hit_t = rayQueryGetIntersectionTEXT(rq, false); + const float overshoot = hit_t - L; + ret += color * smoothstep(additive_soft_overshoot, 0., overshoot); + } + return ret; +} + void main() { const ivec2 pix = ivec2(gl_GlobalInvocationID); const ivec2 res = ivec2(imageSize(out_position_t)); @@ -50,7 +75,7 @@ void main() { //| gl_RayFlagsTerminateOnFirstHitEXT //| gl_RayFlagsSkipClosestHitShaderEXT ; - const float L = 10000.; // TODO Why 10k? + float L = 10000.; // TODO Why 10k? rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_OPAQUE | GEOMETRY_BIT_ALPHA_TEST, origin, 0., direction, L); while (rayQueryProceedEXT(rq)) { if (0 != (rayQueryGetRayFlagsEXT(rq) & gl_RayFlagsOpaqueEXT)) @@ -63,24 +88,9 @@ void main() { // texture sampling for geometry that's ultimately invisible (i.e. behind walls). Also, shader threads congruence. // Separate pass could be more efficient as it'd be doing the same thing for every invocation. // 2. Same as the above, but also with a completely independent TLAS. Why: no need to mask-check geometry for opaque-vs-alpha - const uint instance_kusochki_offset = rayQueryGetIntersectionInstanceCustomIndexEXT(rq, false); - const uint geometry_index = rayQueryGetIntersectionGeometryIndexEXT(rq, false); - const uint kusok_index = instance_kusochki_offset + geometry_index; - const Kusok kusok = getKusok(kusok_index); - - const uint primitive_index = rayQueryGetIntersectionPrimitiveIndexEXT(rq, false); - const uint first_index_offset = kusok.index_offset + primitive_index * 3; - const uint vi1 = uint(getIndex(first_index_offset+0)) + kusok.vertex_offset; - const uint vi2 = uint(getIndex(first_index_offset+1)) + kusok.vertex_offset; - const uint vi3 = uint(getIndex(first_index_offset+2)) + kusok.vertex_offset; - const vec2 uvs[3] = { - getVertex(vi1).gl_tc, - getVertex(vi2).gl_tc, - getVertex(vi3).gl_tc, - }; - const vec2 bary = rayQueryGetIntersectionBarycentricsEXT(rq, false); - const vec2 uv = baryMix(uvs[0], uvs[1], uvs[2], bary); - const vec4 texture_color = texture(textures[nonuniformEXT(kusok.tex_base_color)], uv); + const MiniGeometry geom = readCandidateMiniGeometry(rq); + const uint tex_base_color = getKusok(geom.kusok_index).tex_base_color; + const vec4 texture_color = texture(textures[nonuniformEXT(tex_base_color)], geom.uv); const float alpha_mask_threshold = .1f; if (texture_color.a >= alpha_mask_threshold) { @@ -90,8 +100,11 @@ void main() { if (rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionTriangleEXT) { primaryRayHit(rq, payload); + L = rayQueryGetIntersectionTEXT(rq, true); } + payload.emissive.rgb += traceAdditive(origin, direction, L); + imageStore(out_position_t, pix, payload.hit_t); imageStore(out_base_color_a, pix, payload.base_color_a); imageStore(out_normals_gs, pix, payload.normals_gs); diff --git a/ref_vk/shaders/rt_geometry.glsl b/ref_vk/shaders/rt_geometry.glsl index 5fbee368..87b42e72 100644 --- a/ref_vk/shaders/rt_geometry.glsl +++ b/ref_vk/shaders/rt_geometry.glsl @@ -125,4 +125,37 @@ Geometry readHitGeometry(vec2 bary, float ray_cone_width) { return geom; } + +#ifdef RAY_QUERY +struct MiniGeometry { + vec2 uv; + uint kusok_index; +}; + +MiniGeometry readCandidateMiniGeometry(rayQueryEXT rq) { + const uint instance_kusochki_offset = rayQueryGetIntersectionInstanceCustomIndexEXT(rq, false); + const uint geometry_index = rayQueryGetIntersectionGeometryIndexEXT(rq, false); + const uint kusok_index = instance_kusochki_offset + geometry_index; + const Kusok kusok = getKusok(kusok_index); + + const uint primitive_index = rayQueryGetIntersectionPrimitiveIndexEXT(rq, false); + const uint first_index_offset = kusok.index_offset + primitive_index * 3; + const uint vi1 = uint(getIndex(first_index_offset+0)) + kusok.vertex_offset; + const uint vi2 = uint(getIndex(first_index_offset+1)) + kusok.vertex_offset; + const uint vi3 = uint(getIndex(first_index_offset+2)) + kusok.vertex_offset; + const vec2 uvs[3] = { + getVertex(vi1).gl_tc, + getVertex(vi2).gl_tc, + getVertex(vi3).gl_tc, + }; + const vec2 bary = rayQueryGetIntersectionBarycentricsEXT(rq, false); + const vec2 uv = baryMix(uvs[0], uvs[1], uvs[2], bary); + + MiniGeometry ret; + ret.uv = uv; + ret.kusok_index = kusok_index; + return ret; +} +#endif // #ifdef RAY_QUERY + #endif // RT_GEOMETRY_GLSL_INCLUDED From 51641234ab9547234c20fa72dd1000eb17f6c7e4 Mon Sep 17 00:00:00 2001 From: Ivan 'provod' Avdeev Date: Fri, 3 Feb 2023 12:00:29 -0800 Subject: [PATCH 6/6] rt: fixup additive color --- ref_vk/shaders/ray_primary.comp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ref_vk/shaders/ray_primary.comp b/ref_vk/shaders/ray_primary.comp index a0f20c77..b4fd7aa3 100644 --- a/ref_vk/shaders/ray_primary.comp +++ b/ref_vk/shaders/ray_primary.comp @@ -37,9 +37,8 @@ vec3 traceAdditive(vec3 pos, vec3 dir, float L) { const MiniGeometry geom = readCandidateMiniGeometry(rq); const uint tex_base_color = getKusok(geom.kusok_index).tex_base_color; const vec4 texture_color = texture(textures[nonuniformEXT(tex_base_color)], geom.uv); - const vec4 kusok_color = getKusok(geom.kusok_index).color; - const vec3 color = texture_color.rgb * kusok_color.rgb * texture_color.a; // * kusok_color.a; - //const vec3 color = texture_color.rgb * kusok_color.rgb * texture_color.a * kusok_color.a; + const vec3 kusok_emissive = getKusok(geom.kusok_index).emissive; + const vec3 color = texture_color.rgb * kusok_emissive * texture_color.a; // * kusok_color.a; const float hit_t = rayQueryGetIntersectionTEXT(rq, false); const float overshoot = hit_t - L;