mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-21 03:01:15 +00:00
[scene] Put lights into the bsp tree via efrags
This eliminates the O(N^2) (N = map leaf count) operation of finding visible lights and will later allow for finer culling of the lights as they can be tested against the leaf volume (which they currently are not as this was just getting things going). However, this has severely hurt ad_tears' performance (I suspect due to the extreme number of leafs), but the speed seems to be very steady. Hopefully, reconstructing the vis clusters will help (I imagine it will help in many places, not just lights).
This commit is contained in:
parent
c0f8d102ad
commit
72f6048a20
9 changed files with 110 additions and 120 deletions
|
@ -369,6 +369,8 @@ typedef enum {
|
|||
mod_alias,
|
||||
mod_iqm,
|
||||
|
||||
mod_light,
|
||||
|
||||
mod_num_types
|
||||
} modtype_t;
|
||||
|
||||
|
|
|
@ -150,6 +150,8 @@ Entity_Transform (entity_t ent)
|
|||
}
|
||||
|
||||
struct mod_brush_s;
|
||||
efrag_t **R_LinkEfrag (struct mleaf_s *leaf, entity_t ent, uint32_t queue,
|
||||
efrag_t **lastlink);
|
||||
void R_AddEfrags (struct mod_brush_s *, entity_t ent);
|
||||
void R_ShutdownEfrags (void);
|
||||
void R_ClearEfragChain (efrag_t *ef);
|
||||
|
|
|
@ -53,15 +53,7 @@ typedef struct light_s {
|
|||
vec4f_t attenuation;
|
||||
} light_t;
|
||||
|
||||
typedef struct lightset_s DARRAY_TYPE (light_t) lightset_t;
|
||||
typedef struct lightleafset_s DARRAY_TYPE (int) lightintset_t;
|
||||
typedef struct lightvisset_s DARRAY_TYPE (byte) lightvisset_t;
|
||||
|
||||
typedef struct lightingdata_s {
|
||||
lightset_t lights;
|
||||
lightintset_t lightstyles;
|
||||
lightintset_t lightleafs;
|
||||
lightvisset_t lightvis;
|
||||
struct set_s *sun_pvs;
|
||||
// A fat PVS of leafs visible from visible leafs so hidden lights can
|
||||
// illuminate the leafs visible to the player
|
||||
|
@ -75,6 +67,5 @@ void Light_DestroyLightingData (lightingdata_t *ldata);
|
|||
void Light_ClearLights (lightingdata_t *ldata);
|
||||
void Light_AddLight (lightingdata_t *ldata, const light_t *light, int style);
|
||||
void Light_EnableSun (lightingdata_t *ldata);
|
||||
void Light_FindVisibleLights (lightingdata_t *ldata);
|
||||
|
||||
#endif//__QF_scene_light_h
|
||||
|
|
|
@ -49,6 +49,10 @@ enum scene_components {
|
|||
scene_old_origin, //XXX FIXME XXX should not be here
|
||||
scene_colormap,
|
||||
|
||||
scene_light,
|
||||
scene_efrags,
|
||||
scene_lightstyle,
|
||||
|
||||
//FIXME these should probably be private to the sw renderer (and in a
|
||||
//group, which needs to be implemented), but need to sort out a good
|
||||
//scheme for semi-dynamic components
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "QF/plist.h"
|
||||
#include "QF/progs.h" //for ED_ConvertToPlist
|
||||
#include "QF/set.h"
|
||||
#include "QF/ecs.h"
|
||||
#include "QF/scene/entity.h"
|
||||
#include "QF/scene/light.h"
|
||||
#include "QF/scene/scene.h"
|
||||
#include "QF/simd/vec4f.h"
|
||||
|
@ -17,8 +19,12 @@
|
|||
#include "client/world.h"
|
||||
|
||||
static void
|
||||
dump_light (light_t *light, int leaf)
|
||||
dump_light (light_t *light, efrag_t *efrags)
|
||||
{
|
||||
int leafcount = 0;
|
||||
for (auto e = efrags; e; e = e->leafnext) {
|
||||
leafcount++;
|
||||
}
|
||||
Sys_MaskPrintf (SYS_lighting,
|
||||
"[%g, %g, %g] %g, "
|
||||
"[%g, %g, %g, %g], [%g %g %g] %g, [%g, %g, %g, %g] %d\n",
|
||||
|
@ -26,7 +32,7 @@ dump_light (light_t *light, int leaf)
|
|||
VEC4_EXP (light->position),
|
||||
VEC4_EXP (light->direction),
|
||||
VEC4_EXP (light->attenuation),
|
||||
leaf);
|
||||
leafcount);
|
||||
}
|
||||
|
||||
static float
|
||||
|
@ -323,8 +329,12 @@ CL_LoadLights (plitem_t *entities, scene_t *scene)
|
|||
}
|
||||
PL_Release (targets);
|
||||
|
||||
for (size_t i = 0; i < ldata->lights.size; i++) {
|
||||
dump_light (&ldata->lights.a[i], ldata->lightleafs.a[i]);
|
||||
auto lights = &scene->reg->comp_pools[scene_light];
|
||||
auto lefrags = &scene->reg->comp_pools[scene_efrags];
|
||||
for (uint32_t i = 0; i < lights->count; i++) {
|
||||
auto light = &((light_t *)lights->data)[i];
|
||||
auto efrags = ((efrag_t **)lefrags->data)[i];
|
||||
dump_light (light, efrags);
|
||||
}
|
||||
Sys_MaskPrintf (SYS_lighting, "loaded %zd lights\n", ldata->lights.size);
|
||||
Sys_MaskPrintf (SYS_lighting, "loaded %d lights\n", lights->count);
|
||||
}
|
||||
|
|
|
@ -130,11 +130,28 @@ R_ClearEfragChain (efrag_t *ef)
|
|||
}
|
||||
}
|
||||
|
||||
efrag_t **
|
||||
R_LinkEfrag (mleaf_t *leaf, entity_t ent, uint32_t queue, efrag_t **lastlink)
|
||||
{
|
||||
efrag_t *ef = new_efrag (); // ensures ef->entnext is 0
|
||||
|
||||
// add the link to the chain of links on the entity
|
||||
ef->entity = ent;
|
||||
ef->queue_num = queue;
|
||||
*lastlink = ef;
|
||||
|
||||
// add the link too the chain of links on the leaf
|
||||
ef->leaf = leaf;
|
||||
ef->leafnext = leaf->efrags;
|
||||
leaf->efrags = ef;
|
||||
|
||||
return &ef->entnext;
|
||||
}
|
||||
|
||||
static void
|
||||
R_SplitEntityOnNode (mod_brush_t *brush, entity_t ent, uint32_t queue,
|
||||
visibility_t *visibility, vec3_t emins, vec3_t emaxs)
|
||||
{
|
||||
efrag_t *ef;
|
||||
plane_t *splitplane;
|
||||
mleaf_t *leaf;
|
||||
int sides;
|
||||
|
@ -159,18 +176,7 @@ R_SplitEntityOnNode (mod_brush_t *brush, entity_t ent, uint32_t queue,
|
|||
|
||||
leaf = brush->leafs + ~node_id;
|
||||
|
||||
ef = new_efrag (); // ensures ef->entnext is 0
|
||||
|
||||
// add the link to the chain of links on the entity
|
||||
ef->entity = ent;
|
||||
ef->queue_num = queue;
|
||||
*lastlink = ef;
|
||||
lastlink = &ef->entnext;
|
||||
|
||||
// add the link too the chain of links on the leaf
|
||||
ef->leaf = leaf;
|
||||
ef->leafnext = leaf->efrags;
|
||||
leaf->efrags = ef;
|
||||
lastlink = R_LinkEfrag (leaf, ent, queue, lastlink);
|
||||
|
||||
node_id = *--node_ptr;
|
||||
} else {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "QF/model.h"
|
||||
#include "QF/set.h"
|
||||
#include "QF/scene/entity.h"
|
||||
#include "QF/scene/light.h"
|
||||
#include "QF/scene/scene.h"
|
||||
#include "QF/simd/vec4f.h"
|
||||
|
@ -27,11 +28,6 @@ Light_CreateLightingData (scene_t *scene)
|
|||
{
|
||||
lightingdata_t *ldata = calloc (1, sizeof (lightingdata_t));
|
||||
|
||||
DARRAY_INIT (&ldata->lights, 16);
|
||||
DARRAY_INIT (&ldata->lightstyles, 16);
|
||||
DARRAY_INIT (&ldata->lightleafs, 16);
|
||||
DARRAY_INIT (&ldata->lightvis, 16);
|
||||
|
||||
ldata->scene = scene;
|
||||
|
||||
return ldata;
|
||||
|
@ -40,21 +36,12 @@ Light_CreateLightingData (scene_t *scene)
|
|||
void
|
||||
Light_DestroyLightingData (lightingdata_t *ldata)
|
||||
{
|
||||
DARRAY_CLEAR (&ldata->lights);
|
||||
DARRAY_CLEAR (&ldata->lightstyles);
|
||||
DARRAY_CLEAR (&ldata->lightleafs);
|
||||
DARRAY_CLEAR (&ldata->lightvis);
|
||||
|
||||
free (ldata);
|
||||
}
|
||||
|
||||
void
|
||||
Light_ClearLights (lightingdata_t *ldata)
|
||||
{
|
||||
ldata->lights.size = 0;
|
||||
ldata->lightstyles.size = 0;
|
||||
ldata->lightleafs.size = 0;
|
||||
ldata->lightvis.size = 0;
|
||||
if (ldata->sun_pvs) {
|
||||
set_delete (ldata->sun_pvs);
|
||||
}
|
||||
|
@ -72,20 +59,34 @@ Light_AddLight (lightingdata_t *ldata, const light_t *light, int style)
|
|||
scene_t *scene = ldata->scene;
|
||||
model_t *model = scene->worldmodel;
|
||||
|
||||
DARRAY_APPEND (&ldata->lights, *light);
|
||||
DARRAY_APPEND (&ldata->lightstyles, style);
|
||||
entity_t ent = {
|
||||
.reg = scene->reg,
|
||||
.id = ECS_NewEntity (scene->reg),
|
||||
};
|
||||
|
||||
int visleaf = -1; // directional light
|
||||
Ent_SetComponent (ent.id, scene_light, ent.reg, light);
|
||||
Ent_SetComponent (ent.id, scene_lightstyle, ent.reg, &style);
|
||||
|
||||
set_t _pvs = SET_STATIC_INIT (model->brush.visleafs, alloca);
|
||||
set_t *pvs = &_pvs;
|
||||
if (light->position[3]) {
|
||||
// positional light
|
||||
mleaf_t *leaf = Mod_PointInLeaf (light->position, &model->brush);
|
||||
visleaf = leaf - model->brush.leafs - 1;
|
||||
} else if (!DotProduct (light->direction, light->direction)) {
|
||||
Mod_LeafPVS_set (leaf, &model->brush, 0, pvs);
|
||||
} else if (DotProduct (light->direction, light->direction)) {
|
||||
// directional light (sun)
|
||||
pvs = ldata->sun_pvs;
|
||||
} else {
|
||||
// ambient light
|
||||
visleaf = -2;
|
||||
Mod_LeafPVS_set (model->brush.leafs, &model->brush, 0, pvs);
|
||||
}
|
||||
DARRAY_APPEND (&ldata->lightleafs, visleaf);
|
||||
DARRAY_APPEND (&ldata->lightvis, 0);
|
||||
efrag_t *efrags = 0;
|
||||
efrag_t **lastlink = &efrags;
|
||||
for (auto li = set_first (pvs); li; li = set_next (li)) {
|
||||
mleaf_t *leaf = model->brush.leafs + li->element + 1;
|
||||
lastlink = R_LinkEfrag (leaf, ent, mod_light, lastlink);
|
||||
}
|
||||
Ent_SetComponent (ent.id, scene_efrags, ent.reg, &efrags);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -111,52 +112,3 @@ Light_EnableSun (lightingdata_t *ldata)
|
|||
// can receive shadows from the sun
|
||||
expand_pvs (ldata->sun_pvs, brush);
|
||||
}
|
||||
|
||||
void
|
||||
Light_FindVisibleLights (lightingdata_t *ldata)
|
||||
{
|
||||
scene_t *scene = ldata->scene;
|
||||
mleaf_t *leaf = scene->viewleaf;
|
||||
auto brush = &scene->worldmodel->brush;
|
||||
|
||||
if (!leaf) {
|
||||
return;
|
||||
}
|
||||
if (!ldata->pvs) {
|
||||
ldata->pvs = set_new_size (brush->visleafs);
|
||||
}
|
||||
|
||||
if (leaf != ldata->leaf) {
|
||||
//double start = Sys_DoubleTime ();
|
||||
int flags = 0;
|
||||
|
||||
if (leaf == brush->leafs) {
|
||||
set_everything (ldata->pvs);
|
||||
flags = SURF_DRAWSKY;
|
||||
} else {
|
||||
Mod_LeafPVS_set (leaf, brush, 0, ldata->pvs);
|
||||
if (set_is_intersecting (ldata->pvs, ldata->sun_pvs)) {
|
||||
flags |= SURF_DRAWSKY;
|
||||
}
|
||||
expand_pvs (ldata->pvs, brush);
|
||||
}
|
||||
ldata->leaf = leaf;
|
||||
|
||||
//double end = Sys_DoubleTime ();
|
||||
//Sys_Printf ("find_visible_lights: %.5gus\n", (end - start) * 1e6);
|
||||
|
||||
int visible = 0;
|
||||
memset (ldata->lightvis.a, 0, ldata->lightvis.size * sizeof (byte));
|
||||
for (size_t i = 0; i < ldata->lightleafs.size; i++) {
|
||||
int l = ldata->lightleafs.a[i];
|
||||
if ((l == -2) || (l == -1 && (flags & SURF_DRAWSKY))
|
||||
|| set_is_member (ldata->pvs, l)) {
|
||||
ldata->lightvis.a[i] = 1;
|
||||
visible++;
|
||||
}
|
||||
}
|
||||
Sys_MaskPrintf (SYS_lighting,
|
||||
"find_visible_lights: %d / %zd visible\n", visible,
|
||||
ldata->lightvis.size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,9 @@
|
|||
#include "QF/model.h"
|
||||
|
||||
#include "QF/plugin/vid_render.h"
|
||||
|
||||
#include "QF/scene/entity.h"
|
||||
#include "QF/scene/light.h"
|
||||
#include "QF/scene/scene.h"
|
||||
#include "QF/scene/transform.h"
|
||||
|
||||
|
@ -83,6 +85,13 @@ destroy_renderer (void *_renderer)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_efrags (void *_efrags)
|
||||
{
|
||||
efrag_t **efrags = _efrags;
|
||||
R_ClearEfragChain (*efrags);
|
||||
}
|
||||
|
||||
static void
|
||||
sw_identity_matrix (void *_mat)
|
||||
{
|
||||
|
@ -144,6 +153,20 @@ static const component_t scene_components[scene_comp_count] = {
|
|||
.name = "colormap",
|
||||
},
|
||||
|
||||
[scene_light] = {
|
||||
.size = sizeof (light_t),
|
||||
.name = "light",
|
||||
},
|
||||
[scene_efrags] = {
|
||||
.size = sizeof (efrag_t *),
|
||||
.destroy = destroy_efrags,
|
||||
.name = "efrags",
|
||||
},
|
||||
[scene_lightstyle] = {
|
||||
.size = sizeof (int),
|
||||
.name = "lightstyle",
|
||||
},
|
||||
|
||||
[scene_sw_matrix] = {
|
||||
.size = sizeof (mat4f_t),
|
||||
.create = sw_identity_matrix,
|
||||
|
|
|
@ -183,10 +183,6 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
|
|||
return;
|
||||
}
|
||||
|
||||
lightingdata_t *ldata = lctx->ldata;
|
||||
|
||||
Light_FindVisibleLights (ldata);
|
||||
|
||||
dlight_t *lights[MaxLights];
|
||||
auto packet = QFV_PacketAcquire (ctx->staging);
|
||||
qfv_light_buffer_t *light_data = QFV_PacketExtend (packet,
|
||||
|
@ -220,23 +216,26 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
|
|||
// full sphere, normal light (not ambient)
|
||||
light_data->lights[i].direction = (vec4f_t) { 0, 0, 1, 1 };
|
||||
}
|
||||
for (size_t i = 0; (i < ldata->lightvis.size
|
||||
&& light_data->lightCount < MaxLights); i++) {
|
||||
if (ldata->lightvis.a[i]) {
|
||||
uint32_t id = light_data->lightCount++;
|
||||
auto light = &light_data->lights[id];
|
||||
*light = ldata->lights.a[i];
|
||||
light->color[3] *= style_intensities[ldata->lightstyles.a[i]];
|
||||
if (light->position[3] && !VectorIsZero (light->direction)
|
||||
&& light->attenuation[3]) {
|
||||
if (light->direction[3] < 0) {
|
||||
cone_ids[lframe->cone_count++] = id;
|
||||
} else {
|
||||
ico_ids[lframe->ico_count++] = id;
|
||||
}
|
||||
auto queue = r_ent_queue; //FIXME fetch from scene
|
||||
for (size_t i = 0; i < queue->ent_queues[mod_light].size; i++) {
|
||||
entity_t ent = queue->ent_queues[mod_light].a[i];
|
||||
light_t *l = Ent_GetComponent (ent.id, scene_light, ent.reg);
|
||||
int ls = *(int *) Ent_GetComponent (ent.id, scene_lightstyle,
|
||||
ent.reg);
|
||||
|
||||
uint32_t id = light_data->lightCount++;
|
||||
auto light = &light_data->lights[id];
|
||||
*light = *l;
|
||||
light->color[3] *= style_intensities[ls];
|
||||
if (light->position[3] && !VectorIsZero (light->direction)
|
||||
&& light->attenuation[3]) {
|
||||
if (light->direction[3] < 0) {
|
||||
cone_ids[lframe->cone_count++] = id;
|
||||
} else {
|
||||
flat_ids[lframe->flat_count++] = id;
|
||||
ico_ids[lframe->ico_count++] = id;
|
||||
}
|
||||
} else {
|
||||
flat_ids[lframe->flat_count++] = id;
|
||||
}
|
||||
}
|
||||
if (developer & SYS_lighting) {
|
||||
|
@ -700,7 +699,7 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx)
|
|||
free (lctx->frames.a);
|
||||
free (lctx);
|
||||
}
|
||||
|
||||
/*
|
||||
static vec4f_t ref_direction = { 0, 0, 1, 0 };
|
||||
|
||||
static void
|
||||
|
@ -1026,7 +1025,7 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
|
|||
totalLayers, lctx->light_images.size,
|
||||
lctx->shadow_resources->size);
|
||||
}
|
||||
|
||||
*/
|
||||
void
|
||||
Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx)
|
||||
{
|
||||
|
@ -1034,11 +1033,12 @@ Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx)
|
|||
|
||||
lctx->scene = scene;
|
||||
lctx->ldata = scene ? scene->lights : 0;
|
||||
|
||||
/*
|
||||
clear_shadows (ctx);
|
||||
|
||||
if (lctx->ldata && lctx->ldata->lights.size) {
|
||||
build_shadow_maps (lctx, ctx);
|
||||
create_light_matrices (lctx);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue