rtx: draw skybox on SURF_SKY surfaces only

- 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
This commit is contained in:
Ivan 'provod' Avdeev 2021-11-25 11:53:44 -08:00
parent 12565a35a1
commit a9d5e4dd22
12 changed files with 126 additions and 39 deletions

View File

@ -7,6 +7,7 @@
layout (constant_id = 6) const uint MAX_TEXTURES = 4096;
layout (set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES];
layout (set = 0, binding = 13) uniform samplerCube skybox;
layout(location = PAYLOAD_LOCATION_OPAQUE) rayPayloadInEXT RayPayloadOpaque payload;
@ -79,6 +80,30 @@ void main() {
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 pos[3] = {
gl_ObjectToWorldEXT * vec4(vertices[vi1].pos, 1.),
gl_ObjectToWorldEXT * vec4(vertices[vi2].pos, 1.),
gl_ObjectToWorldEXT * vec4(vertices[vi3].pos, 1.),
};
// This one is supposed to be numerically better, but I can't see why
const vec3 hit_pos = pos[0] * (1. - bary.x - bary.y) + pos[1] * bary.x + pos[2] * bary.y;
//const vec3 hit_pos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT
const uint tex_base_color = kusochki[kusok_index].tex_base_color;
if ((tex_base_color & KUSOK_MATERIAL_FLAG_SKYBOX) != 0) {
payload.hit_pos_t = vec4(hit_pos, gl_HitTEXT);
payload.base_color = vec3(0.);
payload.transmissiveness = 0.;
payload.normal = vec3(0.);
payload.geometry_normal = vec3(0.);
payload.emissive = texture(skybox, gl_WorldRayDirectionEXT).rgb;
payload.kusok_index = -1;
payload.roughness = 0.;
payload.metalness = 0.;
payload.material_index = tex_base_color;
return;
}
const vec3 n1 = vertices[vi1].normal;
const vec3 n2 = vertices[vi2].normal;
const vec3 n3 = vertices[vi3].normal;
@ -94,11 +119,6 @@ void main() {
vertices[vi3].gl_tc,
};
const vec3 pos[3] = {
gl_ObjectToWorldEXT * vec4(vertices[vi1].pos, 1.),
gl_ObjectToWorldEXT * vec4(vertices[vi2].pos, 1.),
gl_ObjectToWorldEXT * vec4(vertices[vi3].pos, 1.),
};
const vec2 texture_uv_stationary = vertices[vi1].gl_tc * (1. - bary.x - bary.y) + vertices[vi2].gl_tc * bary.x + vertices[vi3].gl_tc * bary.y;
const vec2 texture_uv = texture_uv_stationary + push_constants.time * kusochki[kusok_index].uv_speed;
@ -106,15 +126,11 @@ void main() {
const float geom_normal_sign = sign(dot(real_geom_normal, -gl_WorldRayDirectionEXT));
const vec3 geom_normal = geom_normal_sign * real_geom_normal;
// This one is supposed to be numerically better, but I can't see why
const vec3 hit_pos = pos[0] * (1. - bary.x - bary.y) + pos[1] * bary.x + pos[2] * bary.y + geom_normal * normal_offset_fudge;
//const vec3 hit_pos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT + geom_normal * normal_offset_fudge;
const float ray_cone_width = payload.pixel_cone_spread_angle * payload.t_offset;
vec4 uv_lods;
computeAnisotropicEllipseAxes(hit_pos, /* TODO geom_?*/ normal, gl_WorldRayDirectionEXT, ray_cone_width, pos, uvs, texture_uv_stationary, uv_lods.xy, uv_lods.zw);
const uint tex_index = kusochki[kusok_index].tex_base_color;
const uint tex_index = tex_base_color;
const vec4 tex_color = sampleTexture(tex_index, texture_uv, uv_lods);
//const vec3 base_color = pow(tex_color.rgb, vec3(2.));
const vec3 base_color = ((push_constants.flags & PUSH_FLAG_LIGHTMAP_ONLY) != 0) ? vec3(1.) : tex_color.rgb;// pow(tex_color.rgb, vec3(2.));
@ -135,7 +151,7 @@ void main() {
// FIXME read alpha from texture
payload.hit_pos_t = vec4(hit_pos, gl_HitTEXT);
payload.hit_pos_t = vec4(hit_pos + geom_normal * normal_offset_fudge, gl_HitTEXT);
payload.base_color = base_color * kusochki[kusok_index].color.rgb;
payload.transmissiveness = (1. - tex_color.a * kusochki[kusok_index].color.a);
payload.normal = normal;

View File

@ -16,6 +16,7 @@ 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;
@ -51,7 +52,7 @@ layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadEXT RayPayloadShadow payloa
layout(location = PAYLOAD_LOCATION_ADDITIVE) rayPayloadEXT RayPayloadAdditive payload_additive;
bool shadowed(vec3 pos, vec3 dir, float dist) {
payload_shadow.shadow = true;
payload_shadow.hit_type = SHADOW_HIT;
const uint flags = 0
//| gl_RayFlagsCullFrontFacingTrianglesEXT
//| gl_RayFlagsOpaqueEXT
@ -63,7 +64,24 @@ bool shadowed(vec3 pos, vec3 dir, float dist) {
GEOMETRY_BIT_OPAQUE,
0, 0, SHADER_OFFSET_MISS_SHADOW,
pos, 0., dir, dist - shadow_offset_fudge, PAYLOAD_LOCATION_SHADOW);
return payload_shadow.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)
@ -182,9 +200,9 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
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 environment = (lights.point_lights[i].environment == 0);
const bool not_environment = (lights.point_lights[i].environment == 0);
const vec3 light_dir = 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 = 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)
@ -199,8 +217,8 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
spot_attenuation = (spot_dot - stopdot2) / (stopdot - stopdot2);
float fdist = 1.f;
float light_dist = 1e6; // 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 (environment) {
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;
@ -221,7 +239,6 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
// if (dot(color,color) < color_culling_threshold)
// continue;
// TODO split into diffuse and specular for denoiser
vec3 ldiffuse, lspecular;
evalSplitBRDF(payload_opaque.normal, light_dir_norm, view_dir, material, ldiffuse, lspecular);
ldiffuse *= color;
@ -232,9 +249,14 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
if (dot(combined,combined) < color_culling_threshold)
continue;
// TODO for environment light check that we've hit SURF_SKY
if (shadowed(payload_opaque.hit_pos_t.xyz, light_dir_norm, light_dist + shadow_offset_fudge))
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;
@ -365,7 +387,7 @@ void main() {
vec3 additive = traceAdditive(origin, direction, payload_opaque.hit_pos_t.w <= 0. ? L : payload_opaque.hit_pos_t.w);
// Sky/envmap
if (payload_opaque.hit_pos_t.w <= 0.) {
if (payload_opaque.kusok_index < 0) {
if (bounce == 0) {
out_additive += payload_opaque.emissive * color_factor + additive;
} else {

View File

@ -1,15 +1,9 @@
#version 460 core
#extension GL_EXT_nonuniform_qualifier : enable
#extension GL_GOOGLE_include_directive : require
#include "ray_common.glsl"
#include "ray_kusochki.glsl"
//layout (constant_id = 6) const uint MAX_TEXTURES = 4096;
//layout (set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES];
layout (set = 0, binding = 13) uniform samplerCube skybox;
layout (set = 0, binding = 7/*, align=4*/) uniform UBOLights { Lights lights; };
layout(location = PAYLOAD_LOCATION_OPAQUE) rayPayloadInEXT RayPayloadOpaque payload;
void main() {
@ -20,5 +14,5 @@ void main() {
payload.base_color = vec3(1., 0., 1.);
payload.kusok_index = -1;
payload.material_index = 0;
payload.emissive = texture(skybox, gl_WorldRayDirectionEXT).rgb;
payload.emissive = vec3(1., 0., 1.);
}

View File

@ -19,8 +19,13 @@ struct RayPayloadOpaque {
vec4 debug;
};
#define SHADOW_MISS 0
#define SHADOW_HIT 1
#define SHADOW_SKY 2
struct RayPayloadShadow {
bool shadow;
uint hit_type;
};

View File

@ -32,6 +32,9 @@ layout (constant_id = 3) const uint MAX_VISIBLE_SURFACE_LIGHTS = 255;
#define SHADER_OFFSET_HIT_REGULAR 0
#define SHADER_OFFSET_HIT_ALPHA_TEST 1
#define SHADER_OFFSET_HIT_ADDITIVE 2
#define SHADER_OFFSET_HIT_SHADOW 3
#define KUSOK_MATERIAL_FLAG_SKYBOX 0x80000000
struct Kusok {
uint index_offset;

View File

@ -0,0 +1,15 @@
#version 460 core
#extension GL_EXT_ray_tracing: require
#include "ray_kusochki.glsl"
#include "ray_common.glsl"
layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadInEXT RayPayloadShadow payload_shadow;
void main() {
const int instance_kusochki_offset = gl_InstanceCustomIndexEXT;
const int kusok_index = instance_kusochki_offset + gl_GeometryIndexEXT;
const uint tex_base_color = kusochki[kusok_index].tex_base_color;
payload_shadow.hit_type = ((tex_base_color & KUSOK_MATERIAL_FLAG_SKYBOX) == 0) ? SHADOW_HIT : SHADOW_SKY ;
}

View File

@ -6,5 +6,5 @@
layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadInEXT RayPayloadShadow payload_shadow;
void main() {
payload_shadow.shadow = false;
payload_shadow.hit_type = SHADOW_MISS;
}

View File

@ -382,8 +382,9 @@ static qboolean renderableSurface( const msurface_t *surf, int i ) {
return false;
}
// Explicitly enable SURF_SKY, otherwise they will be skipped by SURF_DRAWTILED
if( FBitSet( surf->flags, SURF_DRAWSKY )) {
return false;
return true;
}
if( FBitSet( surf->flags, SURF_DRAWTILED )) {
@ -409,7 +410,6 @@ static model_sizes_t computeSizes( const model_t *mod ) {
const msurface_t *surf = mod->surfaces + mod->firstmodelsurface + i;
sizes.water_surfaces += !!(surf->flags & (SURF_DRAWTURB | SURF_DRAWTURB_QUADS));
//sizes.sky_surfaces += !!(surf->flags & SURF_DRAWSKY);
if (!renderableSurface(surf, i))
continue;
@ -487,7 +487,9 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
model_geometry->material = kXVkMaterialSky;
} else {
model_geometry->material = kXVkMaterialRegular;
VK_CreateSurfaceLightmap( surf, mod );
if (!FBitSet( surf->flags, SURF_DRAWTILED )) {
VK_CreateSurfaceLightmap( surf, mod );
}
}
if (FBitSet( surf->flags, SURF_CONVEYOR )) {

View File

@ -637,8 +637,8 @@ void VK_LightsAddEmissiveSurface( const struct vk_render_geometry_s *geom, const
if (geom->material != kXVkMaterialSky && geom->material != kXVkMaterialEmissive) {
VectorCopy(g_lights.map.emissive_textures[texture_num].emissive, esurf->emissive);
} else {
// TODO per-map sky emissive
VectorSet(esurf->emissive, 1000.f, 1000.f, 1000.f);
// TODO see #227
VectorSet(esurf->emissive, 0.f, 0.f, 0.f);
}
Matrix3x4_Copy(esurf->transform, *transform_row);

View File

@ -217,6 +217,12 @@ vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) {
kusochki[i].index_offset = mg->index_offset;
kusochki[i].triangles = prim_count;
if (mg->material == kXVkMaterialSky) {
kusochki[i].tex_base_color |= KUSOK_MATERIAL_FLAG_SKYBOX;
} else {
kusochki[i].tex_base_color &= (~KUSOK_MATERIAL_FLAG_SKYBOX);
}
//kusochki[i].texture = mg->texture;
//kusochki[i].roughness = mg->material == kXVkMaterialWater ? 0. : 1.; // FIXME
VectorSet(kusochki[i].emissive, 0, 0, 0 );
@ -379,6 +385,10 @@ void VK_RayFrameAddModel( vk_ray_model_t *model, const vk_render_model_t *render
kusok->tex_roughness = tglob.grayTexture;
}
if (geom->material == kXVkMaterialSky) {
kusok->tex_base_color |= KUSOK_MATERIAL_FLAG_SKYBOX;
}
Vector4Copy(color, kusok->color);
XVK_GetEmissiveForTexture( kusok->emissive, geom->texture );

View File

@ -31,6 +31,8 @@ enum {
ShaderBindingTable_Hit,
ShaderBindingTable_Hit_WithAlphaTest,
ShaderBindingTable_Hit_Additive,
ShaderBindingTable_Hit_Shadow,
ShaderBindingTable_Hit__END = ShaderBindingTable_Hit_Shadow,
ShaderBindingTable_COUNT
};
@ -353,6 +355,8 @@ static void createPipeline( void )
uint32_t max_visible_surface_lights;
float light_grid_cell_size;
int max_light_clusters;
uint32_t max_textures;
uint32_t sbt_record_size;
} spec_data = {
.max_point_lights = MAX_POINT_LIGHTS,
.max_emissive_kusochki = MAX_EMISSIVE_KUSOCHKI,
@ -360,6 +364,8 @@ static void createPipeline( void )
.max_visible_surface_lights = MAX_VISIBLE_SURFACE_LIGHTS,
.light_grid_cell_size = LIGHT_GRID_CELL_SIZE,
.max_light_clusters = MAX_LIGHT_CLUSTERS,
.max_textures = MAX_TEXTURES,
.sbt_record_size = g_rtx.sbt_record_size,
};
const VkSpecializationMapEntry spec_map[] = {
{.constantID = 0, .offset = offsetof(struct RayShaderSpec, max_point_lights), .size = sizeof(int) },
@ -368,6 +374,8 @@ static void createPipeline( void )
{.constantID = 3, .offset = offsetof(struct RayShaderSpec, max_visible_surface_lights), .size = sizeof(uint32_t) },
{.constantID = 4, .offset = offsetof(struct RayShaderSpec, light_grid_cell_size), .size = sizeof(float) },
{.constantID = 5, .offset = offsetof(struct RayShaderSpec, max_light_clusters), .size = sizeof(int) },
{.constantID = 6, .offset = offsetof(struct RayShaderSpec, max_textures), .size = sizeof(uint32_t) },
{.constantID = 7, .offset = offsetof(struct RayShaderSpec, sbt_record_size), .size = sizeof(uint32_t) },
};
VkSpecializationInfo spec = {
@ -383,6 +391,7 @@ static void createPipeline( void )
ShaderStageIndex_Miss_Shadow,
ShaderStageIndex_Miss_Empty,
ShaderStageIndex_ClosestHit,
ShaderStageIndex_ClosestHit_Shadow,
ShaderStageIndex_AnyHit_AlphaTest,
ShaderStageIndex_AnyHit_Additive,
ShaderStageIndex_COUNT,
@ -416,6 +425,7 @@ static void createPipeline( void )
DEFINE_SHADER("shadow.rmiss.spv", MISS, ShaderStageIndex_Miss_Shadow);
DEFINE_SHADER("empty.rmiss.spv", MISS, ShaderStageIndex_Miss_Empty);
DEFINE_SHADER("ray.rchit.spv", CLOSEST_HIT, ShaderStageIndex_ClosestHit);
DEFINE_SHADER("shadow.rchit.spv", CLOSEST_HIT, ShaderStageIndex_ClosestHit_Shadow);
DEFINE_SHADER("alphamask.rahit.spv", ANY_HIT, ShaderStageIndex_AnyHit_AlphaTest);
DEFINE_SHADER("additive.rahit.spv", ANY_HIT, ShaderStageIndex_AnyHit_Additive);
@ -429,6 +439,7 @@ static void createPipeline( void )
ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit, SHADER_OFFSET_HIT_REGULAR);
ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit_WithAlphaTest, SHADER_OFFSET_HIT_ALPHA_TEST);
ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit_Additive, SHADER_OFFSET_HIT_ADDITIVE);
ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit_Shadow, SHADER_OFFSET_HIT_SHADOW);
shader_groups[ShaderBindingTable_RayGen] = (VkRayTracingShaderGroupCreateInfoKHR) {
.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR,
@ -493,6 +504,15 @@ static void createPipeline( void )
.intersectionShader = VK_SHADER_UNUSED_KHR,
};
shader_groups[ShaderBindingTable_Hit_Shadow] = (VkRayTracingShaderGroupCreateInfoKHR) {
.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR,
.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR,
.anyHitShader = VK_SHADER_UNUSED_KHR,
.closestHitShader = ShaderStageIndex_ClosestHit_Shadow,
.generalShader = VK_SHADER_UNUSED_KHR,
.intersectionShader = VK_SHADER_UNUSED_KHR,
};
XVK_CHECK(vkCreateRayTracingPipelinesKHR(vk_core.device, VK_NULL_HANDLE, g_pipeline_cache, 1, &rtpci, NULL, &g_rtx.pipeline));
ASSERT(g_rtx.pipeline != VK_NULL_HANDLE);
@ -739,7 +759,7 @@ LIST_GBUFFER_IMAGES(GBUFFER_WRITE_BARRIER)
}
const VkStridedDeviceAddressRegionKHR sbt_raygen = SBT_INDEX(ShaderBindingTable_RayGen, 1);
const VkStridedDeviceAddressRegionKHR sbt_miss = SBT_INDEX(ShaderBindingTable_Miss, ShaderBindingTable_Miss_Empty - ShaderBindingTable_Miss);
const VkStridedDeviceAddressRegionKHR sbt_hit = SBT_INDEX(ShaderBindingTable_Hit, ShaderBindingTable_Hit_Additive - ShaderBindingTable_Hit);
const VkStridedDeviceAddressRegionKHR sbt_hit = SBT_INDEX(ShaderBindingTable_Hit, ShaderBindingTable_Hit__END - ShaderBindingTable_Hit);
const VkStridedDeviceAddressRegionKHR sbt_callable = { 0 };
vkCmdTraceRaysKHR(cmdbuf, &sbt_raygen, &sbt_miss, &sbt_hit, &sbt_callable, FRAME_WIDTH, FRAME_HEIGHT, 1 );

View File

@ -508,7 +508,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
tex->height = layers[0]->height;
mipCount = CalcMipmapCount( tex, true);
gEngine.Con_Reportf("Uploading texture %s, mips=%d, layers=%d\n", tex->name, mipCount, layers);
gEngine.Con_Reportf("Uploading texture %s, mips=%d, layers=%d\n", tex->name, mipCount, num_layers);
// TODO this vvv
// // NOTE: only single uncompressed textures can be resamples, no mips, no layers, no sides
@ -989,7 +989,7 @@ void XVK_SetupSky( const char *skyboxname )
if( !Common_CheckTexName( loadname ))
goto fail;
// needed? VK_ProcessImage( tex, pic );
Q_strncpy( tglob.skybox_cube.name, loadname, sizeof( tglob.skybox_cube.name ));
if (uploadTexture(&tglob.skybox_cube, sides, 6, true)) {
tglob.fCustomSkybox = true;
gEngine.Con_DPrintf( "done\n" );