rtx: improve surface lights
use bsp/pvs-based visibility data for acceleration: + fps 5 -> 60 - correctness: some areas have too many lights, which ends up culling visible ones too also fix shadow artefacts
This commit is contained in:
parent
0407f12638
commit
ad7b210228
|
@ -1,7 +1,13 @@
|
|||
## 2021-04-12
|
||||
- [x] rtx: fix surface-kusok index mismatch
|
||||
- [x] rtx: try to use light visibility data
|
||||
-> too few slots for light sources
|
||||
-> some areas have too many naively visible lights
|
||||
- [x] rtx: fix light shadow artefacts
|
||||
|
||||
# Next
|
||||
- [ ] rtx: use light visibility data
|
||||
- [ ] sometimes we get uninitialized models
|
||||
- [ ] rtx: "toilet error": attempting to get AS device address crashes the driver
|
||||
- [ ] rtx: sometimes we get uninitialized models
|
||||
- [ ] run under asan
|
||||
- [ ] rtx: fix blas destruction on exit
|
||||
- [ ] rtx: read rad file data
|
||||
|
@ -10,8 +16,14 @@
|
|||
- [ ] rtx: textures
|
||||
- [ ] rtx: better random
|
||||
- [ ] rtx: some studio models have glitchy geometry
|
||||
- [ ] rtx: simple convolution denoise (bilateral?)
|
||||
|
||||
# Planned
|
||||
- [ ] rtx: denoise
|
||||
- [ ] non local means ?
|
||||
- [ ] reprojection
|
||||
- [ ] SVG+
|
||||
- [ ] ...
|
||||
- [ ] rtx: add fps: rasterize into G-buffer, and only then compute lighting with rtx
|
||||
- [ ] bake light visibility in compute shader
|
||||
- [ ] rtx: cull light sources (dlights and light textures) using bsp
|
||||
|
@ -168,3 +180,6 @@
|
|||
- [x] rtx: add fps
|
||||
- [x] rtx: don't group brush draws by texture
|
||||
- [x] better AS structure (fewer blases, etc)
|
||||
|
||||
## 2021-04-11
|
||||
- [x] vscode build and debug
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#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.,
|
||||
|
@ -65,6 +69,10 @@ struct Kusok {
|
|||
uint index_offset;
|
||||
uint vertex_offset;
|
||||
uint triangles;
|
||||
uint leaf;
|
||||
uint num_dlights;
|
||||
uint num_surface_lights;
|
||||
uint is_emissive;
|
||||
//vec4 emissive;
|
||||
};
|
||||
|
||||
|
@ -93,14 +101,43 @@ layout(set=0,binding=6) uniform UBODLights {
|
|||
Light lights[max_dlights];
|
||||
};
|
||||
|
||||
layout (constant_id = 2) const uint max_lighttextures = 256;
|
||||
layout (set=0,binding=7) uniform UBOLightTextures {
|
||||
uint num_lighttextures;
|
||||
uint lighttextures[max_lighttextures];
|
||||
struct EmissiveKusok {
|
||||
uint kusok_index;
|
||||
vec3 emissive_color;
|
||||
};
|
||||
|
||||
layout (constant_id = 2) const uint max_lighttextures = 256;
|
||||
layout (set = 0, binding = 7/*, align=4*/) uniform UBOEmissiveKusochki {
|
||||
uint num_kusochki;
|
||||
EmissiveKusok kusochki[256];
|
||||
} emissive_kusochki;
|
||||
|
||||
layout(binding = 8, set = 0, rgba8) uniform readonly image2D previous_frame;
|
||||
|
||||
// FIXME shader specialization constants
|
||||
#define MAX_VISIBLE_DLIGHTS 15
|
||||
#define MAX_VISIBLE_SURFACE_LIGHTS 15
|
||||
struct LightLeaf {
|
||||
uint8_t num_dlights;
|
||||
uint8_t num_slights;
|
||||
uint8_t dlights[MAX_VISIBLE_DLIGHTS];
|
||||
uint8_t slights[MAX_VISIBLE_SURFACE_LIGHTS];
|
||||
};
|
||||
|
||||
// FIMXE specialize
|
||||
layout (constant_id = 3) const uint max_light_leaves = 8192;
|
||||
layout (set = 0, binding = 9, align = 1) readonly buffer UBOLightLeaves {
|
||||
LightLeaf light_leaves[max_light_leaves];
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
float printText(in vec2 p) {
|
||||
#define PIXSZ 4.
|
||||
p = floor(p / PIXSZ);
|
||||
|
@ -119,8 +156,35 @@ float printText(in vec2 p) {
|
|||
return 0.;
|
||||
|
||||
const int idx = int(pc.y);
|
||||
const Kusok kusok = kusochki[idx];
|
||||
PUTN(idx); PUTC(0.); PUTN(kusok.index_offset); PUTC(0.); PUTN(kusok.vertex_offset); PUTC(0.); PUTN(kusok.triangles);
|
||||
#define _ PUTC(0.);
|
||||
if (false) {
|
||||
const Kusok kusok = kusochki[idx];
|
||||
PUTN(idx); PUTC(0.); PUTN(kusok.leaf); PUTC(0.); PUTN(kusok.num_surface_lights); PUTC(0.);
|
||||
PUTN(kusok.num_dlights);
|
||||
//PUTN(kusok.index_offset); PUTC(0.); PUTN(kusok.vertex_offset); PUTC(0.); PUTN(kusok.triangles);
|
||||
} else if (false) {
|
||||
PUTN(idx);
|
||||
_ PUTN(float(int(light_leaves[idx].num_slights)));
|
||||
_ PUTN(float(int(light_leaves[idx].slights[0])));
|
||||
_ PUTN(float(int(light_leaves[idx].slights[1])));
|
||||
_ PUTN(float(int(light_leaves[idx].slights[2])));
|
||||
_ PUTN(float(int(light_leaves[idx].slights[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].leaf);
|
||||
_ PUTN(kusochki[kidx].triangles);
|
||||
} else if (true) {
|
||||
//PUTN(picked_light);
|
||||
}
|
||||
#undef _
|
||||
return col;
|
||||
}
|
||||
|
||||
|
@ -148,11 +212,6 @@ float rand01() {
|
|||
|
||||
float hash(float f) { return fract(sin(f)*53478.4327); }
|
||||
|
||||
layout (push_constant) uniform PC {
|
||||
float t;
|
||||
int bounces;
|
||||
} pc;
|
||||
|
||||
bool shadowed(vec3 pos, vec3 dir, float dist) {
|
||||
rayQueryEXT shadowRayQuery;
|
||||
rayQueryInitializeEXT(shadowRayQuery, tlas,
|
||||
|
@ -194,10 +253,18 @@ void main() {
|
|||
//const int instance_index = rayQueryGetIntersectionInstanceIdEXT(rayQuery, true);
|
||||
const int geom_index = rayQueryGetIntersectionGeometryIndexEXT(rayQuery, true);
|
||||
const int kusok_index = instance_kusochki_offset + geom_index;
|
||||
const Kusok kusok = kusochki[kusok_index];
|
||||
const uint leaf = kusochki[kusok_index].leaf-1;
|
||||
|
||||
//C = fract(pos / 100.);
|
||||
//C = vec3(hash(float(geom_index)), hash(float(geom_index)+15.43), hash(float(geom_index)+34.));
|
||||
//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);
|
||||
|
@ -218,57 +285,76 @@ void main() {
|
|||
// TODO read from texture
|
||||
const vec3 baseColor = vec3(1.);
|
||||
|
||||
// FIXME upload this data
|
||||
#if 0
|
||||
for (uint i = 0; i < num_lighttextures; ++i) {
|
||||
const uint kusok_index_light = lighttextures[i];
|
||||
const Kusok kusok = kusochki[kusok_index];
|
||||
if (kusok_index_light == 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;
|
||||
continue;
|
||||
}
|
||||
#if 1
|
||||
if (kusok.leaf != 0xffffffff) {
|
||||
const uint num_emissive_kusochki = uint(light_leaves[kusok.leaf].num_slights);
|
||||
//const uint num_emissive_kusochki = emissive_kusochki.num_kusochki;
|
||||
for (uint i = 0; i < num_emissive_kusochki; ++i) {
|
||||
const uint index_into_emissive_kusochki = uint(light_leaves[kusok.leaf].slights[i]);
|
||||
//const uint index_into_emissive_kusochki = i;
|
||||
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;
|
||||
|
||||
const uint picked_tri = rand_range(kusok.triangles);
|
||||
for (uint ti = 0; ti < kusok.triangles; ++ti) {
|
||||
const uint first_index_offset = kusok.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]) + kusok.vertex_offset;
|
||||
const vec3 n1 = vertices[vi1].normal;
|
||||
// if (dot(n1, normal) >= 0. /* TODO epsilon */ )
|
||||
// if (i != picked_light) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
if (picked_tri > ti)
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO random sample point on the entire kusok geometry
|
||||
const uint vi2 = uint(indices[first_index_offset+1]) + kusok.vertex_offset;
|
||||
const uint vi3 = uint(indices[first_index_offset+2]) + kusok.vertex_offset;
|
||||
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;
|
||||
|
||||
const vec3 sample_pos = mix(mix(
|
||||
vertices[vi1].pos, vertices[vi2].pos, rand01()
|
||||
), vertices[vi3].pos, rand01());
|
||||
// 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 = vertices[vi1].normal;
|
||||
// if (dot(n1, normal) >= 0. /* TODO epsilon */ )
|
||||
// continue;
|
||||
|
||||
// const vec3 n2 = vertices[vi2].normal;
|
||||
// const vec3 n3 = vertices[vi3].normal;
|
||||
if (picked_tri > ti)
|
||||
continue;
|
||||
|
||||
vec3 light_dir = sample_pos - pos;
|
||||
if (dot(light_dir, normal) <= 0.)
|
||||
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 float light_dist = length(light_dir);
|
||||
light_dir /= light_dist;
|
||||
if (shadowed(pos + .01 * normal, light_dir, light_dist))
|
||||
continue;
|
||||
const vec3 sample_pos = mix(mix(
|
||||
vertices[vi1].pos, vertices[vi2].pos, rand01()
|
||||
), vertices[vi3].pos, rand01());
|
||||
|
||||
// TODO
|
||||
const float brightness_fudge = 1000.;
|
||||
//const vec3 emissive = kusochki[kusok_index].emissive.rgb;
|
||||
//C += brightness_fudge * kc * baseColor * emissive * dot(light_dir, normal) / (light_dist * light_dist);
|
||||
//const vec3 sample_pos = vertices[vi1].pos;
|
||||
|
||||
// Sample just one triangle
|
||||
break;
|
||||
// const vec3 n2 = vertices[vi2].normal;
|
||||
// const vec3 n3 = vertices[vi3].normal;
|
||||
|
||||
vec3 light_dir = sample_pos - pos;
|
||||
if (dot(light_dir, normal) <= 0.) {
|
||||
//C = vec3(1., 0., 1.);
|
||||
continue;
|
||||
}
|
||||
|
||||
const float light_dist = length(light_dir);
|
||||
light_dir /= light_dist;
|
||||
if (shadowed(pos + normal_offset_fudge * normal, light_dir, light_dist - shadow_offset_fudge)) {
|
||||
//C = vec3(0., 1., 0.);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO
|
||||
const float brightness_fudge = 100.;
|
||||
C += brightness_fudge * kc * baseColor * emissive * dot(light_dir, normal) / (light_dist * light_dist);
|
||||
|
||||
// Sample just one triangle
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -297,7 +383,7 @@ void main() {
|
|||
const float d2 = dot(light_dir, light_dir);
|
||||
const float light_dist = sqrt(d2);
|
||||
|
||||
if (shadowed(pos + .01 * normal, light_dir_norm, light_dist))
|
||||
if (shadowed(pos + .01 * normal, light_dir_norm, light_dist + shadow_offset_fudge))
|
||||
continue;
|
||||
|
||||
const float r2 = light_pos_r.w * light_pos_r.w;
|
||||
|
@ -323,13 +409,12 @@ void main() {
|
|||
} // 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)));
|
||||
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 (false)
|
||||
if (true)
|
||||
{
|
||||
const float wet = .5;
|
||||
C = mix(C, imageLoad(previous_frame, ivec2(gl_GlobalInvocationID.xy)).rgb, wet);
|
||||
C = mix(C, imageLoad(previous_frame, ivec2(gl_GlobalInvocationID.xy)).rgb, pc.prev_frame_blend_factor);
|
||||
}
|
||||
imageStore(image, ivec2(gl_GlobalInvocationID.xy), vec4(C, 1.));
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "vk_lightmap.h"
|
||||
#include "vk_scene.h"
|
||||
#include "vk_render.h"
|
||||
#include "vk_light.h"
|
||||
|
||||
#include "ref_params.h"
|
||||
#include "eiface.h"
|
||||
|
@ -212,7 +213,8 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
|
|||
{
|
||||
for( int i = 0; i < mod->nummodelsurfaces; ++i)
|
||||
{
|
||||
msurface_t *surf = mod->surfaces + mod->firstmodelsurface + i;
|
||||
const int surface_index = mod->firstmodelsurface + i;
|
||||
msurface_t *surf = mod->surfaces + surface_index;
|
||||
mextrasurf_t *info = surf->info;
|
||||
vk_render_geometry_t *model_geometry = bmodel->render_model.geometries + num_surfaces;
|
||||
const float sample_size = gEngine.Mod_SampleSizeForFace( surf );
|
||||
|
@ -241,6 +243,8 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
|
|||
model_geometry->vertex_offset = 0;
|
||||
model_geometry->texture = t;
|
||||
model_geometry->vertex_count = surf->numedges;
|
||||
model_geometry->leaf = surface_index < g_lights.num_surfaces ? g_lights.surfaces[surface_index].leaf : -1;
|
||||
model_geometry->surface_index = i;
|
||||
|
||||
VK_CreateSurfaceLightmap( surf, mod );
|
||||
|
||||
|
|
|
@ -380,12 +380,17 @@ static qboolean pickAndCreateDevice( void )
|
|||
.accelerationStructure = VK_TRUE,
|
||||
.pNext = &buffer_address_feature,
|
||||
};
|
||||
VkPhysicalDevice8BitStorageFeatures eight_bit_feature = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES,
|
||||
.pNext = &accel_feature,
|
||||
.storageBuffer8BitAccess = VK_TRUE,
|
||||
.uniformAndStorageBuffer8BitAccess = VK_TRUE,
|
||||
};
|
||||
VkPhysicalDeviceRayQueryFeaturesKHR ray_query_feature = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR,
|
||||
.rayQuery = VK_TRUE,
|
||||
.pNext = &accel_feature,
|
||||
.pNext = &eight_bit_feature,
|
||||
};
|
||||
|
||||
VkDeviceCreateInfo create_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = vk_core.rtx ? &ray_query_feature : NULL,
|
||||
|
|
|
@ -13,4 +13,5 @@ void VK_LoadCvars( void )
|
|||
cl_lightstyle_lerping = gEngine.pfnGetCvarPointer( "cl_lightstyle_lerping", 0 );
|
||||
r_drawentities = gEngine.pfnGetCvarPointer( "r_drawentities", 0 );
|
||||
vk_rtx_bounces = gEngine.Cvar_Get( "vk_rtx_bounces", "2", FCVAR_ARCHIVE, "RTX path tracing ray bounces" );
|
||||
vk_rtx_prev_frame_blend_factor = gEngine.Cvar_Get("vk_rtx_prev_frame_blend_factor", "0.1", FCVAR_ARCHIVE, "RTX path tracer ghetto temporal denoiser strength");
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ void VK_LoadCvars( void );
|
|||
X(r_lighting_modulate) \
|
||||
X(cl_lightstyle_lerping) \
|
||||
X(vk_rtx_bounces) \
|
||||
X(vk_rtx_prev_frame_blend_factor) \
|
||||
|
||||
#define EXTERN_CVAR(cvar) extern cvar_t *cvar;
|
||||
DECLARE_CVAR(EXTERN_CVAR)
|
||||
|
|
|
@ -384,22 +384,20 @@ static void initPVL( void ) {
|
|||
Mem_Free(g_lights.leaves);
|
||||
}
|
||||
|
||||
if (g_lights.surfaces) {
|
||||
Mem_Free(g_lights.surfaces);
|
||||
}
|
||||
|
||||
g_lights.num_leaves = map->numleafs;
|
||||
g_lights.leaves = Mem_Malloc(vk_core.pool, g_lights.num_leaves * sizeof(vk_light_leaf_t));
|
||||
g_lights.frame_number = -1;
|
||||
|
||||
g_lights.num_surfaces = map->nummarksurfaces;
|
||||
g_lights.surfaces = Mem_Malloc(vk_core.pool, g_lights.num_surfaces * sizeof(*g_lights.surfaces));
|
||||
|
||||
g_lights.num_emissive_surfaces = 0;
|
||||
}
|
||||
|
||||
void VK_LightsLoad( void ) {
|
||||
parseStaticLightEntities();
|
||||
initPVL();
|
||||
|
||||
// FIXME ...
|
||||
initHackRadTable();
|
||||
}
|
||||
|
||||
void VK_LightsBakePVL( int frame_number ) {
|
||||
static void bakeLights( void ) {
|
||||
const model_t *map = gEngine.pfnGetModelByIndex( 1 );
|
||||
const world_static_t *world = gEngine.GetWorld();
|
||||
|
||||
|
@ -476,6 +474,8 @@ void VK_LightsBakePVL( int frame_number ) {
|
|||
ASSERT(surface_index >= 0);
|
||||
ASSERT(surface_index < map->numsurfaces);
|
||||
|
||||
g_lights.surfaces[surface_index].leaf = leaf->cluster;
|
||||
|
||||
// TODO entity transformation
|
||||
// TODO ^^^ we need to bake it per-entity probably
|
||||
|
||||
|
@ -574,5 +574,14 @@ void VK_LightsBakePVL( int frame_number ) {
|
|||
|
||||
Mem_Free(surface_to_emissive_surface_map);
|
||||
Mem_Free(eigenlicht);
|
||||
g_lights.frame_number = frame_number;
|
||||
}
|
||||
|
||||
void VK_LightsLoadMap( void ) {
|
||||
parseStaticLightEntities();
|
||||
initPVL();
|
||||
|
||||
// FIXME ...
|
||||
initHackRadTable();
|
||||
|
||||
bakeLights();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ typedef struct {
|
|||
|
||||
extern vk_emissive_texture_table_t g_emissive_texture_table[MAX_TEXTURES];
|
||||
|
||||
void VK_LightsLoad( void );
|
||||
void VK_LightsLoadMap( void );
|
||||
|
||||
typedef struct {
|
||||
uint8_t num_dlights;
|
||||
|
@ -30,18 +30,19 @@ typedef struct {
|
|||
} vk_emissive_surface_t;
|
||||
|
||||
typedef struct {
|
||||
int frame_number;
|
||||
|
||||
// TODO make this opaque light clusters
|
||||
int num_leaves; // same as worldmodel->numleaves
|
||||
vk_light_leaf_t *leaves;
|
||||
|
||||
int num_emissive_surfaces;
|
||||
vk_emissive_surface_t emissive_surfaces[256]; // indexed by uint8_t
|
||||
|
||||
int num_surfaces;
|
||||
struct {
|
||||
int leaf;
|
||||
} *surfaces;
|
||||
} vk_potentially_visible_lights_t;
|
||||
|
||||
extern vk_potentially_visible_lights_t g_lights;
|
||||
|
||||
void VK_LightsBakePVL( int frame_number );
|
||||
|
||||
void VK_LightsShutdown( void );
|
||||
|
|
|
@ -74,6 +74,7 @@ typedef struct {
|
|||
uint32_t element_count;
|
||||
uint32_t index_offset, vertex_offset;
|
||||
uint32_t vertex_count;
|
||||
int leaf, surface_index;
|
||||
// TODO potentially dynamic int light_cluster;
|
||||
} vk_render_geometry_t;
|
||||
|
||||
|
|
102
ref_vk/vk_rtx.c
102
ref_vk/vk_rtx.c
|
@ -18,7 +18,8 @@
|
|||
#define MAX_KUSOCHKI 8192
|
||||
#define MAX_SCRATCH_BUFFER (16*1024*1024)
|
||||
#define MAX_ACCELS_BUFFER (64*1024*1024)
|
||||
#define MAX_LIGHT_TEXTURES 256
|
||||
#define MAX_EMISSIVE_KUSOCHKI 256
|
||||
#define MAX_LIGHT_LEAVES 8192
|
||||
|
||||
// TODO settings/realtime modifiable/adaptive
|
||||
#define FRAME_WIDTH 1280
|
||||
|
@ -40,20 +41,24 @@ typedef struct {
|
|||
uint32_t index_offset;
|
||||
uint32_t vertex_offset;
|
||||
uint32_t triangles;
|
||||
//uint32_t leaf;
|
||||
uint32_t leaf;
|
||||
uint32_t num_dlights;
|
||||
uint32_t num_surface_lights;
|
||||
uint32_t emissive;
|
||||
//float sad_padding_[1];
|
||||
//vec4_t emissive;
|
||||
} vk_kusok_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t num_lighttextures;
|
||||
uint32_t num_kusochki;
|
||||
uint32_t padding__[3];
|
||||
struct {
|
||||
// TODO should we move emissive here?
|
||||
uint32_t kusok_index;
|
||||
uint32_t padding__[3];
|
||||
} lighttexture[MAX_LIGHT_TEXTURES];
|
||||
} vk_lighttexture_data_t;
|
||||
vec3_t emissive_color;
|
||||
uint32_t padding___;
|
||||
} kusochki[MAX_EMISSIVE_KUSOCHKI];
|
||||
} vk_emissive_kusochki_t;
|
||||
|
||||
typedef struct {
|
||||
matrix3x4 transform_row;
|
||||
|
@ -64,6 +69,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
float t;
|
||||
int bounces;
|
||||
float prev_frame_blend_factor;
|
||||
} vk_rtx_push_constants_t;
|
||||
|
||||
static struct {
|
||||
|
@ -82,7 +88,8 @@ static struct {
|
|||
vk_buffer_t kusochki_buffer;
|
||||
|
||||
// TODO this should really be a single uniform buffer for matrices and light data
|
||||
vk_buffer_t lighttextures_buffer;
|
||||
vk_buffer_t emissive_kusochki_buffer;
|
||||
vk_buffer_t light_leaves_buffer;
|
||||
|
||||
VkAccelerationStructureKHR tlas;
|
||||
|
||||
|
@ -205,6 +212,22 @@ void VK_RayNewMap( void ) {
|
|||
|
||||
g_rtx.map.buffer_offset = 0;
|
||||
g_rtx.map.num_kusochki = 0;
|
||||
|
||||
// Upload light leaves
|
||||
ASSERT(g_lights.num_leaves <= MAX_LIGHT_LEAVES);
|
||||
memcpy(g_rtx.light_leaves_buffer.mapped, g_lights.leaves, g_lights.num_leaves * sizeof(vk_light_leaf_t));
|
||||
|
||||
// Upload emissive kusochki
|
||||
{
|
||||
vk_emissive_kusochki_t *ek = g_rtx.emissive_kusochki_buffer.mapped;
|
||||
ASSERT(g_lights.num_emissive_surfaces <= MAX_EMISSIVE_KUSOCHKI);
|
||||
memset(ek, 0, sizeof(*ek));
|
||||
ek->num_kusochki = g_lights.num_emissive_surfaces;
|
||||
// for (int i = 0; i < g_lights.num_emissive_surfaces; ++i) {
|
||||
// VectorCopy(g_lights.emissive_surfaces[i].emissive, ek->kusochki[i].emissive_color);
|
||||
// ek->kusochki[i].kusok_index = g_lights.emissive_surfaces[i].surface_index;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
void VK_RayFrameBegin( void )
|
||||
|
@ -447,8 +470,13 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
|
|||
.offset = args->dlights.offset,
|
||||
.range = args->dlights.size,
|
||||
};
|
||||
const VkDescriptorBufferInfo dbi_lighttextures = {
|
||||
.buffer = g_rtx.lighttextures_buffer.buffer,
|
||||
const VkDescriptorBufferInfo dbi_emissive_kusochki = {
|
||||
.buffer = g_rtx.emissive_kusochki_buffer.buffer,
|
||||
.offset = 0,
|
||||
.range = VK_WHOLE_SIZE,
|
||||
};
|
||||
const VkDescriptorBufferInfo dbi_light_leaves = {
|
||||
.buffer = g_rtx.light_leaves_buffer.buffer,
|
||||
.offset = 0,
|
||||
.range = VK_WHOLE_SIZE,
|
||||
};
|
||||
|
@ -523,7 +551,7 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
|
|||
.dstSet = g_rtx.desc_set,
|
||||
.dstBinding = 7,
|
||||
.dstArrayElement = 0,
|
||||
.pBufferInfo = &dbi_lighttextures,
|
||||
.pBufferInfo = &dbi_emissive_kusochki,
|
||||
},
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
|
@ -534,6 +562,15 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
|
|||
.dstArrayElement = 0,
|
||||
.pImageInfo = &dii_src,
|
||||
},
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.dstSet = g_rtx.desc_set,
|
||||
.dstBinding = 9,
|
||||
.dstArrayElement = 0,
|
||||
.pBufferInfo = &dbi_light_leaves,
|
||||
},
|
||||
};
|
||||
|
||||
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
|
||||
|
@ -575,6 +612,7 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
|
|||
vk_rtx_push_constants_t push_constants = {
|
||||
.t = gpGlobals->realtime,
|
||||
.bounces = vk_rtx_bounces->value,
|
||||
.prev_frame_blend_factor = vk_rtx_prev_frame_blend_factor->value,
|
||||
};
|
||||
vkCmdPushConstants(cmdbuf, g_rtx.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(push_constants), &push_constants);
|
||||
}
|
||||
|
@ -685,6 +723,11 @@ static void createLayouts( void ) {
|
|||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
}, {
|
||||
.binding = 9,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -710,7 +753,7 @@ static void createLayouts( void ) {
|
|||
{
|
||||
VkDescriptorPoolSize pools[] = {
|
||||
{.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .descriptorCount = 2},
|
||||
{.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 3},
|
||||
{.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 4},
|
||||
{.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = 3},
|
||||
{.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, .descriptorCount = 1},
|
||||
};
|
||||
|
@ -772,14 +815,20 @@ qboolean VK_RayInit( void )
|
|||
// FIXME complain, handle
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!createBuffer(&g_rtx.lighttextures_buffer, sizeof(vk_lighttexture_data_t),
|
||||
if (!createBuffer(&g_rtx.emissive_kusochki_buffer, sizeof(vk_emissive_kusochki_t),
|
||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT /* | VK_BUFFER_USAGE_TRANSFER_DST_BIT */,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
|
||||
// FIXME complain, handle
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!createBuffer(&g_rtx.light_leaves_buffer, sizeof(vk_light_leaf_t) * MAX_LIGHT_LEAVES,
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT /* | VK_BUFFER_USAGE_TRANSFER_DST_BIT */,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
|
||||
// FIXME complain, handle
|
||||
return false;
|
||||
}
|
||||
|
||||
createLayouts();
|
||||
createPipeline();
|
||||
|
||||
|
@ -855,7 +904,8 @@ void VK_RayShutdown( void )
|
|||
destroyBuffer(&g_rtx.accels_buffer);
|
||||
destroyBuffer(&g_rtx.tlas_geom_buffer);
|
||||
destroyBuffer(&g_rtx.kusochki_buffer);
|
||||
destroyBuffer(&g_rtx.lighttextures_buffer);
|
||||
destroyBuffer(&g_rtx.emissive_kusochki_buffer);
|
||||
destroyBuffer(&g_rtx.light_leaves_buffer);
|
||||
}
|
||||
|
||||
qboolean VK_RayModelInit( vk_ray_model_init_t args ) {
|
||||
|
@ -915,6 +965,30 @@ qboolean VK_RayModelInit( vk_ray_model_init_t args ) {
|
|||
kusochki[i].vertex_offset = vertex_offset;
|
||||
kusochki[i].index_offset = index_offset;
|
||||
kusochki[i].triangles = prim_count;
|
||||
kusochki[i].leaf = mg->leaf;
|
||||
kusochki[i].emissive = ((mg->texture >= 0 && mg->texture < MAX_TEXTURES)
|
||||
? g_emissive_texture_table[mg->texture].set
|
||||
: 0);
|
||||
|
||||
if (mg->leaf >= 0 && mg->leaf < g_lights.num_leaves)
|
||||
{
|
||||
const vk_light_leaf_t* leaflight = g_lights.leaves + mg->leaf;
|
||||
kusochki[i].num_dlights = leaflight->num_dlights;
|
||||
kusochki[i].num_surface_lights = leaflight->num_slights;
|
||||
} else {
|
||||
kusochki[i].num_dlights = kusochki[i].num_surface_lights = 0;
|
||||
}
|
||||
|
||||
if (kusochki[i].emissive && mg->surface_index >= 0) {
|
||||
vk_emissive_kusochki_t *ek = g_rtx.emissive_kusochki_buffer.mapped;
|
||||
for (int j = 0; j < g_lights.num_emissive_surfaces; ++j) {
|
||||
if (mg->surface_index == g_lights.emissive_surfaces[j].surface_index) {
|
||||
VectorCopy(g_lights.emissive_surfaces[j].emissive, ek->kusochki[j].emissive_color);
|
||||
ek->kusochki[j].kusok_index = i + args.model->rtx.kusochki_offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "vk_global.h"
|
||||
#include "vk_beams.h"
|
||||
#include "vk_light.h"
|
||||
#include "vk_rtx.h"
|
||||
|
||||
#include "com_strings.h"
|
||||
#include "ref_params.h"
|
||||
|
@ -100,6 +101,8 @@ void R_NewMap( void )
|
|||
// This is to ensure that we have computed lightstyles properly
|
||||
VK_RunLightStyles();
|
||||
|
||||
VK_LightsLoadMap();
|
||||
|
||||
// TODO should we do something like VK_BrushBeginLoad?
|
||||
VK_BrushStatsClear();
|
||||
|
||||
|
@ -109,7 +112,8 @@ void R_NewMap( void )
|
|||
// This leads to ASSERTS firing when trying to draw erased buffers.
|
||||
VK_RenderBufferClearMap();
|
||||
|
||||
VK_LightsLoad();
|
||||
if (vk_core.rtx)
|
||||
VK_RayNewMap();
|
||||
|
||||
// Load all models at once
|
||||
gEngine.Con_Reportf( "Num models: %d:\n", num_models );
|
||||
|
|
Loading…
Reference in New Issue