rtx: add static light entities

This was an attempt to add map lighting w/o lightmaps. Unfortunately
there are just not enought of them to explain all light in maps. We're
missing something else. A lot of it.
This commit is contained in:
Ivan 'provod' Avdeev 2021-03-13 16:33:17 -08:00
parent a04b367a32
commit 379f6ee409
5 changed files with 142 additions and 8 deletions

View File

@ -3,9 +3,9 @@
- [x] rtx: (debug/dev) shader reload
- [x] rtx: make projection matrix independent render global/current/static state
- [x] rtx: model matrices
- [x] rtx: light entities -- still not enough to enlight maps :(
# Next
- [ ] rtx: light entities
- [ ] rtx: path tracing
- [ ] rtx: textures
- [ ] rtx: add fps
@ -15,6 +15,8 @@
- [ ] rtx: some studio models have glitchy geometry
# Planned
- [ ] rtx: lower resolution framebuffer + upscale
- [ ] dlight for flashlight seems to be broken
- [ ] restore render debug labels
- [ ] make 2nd commad buffer for resource upload
- [ ] fix sprite blending; there are commented out functions that we really need (see tunnel before the helicopter in the very beginning)

View File

@ -102,7 +102,8 @@ void main() {
const vec4 light_pos_r = lights[i].pos_r;
const vec3 light_color = lights[i].color.rgb;
rand01_state += fract((light_pos_r.x + light_pos_r.y + light_pos_r.z)/100.);
rand01_state = fract((pos.x + pos.y + pos.z)/100.) + uv.x + uv.y + fract(pc.t) + i;
//rand01_state += fract(fract(pc.t) + i + (light_pos_r.x + light_pos_r.y + light_pos_r.z)/1000.);
// Find random point on a sphere
// TODO proper BRDF importance sampling and correct random point distribution

View File

@ -55,6 +55,11 @@ static struct {
vk_buffer_alloc_t allocs[MAX_ALLOCS];
int allocs_free[MAX_ALLOCS];
int num_free_allocs;
struct {
vec3_t origin, color;
} static_lights[32];
int num_static_lights;
} g_render;
static qboolean createPipelines( void )
@ -405,7 +410,8 @@ void VK_RenderBufferClearFrame( void )
if (alloc->lifetime != LifetimeSingleFrame)
continue;
alloc->unit_size = 0;
alloc->unit_size = 0;
g_render.allocs_free[g_render.num_free_allocs++] = i;
ASSERT(g_render.num_free_allocs <= MAX_ALLOCS);
}
@ -416,6 +422,7 @@ void VK_RenderBufferClearMap( void )
{
g_render.buffer_free_offset = g_render.buffer_frame_begin_offset = 0;
g_render.stat.align_holes_size = 0;
g_render.num_static_lights = 0;
resetAllocFreeList();
}
@ -588,10 +595,21 @@ void VK_RenderScheduleDraw( const render_draw_t *draw )
Matrix3x4_Copy(draw_command->transform, g_render_state.model);
}
void VK_RenderAddStaticLight(vec3_t origin, vec3_t color)
{
if (g_render.num_static_lights == ARRAYSIZE(g_render.static_lights))
return;
VectorCopy(origin, g_render.static_lights[g_render.num_static_lights].origin);
VectorCopy(color, g_render.static_lights[g_render.num_static_lights].color);
g_render.num_static_lights++;
}
// Return offset of dlights data into UBO buffer
static uint32_t writeDlightsToUBO()
{
vk_ubo_lights_t* ubo_lights;
int num_lights = 0;
const uint32_t ubo_lights_offset = allocUniform(sizeof(*ubo_lights), 4);
if (ubo_lights_offset == UINT32_MAX) {
gEngine.Con_Printf(S_ERROR "Cannot allocate UBO for DLights\n");
@ -599,27 +617,45 @@ static uint32_t writeDlightsToUBO()
}
ubo_lights = (vk_ubo_lights_t*)((byte*)(g_render.uniform_buffer.mapped) + ubo_lights_offset);
for (int i = 0; i < g_render.num_static_lights && num_lights < ARRAYSIZE(ubo_lights->light); ++i) {
Vector4Set(
ubo_lights->light[num_lights].color,
g_render.static_lights[i].color[0],
g_render.static_lights[i].color[1],
g_render.static_lights[i].color[2],
1.f);
Vector4Set(
ubo_lights->light[num_lights].pos_r,
g_render.static_lights[i].origin[0],
g_render.static_lights[i].origin[1],
g_render.static_lights[i].origin[2],
50.f /* FIXME WHAT */);
num_lights++;
}
// TODO this should not be here (where? vk_scene?)
ubo_lights->num_lights = 0;
for (int i = 0; i < MAX_DLIGHTS; ++i) {
for (int i = 0; i < MAX_DLIGHTS && num_lights < ARRAYSIZE(ubo_lights->light); ++i) {
const dlight_t *l = gEngine.GetDynamicLight(i);
if( !l || l->die < gpGlobals->time || !l->radius )
continue;
Vector4Set(
ubo_lights->light[ubo_lights->num_lights].color,
ubo_lights->light[num_lights].color,
l->color.r / 255.f,
l->color.g / 255.f,
l->color.b / 255.f,
1.f);
Vector4Set(
ubo_lights->light[ubo_lights->num_lights].pos_r,
ubo_lights->light[num_lights].pos_r,
l->origin[0],
l->origin[1],
l->origin[2],
l->radius);
ubo_lights->num_lights++;
num_lights++;
}
ubo_lights->num_lights = num_lights;
return ubo_lights_offset;
}

View File

@ -48,6 +48,9 @@ void VK_RenderStateSetMatrixProjection(const matrix4x4 proj);
void VK_RenderStateSetMatrixView(const matrix4x4 view);
void VK_RenderStateSetMatrixModel(const matrix4x4 model);
// TODO: radius, intensity, style, PVS bits, etc..
void VK_RenderAddStaticLight(vec3_t origin, vec3_t color);
// TODO is this a good place?
typedef struct vk_vertex_s {
// TODO padding needed for storage buffer reading, figure out how to fix in GLSL/SPV side

View File

@ -79,6 +79,96 @@ int R_FIXME_GetEntityRenderMode( cl_entity_t *ent )
return ent->curstate.rendermode;
}
static void parseLights( void ) {
const model_t* const world = gEngine.pfnGetModelByIndex( 1 );
char *pos;
enum {
Unknown,
Light, LightSpot,
} classname = Unknown;
struct {
vec3_t origin;
vec3_t color;
//float radius;
int style;
} light = {0};
enum {
HaveOrigin = 1,
HaveColor = 2,
//HaveStyle = 4,
HaveClass = 8,
HaveAll = HaveOrigin | HaveColor | HaveClass,
};
unsigned int have = 0;
ASSERT(world);
pos = world->entities;
for (;;) {
string key, value;
pos = gEngine.COM_ParseFile(pos, key);
if (!pos)
break;
if (key[0] == '{') {
classname = Unknown;
have = 0;
continue;
}
if (key[0] == '}') {
// TODO handle entity
if (have != HaveAll)
continue;
if (classname != Light && classname != LightSpot)
continue;
VK_RenderAddStaticLight(light.origin, light.color);
continue;
}
pos = gEngine.COM_ParseFile(pos, value);
if (!pos)
break;
if (Q_strcmp(key, "origin") == 0) {
const int components = sscanf(value, "%f %f %f",
&light.origin[0],
&light.origin[1],
&light.origin[2]);
if (components == 3)
have |= HaveOrigin;
} else
if (Q_strcmp(key, "_light") == 0) {
float scale = 1.f / 255.f;
const int components = sscanf(value, "%f %f %f %f",
&light.color[0],
&light.color[1],
&light.color[2],
&scale);
if (components == 1) {
light.color[2] = light.color[1] = light.color[0] = light.color[0] / 255.f;
have |= HaveColor;
} else if (components == 4) {
scale /= 255.f * 255.f;
light.color[0] *= scale;
light.color[1] *= scale;
light.color[2] *= scale;
have |= HaveColor;
} else if (components == 3) {
light.color[0] *= scale;
light.color[1] *= scale;
light.color[2] *= scale;
have |= HaveColor;
}
} else if (Q_strcmp(key, "classname") == 0) {
if (Q_strcmp(value, "light") == 0)
classname = Light;
else if (Q_strcmp(value, "light_spot") == 0)
classname = LightSpot;
have |= HaveClass;
}
}
}
// tell the renderer what new map is started
void R_NewMap( void )
{
@ -100,6 +190,8 @@ void R_NewMap( void )
// This leads to ASSERTS firing when trying to draw erased buffers.
VK_RenderBufferClearMap();
parseLights();
// Load all models at once
gEngine.Con_Reportf( "Num models: %d:\n", num_models );
for( int i = 0; i < num_models; i++ )