[vulkan] Make near and far clip explicit parameters

This improves the projection API in that near clip is a parameter rather
than being taken directly from the cvar, and a far clip (ie, finite far
plane) version is available (necessary for cascaded shadow maps as it's
rather hard to fit a box to an infinite frustum).

Also, the orthographic projection matrix is now reversed as per the
perspective matrix (and the code tidied up a little), and a version that
takes min and max vectors is available.
This commit is contained in:
Bill Currie 2023-08-13 17:25:17 +09:00
parent 2b879af3e1
commit 558e11e9b7
5 changed files with 87 additions and 42 deletions

View file

@ -5,9 +5,17 @@
void QFV_Orthographic (mat4f_t proj, float xmin, float xmax,
float ymin, float ymax, float znear, float zfar);
void QFV_OrthographicV (mat4f_t proj, vec4f_t mins, vec4f_t maxs);
// fov_x and fov_y are tan(fov/2) for x and y respectively
void QFV_PerspectiveTan (mat4f_t proj, float fov_x, float fov_y);
void QFV_PerspectiveCos (mat4f_t proj, float fov);
void QFV_PerspectiveTan (mat4f_t proj, float fov_x, float fov_y,
float nearclip);
void QFV_InversePerspectiveTan (mat4f_t proj, float fov_x, float fov_y,
float nearclip);
void QFV_PerspectiveTanFar (mat4f_t proj, float fov_x, float fov_y,
float nearclip, float farclip);
void QFV_InversePerspectiveTanFar (mat4f_t proj, float fov_x, float fov_y,
float nearclip, float farclip);
void QFV_PerspectiveCos (mat4f_t proj, float fov, float nearclip);
extern const mat4f_t qfv_z_up;
extern const mat4f_t qfv_box_rotations[6];

View file

@ -359,7 +359,7 @@ vulkan_set_fov (float x, float y)
__auto_type mctx = vulkan_ctx->matrix_context;
__auto_type mat = &mctx->matrices;
QFV_PerspectiveTan (mat->Projection3d, x, y);
QFV_PerspectiveTan (mat->Projection3d, x, y, r_nearclip);
mctx->dirty = mctx->frames.size;
}

View file

@ -89,50 +89,86 @@ void
QFV_Orthographic (mat4f_t proj, float xmin, float xmax, float ymin, float ymax,
float znear, float zfar)
{
proj[0] = (vec4f_t) {
2 / (xmax - xmin),
0,
0,
0
};
proj[1] = (vec4f_t) {
0,
2 / (ymax - ymin),
0,
0
};
proj[2] = (vec4f_t) {
0,
0,
1 / (znear - zfar),
0
};
proj[3] = (vec4f_t) {
-(xmax + xmin) / (xmax - xmin),
-(ymax + ymin) / (ymax - ymin),
znear / (znear - zfar),
1,
};
float d = zfar - znear;
float w = xmax - xmin;
float h = ymax - ymin;
float m = xmax + xmin;
float c = ymax + ymin;
float f = zfar;
proj[0] = (vec4f_t) { 2/w, 0, 0, 0 };
proj[1] = (vec4f_t) { 0, 2/h, 0, 0 };
proj[2] = (vec4f_t) { 0, 0, -1/d, 0 };
proj[3] = (vec4f_t) { -m/w, -c/h, f/d, 1 };
}
void
QFV_PerspectiveTan (mat4f_t proj, float fov_x, float fov_y)
QFV_OrthographicV (mat4f_t proj, vec4f_t mins, vec4f_t maxs)
{
float neard;
neard = r_nearclip;
proj[0] = (vec4f_t) { 1 / fov_x, 0, 0, 0 };
proj[1] = (vec4f_t) { 0, 1 / fov_y, 0, 0 };
proj[2] = (vec4f_t) { 0, 0, 0, 1 };
proj[3] = (vec4f_t) { 0, 0, neard, 0 };
QFV_Orthographic (proj, mins[0], maxs[0], mins[1], maxs[1],
mins[2], maxs[2]);
}
void
QFV_PerspectiveCos (mat4f_t proj, float fov)
QFV_PerspectiveTan (mat4f_t proj, float fov_x, float fov_y, float nearclip)
{
float n = nearclip;
float fx = fov_x;
float fy = fov_y;
proj[0] = (vec4f_t) { 1/fx, 0, 0, 0 };
proj[1] = (vec4f_t) { 0, 1/fy, 0, 0 };
proj[2] = (vec4f_t) { 0, 0, 0, 1 };
proj[3] = (vec4f_t) { 0, 0, n, 0 };
}
void
QFV_InversePerspectiveTan (mat4f_t proj, float fov_x, float fov_y,
float nearclip)
{
float n = r_nearclip;
float fx = fov_x;
float fy = fov_y;
proj[0] = (vec4f_t) { fx, 0, 0, 0 };
proj[1] = (vec4f_t) { 0, fy, 0, 0 };
proj[2] = (vec4f_t) { 0, 0, 0, 1/n };
proj[3] = (vec4f_t) { 0, 0, 1, 0 };
}
void
QFV_PerspectiveTanFar (mat4f_t proj, float fov_x, float fov_y,
float nearclip, float farclip)
{
float n = nearclip;
float f = farclip;
float fx = fov_x;
float fy = fov_y;
proj[0] = (vec4f_t) { 1/fx, 0, 0, 0 };
proj[1] = (vec4f_t) { 0, 1/fy, 0, 0 };
proj[2] = (vec4f_t) { 0, 0, n/(n-f), 1 };
proj[3] = (vec4f_t) { 0, 0, n*f/(n-f), 0 };
}
void
QFV_InversePerspectiveTanFar (mat4f_t proj, float fov_x, float fov_y,
float nearclip, float farclip)
{
float n = r_nearclip;
float f = farclip;
float fx = fov_x;
float fy = fov_y;
proj[0] = (vec4f_t) { fx, 0, 0, 0 };
proj[1] = (vec4f_t) { 0, fy, 0, 0 };
proj[2] = (vec4f_t) { 0, 0, 0, (f-n)/(n*f) };
proj[3] = (vec4f_t) { 0, 0, 1, 1/f };
}
void
QFV_PerspectiveCos (mat4f_t proj, float fov, float nearclip)
{
// square first for auto-abs (no support for > 180 degree fov)
fov = fov * fov;
float t = sqrt ((1 - fov) / fov);
QFV_PerspectiveTan (proj, t, t);
QFV_PerspectiveTan (proj, t, t, nearclip);
}

View file

@ -79,6 +79,7 @@
#include "vid_vulkan.h"
#include "vkparse.h"
#define lnearclip 4
#define ico_verts 12
#define cone_verts 7
static int ico_inds[] = {
@ -336,7 +337,7 @@ cube_mat (mat4f_t *mat, vec4f_t position)
view[3][3] = 1;
mat4f_t proj;
QFV_PerspectiveTan (proj, 1, 1);
QFV_PerspectiveTan (proj, 1, 1, lnearclip);
for (int j = 0; j < 6; j++) {
mat4f_t side_view;
mat4f_t rotinv;
@ -1275,7 +1276,7 @@ create_light_matrices (lightingctx_t *lctx)
case ST_NONE:
continue;
case ST_CUBE:
QFV_PerspectiveTan (proj, 1, 1);
QFV_PerspectiveTan (proj, 1, 1, lnearclip);
for (int j = 0; j < 6; j++) {
mat4f_t side_view;
mat4f_t rotinv;
@ -1294,7 +1295,7 @@ create_light_matrices (lightingctx_t *lctx)
}
break;
case ST_PLANE:
QFV_PerspectiveCos (proj, -light->direction[3]);
QFV_PerspectiveCos (proj, -light->direction[3], lnearclip);
mmulf (view, qfv_z_up, view);
mmulf (lm[0], proj, view);
break;

View file

@ -64,7 +64,7 @@ setup_view (vulkan_ctx_t *ctx)
//FIXME this should check for cube map rather than fisheye
if (scr_fisheye) {
__auto_type mctx = ctx->matrix_context;
QFV_PerspectiveTan (mctx->matrices.Projection3d, 1, 1);
QFV_PerspectiveTan (mctx->matrices.Projection3d, 1, 1, r_nearclip);
mat4f_t views[6];
for (int i = 0; i < 6; i++) {
mat4f_t rotinv;