rt: stub better emissive surfaces representation path

Light polygons that are:
- self-sufficient (no kusochki indirection needed).
- pre-transformed
- contain enough metadata (area, center, normal) for quick sampling
- are polygons with up to 7 vertices and not triangles (easier sampling)

Also move rad file reading to before brush model loading, as it now
requires lighting data.
This commit is contained in:
Ivan Avdeev 2022-01-13 22:36:21 -08:00
parent e4ade833e8
commit b31462fe18
5 changed files with 122 additions and 21 deletions

View File

@ -438,6 +438,63 @@ static model_sizes_t computeSizes( const model_t *mod ) {
return sizes;
}
static void loadEmissiveSurface(const model_t *mod, const int surface_index, const msurface_t *surf, const vec3_t emissive) {
rt_light_polygon_t lpoly;
lpoly.num_vertices = Q_min(7, surf->numedges);
if (surf->numedges > 7)
gEngine.Con_Printf(S_WARN "emissive surface %d has %d vertices; clipping to 7\n", surface_index, surf->numedges);
VectorCopy(emissive, lpoly.emissive);
VectorSet(lpoly.center, 0, 0, 0);
VectorSet(lpoly.normal, 0, 0, 0);
for (int i = 0; i < lpoly.num_vertices; ++i) {
const int iedge = mod->surfedges[surf->firstedge + i];
const medge_t *edge = mod->edges + (iedge >= 0 ? iedge : -iedge);
const mvertex_t *vertex = mod->vertexes + (iedge >= 0 ? edge->v[0] : edge->v[1]);
VectorCopy(vertex->position, lpoly.vertices[i]);
VectorAdd(vertex->position, lpoly.center, lpoly.center);
if (i > 1) {
vec3_t e[2], normal;
VectorSubtract(lpoly.vertices[i-1], lpoly.vertices[i-2], e[0]);
VectorSubtract(lpoly.vertices[i-0], lpoly.vertices[i-2], e[1]);
CrossProduct(e[0], e[1], normal);
VectorAdd(normal, lpoly.normal, lpoly.normal);
}
}
VectorM(1.f / lpoly.num_vertices, lpoly.center, lpoly.center);
lpoly.area = VectorLength(lpoly.normal);
VectorNormalize(lpoly.normal);
{
const float dot = DotProduct(lpoly.normal, surf->plane->normal);
if (fabs(dot) < (1.f - 1e-5f)) {
gEngine.Con_Reportf(S_WARN "surf=%d normal=(%f, %f, %f) computed=(%f, %f, %f) dot=%f dir=%d\n",
surf->plane->normal[0],
surf->plane->normal[1],
surf->plane->normal[2],
lpoly.normal[0],
lpoly.normal[1],
lpoly.normal[2],
dot,
!!FBitSet( surf->flags, SURF_PLANEBACK )
);
}
}
if( FBitSet( surf->flags, SURF_PLANEBACK ))
VectorNegate( surf->plane->normal, lpoly.normal );
else
VectorCopy( surf->plane->normal, lpoly.normal );
RT_LightAddPolygon(&lpoly);
}
static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
vk_brush_model_t *bmodel = mod->cache.data;
uint32_t vertex_offset = 0;
@ -460,6 +517,7 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
index_offset = index_buffer.buffer.unit.offset;
// Load sorted by gl_texturenum
// TODO this does not make that much sense in vulkan (can sort later)
for (int t = 0; t <= sizes.max_texture_id; ++t)
{
for( int i = 0; i < mod->nummodelsurfaces; ++i)
@ -480,6 +538,15 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
if (t != tex_id)
continue;
{
vec3_t emissive;
if (psurf && (psurf->flags & Patch_Surface_Emissive)) {
loadEmissiveSurface(mod, surface_index, surf, psurf->emissive);
} else if (RT_GetEmissiveForTexture(emissive, tex_id)) {
loadEmissiveSurface(mod, surface_index, surf, emissive);
}
}
++num_geometries;
//gEngine.Con_Reportf( "surface %d: numverts=%d numedges=%d\n", i, surf->polys ? surf->polys->numverts : -1, surf->numedges );

View File

@ -489,6 +489,20 @@ void VK_LightsNewMap( void ) {
clusterBitMapInit();
prepareSurfacesLeafVisibilityCache();
// Load RAD data based on map name
memset(g_lights.map.emissive_textures, 0, sizeof(g_lights.map.emissive_textures));
loadRadData( map, "maps/lights.rad" );
{
int name_len = Q_strlen(map->name);
// Strip ".bsp" suffix
if (name_len > 4 && 0 == Q_stricmp(map->name + name_len - 4, ".bsp"))
name_len -= 4;
loadRadData( map, "%.*s.rad", name_len, map->name );
}
}
void VK_LightsFrameInit( void ) {
@ -1019,20 +1033,6 @@ void VK_LightsLoadMapStaticLights( void ) {
processStaticPointLights();
// Load RAD data based on map name
memset(g_lights.map.emissive_textures, 0, sizeof(g_lights.map.emissive_textures));
loadRadData( map, "maps/lights.rad" );
{
int name_len = Q_strlen(map->name);
// Strip ".bsp" suffix
if (name_len > 4 && 0 == Q_stricmp(map->name + name_len - 4, ".bsp"))
name_len -= 4;
loadRadData( map, "%.*s.rad", name_len, map->name );
}
// Load static map model
{
matrix3x4 xform;
@ -1060,7 +1060,7 @@ void VK_LightsLoadMapStaticLights( void ) {
}
}
void XVK_GetEmissiveForTexture( vec3_t out, int texture_id ) {
qboolean RT_GetEmissiveForTexture( vec3_t out, int texture_id ) {
ASSERT(texture_id >= 0);
ASSERT(texture_id < MAX_TEXTURES);
@ -1068,8 +1068,9 @@ void XVK_GetEmissiveForTexture( vec3_t out, int texture_id ) {
vk_emissive_texture_t *const etex = g_lights.map.emissive_textures + texture_id;
if (etex->set) {
VectorCopy(etex->emissive, out);
return true;
} else {
VectorSet(out, 0, 0, 0);
return false;
}
}
}
@ -1158,3 +1159,18 @@ void VK_LightsFrameFinalize( void ) {
debug_dump_lights.enabled = false;
APROF_SCOPE_END(finalize);
}
int RT_LightAddPolygon(const rt_light_polygon_t *lpoly) {
gEngine.Con_Reportf("RT_LightAddPolygon center=(%f, %f, %f) normal=(%f, %f, %f) area=%f num_vertices=%d\n",
lpoly->center[0],
lpoly->center[1],
lpoly->center[2],
lpoly->normal[0],
lpoly->normal[1],
lpoly->normal[2],
lpoly->area,
lpoly->num_vertices
);
return -1;
}

View File

@ -30,6 +30,16 @@ typedef struct {
matrix3x4 transform;
} vk_emissive_surface_t;
typedef struct {
vec3_t emissive;
vec3_t normal;
vec3_t center;
float area;
int num_vertices;
vec3_t vertices[7];
// uint32_t kusok_index;
} rt_light_polygon_t;
enum {
LightFlag_Environment = 0x1,
};
@ -57,9 +67,14 @@ typedef struct {
vk_emissive_texture_t emissive_textures[MAX_TEXTURES];
} map;
// FIXME deprecate
int num_emissive_surfaces;
vk_emissive_surface_t emissive_surfaces[MAX_SURFACE_LIGHTS];
int num_light_polygons;
rt_light_polygon_t light_polygons[MAX_SURFACE_LIGHTS];
int num_point_lights;
vk_point_light_t point_lights[MAX_POINT_LIGHTS];
@ -87,7 +102,9 @@ void VK_LightsFrameInit( void );
// separately in emissive surfaces.
struct vk_render_geometry_s;
void VK_LightsAddEmissiveSurface( const struct vk_render_geometry_s *geom, const matrix3x4 *transform_row, qboolean static_map );
void XVK_GetEmissiveForTexture( vec3_t out, int texture_id );
qboolean RT_GetEmissiveForTexture( vec3_t out, int texture_id );
int RT_LightAddPolygon(const rt_light_polygon_t *light);
void VK_LightsFrameFinalize( void );

View File

@ -400,7 +400,7 @@ void VK_RayFrameAddModel( vk_ray_model_t *model, const vk_render_model_t *render
if (geom->material == kXVkMaterialEmissive) {
VectorCopy( geom->emissive, kusok->emissive );
} else {
XVK_GetEmissiveForTexture( kusok->emissive, geom->texture );
RT_GetEmissiveForTexture( kusok->emissive, geom->texture );
}
if (geom->material == kXVkMaterialConveyor) {

View File

@ -142,8 +142,6 @@ void R_NewMap( void )
// This is to ensure that we have computed lightstyles properly
VK_RunLightStyles();
VK_LightsNewMap();
XVK_SetupSky( gEngine.pfnGetMoveVars()->skyName );
if (vk_core.rtx)
@ -167,9 +165,12 @@ void R_NewMap( void )
XVK_ReloadMaterials();
// Parse patch data
// Depens on loaded materials. Must preceed loading brush models.
// Depends on loaded materials. Must preceed loading brush models.
XVK_ParseMapPatches();
// Need parsed map entities, and also should happen before brush model loading
VK_LightsNewMap();
// Load all models at once
gEngine.Con_Reportf( "Num models: %d:\n", num_models );
for( int i = 0; i < num_models; i++ )