mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-29 23:52:22 +00:00
[vulkan] Rework lighting model to be more algebraic
This leaves only the one conditional in the shader code, that being the distance check. It doesn't seem to make any noticeable difference to performance, but other than explosion sprites being blue, lighting quality seems to have improved. However, I really need to get shadows working: marcher is just silly-bright without them, and light levels changing as I move around is a bit disconcerting (but reasonable as those lights' leaf nodes go in and out of visibility).
This commit is contained in:
parent
e1f4df27c3
commit
e323fbbbed
3 changed files with 192 additions and 200 deletions
|
@ -39,12 +39,10 @@
|
|||
#include "QF/simd/types.h"
|
||||
|
||||
typedef struct qfv_light_s {
|
||||
vec3_t color;
|
||||
int data;
|
||||
vec3_t position;
|
||||
float light;
|
||||
vec3_t direction;
|
||||
float cone;
|
||||
vec4f_t color;
|
||||
vec4f_t position;
|
||||
vec4f_t direction;
|
||||
vec4f_t attenuation;
|
||||
} qfv_light_t;
|
||||
|
||||
typedef struct qfv_lightset_s DARRAY_TYPE (qfv_light_t) qfv_lightset_t;
|
||||
|
@ -54,32 +52,25 @@ typedef struct qfv_lightmatset_s DARRAY_TYPE (mat4f_t) qfv_lightmatset_t;
|
|||
|
||||
#define MaxLights 256
|
||||
|
||||
#define StyleMask 0x07f
|
||||
#define ModelMask 0x380
|
||||
#define ShadowMask 0xc00
|
||||
#define LM_LINEAR 0 // light - dist (or radius + dist if -ve)
|
||||
#define LM_INVERSE 1 // distFactor1 * light / dist
|
||||
#define LM_INVERSE2 2 // distFactor2 * light / (dist * dist)
|
||||
#define LM_INFINITE 3 // light
|
||||
#define LM_AMBIENT 4 // light
|
||||
#define LM_INVERSE3 5 // distFactor2 * light / (dist + distFactor2)**2
|
||||
|
||||
#define LM_LINEAR (0 << 7) // light - dist (or radius + dist if -ve)
|
||||
#define LM_INVERSE (1 << 7) // distFactor1 * light / dist
|
||||
#define LM_INVERSE2 (2 << 7) // distFactor2 * light / (dist * dist)
|
||||
#define LM_INFINITE (3 << 7) // light
|
||||
#define LM_AMBIENT (4 << 7) // light
|
||||
#define LM_INVERSE3 (5 << 7) // distFactor2 * light / (dist + distFactor2)**2
|
||||
|
||||
#define ST_NONE (0 << 10) // no shadows
|
||||
#define ST_PLANE (1 << 10) // single plane shadow map (small spotlight)
|
||||
#define ST_CASCADE (2 << 10) // cascaded shadow maps
|
||||
#define ST_CUBE (3 << 10) // cubemap (omni, large spotlight)
|
||||
#define ST_NONE 0 // no shadows
|
||||
#define ST_PLANE 1 // single plane shadow map (small spotlight)
|
||||
#define ST_CASCADE 2 // cascaded shadow maps
|
||||
#define ST_CUBE 3 // cubemap (omni, large spotlight)
|
||||
|
||||
#define NumStyles 64
|
||||
|
||||
typedef struct qfv_light_buffer_s {
|
||||
float intensity[NumStyles + 4];
|
||||
float distFactor1;
|
||||
float distFactor2;
|
||||
int lightCount;
|
||||
qfv_light_t lights[MaxLights] __attribute__((aligned(16)));
|
||||
mat4f_t shadowMat[MaxLights];
|
||||
vec4f_t shadowCascade[MaxLights];
|
||||
int lightCount;
|
||||
//mat4f_t shadowMat[MaxLights];
|
||||
//vec4f_t shadowCascade[MaxLights];
|
||||
} qfv_light_buffer_t;
|
||||
|
||||
#define LIGHTING_BUFFER_INFOS 1
|
||||
|
@ -119,6 +110,7 @@ typedef struct lightingctx_s {
|
|||
VkDeviceMemory light_memory;
|
||||
VkDeviceMemory shadow_memory;
|
||||
qfv_lightset_t lights;
|
||||
qfv_lightintset_t lightstyles;
|
||||
qfv_lightintset_t lightleafs;
|
||||
qfv_lightmatset_t lightmats;
|
||||
qfv_imageset_t lightimages;
|
||||
|
|
|
@ -7,12 +7,10 @@ layout (input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput n
|
|||
layout (input_attachment_index = 4, set = 0, binding = 4) uniform subpassInput position;
|
||||
|
||||
struct LightData {
|
||||
vec3 color;
|
||||
int data;// bits 0-6: intensity key (however, values 0-66)
|
||||
vec3 position;
|
||||
float light; // doubles as radius for linear
|
||||
vec3 direction;
|
||||
float cone;
|
||||
vec4 color; // .a is intensity
|
||||
vec4 position; // .w = 0 -> directional, .w = 1 -> point/cone
|
||||
vec4 direction; // .w = -cos(cone_angle/2) (1 for omni/dir)
|
||||
vec4 attenuation;
|
||||
};
|
||||
|
||||
#define StyleMask 0x07f
|
||||
|
@ -38,13 +36,10 @@ layout (set = 2, binding = 0) uniform sampler2DShadow shadowPlane[MaxLights];
|
|||
layout (set = 2, binding = 0) uniform samplerCubeShadow shadowCube[MaxLights];
|
||||
|
||||
layout (set = 1, binding = 0) uniform Lights {
|
||||
vec4 intensity[17]; // 68 floats
|
||||
float distFactor1; // for inverse
|
||||
float distFactor2; // for inverse2 and inverse3
|
||||
int lightCount;
|
||||
LightData lights[MaxLights];
|
||||
mat4 shadowMat[MaxLights];
|
||||
vec4 shadowCascale[MaxLights];
|
||||
int lightCount;
|
||||
//mat4 shadowMat[MaxLights];
|
||||
//vec4 shadowCascale[MaxLights];
|
||||
};
|
||||
|
||||
layout (location = 0) out vec4 frag_color;
|
||||
|
@ -52,8 +47,10 @@ layout (location = 0) out vec4 frag_color;
|
|||
float
|
||||
spot_cone (LightData light, vec3 incoming)
|
||||
{
|
||||
float spotdot = dot (incoming, light.direction);
|
||||
return smoothstep (spotdot, 1 - (1 - spotdot) * 0.995, light.cone);
|
||||
vec3 dir = light.direction.xyz;
|
||||
float cone = light.direction.w;
|
||||
float spotdot = dot (incoming, dir);
|
||||
return 1 - smoothstep (cone, cone + 0.02, spotdot);
|
||||
}
|
||||
|
||||
float
|
||||
|
@ -63,50 +60,6 @@ diffuse (vec3 incoming, vec3 normal)
|
|||
return clamp (lightdot, 0, 1);
|
||||
}
|
||||
|
||||
float
|
||||
light_linear (LightData light, float d)
|
||||
{
|
||||
float l = light.light;
|
||||
if (l < 0) {
|
||||
return min (l + d, 0);
|
||||
} else {
|
||||
return max (l - d, 0);
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
light_inverse (LightData light, float d)
|
||||
{
|
||||
float l = light.light;
|
||||
return l / (distFactor1 * d);
|
||||
}
|
||||
|
||||
float
|
||||
light_inverse2 (LightData light, float d)
|
||||
{
|
||||
float l = light.light;
|
||||
return l / (distFactor2 * d);
|
||||
}
|
||||
|
||||
float
|
||||
light_infinite (LightData light)
|
||||
{
|
||||
return light.light;
|
||||
}
|
||||
|
||||
float
|
||||
light_ambient (LightData light)
|
||||
{
|
||||
return light.light;
|
||||
}
|
||||
|
||||
float
|
||||
light_inverse3 (LightData light, float d)
|
||||
{
|
||||
float l = light.light;
|
||||
return l / (distFactor2 * d + 1);
|
||||
}
|
||||
|
||||
float
|
||||
shadow_cascade (sampler2DArrayShadow map)
|
||||
{
|
||||
|
@ -138,55 +91,31 @@ main (void)
|
|||
if (MaxLights > 0) {
|
||||
vec3 minLight = vec3 (0);
|
||||
for (int i = 0; i < lightCount; i++) {
|
||||
vec3 dist = lights[i].position - p;
|
||||
float d = dot (dist, dist);
|
||||
int model = lights[i].data & ModelMask;
|
||||
LightData l = lights[i];
|
||||
vec3 dir = l.position.xyz - l.position.w * p;
|
||||
float r2 = dot (dir, dir);
|
||||
vec4 a = l.attenuation;
|
||||
|
||||
if (model != LM_INFINITE
|
||||
&& d > lights[i].light * lights[i].light) {
|
||||
if (l.position.w * a.w * a.w * r2 >= 1) {
|
||||
continue;
|
||||
}
|
||||
vec4 r = vec4 (r2, sqrt(r2), 1, 0);
|
||||
vec3 incoming = dir / r.y;
|
||||
float I = (1 - a.w * r.y) / dot (a, r);
|
||||
|
||||
float l = 0;
|
||||
if (model == LM_LINEAR) {
|
||||
d = sqrt (d);
|
||||
l = light_linear (lights[i], d);
|
||||
} else if (model == LM_INVERSE) {
|
||||
d = sqrt (d);
|
||||
l = light_inverse (lights[i], d);
|
||||
} else if (model == LM_INVERSE2) {
|
||||
l = light_inverse2 (lights[i], d);
|
||||
d = sqrt (d);
|
||||
} else if (model == LM_INFINITE) {
|
||||
l = light_infinite (lights[i]);
|
||||
dist = lights[i].direction;
|
||||
d = -1;
|
||||
} else if (model == LM_AMBIENT) {
|
||||
l = light_ambient (lights[i]);
|
||||
} else if (model == LM_INVERSE3) {
|
||||
l = light_inverse3 (lights[i], d);
|
||||
d = sqrt (d);
|
||||
}
|
||||
|
||||
int style = lights[i].data & StyleMask;
|
||||
l *= intensity[style / 4][style % 4];
|
||||
|
||||
int shadow = lights[i].data & ShadowMask;
|
||||
/*int shadow = lights[i].data & ShadowMask;
|
||||
if (shadow == ST_CASCADE) {
|
||||
l *= shadow_cascade (shadowCascade[i]);
|
||||
I *= shadow_cascade (shadowCascade[i]);
|
||||
} else if (shadow == ST_PLANE) {
|
||||
l *= shadow_plane (shadowPlane[i]);
|
||||
I *= shadow_plane (shadowPlane[i]);
|
||||
} else if (shadow == ST_CUBE) {
|
||||
l *= shadow_cube (shadowCube[i]);
|
||||
}
|
||||
I *= shadow_cube (shadowCube[i]);
|
||||
}*/
|
||||
|
||||
if (model == LM_AMBIENT) {
|
||||
minLight = max (l * lights[i].color, minLight);
|
||||
} else {
|
||||
vec3 incoming = dist / d;
|
||||
l *= spot_cone (lights[i], incoming) * diffuse (incoming, n);
|
||||
light += l * lights[i].color;
|
||||
}
|
||||
float namb = dot(l.direction.xyz, l.direction.xyz);
|
||||
I *= spot_cone (l, incoming) * diffuse (incoming, n);
|
||||
I = mix (1, I, namb);
|
||||
light += I * l.color.w * l.color.xyz;
|
||||
}
|
||||
light = max (light, minLight);
|
||||
}
|
||||
|
|
|
@ -147,17 +147,10 @@ update_lights (vulkan_ctx_t *ctx)
|
|||
qfv_light_buffer_t *light_data = QFV_PacketExtend (packet,
|
||||
sizeof (*light_data));
|
||||
|
||||
float style_intensities[NumStyles];
|
||||
for (int i = 0; i < NumStyles; i++) {
|
||||
light_data->intensity[i] = d_lightstylevalue[i] / 65536.0;
|
||||
style_intensities[i] = d_lightstylevalue[i] / 65536.0;
|
||||
}
|
||||
// dynamic lights seem a tad faint, so 16x map lights
|
||||
light_data->intensity[64] = 1 / 16.0;
|
||||
light_data->intensity[65] = 1 / 16.0;
|
||||
light_data->intensity[66] = 1 / 16.0;
|
||||
light_data->intensity[67] = 1 / 16.0;
|
||||
|
||||
light_data->distFactor1 = 1 / 128.0;
|
||||
light_data->distFactor2 = 1 / 16384.0;
|
||||
|
||||
light_data->lightCount = 0;
|
||||
R_FindNearLights (r_refdef.frame.position, MaxLights - 1, lights);
|
||||
|
@ -167,16 +160,20 @@ update_lights (vulkan_ctx_t *ctx)
|
|||
}
|
||||
light_data->lightCount++;
|
||||
VectorCopy (lights[i]->color, light_data->lights[i].color);
|
||||
// dynamic lights seem a tad faint, so 16x map lights
|
||||
light_data->lights[i].color[3] = lights[i]->radius / 16;
|
||||
VectorCopy (lights[i]->origin, light_data->lights[i].position);
|
||||
light_data->lights[i].light = lights[i]->radius;
|
||||
light_data->lights[i].data = 64; // default dynamic light
|
||||
VectorZero (light_data->lights[i].direction);
|
||||
light_data->lights[i].cone = 1;
|
||||
light_data->lights[i].attenuation =
|
||||
(vec4f_t) { 0, 0, 1, 1/lights[i]->radius };
|
||||
light_data->lights[i].direction =
|
||||
(vec4f_t) { 0, 0, 1, 1 };
|
||||
}
|
||||
for (size_t i = 0; (i < lframe->lightvis.size
|
||||
&& light_data->lightCount < MaxLights); i++) {
|
||||
if (lframe->lightvis.a[i]) {
|
||||
light_data->lights[light_data->lightCount++] = lctx->lights.a[i];
|
||||
qfv_light_t *light = &light_data->lights[light_data->lightCount++];
|
||||
*light = lctx->lights.a[i];
|
||||
light->color[3] *= style_intensities[lctx->lightstyles.a[i]];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,6 +300,7 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
|
|||
ctx->lighting_context = lctx;
|
||||
|
||||
DARRAY_INIT (&lctx->lights, 16);
|
||||
DARRAY_INIT (&lctx->lightstyles, 16);
|
||||
DARRAY_INIT (&lctx->lightleafs, 16);
|
||||
DARRAY_INIT (&lctx->lightmats, 16);
|
||||
DARRAY_INIT (&lctx->lightlayers, 16);
|
||||
|
@ -462,6 +460,7 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx)
|
|||
dfunc->vkFreeMemory (device->dev, lctx->light_memory, 0);
|
||||
dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0);
|
||||
DARRAY_CLEAR (&lctx->lights);
|
||||
DARRAY_CLEAR (&lctx->lightstyles);
|
||||
DARRAY_CLEAR (&lctx->lightleafs);
|
||||
DARRAY_CLEAR (&lctx->lightmats);
|
||||
DARRAY_CLEAR (&lctx->lightimages);
|
||||
|
@ -475,19 +474,17 @@ static void
|
|||
dump_light (qfv_light_t *light, int leaf, mat4f_t mat)
|
||||
{
|
||||
Sys_MaskPrintf (SYS_vulkan,
|
||||
"[%g, %g, %g] %d %d %d, "
|
||||
"[%g %g %g] %g, [%g %g %g] %g, %d\n",
|
||||
VectorExpand (light->color),
|
||||
(light->data & 0x07f),
|
||||
(light->data & 0x380) >> 7,
|
||||
(light->data & 0xc00) >> 10,
|
||||
VectorExpand (light->position), light->light,
|
||||
VectorExpand (light->direction), light->cone,
|
||||
"[%g, %g, %g] %g, "
|
||||
"[%g, %g, %g, %g], [%g %g %g] %g, [%g, %g, %g, %g] %d\n",
|
||||
VEC4_EXP (light->color),
|
||||
VEC4_EXP (light->position),
|
||||
VEC4_EXP (light->direction),
|
||||
VEC4_EXP (light->attenuation),
|
||||
leaf);
|
||||
Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 0));
|
||||
Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 1));
|
||||
Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 2));
|
||||
Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 3));
|
||||
// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 0));
|
||||
// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 1));
|
||||
// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 2));
|
||||
// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 3));
|
||||
}
|
||||
|
||||
static float
|
||||
|
@ -548,13 +545,17 @@ esin (float ang)
|
|||
return sin (ang * M_PI / 180);
|
||||
}
|
||||
|
||||
static void
|
||||
sun_vector (const vec_t *ang, vec_t *vec)
|
||||
static vec4f_t
|
||||
sun_vector (const vec_t *ang)
|
||||
{
|
||||
// ang is yaw, pitch (maybe roll, but ignored
|
||||
vec[0] = ecos (ang[1]) * ecos (ang[0]);
|
||||
vec[1] = ecos (ang[1]) * esin (ang[0]);
|
||||
vec[2] = esin (ang[1]);
|
||||
vec4f_t vec = {
|
||||
ecos (ang[1]) * ecos (ang[0]),
|
||||
ecos (ang[1]) * esin (ang[0]),
|
||||
esin (ang[1]),
|
||||
0,
|
||||
};
|
||||
return vec;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -577,11 +578,13 @@ parse_sun (lightingctx_t *lctx, plitem_t *entity, model_t *model)
|
|||
return;
|
||||
}
|
||||
VectorSet (1, 1, 1, light.color);
|
||||
light.data = LM_INFINITE | ST_CASCADE;
|
||||
light.light = sunlight;
|
||||
sun_vector (sunangle, light.direction);
|
||||
light.cone = 1;
|
||||
light.color[3] = sunlight;
|
||||
light.position = sun_vector (sunangle);
|
||||
light.direction = light.position;
|
||||
light.direction[3] = 1;
|
||||
light.attenuation = (vec4f_t) { 0, 0, 1, 0 };
|
||||
DARRAY_APPEND (&lctx->lights, light);
|
||||
DARRAY_APPEND (&lctx->lightstyles, 0);
|
||||
DARRAY_APPEND (&lctx->lightleafs, -1);
|
||||
|
||||
// Any leaf with sky surfaces can potentially see the sun, thus put
|
||||
|
@ -597,8 +600,16 @@ parse_sun (lightingctx_t *lctx, plitem_t *entity, model_t *model)
|
|||
expand_pvs (lctx->sun_pvs, model);
|
||||
}
|
||||
|
||||
static vec4f_t
|
||||
parse_position (const char *str)
|
||||
{
|
||||
vec3_t vec = {};
|
||||
sscanf (str, "%f %f %f", VectorExpandAddr (vec));
|
||||
return (vec4f_t) {vec[0], vec[1], vec[2], 1};
|
||||
}
|
||||
|
||||
static void
|
||||
parse_light (qfv_light_t *light, const plitem_t *entity,
|
||||
parse_light (qfv_light_t *light, int *style, const plitem_t *entity,
|
||||
const plitem_t *targets)
|
||||
{
|
||||
const char *str;
|
||||
|
@ -612,48 +623,47 @@ parse_light (qfv_light_t *light, const plitem_t *entity,
|
|||
}
|
||||
Sys_Printf ("}\n");*/
|
||||
|
||||
light->cone = 1;
|
||||
light->data = 0;
|
||||
light->light = 300;
|
||||
VectorSet (1, 1, 1, light->color);
|
||||
// omnidirectional light (unit length xyz so not treated as ambient)
|
||||
light->direction = (vec4f_t) { 0, 0, 1, 1 };
|
||||
// bright white
|
||||
light->color = (vec4f_t) { 1, 1, 1, 300 };
|
||||
|
||||
if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) {
|
||||
sscanf (str, "%f %f %f", VectorExpandAddr (light->position));
|
||||
light->position = parse_position (str);
|
||||
}
|
||||
|
||||
if ((str = PL_String (PL_ObjectForKey (entity, "target")))) {
|
||||
vec3_t position = {};
|
||||
plitem_t *target = PL_ObjectForKey (targets, str);
|
||||
vec4f_t dir = { 1, 0, 0, 0 };
|
||||
if (target) {
|
||||
if ((str = PL_String (PL_ObjectForKey (target, "origin")))) {
|
||||
sscanf (str, "%f %f %f", VectorExpandAddr (position));
|
||||
dir = parse_position (str);
|
||||
dir = normalf (dir - light->position);
|
||||
}
|
||||
VectorSubtract (position, light->position, light->direction);
|
||||
VectorNormalize (light->direction);
|
||||
}
|
||||
|
||||
float angle = 40;
|
||||
if ((str = PL_String (PL_ObjectForKey (entity, "angle")))) {
|
||||
angle = atof (str);
|
||||
}
|
||||
light->cone = -cos (angle * M_PI / 360); // half angle
|
||||
dir[3] = -cos (angle * M_PI / 360); // half angle
|
||||
light->direction = dir;
|
||||
}
|
||||
|
||||
if ((str = PL_String (PL_ObjectForKey (entity, "light_lev")))
|
||||
|| (str = PL_String (PL_ObjectForKey (entity, "_light")))) {
|
||||
light->light = atof (str);
|
||||
light->color[3] = atof (str);
|
||||
}
|
||||
|
||||
if ((str = PL_String (PL_ObjectForKey (entity, "style")))) {
|
||||
light->data = atoi (str) & 0x3f;
|
||||
*style = atoi (str) & 0x3f;
|
||||
}
|
||||
|
||||
if ((str = PL_String (PL_ObjectForKey (entity, "delay")))) {
|
||||
model = (atoi (str) & 0x7) << 7;
|
||||
model = atoi (str) & 0x7;
|
||||
if (model == LM_INVERSE2) {
|
||||
model = LM_INVERSE3; //FIXME for marcher (need a map)
|
||||
}
|
||||
light->data |= model;
|
||||
}
|
||||
|
||||
if ((str = PL_String (PL_ObjectForKey (entity, "color")))
|
||||
|
@ -662,15 +672,29 @@ parse_light (qfv_light_t *light, const plitem_t *entity,
|
|||
VectorScale (light->color, 1/255.0, light->color);
|
||||
}
|
||||
|
||||
if (model == LM_INFINITE) {
|
||||
light->data |= ST_CASCADE;
|
||||
} else if (model != LM_AMBIENT) {
|
||||
if (light->cone > -0.5) {
|
||||
light->data |= ST_CUBE;
|
||||
} else {
|
||||
light->data |= ST_PLANE;
|
||||
}
|
||||
vec4f_t attenuation = { 1, 0, 0, 0 }; // inverse square
|
||||
switch (model) {
|
||||
case LM_LINEAR:
|
||||
attenuation = (vec4f_t) { 0, 0, 1, 1 / fabsf (light->color[3]) };
|
||||
break;
|
||||
case LM_INVERSE:
|
||||
attenuation = (vec4f_t) { 0, 1.0 / 128, 0, 0 };
|
||||
break;
|
||||
case LM_INVERSE2:
|
||||
attenuation = (vec4f_t) { 1.0 / 16384, 0, 0, 0 };
|
||||
break;
|
||||
case LM_INFINITE:
|
||||
attenuation = (vec4f_t) { 0, 0, 1, 0 };
|
||||
break;
|
||||
case LM_AMBIENT:
|
||||
attenuation = (vec4f_t) { 0, 0, 1, 0 };
|
||||
light->direction = (vec4f_t) { 0, 0, 0, 1 };
|
||||
break;
|
||||
case LM_INVERSE3:
|
||||
attenuation = (vec4f_t) { 1.0 / 16384, 2.0 / 128, 1, 0 };
|
||||
break;
|
||||
}
|
||||
light->attenuation = attenuation;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -681,8 +705,18 @@ create_light_matrices (lightingctx_t *lctx)
|
|||
qfv_light_t *light = &lctx->lights.a[i];
|
||||
mat4f_t view;
|
||||
mat4f_t proj;
|
||||
int mode = ST_NONE;
|
||||
|
||||
switch (light->data & ShadowMask) {
|
||||
if (!light->position[3]) {
|
||||
mode = ST_CASCADE;
|
||||
} else {
|
||||
if (light->direction[3] > -0.5) {
|
||||
mode = ST_CUBE;
|
||||
} else {
|
||||
mode = ST_PLANE;
|
||||
}
|
||||
}
|
||||
switch (mode) {
|
||||
default:
|
||||
case ST_NONE:
|
||||
case ST_CUBE:
|
||||
|
@ -691,13 +725,14 @@ create_light_matrices (lightingctx_t *lctx)
|
|||
case ST_CASCADE:
|
||||
case ST_PLANE:
|
||||
//FIXME will fail for -ref_direction
|
||||
mat4fquat (view, qrotf (loadvec3f (light->direction),
|
||||
ref_direction));
|
||||
vec4f_t dir = light->direction;
|
||||
dir[3] = 0;
|
||||
mat4fquat (view, qrotf (dir, ref_direction));
|
||||
break;
|
||||
}
|
||||
VectorNegate (light->position, view[3]);
|
||||
|
||||
switch (light->data & ShadowMask) {
|
||||
switch (mode) {
|
||||
case ST_NONE:
|
||||
mat4fidentity (proj);
|
||||
break;
|
||||
|
@ -709,7 +744,7 @@ create_light_matrices (lightingctx_t *lctx)
|
|||
mat4fidentity (proj);
|
||||
break;
|
||||
case ST_PLANE:
|
||||
QFV_PerspectiveCos (proj, light->cone);
|
||||
QFV_PerspectiveCos (proj, -light->direction[3]);
|
||||
break;
|
||||
}
|
||||
mmulf (lctx->lightmats.a[i], proj, view);
|
||||
|
@ -722,10 +757,11 @@ light_compare (const void *_l2, const void *_l1)
|
|||
const qfv_light_t *l1 = _l1;
|
||||
const qfv_light_t *l2 = _l2;
|
||||
|
||||
if (l1->light == l2->light) {
|
||||
return (l1->data & ShadowMask) - (l2->data & ShadowMask);
|
||||
if (l1->color[3] == l2->color[3]) {
|
||||
return (l1->position[3] == l2->position[3])
|
||||
&& (l1->direction[3] > -0.5) == (l2->direction[3] > -0.5);
|
||||
}
|
||||
return l1->light - l2->light;
|
||||
return l1->color[3] - l2->color[3];
|
||||
}
|
||||
|
||||
static VkImage
|
||||
|
@ -758,7 +794,7 @@ create_map (int size, int layers, int cube, vulkan_ctx_t *ctx)
|
|||
}
|
||||
|
||||
static VkImageView
|
||||
create_view (VkImage image, int baseLayer, int data, int id, vulkan_ctx_t *ctx)
|
||||
create_view (VkImage image, int baseLayer, int mode, int id, vulkan_ctx_t *ctx)
|
||||
{
|
||||
qfv_device_t *device = ctx->device;
|
||||
qfv_devfuncs_t *dfunc = device->funcs;
|
||||
|
@ -767,7 +803,7 @@ create_view (VkImage image, int baseLayer, int data, int id, vulkan_ctx_t *ctx)
|
|||
VkImageViewType type = 0;
|
||||
const char *viewtype = 0;
|
||||
|
||||
switch (data & ShadowMask) {
|
||||
switch (mode) {
|
||||
case ST_NONE:
|
||||
return 0;
|
||||
case ST_PLANE:
|
||||
|
@ -827,8 +863,18 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
|
|||
DARRAY_RESIZE (&lctx->lightlayers, numLights);
|
||||
qsort (lights, numLights, sizeof (qfv_light_t), light_compare);
|
||||
for (int i = 0; i < numLights; i++) {
|
||||
int shadow = lights[i].data & ShadowMask;
|
||||
int layers = 1;
|
||||
int shadow = ST_NONE;
|
||||
|
||||
if (!lights[i].position[3]) {
|
||||
shadow = ST_CASCADE;
|
||||
} else {
|
||||
if (lights[i].direction[3] > -0.5) {
|
||||
shadow = ST_CUBE;
|
||||
} else {
|
||||
shadow = ST_PLANE;
|
||||
}
|
||||
}
|
||||
if (shadow == ST_CASCADE || shadow == ST_NONE) {
|
||||
// cascade shadows will be handled separately, and "none" has no
|
||||
// shadow map at all
|
||||
|
@ -838,13 +884,14 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
|
|||
if (shadow == ST_CUBE) {
|
||||
layers = 6;
|
||||
}
|
||||
if (size != (int) lights[i].light || numLayers + layers > maxLayers) {
|
||||
if (size != (int) lights[i].color[3]
|
||||
|| numLayers + layers > maxLayers) {
|
||||
if (numLayers) {
|
||||
VkImage shadow_map = create_map (size, numLayers, 1, ctx);
|
||||
DARRAY_APPEND (&lctx->lightimages, shadow_map);
|
||||
numLayers = 0;
|
||||
}
|
||||
size = lights[i].light;
|
||||
size = lights[i].color[3];
|
||||
}
|
||||
imageMap[i] = lctx->lightimages.size;
|
||||
lctx->lightlayers.a[i] = numLayers;
|
||||
|
@ -859,8 +906,18 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
|
|||
numLayers = 0;
|
||||
size = 1024;
|
||||
for (int i = 0; i < numLights; i++) {
|
||||
int shadow = lights[i].data & ShadowMask;
|
||||
int layers = 4;
|
||||
int shadow = ST_NONE;
|
||||
|
||||
if (!lights[i].position[3]) {
|
||||
shadow = ST_CASCADE;
|
||||
} else {
|
||||
if (lights[i].direction[3] > -0.5) {
|
||||
shadow = ST_CUBE;
|
||||
} else {
|
||||
shadow = ST_PLANE;
|
||||
}
|
||||
}
|
||||
|
||||
if (shadow != ST_CASCADE) {
|
||||
continue;
|
||||
|
@ -902,9 +959,20 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
|
|||
lctx->lightviews.a[i] = 0;
|
||||
continue;
|
||||
}
|
||||
int mode = ST_NONE;
|
||||
|
||||
if (!lctx->lights.a[i].position[3]) {
|
||||
mode = ST_CASCADE;
|
||||
} else {
|
||||
if (lctx->lights.a[i].direction[3] > -0.5) {
|
||||
mode = ST_CUBE;
|
||||
} else {
|
||||
mode = ST_PLANE;
|
||||
}
|
||||
}
|
||||
lctx->lightviews.a[i] = create_view (lctx->lightimages.a[imageMap[i]],
|
||||
lctx->lightlayers.a[i],
|
||||
lctx->lights.a[i].data, i, ctx);
|
||||
mode, i, ctx);
|
||||
}
|
||||
Sys_MaskPrintf (SYS_vulkan, "shadow maps: %d layers in %zd images: %zd\n",
|
||||
totalLayers, lctx->lightimages.size, memsize);
|
||||
|
@ -932,6 +1000,7 @@ Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx)
|
|||
}
|
||||
|
||||
lctx->lights.size = 0;
|
||||
lctx->lightstyles.size = 0;
|
||||
lctx->lightleafs.size = 0;
|
||||
lctx->lightmats.size = 0;
|
||||
if (lctx->sun_pvs) {
|
||||
|
@ -989,11 +1058,13 @@ Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx)
|
|||
parse_sun (lctx, entity, model);
|
||||
} else if (strnequal (classname, "light", 5)) {
|
||||
qfv_light_t light = {};
|
||||
int style = 0;
|
||||
|
||||
parse_light (&light, entity, targets);
|
||||
parse_light (&light, &style, entity, targets);
|
||||
// some lights have 0 output, so drop them
|
||||
if (light.light) {
|
||||
if (light.color[3]) {
|
||||
DARRAY_APPEND (&lctx->lights, light);
|
||||
DARRAY_APPEND (&lctx->lightstyles, style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue