mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-23 04:42:32 +00:00
[vulkan] Implement real-time lighting
Light styles and shadows aren't implemented yet. The map's entities are used to create the lights, and the PVS used to determine which lights might be visible (ie, the surfaces they light). That could do with some more improvements (eg, checking if a leaf is outside a spotlight's cone), but the concept seems to work.
This commit is contained in:
parent
e0eacf4014
commit
bab3e0720f
5 changed files with 104 additions and 13 deletions
|
@ -46,8 +46,10 @@ typedef struct qfv_light_s {
|
||||||
} qfv_light_t;
|
} qfv_light_t;
|
||||||
|
|
||||||
typedef struct qfv_lightset_s DARRAY_TYPE (qfv_light_t) qfv_lightset_t;
|
typedef struct qfv_lightset_s DARRAY_TYPE (qfv_light_t) qfv_lightset_t;
|
||||||
|
typedef struct qfv_lightleafset_s DARRAY_TYPE (int) qfv_lightleafset_t;
|
||||||
|
typedef struct qfv_lightvisset_s DARRAY_TYPE (byte) qfv_lightvisset_t;
|
||||||
|
|
||||||
#define NUM_LIGHTS 128
|
#define NUM_LIGHTS 256
|
||||||
|
|
||||||
typedef struct qfv_light_buffer_s {
|
typedef struct qfv_light_buffer_s {
|
||||||
int lightCount;
|
int lightCount;
|
||||||
|
@ -64,6 +66,11 @@ typedef struct lightingframe_s {
|
||||||
VkDescriptorImageInfo imageInfo[LIGHTING_IMAGE_INFOS];
|
VkDescriptorImageInfo imageInfo[LIGHTING_IMAGE_INFOS];
|
||||||
VkWriteDescriptorSet descriptors[LIGHTING_BUFFER_INFOS
|
VkWriteDescriptorSet descriptors[LIGHTING_BUFFER_INFOS
|
||||||
+ LIGHTING_IMAGE_INFOS];
|
+ LIGHTING_IMAGE_INFOS];
|
||||||
|
// A fat PVS of leafs visible from visible leafs so hidden lights can
|
||||||
|
// illuminate the leafs visible to the player
|
||||||
|
byte pvs[MAP_PVS_BYTES];
|
||||||
|
struct mleaf_s *leaf; // the last leaf used to generate the pvs
|
||||||
|
qfv_lightleafset_t lightvis;
|
||||||
} lightingframe_t;
|
} lightingframe_t;
|
||||||
|
|
||||||
typedef struct lightingframeset_s
|
typedef struct lightingframeset_s
|
||||||
|
@ -75,6 +82,7 @@ typedef struct lightingctx_s {
|
||||||
VkPipelineLayout layout;
|
VkPipelineLayout layout;
|
||||||
VkDeviceMemory light_memory;
|
VkDeviceMemory light_memory;
|
||||||
qfv_lightset_t lights;
|
qfv_lightset_t lights;
|
||||||
|
qfv_lightleafset_t lightleafs;
|
||||||
} lightingctx_t;
|
} lightingctx_t;
|
||||||
|
|
||||||
struct vulkan_ctx_s;
|
struct vulkan_ctx_s;
|
||||||
|
@ -82,6 +90,7 @@ struct vulkan_ctx_s;
|
||||||
void Vulkan_Lighting_Init (struct vulkan_ctx_s *ctx);
|
void Vulkan_Lighting_Init (struct vulkan_ctx_s *ctx);
|
||||||
void Vulkan_Lighting_Shutdown (struct vulkan_ctx_s *ctx);
|
void Vulkan_Lighting_Shutdown (struct vulkan_ctx_s *ctx);
|
||||||
void Vulkan_Lighting_Draw (struct vulkan_ctx_s *ctx);
|
void Vulkan_Lighting_Draw (struct vulkan_ctx_s *ctx);
|
||||||
void Vulkan_LoadLights (const char *entity_data, struct vulkan_ctx_s *ctx);
|
void Vulkan_LoadLights (model_t *model, const char *entity_data,
|
||||||
|
struct vulkan_ctx_s *ctx);
|
||||||
|
|
||||||
#endif//__QF_Vulkan_qf_lighting_h
|
#endif//__QF_Vulkan_qf_lighting_h
|
||||||
|
|
|
@ -856,6 +856,12 @@
|
||||||
stage = fragment;
|
stage = fragment;
|
||||||
name = main;
|
name = main;
|
||||||
module = $builtin/lighting.frag;
|
module = $builtin/lighting.frag;
|
||||||
|
specializationInfo = {
|
||||||
|
mapEntries = (
|
||||||
|
{ size = 4; offset = 0; constantID = 0; },
|
||||||
|
);
|
||||||
|
data = <00000100>;
|
||||||
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
vertexInput = {
|
vertexInput = {
|
||||||
|
|
|
@ -26,15 +26,15 @@ vec3
|
||||||
calc_light (LightData light, vec3 position, vec3 normal)
|
calc_light (LightData light, vec3 position, vec3 normal)
|
||||||
{
|
{
|
||||||
vec3 dist = light.position - position;
|
vec3 dist = light.position - position;
|
||||||
vec3 incoming = normalize (dist);
|
|
||||||
float spotdot = -dot (incoming, light.direction);
|
|
||||||
float lightdot = dot (incoming, normal);
|
|
||||||
float d = sqrt (dot (dist, dist));
|
float d = sqrt (dot (dist, dist));
|
||||||
|
vec3 incoming = dist / d;
|
||||||
|
float spotdot = dot (incoming, light.direction);
|
||||||
|
float lightdot = dot (incoming, normal);
|
||||||
float r = light.radius;
|
float r = light.radius;
|
||||||
|
|
||||||
float intensity = light.intensity * step (d, r);
|
float intensity = light.intensity * step (d, r);
|
||||||
intensity *= step (spotdot, light.cone) * clamp (lightdot, 0, 1);
|
intensity *= step (spotdot, light.cone) * clamp (lightdot, 0, 1);
|
||||||
return light.color * intensity * (r - d);
|
return light.color * intensity * (r - d) / 255.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -44,7 +44,7 @@ main (void)
|
||||||
vec3 c = subpassLoad (color).rgb;
|
vec3 c = subpassLoad (color).rgb;
|
||||||
vec3 n = subpassLoad (normal).rgb;
|
vec3 n = subpassLoad (normal).rgb;
|
||||||
vec3 p = subpassLoad (position).rgb;
|
vec3 p = subpassLoad (position).rgb;
|
||||||
vec3 light = vec3 (0.8);
|
vec3 light = vec3 (0);
|
||||||
|
|
||||||
if (MaxLights > 0) {
|
if (MaxLights > 0) {
|
||||||
for (int i = 0; i < lightCount; i++) {
|
for (int i = 0; i < lightCount; i++) {
|
||||||
|
|
|
@ -61,6 +61,51 @@
|
||||||
#include "r_internal.h"
|
#include "r_internal.h"
|
||||||
#include "vid_vulkan.h"
|
#include "vid_vulkan.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
find_visible_lights (vulkan_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
//qfv_device_t *device = ctx->device;
|
||||||
|
//qfv_devfuncs_t *dfunc = device->funcs;
|
||||||
|
lightingctx_t *lctx = ctx->lighting_context;
|
||||||
|
lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame];
|
||||||
|
|
||||||
|
mleaf_t *leaf = r_viewleaf;
|
||||||
|
model_t *model = r_worldentity.renderer.model;
|
||||||
|
|
||||||
|
if (!leaf || !model) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leaf != lframe->leaf) {
|
||||||
|
double start = Sys_DoubleTime ();
|
||||||
|
byte pvs[MAP_PVS_BYTES];
|
||||||
|
|
||||||
|
Mod_LeafPVS_set (leaf, model, 0, pvs);
|
||||||
|
memcpy (lframe->pvs, pvs, sizeof (pvs));
|
||||||
|
for (int i = 0; i < model->brush.numleafs; i++) {
|
||||||
|
if (pvs[i / 8] & (1 << (i % 8))) {
|
||||||
|
Mod_LeafPVS_mix (model->brush.leafs + i, model, 0, lframe->pvs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lframe->leaf = leaf;
|
||||||
|
|
||||||
|
double end = Sys_DoubleTime ();
|
||||||
|
Sys_Printf ("find_visible_lights: %.5gus\n", (end - start) * 1e6);
|
||||||
|
|
||||||
|
int visible = 0;
|
||||||
|
memset (lframe->lightvis.a, 0, lframe->lightvis.size * sizeof (byte));
|
||||||
|
for (size_t i = 0; i < lctx->lightleafs.size; i++) {
|
||||||
|
int l = lctx->lightleafs.a[i];
|
||||||
|
if (lframe->pvs[l / 8] & (1 << (l % 8))) {
|
||||||
|
lframe->lightvis.a[i] = 1;
|
||||||
|
visible++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Sys_Printf ("find_visible_lights: %d / %zd visible\n", visible,
|
||||||
|
lframe->lightvis.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_lights (vulkan_ctx_t *ctx)
|
update_lights (vulkan_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
|
@ -69,6 +114,8 @@ update_lights (vulkan_ctx_t *ctx)
|
||||||
lightingctx_t *lctx = ctx->lighting_context;
|
lightingctx_t *lctx = ctx->lighting_context;
|
||||||
lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame];
|
lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame];
|
||||||
|
|
||||||
|
find_visible_lights (ctx);
|
||||||
|
|
||||||
dlight_t *lights[NUM_LIGHTS];
|
dlight_t *lights[NUM_LIGHTS];
|
||||||
qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging);
|
qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging);
|
||||||
qfv_light_buffer_t *light_data = QFV_PacketExtend (packet,
|
qfv_light_buffer_t *light_data = QFV_PacketExtend (packet,
|
||||||
|
@ -88,6 +135,12 @@ update_lights (vulkan_ctx_t *ctx)
|
||||||
VectorZero (light_data->lights[i].direction);
|
VectorZero (light_data->lights[i].direction);
|
||||||
light_data->lights[i].cone = 1;
|
light_data->lights[i].cone = 1;
|
||||||
}
|
}
|
||||||
|
for (size_t i = 0;
|
||||||
|
i < lframe->lightvis.size && light_data->lightCount < NUM_LIGHTS; i++) {
|
||||||
|
if (lframe->lightvis.a[i]) {
|
||||||
|
light_data->lights[light_data->lightCount++] = lctx->lights.a[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VkBufferMemoryBarrier wr_barriers[] = {
|
VkBufferMemoryBarrier wr_barriers[] = {
|
||||||
{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
|
{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
|
||||||
|
@ -208,6 +261,7 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
|
||||||
ctx->lighting_context = lctx;
|
ctx->lighting_context = lctx;
|
||||||
|
|
||||||
DARRAY_INIT (&lctx->lights, 16);
|
DARRAY_INIT (&lctx->lights, 16);
|
||||||
|
DARRAY_INIT (&lctx->lightleafs, 16);
|
||||||
|
|
||||||
size_t frames = ctx->frames.size;
|
size_t frames = ctx->frames.size;
|
||||||
DARRAY_INIT (&lctx->frames, frames);
|
DARRAY_INIT (&lctx->frames, frames);
|
||||||
|
@ -258,6 +312,8 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
|
||||||
for (size_t i = 0; i < frames; i++) {
|
for (size_t i = 0; i < frames; i++) {
|
||||||
__auto_type lframe = &lctx->frames.a[i];
|
__auto_type lframe = &lctx->frames.a[i];
|
||||||
|
|
||||||
|
DARRAY_INIT (&lframe->lightvis, 16);
|
||||||
|
|
||||||
QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet);
|
QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet);
|
||||||
lframe->cmd = cmdSet->a[0];
|
lframe->cmd = cmdSet->a[0];
|
||||||
|
|
||||||
|
@ -298,10 +354,12 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx)
|
||||||
for (size_t i = 0; i < lctx->frames.size; i++) {
|
for (size_t i = 0; i < lctx->frames.size; i++) {
|
||||||
lightingframe_t *lframe = &lctx->frames.a[i];
|
lightingframe_t *lframe = &lctx->frames.a[i];
|
||||||
dfunc->vkDestroyBuffer (device->dev, lframe->light_buffer, 0);
|
dfunc->vkDestroyBuffer (device->dev, lframe->light_buffer, 0);
|
||||||
|
DARRAY_CLEAR (&lframe->lightvis);
|
||||||
}
|
}
|
||||||
dfunc->vkFreeMemory (device->dev, lctx->light_memory, 0);
|
dfunc->vkFreeMemory (device->dev, lctx->light_memory, 0);
|
||||||
dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0);
|
dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0);
|
||||||
DARRAY_CLEAR (&lctx->lights);
|
DARRAY_CLEAR (&lctx->lights);
|
||||||
|
DARRAY_CLEAR (&lctx->lightleafs);
|
||||||
free (lctx->frames.a);
|
free (lctx->frames.a);
|
||||||
free (lctx);
|
free (lctx);
|
||||||
}
|
}
|
||||||
|
@ -312,6 +370,14 @@ parse_light (qfv_light_t *light, const plitem_t *entity,
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
|
|
||||||
|
Sys_Printf ("{\n");
|
||||||
|
for (int i = PL_D_NumKeys (entity); i-- > 0; ) {
|
||||||
|
const char *field = PL_KeyAtIndex (entity, i);
|
||||||
|
const char *value = PL_String (PL_ObjectForKey (entity, field));
|
||||||
|
Sys_Printf ("\t%s = %s\n", field, value);
|
||||||
|
}
|
||||||
|
Sys_Printf ("}\n");
|
||||||
|
|
||||||
if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) {
|
if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) {
|
||||||
sscanf (str, "%f %f %f", VectorExpandAddr (light->position));
|
sscanf (str, "%f %f %f", VectorExpandAddr (light->position));
|
||||||
}
|
}
|
||||||
|
@ -336,7 +402,7 @@ parse_light (qfv_light_t *light, const plitem_t *entity,
|
||||||
}
|
}
|
||||||
|
|
||||||
light->intensity = 1;
|
light->intensity = 1;
|
||||||
if ((str = PL_String (PL_ObjectForKey (entity, "light")))
|
if ((str = PL_String (PL_ObjectForKey (entity, "light_lev")))
|
||||||
|| (str = PL_String (PL_ObjectForKey (entity, "_light")))) {
|
|| (str = PL_String (PL_ObjectForKey (entity, "_light")))) {
|
||||||
light->radius = atof (str);
|
light->radius = atof (str);
|
||||||
}
|
}
|
||||||
|
@ -345,12 +411,13 @@ parse_light (qfv_light_t *light, const plitem_t *entity,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Vulkan_LoadLights (const char *entity_data, vulkan_ctx_t *ctx)
|
Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
lightingctx_t *lctx = ctx->lighting_context;
|
lightingctx_t *lctx = ctx->lighting_context;
|
||||||
plitem_t *entities = 0;
|
plitem_t *entities = 0;
|
||||||
|
|
||||||
lctx->lights.size = 0;
|
lctx->lights.size = 0;
|
||||||
|
lctx->lightleafs.size = 0;
|
||||||
|
|
||||||
script_t *script = Script_New ();
|
script_t *script = Script_New ();
|
||||||
Script_Start (script, "ent data", entity_data);
|
Script_Start (script, "ent data", entity_data);
|
||||||
|
@ -389,13 +456,22 @@ Vulkan_LoadLights (const char *entity_data, vulkan_ctx_t *ctx)
|
||||||
qfv_light_t light = {};
|
qfv_light_t light = {};
|
||||||
|
|
||||||
parse_light (&light, entity, targets);
|
parse_light (&light, entity, targets);
|
||||||
printf ("[%g, %g, %g] %g, [%g %g %g] %g, [%g %g %g] %g\n",
|
DARRAY_APPEND (&lctx->lights, light);
|
||||||
|
mleaf_t *leaf = Mod_PointInLeaf (&light.position[0],
|
||||||
|
model);
|
||||||
|
DARRAY_APPEND (&lctx->lightleafs, leaf - model->brush.leafs);
|
||||||
|
printf ("[%g, %g, %g] %g, [%g %g %g] %g, [%g %g %g] %g, %zd\n",
|
||||||
VectorExpand (light.color), light.intensity,
|
VectorExpand (light.color), light.intensity,
|
||||||
VectorExpand (light.position), light.radius,
|
VectorExpand (light.position), light.radius,
|
||||||
VectorExpand (light.direction), light.cone);
|
VectorExpand (light.direction), light.cone,
|
||||||
DARRAY_APPEND (&lctx->lights, light);
|
leaf - model->brush.leafs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
printf ("%zd frames\n", ctx->frames.size);
|
||||||
|
for (size_t i = 0; i < ctx->frames.size; i++) {
|
||||||
|
lightingframe_t *lframe = &lctx->frames.a[i];
|
||||||
|
DARRAY_RESIZE (&lframe->lightvis, lctx->lights.size);
|
||||||
|
}
|
||||||
// targets does not own the objects, so need to remove them before
|
// targets does not own the objects, so need to remove them before
|
||||||
// freeing targets
|
// freeing targets
|
||||||
for (int i = PL_D_NumKeys (targets); i-- > 0; ) {
|
for (int i = PL_D_NumKeys (targets); i-- > 0; ) {
|
||||||
|
|
|
@ -216,7 +216,7 @@ Vulkan_NewMap (model_t *worldmodel, struct model_s **models, int num_models,
|
||||||
Vulkan_RegisterTextures (models, num_models, ctx);
|
Vulkan_RegisterTextures (models, num_models, ctx);
|
||||||
Vulkan_BuildLightmaps (models, num_models, ctx);
|
Vulkan_BuildLightmaps (models, num_models, ctx);
|
||||||
Vulkan_BuildDisplayLists (models, num_models, ctx);
|
Vulkan_BuildDisplayLists (models, num_models, ctx);
|
||||||
Vulkan_LoadLights (worldmodel->brush.entities, ctx);
|
Vulkan_LoadLights (worldmodel, worldmodel->brush.entities, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*void
|
/*void
|
||||||
|
|
Loading…
Reference in a new issue