Projection updates;

- Rename/reorder some projection matrix functions.
- Make perspective functions flip Y and use 0-1 NDC range.
- Flip winding and font vertices based on handedness.

This stuff is really confusing
This commit is contained in:
bjorn 2022-07-17 08:59:39 -07:00
parent 1bc31b7751
commit 430f687add
5 changed files with 74 additions and 57 deletions

View File

@ -145,7 +145,7 @@ static int l_lovrFontGetVertices(lua_State* L) {
lovrAssert(vertices, "Out of memory");
uint32_t glyphCount, lineCount;
Material* material;
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, &glyphCount, &lineCount, &material);
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, &glyphCount, &lineCount, &material, false);
int vertexCount = glyphCount * 4;
lua_createtable(L, vertexCount, 0);
for (int i = 0; i < vertexCount; i++) {

View File

@ -1874,24 +1874,32 @@ static int l_lovrMat4Scale(lua_State* L) {
static int l_lovrMat4Orthographic(lua_State* L) {
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
float left = luax_checkfloat(L, 2);
float right = luax_checkfloat(L, 3);
float top = luax_checkfloat(L, 4);
float bottom = luax_checkfloat(L, 5);
float clipNear = luax_checkfloat(L, 6);
float clipFar = luax_checkfloat(L, 7);
mat4_orthographic(m, left, right, top, bottom, clipNear, clipFar);
if (lua_gettop(L) <= 5) {
float width = luax_checkfloat(L, 2);
float height = luax_checkfloat(L, 3);
float n = luax_optfloat(L, 4, -1.f);
float f = luax_optfloat(L, 5, 1.f);
mat4_orthographic(m, 0.f, width, 0.f, height, n, f);
} else {
float left = luax_checkfloat(L, 2);
float right = luax_checkfloat(L, 3);
float bottom = luax_checkfloat(L, 4);
float top = luax_checkfloat(L, 5);
float n = luax_checkfloat(L, 6);
float f = luax_checkfloat(L, 7);
mat4_orthographic(m, left, right, bottom, top, n, f);
}
lua_settop(L, 1);
return 1;
}
static int l_lovrMat4Perspective(lua_State* L) {
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
float clipNear = luax_checkfloat(L, 2);
float clipFar = luax_checkfloat(L, 3);
float fov = luax_checkfloat(L, 4);
float aspect = luax_checkfloat(L, 5);
mat4_perspective(m, clipNear, clipFar, fov, aspect);
float fovy = luax_checkfloat(L, 2);
float aspect = luax_checkfloat(L, 3);
float n = luax_checkfloat(L, 4);
float f = luax_checkfloat(L, 5);
mat4_perspective(m, fovy, aspect, n, f);
lua_settop(L, 1);
return 1;
}
@ -1902,9 +1910,9 @@ static int l_lovrMat4Fov(lua_State* L) {
float right = luax_checkfloat(L, 3);
float up = luax_checkfloat(L, 4);
float down = luax_checkfloat(L, 5);
float clipNear = luax_checkfloat(L, 6);
float clipFar = luax_checkfloat(L, 7);
mat4_fov(m, left, right, up, down, clipNear, clipFar);
float n = luax_checkfloat(L, 6);
float f = luax_checkfloat(L, 7);
mat4_fov(m, left, right, up, down, n, f);
lua_settop(L, 1);
return 1;
}

View File

@ -590,56 +590,49 @@ MAF void mat4_getScale(mat4 m, vec3 scale) {
vec3_set(scale, vec3_length(m + 0), vec3_length(m + 4), vec3_length(m + 8));
}
MAF mat4 mat4_orthographic(mat4 m, float left, float right, float top, float bottom, float clipNear, float clipFar) {
// Does not have a Y flip, maps z = [-n,-f] to [0,1]
MAF mat4 mat4_orthographic(mat4 m, float left, float right, float bottom, float top, float n, float f) {
float rl = right - left;
float tb = top - bottom;
float fn = clipFar - clipNear;
float fn = f - n;
memset(m, 0, 16 * sizeof(float));
m[0] = 2 / rl;
m[5] = 2 / tb;
m[10] = -2 / fn;
m[12] = -(left + right) / rl;
m[0] = 2.f / rl;
m[5] = 2.f / tb;
m[10] = -1.f / fn;
m[12] = -(right + left) / rl;
m[13] = -(top + bottom) / tb;
m[14] = -(clipFar + clipNear) / fn;
m[15] = 1;
m[14] = -n / fn;
m[15] = 1.f;
return m;
}
MAF mat4 mat4_perspective(mat4 m, float clipNear, float clipFar, float fovy, float aspect) {
float range = tanf(fovy * .5f) * clipNear;
float sx = (2.f * clipNear) / (range * aspect + range * aspect);
float sy = -clipNear / range;
float sz = -clipFar / (clipFar - clipNear);
float pz = (-clipFar * clipNear) / (clipFar - clipNear);
// Flips Y and maps z = [-n,-f] to [0,1] after dividing by w
MAF mat4 mat4_perspective(mat4 m, float fovy, float aspect, float n, float f) {
float cotan = 1.f / tanf(fovy * .5f);
memset(m, 0, 16 * sizeof(float));
m[0] = sx;
m[5] = sy;
m[10] = sz;
m[0] = cotan / aspect;
m[5] = -cotan;
m[10] = f / (n - f);
m[11] = -1.f;
m[14] = pz;
m[14] = (n * f) / (n - f);
m[15] = 0.f;
return m;
}
// This is currently specific to Vulkan
MAF mat4 mat4_fov(mat4 m, float left, float right, float up, float down, float clipNear, float clipFar) {
// Flips Y and maps z = [-n,-f] to [0,1] after dividing by w
MAF mat4 mat4_fov(mat4 m, float left, float right, float up, float down, float n, float f) {
left = -tanf(left);
right = tanf(right);
up = tanf(up);
down = -tanf(down);
float idx = 1.f / (right - left);
float idy = 1.f / (down - up);
float idz = 1.f / (clipFar - clipNear);
float sx = right + left;
float sy = down + up;
memset(m, 0, 16 * sizeof(float));
m[0] = 2.f * idx;
m[5] = 2.f * idy;
m[8] = sx * idx;
m[9] = sy * idy;
m[10] = -clipFar * idz;
m[0] = 2.f / (right - left);
m[5] = 2.f / (down - up);
m[8] = (right + left) / (right - left);
m[9] = (down + up) / (down - up);
m[10] = f / (n - f);
m[11] = -1.f;
m[14] = -(clipFar * clipNear) * idz;
m[14] = (n * f) / (n - f);
return m;
}

View File

@ -3073,7 +3073,7 @@ Pass* lovrGraphicsGetPass(PassInfo* info) {
pass->cameras = tempAlloc(pass->cameraCount * sizeof(Camera));
for (uint32_t i = 0; i < pass->cameraCount; i++) {
mat4_identity(pass->cameras[i].view);
mat4_perspective(pass->cameras[i].projection, .01f, 100.f, 1.0f, (float) main->width / main->height);
mat4_perspective(pass->cameras[i].projection, 1.f, (float) main->width / main->height, .01f, 100.f);
}
pass->cameraDirty = true;
@ -3131,6 +3131,12 @@ void lovrPassSetProjection(Pass* pass, uint32_t index, float* projection) {
lovrCheck(index < pass->cameraCount, "Invalid camera index '%d'", index);
mat4_init(pass->cameras[index].projection, projection);
pass->cameraDirty = true;
// If the handedness of the projection changes, flip the winding
if (index == 0 && (projection[5] > 0.f != pass->cameras[0].projection[5] > 0.f)) {
pass->pipeline->info.rasterizer.winding = !pass->pipeline->info.rasterizer.winding;
pass->pipeline->dirty = true;
}
}
void lovrPassPush(Pass* pass, StackType stack) {
@ -3456,6 +3462,7 @@ void lovrPassSetViewport(Pass* pass, float viewport[4], float depthRange[2]) {
}
void lovrPassSetWinding(Pass* pass, Winding winding) {
if (pass->cameras[0].projection[5] > 0.f) winding = !winding; // Handedness requires winding flip
pass->pipeline->dirty |= pass->pipeline->info.rasterizer.winding != (gpu_winding) winding;
pass->pipeline->info.rasterizer.winding = (gpu_winding) winding;
}
@ -4453,7 +4460,7 @@ static void aline(GlyphVertex* vertices, uint32_t head, uint32_t tail, float wid
}
}
void lovrFontGetVertices(Font* font, ColoredString* strings, uint32_t count, float wrap, HorizontalAlign halign, VerticalAlign valign, GlyphVertex* vertices, uint32_t* glyphCount, uint32_t* lineCount, Material** material) {
void lovrFontGetVertices(Font* font, ColoredString* strings, uint32_t count, float wrap, HorizontalAlign halign, VerticalAlign valign, GlyphVertex* vertices, uint32_t* glyphCount, uint32_t* lineCount, Material** material, bool flip) {
uint32_t vertexCount = 0;
uint32_t lineStart = 0;
uint32_t wordStart = 0;
@ -4508,7 +4515,7 @@ void lovrFontGetVertices(Font* font, ColoredString* strings, uint32_t count, flo
Glyph* glyph = lovrFontGetGlyph(font, codepoint, &resized);
if (resized) {
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, glyphCount, lineCount, material);
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, glyphCount, lineCount, material, flip);
return;
}
@ -4538,10 +4545,17 @@ void lovrFontGetVertices(Font* font, ColoredString* strings, uint32_t count, flo
// Vertices
float* bb = glyph->box;
uint16_t* uv = glyph->uv;
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], y + bb[3] }, { uv[0], uv[1] }, { r, g, b, a } };
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], y + bb[3] }, { uv[2], uv[1] }, { r, g, b, a } };
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], y + bb[1] }, { uv[0], uv[3] }, { r, g, b, a } };
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], y + bb[1] }, { uv[2], uv[3] }, { r, g, b, a } };
if (flip) {
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], -(y + bb[1]) }, { uv[0], uv[3] }, { r, g, b, a } };
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], -(y + bb[1]) }, { uv[2], uv[3] }, { r, g, b, a } };
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], -(y + bb[3]) }, { uv[0], uv[1] }, { r, g, b, a } };
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], -(y + bb[3]) }, { uv[2], uv[1] }, { r, g, b, a } };
} else {
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], y + bb[3] }, { uv[0], uv[1] }, { r, g, b, a } };
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], y + bb[3] }, { uv[2], uv[1] }, { r, g, b, a } };
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], y + bb[1] }, { uv[0], uv[3] }, { r, g, b, a } };
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], y + bb[1] }, { uv[2], uv[3] }, { r, g, b, a } };
}
(*glyphCount)++;
// Advance
@ -4575,10 +4589,12 @@ void lovrPassText(Pass* pass, Font* font, ColoredString* strings, uint32_t count
wrap /= scale;
Material* material;
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, &glyphCount, &lineCount, &material);
bool flip = pass->cameras[0].projection[5] > 0.f;
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, &glyphCount, &lineCount, &material, flip);
mat4_scale(transform, scale, scale, scale);
mat4_translate(transform, 0.f, -ascent + valign / 2.f * (leading * lineCount), 0.f);
float offset = -ascent + valign / 2.f * (leading * lineCount);
mat4_translate(transform, 0.f, flip ? -offset : offset, 0.f);
GlyphVertex* vertexPointer;
uint16_t* indices;

View File

@ -384,7 +384,7 @@ void lovrFontSetLineSpacing(Font* font, float spacing);
float lovrFontGetKerning(Font* font, uint32_t first, uint32_t second);
float lovrFontGetWidth(Font* font, ColoredString* strings, uint32_t count);
void lovrFontGetLines(Font* font, ColoredString* strings, uint32_t count, float wrap, void (*callback)(void* context, const char* string, size_t length), void* context);
void lovrFontGetVertices(Font* font, ColoredString* strings, uint32_t count, float wrap, HorizontalAlign halign, VerticalAlign valign, GlyphVertex* vertices, uint32_t* glyphCount, uint32_t* lineCount, Material** material);
void lovrFontGetVertices(Font* font, ColoredString* strings, uint32_t count, float wrap, HorizontalAlign halign, VerticalAlign valign, GlyphVertex* vertices, uint32_t* glyphCount, uint32_t* lineCount, Material** material, bool flip);
// Model