Add inverse z-buffering
This commit is contained in:
parent
63e8bd1b93
commit
8ede3f1952
3
Makefile
3
Makefile
|
@ -31,7 +31,8 @@ CC=clang++
|
||||||
WARNINGS_ON=-Weverything
|
WARNINGS_ON=-Weverything
|
||||||
WARNINGS_OFF=-Wno-missing-braces -Wno-gnu-anonymous-struct -Wno-old-style-cast\
|
WARNINGS_OFF=-Wno-missing-braces -Wno-gnu-anonymous-struct -Wno-old-style-cast\
|
||||||
-Wno-zero-as-null-pointer-constant -Wno-nested-anon-types\
|
-Wno-zero-as-null-pointer-constant -Wno-nested-anon-types\
|
||||||
-Wno-padded -Wno-exit-time-destructors -Wno-global-constructors
|
-Wno-padded -Wno-exit-time-destructors -Wno-global-constructors\
|
||||||
|
-Wno-c++98-compat
|
||||||
|
|
||||||
CFLAGS=$(D) $(O) -std=c++11 $(WARNINGS_ON) $(WARNINGS_OFF) -I$(INCLUDE_DIR)
|
CFLAGS=$(D) $(O) -std=c++11 $(WARNINGS_ON) $(WARNINGS_OFF) -I$(INCLUDE_DIR)
|
||||||
LIBS=-lSDL2
|
LIBS=-lSDL2
|
||||||
|
|
|
@ -26,7 +26,8 @@ enum Engine_Input
|
||||||
// STRUCTURES
|
// STRUCTURES
|
||||||
struct Engine_Buffer
|
struct Engine_Buffer
|
||||||
{
|
{
|
||||||
uint32_t *pixels;
|
uint32_t *buffer;
|
||||||
|
float *zbuffer;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,10 +77,11 @@ struct Mesh
|
||||||
|
|
||||||
// PUBLIC FUNCTIONS
|
// PUBLIC FUNCTIONS
|
||||||
void FillTriangle(
|
void FillTriangle(
|
||||||
uint32_t *buffer, int width, uint32_t color,
|
uint32_t *buffer, int width,
|
||||||
float x0, float y0,
|
float *zbuffer, uint32_t color,
|
||||||
float x1, float y1,
|
float x0, float y0, float z0,
|
||||||
float x2, float y2);
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2);
|
||||||
|
|
||||||
|
|
||||||
#define GEOMETRY_H
|
#define GEOMETRY_H
|
||||||
|
|
|
@ -74,6 +74,13 @@ inline Point operator*(Point v, Matrix m)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Point &operator*=(Point &v, Matrix m)
|
||||||
|
{
|
||||||
|
v = v * m;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define MATRIX_H
|
#define MATRIX_H
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,6 +36,14 @@ inline Point operator/(Point v, float f)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// v /= f
|
||||||
|
inline Point &operator/=(Point &v, float f)
|
||||||
|
{
|
||||||
|
v = v / f;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
// v1 - v2
|
// v1 - v2
|
||||||
inline Vector operator-(Point v1, Point v2)
|
inline Vector operator-(Point v1, Point v2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include "transform.h"
|
#include "transform.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
#include <cstdio>
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
// GLOBALS
|
// GLOBALS
|
||||||
|
@ -50,6 +50,8 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
|
||||||
{
|
{
|
||||||
CheckInputs(input);
|
CheckInputs(input);
|
||||||
|
|
||||||
|
unsigned long bufferSize = (unsigned long)(buffer.width * buffer.height);
|
||||||
|
memset(buffer.zbuffer, 0, bufferSize * sizeof(float));
|
||||||
|
|
||||||
// Local space to world space
|
// Local space to world space
|
||||||
Matrix tTranslate = Transform_Translate(
|
Matrix tTranslate = Transform_Translate(
|
||||||
|
@ -62,8 +64,7 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
|
||||||
|
|
||||||
for (size_t v = 0; v < mesh.verts.size(); ++v)
|
for (size_t v = 0; v < mesh.verts.size(); ++v)
|
||||||
{
|
{
|
||||||
mesh.vertsTransformed[v] =
|
mesh.vertsTransformed[v] = mesh.verts[v] * tScale * tRotate * tTranslate;
|
||||||
mesh.verts[v] * tScale * tRotate * tTranslate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,25 +100,17 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
|
||||||
// World space to camera (view) space
|
// World space to camera (view) space
|
||||||
Matrix tView = Transform_View(camera.position, camera.rotation);
|
Matrix tView = Transform_View(camera.position, camera.rotation);
|
||||||
|
|
||||||
|
|
||||||
// Camera space to perspective
|
// Camera space to perspective
|
||||||
Matrix tPersp = Transform_Perspective(
|
Matrix tPersp = Transform_Perspective(
|
||||||
camera.xZoom, camera.yZoom, camera.nearClip, camera.farClip);
|
camera.xZoom, camera.yZoom, camera.nearClip, camera.farClip);
|
||||||
|
|
||||||
for (size_t v = 0; v < mesh.verts.size(); ++v)
|
|
||||||
{
|
|
||||||
mesh.vertsTransformed[v] = mesh.vertsTransformed[v] * tView * tPersp;
|
|
||||||
|
|
||||||
mesh.vertsTransformed[v] =
|
|
||||||
mesh.vertsTransformed[v] / mesh.vertsTransformed[v].w;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perspective to screen
|
// Perspective to screen
|
||||||
Matrix tScreen = Transform_Screen(camera.xScale, camera.yScale);
|
Matrix tScreen = Transform_Screen(camera.xScale, camera.yScale);
|
||||||
|
|
||||||
for (size_t v = 0; v < mesh.verts.size(); ++v)
|
for (size_t v = 0; v < mesh.verts.size(); ++v)
|
||||||
{
|
{
|
||||||
mesh.vertsTransformed[v] = mesh.vertsTransformed[v] * tScreen;
|
mesh.vertsTransformed[v] *= tView * tPersp * tScreen;
|
||||||
|
mesh.vertsTransformed[v] /= mesh.vertsTransformed[v].w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,10 +122,11 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
|
||||||
unsigned int v2 = mesh.culledFaces[f].vertIndex[2];
|
unsigned int v2 = mesh.culledFaces[f].vertIndex[2];
|
||||||
|
|
||||||
FillTriangle(
|
FillTriangle(
|
||||||
buffer.pixels, buffer.width, mesh.faces[f].color.u32,
|
buffer.buffer, buffer.width,
|
||||||
mesh.vertsTransformed[v0].x, mesh.vertsTransformed[v0].y,
|
buffer.zbuffer, mesh.faces[f].color.u32,
|
||||||
mesh.vertsTransformed[v1].x, mesh.vertsTransformed[v1].y,
|
mesh.vertsTransformed[v0].x, mesh.vertsTransformed[v0].y, mesh.vertsTransformed[v0].z,
|
||||||
mesh.vertsTransformed[v2].x, mesh.vertsTransformed[v2].y);
|
mesh.vertsTransformed[v1].x, mesh.vertsTransformed[v1].y, mesh.vertsTransformed[v1].z,
|
||||||
|
mesh.vertsTransformed[v2].x, mesh.vertsTransformed[v2].y, mesh.vertsTransformed[v2].z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
114
src/geometry.cpp
114
src/geometry.cpp
|
@ -12,24 +12,27 @@
|
||||||
|
|
||||||
// PRIVATE PROTOTYPES
|
// PRIVATE PROTOTYPES
|
||||||
static void FillTriangleFlatBottom(
|
static void FillTriangleFlatBottom(
|
||||||
uint32_t *buffer, int width, uint32_t color,
|
uint32_t *buffer, int width,
|
||||||
float x0, float y0,
|
float *zbuffer, uint32_t color,
|
||||||
float x1, float y1,
|
float x0, float y0, float z0,
|
||||||
float x2, float y2);
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2);
|
||||||
|
|
||||||
static void FillTriangleFlatTop(
|
static void FillTriangleFlatTop(
|
||||||
uint32_t *buffer, int width, uint32_t color,
|
uint32_t *buffer, int width,
|
||||||
float x0, float y0,
|
float *zbuffer, uint32_t color,
|
||||||
float x1, float y1,
|
float x0, float y0, float z0,
|
||||||
float x2, float y2);
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2);
|
||||||
|
|
||||||
|
|
||||||
// PUBLIC FUNCTIONS
|
// PUBLIC FUNCTIONS
|
||||||
void FillTriangle(
|
void FillTriangle(
|
||||||
uint32_t *buffer, int width, uint32_t color,
|
uint32_t *buffer, int width,
|
||||||
float x0, float y0,
|
float *zbuffer, uint32_t color,
|
||||||
float x1, float y1,
|
float x0, float y0, float z0,
|
||||||
float x2, float y2)
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2)
|
||||||
{
|
{
|
||||||
// Horizontal or vertical
|
// Horizontal or vertical
|
||||||
if ((FLOAT_EQUAL(x0,x1) && FLOAT_EQUAL(x1, x2))
|
if ((FLOAT_EQUAL(x0,x1) && FLOAT_EQUAL(x1, x2))
|
||||||
|
@ -44,31 +47,34 @@ void FillTriangle(
|
||||||
{
|
{
|
||||||
SWAP(x0, x1, temp);
|
SWAP(x0, x1, temp);
|
||||||
SWAP(y0, y1, temp);
|
SWAP(y0, y1, temp);
|
||||||
|
SWAP(z0, z1, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y0 > y2)
|
if (y0 > y2)
|
||||||
{
|
{
|
||||||
SWAP(x0, x2, temp);
|
SWAP(x0, x2, temp);
|
||||||
SWAP(y0, y2, temp);
|
SWAP(y0, y2, temp);
|
||||||
|
SWAP(z0, z2, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y1 > y2)
|
if (y1 > y2)
|
||||||
{
|
{
|
||||||
SWAP(x1, x2, temp);
|
SWAP(x1, x2, temp);
|
||||||
SWAP(y1, y2, temp);
|
SWAP(y1, y2, temp);
|
||||||
|
SWAP(z1, z2, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Flat top triangle
|
// Flat top triangle
|
||||||
if (FLOAT_EQUAL(y0, y1))
|
if (FLOAT_EQUAL(y0, y1))
|
||||||
{
|
{
|
||||||
FillTriangleFlatTop(buffer, width, color, x0, y0, x1, y1, x2, y2);
|
FillTriangleFlatTop(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x2, y2, z2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flat bottom triangle
|
// Flat bottom triangle
|
||||||
else if (FLOAT_EQUAL(y1, y2))
|
else if (FLOAT_EQUAL(y1, y2))
|
||||||
{
|
{
|
||||||
FillTriangleFlatBottom(buffer, width, color, x0, y0, x1, y1, x2, y2);
|
FillTriangleFlatBottom(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x2, y2, z2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other - decompose into two triangles
|
// Other - decompose into two triangles
|
||||||
|
@ -78,27 +84,30 @@ void FillTriangle(
|
||||||
// New y is the same as y1
|
// New y is the same as y1
|
||||||
float x3 = x0 + (((y1 - y0) / (y2 - y0)) * (x2 - x0));
|
float x3 = x0 + (((y1 - y0) / (y2 - y0)) * (x2 - x0));
|
||||||
float y3 = y1;
|
float y3 = y1;
|
||||||
|
float z3 = z1;
|
||||||
|
|
||||||
FillTriangleFlatBottom(buffer, width, color, x0, y0, x1, y1, x3, y3);
|
FillTriangleFlatBottom(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x3, y3, z3);
|
||||||
FillTriangleFlatTop(buffer, width, color, x1, y1, x3, y3, x2, y2);
|
FillTriangleFlatTop(buffer, width, zbuffer, color, x1, y1, z1, x3, y3, z3, x2, y2, z2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// PRIVATE FUNCTIONS
|
// PRIVATE FUNCTIONS
|
||||||
static void FillTriangleFlatBottom(
|
static void FillTriangleFlatBottom(
|
||||||
uint32_t *buffer, int width, uint32_t color,
|
uint32_t *buffer, int width,
|
||||||
float x0, float y0,
|
float *zbuffer, uint32_t color,
|
||||||
float x1, float y1,
|
float x0, float y0, float z0,
|
||||||
float x2, float y2)
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2)
|
||||||
{
|
{
|
||||||
if (x2 < x1)
|
if (x2 < x1)
|
||||||
{
|
{
|
||||||
float temp;
|
float temp;
|
||||||
SWAP(x1, x2, temp);
|
SWAP(x2, x1, temp);
|
||||||
|
SWAP(y2, y1, temp);
|
||||||
|
SWAP(z2, z1, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Top-left fill convention
|
// Top-left fill convention
|
||||||
float dxdy_left = (x1 - x0) / (y1 - y0);
|
float dxdy_left = (x1 - x0) / (y1 - y0);
|
||||||
float dxdy_right = (x2 - x0) / (y2 - y0);
|
float dxdy_right = (x2 - x0) / (y2 - y0);
|
||||||
|
@ -108,35 +117,62 @@ static void FillTriangleFlatBottom(
|
||||||
float xEnd = x0 + dxdy_right * (yStart - y0);
|
float xEnd = x0 + dxdy_right * (yStart - y0);
|
||||||
|
|
||||||
|
|
||||||
|
// Inverse z-buffering
|
||||||
|
float z0Inv = 1.0f / z0;
|
||||||
|
float z1Inv = 1.0f / z1;
|
||||||
|
float z2Inv = 1.0f / z2;
|
||||||
|
float dzdy_left = (z1Inv - z0Inv) / (y1 - y0);
|
||||||
|
float dzdy_right = (z2Inv - z0Inv) / (y2 - y0);
|
||||||
|
float zStart = z0Inv;
|
||||||
|
float zEnd = z0Inv;
|
||||||
|
|
||||||
|
|
||||||
// Fill
|
// Fill
|
||||||
for (int y = yStart; y <= yEnd; ++y)
|
for (int y = yStart; y <= yEnd; ++y)
|
||||||
{
|
{
|
||||||
|
float dzdx = (zEnd - zStart) / (xEnd - xStart);
|
||||||
|
float z = zStart;
|
||||||
|
|
||||||
int xStartInt = (int)xStart;
|
int xStartInt = (int)xStart;
|
||||||
int xEndInt = (int)xEnd;
|
int xEndInt = (int)xEnd;
|
||||||
|
|
||||||
for (int x = xStartInt; x <= xEndInt; ++x)
|
for (int x = xStartInt; x <= xEndInt; ++x)
|
||||||
|
{
|
||||||
|
int pixel = (y * width) + x;
|
||||||
|
|
||||||
|
if (z > zbuffer[pixel])
|
||||||
{
|
{
|
||||||
DrawPixel(buffer, width, color, x, y);
|
DrawPixel(buffer, width, color, x, y);
|
||||||
|
|
||||||
|
zbuffer[pixel] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
z += dzdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
xStart += dxdy_left;
|
xStart += dxdy_left;
|
||||||
xEnd += dxdy_right;
|
xEnd += dxdy_right;
|
||||||
|
|
||||||
|
zStart += dzdy_left;
|
||||||
|
zEnd += dzdy_right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FillTriangleFlatTop(
|
static void FillTriangleFlatTop(
|
||||||
uint32_t *buffer, int width, uint32_t color,
|
uint32_t *buffer, int width,
|
||||||
float x0, float y0,
|
float *zbuffer, uint32_t color,
|
||||||
float x1, float y1,
|
float x0, float y0, float z0,
|
||||||
float x2, float y2)
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2)
|
||||||
{
|
{
|
||||||
if (x1 < x0)
|
if (x1 < x0)
|
||||||
{
|
{
|
||||||
float temp;
|
float temp;
|
||||||
SWAP(x1, x0, temp);
|
SWAP(x1, x0, temp);
|
||||||
|
SWAP(y1, y0, temp);
|
||||||
|
SWAP(z1, z0, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Top-left fill convention
|
// Top-left fill convention
|
||||||
float dxdy_left = (x2 - x0) / (y2 - y0);
|
float dxdy_left = (x2 - x0) / (y2 - y0);
|
||||||
float dxdy_right = (x2 - x1) / (y2 - y1);
|
float dxdy_right = (x2 - x1) / (y2 - y1);
|
||||||
|
@ -146,19 +182,43 @@ static void FillTriangleFlatTop(
|
||||||
float xEnd = x1 + dxdy_right * (yStart - y0);
|
float xEnd = x1 + dxdy_right * (yStart - y0);
|
||||||
|
|
||||||
|
|
||||||
|
// Inverse z-buffering
|
||||||
|
float z0Inv = 1.0f / z0;
|
||||||
|
float z1Inv = 1.0f / z1;
|
||||||
|
float z2Inv = 1.0f / z2;
|
||||||
|
float dzdy_left = (z2Inv - z0Inv) / (y2 - y0);
|
||||||
|
float dzdy_right = (z2Inv - z1Inv) / (y2 - y1);
|
||||||
|
float zStart = z0Inv;
|
||||||
|
float zEnd = z1Inv;
|
||||||
|
|
||||||
// Fill
|
// Fill
|
||||||
for (int y = yStart; y <= yEnd; ++y)
|
for (int y = yStart; y <= yEnd; ++y)
|
||||||
{
|
{
|
||||||
|
float dzdx = (zEnd - zStart) / (xEnd - xStart);
|
||||||
|
float z = zStart;
|
||||||
|
|
||||||
int xStartInt = (int)xStart;
|
int xStartInt = (int)xStart;
|
||||||
int xEndInt = (int)xEnd;
|
int xEndInt = (int)xEnd;
|
||||||
|
|
||||||
for (int x = xStartInt; x <= xEndInt; ++x)
|
for (int x = xStartInt; x <= xEndInt; ++x)
|
||||||
|
{
|
||||||
|
int pixel = (y * width) + x;
|
||||||
|
|
||||||
|
if (z > zbuffer[pixel])
|
||||||
{
|
{
|
||||||
DrawPixel(buffer, width, color, x, y);
|
DrawPixel(buffer, width, color, x, y);
|
||||||
|
|
||||||
|
zbuffer[pixel] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
z += dzdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
xStart += dxdy_left;
|
xStart += dxdy_left;
|
||||||
xEnd += dxdy_right;
|
xEnd += dxdy_right;
|
||||||
|
|
||||||
|
zStart += dzdy_left;
|
||||||
|
zEnd += dzdy_right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,8 @@ int main(int argc, char *argv[])
|
||||||
if (result == PLATFORM_OK)
|
if (result == PLATFORM_OK)
|
||||||
{
|
{
|
||||||
Engine_Buffer buffer = {};
|
Engine_Buffer buffer = {};
|
||||||
buffer.pixels = (uint32_t*)platform.surface->pixels;
|
buffer.buffer = (uint32_t*)platform.surface->pixels;
|
||||||
|
buffer.zbuffer = (float*)calloc((size_t)(platform.surface->w * platform.surface->h), sizeof(float));
|
||||||
buffer.width = platform.surface->w;
|
buffer.width = platform.surface->w;
|
||||||
buffer.height = platform.surface->h;
|
buffer.height = platform.surface->h;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue