Convert triangle rasterization to use barycentric
This commit is contained in:
parent
d0041c77c4
commit
0c5cf83748
|
@ -1,6 +1,7 @@
|
||||||
#ifndef GEOMETRY_H
|
#ifndef GEOMETRY_H
|
||||||
|
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
|
#include "engine.h"
|
||||||
#include "point.h"
|
#include "point.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -77,11 +78,8 @@ struct Mesh
|
||||||
|
|
||||||
// PUBLIC FUNCTIONS
|
// PUBLIC FUNCTIONS
|
||||||
void FillTriangle(
|
void FillTriangle(
|
||||||
uint32_t *buffer, int width,
|
Engine_Buffer &buffer, ColorU32 &color,
|
||||||
float *zbuffer, uint32_t color,
|
Point &p0, Point &p1, Point &p2);
|
||||||
float x0, float y0, float z0,
|
|
||||||
float x1, float y1, float z1,
|
|
||||||
float x2, float y2, float z2);
|
|
||||||
|
|
||||||
|
|
||||||
#define GEOMETRY_H
|
#define GEOMETRY_H
|
||||||
|
|
|
@ -50,9 +50,12 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
|
||||||
{
|
{
|
||||||
CheckInputs(input);
|
CheckInputs(input);
|
||||||
|
|
||||||
|
|
||||||
|
// Clear the z-buffer
|
||||||
unsigned long bufferSize = (unsigned long)(buffer.width * buffer.height);
|
unsigned long bufferSize = (unsigned long)(buffer.width * buffer.height);
|
||||||
memset(buffer.zbuffer, 0, bufferSize * sizeof(float));
|
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(
|
||||||
mesh.position.x, mesh.position.y, mesh.position.z);
|
mesh.position.x, mesh.position.y, mesh.position.z);
|
||||||
|
@ -122,11 +125,10 @@ 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.buffer, buffer.width,
|
buffer, mesh.faces[f].color,
|
||||||
buffer.zbuffer, mesh.faces[f].color.u32,
|
mesh.vertsTransformed[v0],
|
||||||
mesh.vertsTransformed[v0].x, mesh.vertsTransformed[v0].y, mesh.vertsTransformed[v0].z,
|
mesh.vertsTransformed[v1],
|
||||||
mesh.vertsTransformed[v1].x, mesh.vertsTransformed[v1].y, mesh.vertsTransformed[v1].z,
|
mesh.vertsTransformed[v2]);
|
||||||
mesh.vertsTransformed[v2].x, mesh.vertsTransformed[v2].y, mesh.vertsTransformed[v2].z);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
265
src/geometry.cpp
265
src/geometry.cpp
|
@ -1,6 +1,8 @@
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
|
#include "engine.h"
|
||||||
#include "geometry.h"
|
#include "geometry.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
|
||||||
// MACROS
|
// MACROS
|
||||||
|
@ -10,215 +12,80 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// PRIVATE PROTOTYPES
|
// STRUCTURES
|
||||||
static void FillTriangleFlatBottom(
|
struct BoundingBox
|
||||||
uint32_t *buffer, int width,
|
{
|
||||||
float *zbuffer, uint32_t color,
|
BoundingBox(Point &v0, Point &v1, Point &v2)
|
||||||
float x0, float y0, float z0,
|
{
|
||||||
float x1, float y1, float z1,
|
yMin = MIN(v0.y, MIN(v1.y, v2.y));
|
||||||
float x2, float y2, float z2);
|
yMax = MAX(v0.y, MAX(v1.y, v2.y));
|
||||||
|
|
||||||
static void FillTriangleFlatTop(
|
xMin = MIN(v0.x, MIN(v1.x, v2.x));
|
||||||
uint32_t *buffer, int width,
|
xMax = MAX(v0.x, MAX(v1.x, v2.x));
|
||||||
float *zbuffer, uint32_t color,
|
}
|
||||||
float x0, float y0, float z0,
|
|
||||||
float x1, float y1, float z1,
|
float yMin, yMax;
|
||||||
float x2, float y2, float z2);
|
float xMin, xMax;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void ComputeBarycenter(float *w, Point &v0, Point &v1, Point &v2, Point &p)
|
||||||
|
{
|
||||||
|
float area = (v2.x - v0.x) * (v1.y - v0.y) - (v2.y - v0.y) * (v1.x - v0.x);
|
||||||
|
|
||||||
|
float result[3];
|
||||||
|
result[0] = (p.x - v1.x) * (v2.y - v1.y) - (p.y - v1.y) * (v2.x - v1.x);
|
||||||
|
result[1] = (p.x - v2.x) * (v0.y - v2.y) - (p.y - v2.y) * (v0.x - v2.x);
|
||||||
|
result[2] = (p.x - v0.x) * (v1.y - v0.y) - (p.y - v0.y) * (v1.x - v0.x);
|
||||||
|
|
||||||
|
result[0] /= area;
|
||||||
|
result[1] /= area;
|
||||||
|
result[2] /= area;
|
||||||
|
|
||||||
|
w[0] = result[0];
|
||||||
|
w[1] = result[1];
|
||||||
|
w[2] = result[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// PUBLIC FUNCTIONS
|
// PUBLIC FUNCTIONS
|
||||||
void FillTriangle(
|
void FillTriangle(
|
||||||
uint32_t *buffer, int width,
|
Engine_Buffer &buffer, ColorU32 &color,
|
||||||
float *zbuffer, uint32_t color,
|
Point &v0, Point &v1, Point &v2)
|
||||||
float x0, float y0, float z0,
|
|
||||||
float x1, float y1, float z1,
|
|
||||||
float x2, float y2, float z2)
|
|
||||||
{
|
{
|
||||||
// Horizontal or vertical
|
BoundingBox box(v0, v1, v2);
|
||||||
if ((FLOAT_EQUAL(x0,x1) && FLOAT_EQUAL(x1, x2))
|
int yMin = (int)ceilf(box.yMin);
|
||||||
|| (FLOAT_EQUAL(y0, y1) && FLOAT_EQUAL(y1, y2)))
|
int yMax = (int)ceilf(box.yMax) - 1;
|
||||||
|
int xMin = (int)ceilf(box.xMin);
|
||||||
|
int xMax = (int)ceilf(box.xMax) - 1;
|
||||||
|
|
||||||
|
for (int y = yMin; y <= yMax; ++y)
|
||||||
{
|
{
|
||||||
return;
|
for (int x = xMin; x <= xMax; ++x)
|
||||||
|
{
|
||||||
|
Point p(x, y, 1.0f);
|
||||||
|
|
||||||
|
float barycenter[3];
|
||||||
|
|
||||||
|
ComputeBarycenter(barycenter, v0, v1, v2, p);
|
||||||
|
|
||||||
|
if (barycenter[0] >= 0 && barycenter[1] >= 0 && barycenter[2] >= 0)
|
||||||
|
{
|
||||||
|
float zInv =
|
||||||
|
(barycenter[0] * (1.0f/v0.z))
|
||||||
|
+ (barycenter[1] * (1.0f/v1.z))
|
||||||
|
+ (barycenter[2] * (1.0f/v2.z));
|
||||||
|
|
||||||
|
int pixel = (y * buffer.width + x);
|
||||||
|
|
||||||
|
if (zInv > buffer.zbuffer[pixel])
|
||||||
|
{
|
||||||
|
DrawPixel(buffer.buffer, buffer.width, color.u32, x, y);
|
||||||
|
|
||||||
|
buffer.zbuffer[pixel] = zInv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort in ascending Y order
|
|
||||||
float temp;
|
|
||||||
if (y0 > y1)
|
|
||||||
{
|
|
||||||
SWAP(x0, x1, temp);
|
|
||||||
SWAP(y0, y1, temp);
|
|
||||||
SWAP(z0, z1, temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y0 > y2)
|
|
||||||
{
|
|
||||||
SWAP(x0, x2, temp);
|
|
||||||
SWAP(y0, y2, temp);
|
|
||||||
SWAP(z0, z2, temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y1 > y2)
|
|
||||||
{
|
|
||||||
SWAP(x1, x2, temp);
|
|
||||||
SWAP(y1, y2, temp);
|
|
||||||
SWAP(z1, z2, temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Flat top triangle
|
|
||||||
if (FLOAT_EQUAL(y0, y1))
|
|
||||||
{
|
|
||||||
FillTriangleFlatTop(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x2, y2, z2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flat bottom triangle
|
|
||||||
else if (FLOAT_EQUAL(y1, y2))
|
|
||||||
{
|
|
||||||
FillTriangleFlatBottom(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x2, y2, z2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other - decompose into two triangles
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Calculate x coordinate at point of decomposition using intercept theorem
|
|
||||||
// New y is the same as y1
|
|
||||||
float x3 = x0 + (((y1 - y0) / (y2 - y0)) * (x2 - x0));
|
|
||||||
float y3 = y1;
|
|
||||||
float z3 = z1;
|
|
||||||
|
|
||||||
FillTriangleFlatBottom(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x3, y3, z3);
|
|
||||||
FillTriangleFlatTop(buffer, width, zbuffer, color, x1, y1, z1, x3, y3, z3, x2, y2, z2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// PRIVATE FUNCTIONS
|
|
||||||
static void FillTriangleFlatBottom(
|
|
||||||
uint32_t *buffer, int width,
|
|
||||||
float *zbuffer, uint32_t color,
|
|
||||||
float x0, float y0, float z0,
|
|
||||||
float x1, float y1, float z1,
|
|
||||||
float x2, float y2, float z2)
|
|
||||||
{
|
|
||||||
if (x2 < x1)
|
|
||||||
{
|
|
||||||
float temp;
|
|
||||||
SWAP(x2, x1, temp);
|
|
||||||
SWAP(y2, y1, temp);
|
|
||||||
SWAP(z2, z1, temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top-left fill convention
|
|
||||||
float dxdy_left = (x1 - x0) / (y1 - y0);
|
|
||||||
float dxdy_right = (x2 - x0) / (y2 - y0);
|
|
||||||
int yStart = (int)ceilf(y0);
|
|
||||||
int yEnd = (int)ceilf(y2) - 1;
|
|
||||||
float xStart = x0 + dxdy_left * (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
|
|
||||||
for (int y = yStart; y <= yEnd; ++y)
|
|
||||||
{
|
|
||||||
float dzdx = (zEnd - zStart) / (xEnd - xStart);
|
|
||||||
float z = zStart;
|
|
||||||
|
|
||||||
int xStartInt = (int)xStart;
|
|
||||||
int xEndInt = (int)xEnd;
|
|
||||||
|
|
||||||
for (int x = xStartInt; x <= xEndInt; ++x)
|
|
||||||
{
|
|
||||||
int pixel = (y * width) + x;
|
|
||||||
|
|
||||||
if (z > zbuffer[pixel])
|
|
||||||
{
|
|
||||||
DrawPixel(buffer, width, color, x, y);
|
|
||||||
|
|
||||||
zbuffer[pixel] = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
z += dzdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
xStart += dxdy_left;
|
|
||||||
xEnd += dxdy_right;
|
|
||||||
|
|
||||||
zStart += dzdy_left;
|
|
||||||
zEnd += dzdy_right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FillTriangleFlatTop(
|
|
||||||
uint32_t *buffer, int width,
|
|
||||||
float *zbuffer, uint32_t color,
|
|
||||||
float x0, float y0, float z0,
|
|
||||||
float x1, float y1, float z1,
|
|
||||||
float x2, float y2, float z2)
|
|
||||||
{
|
|
||||||
if (x1 < x0)
|
|
||||||
{
|
|
||||||
float temp;
|
|
||||||
SWAP(x1, x0, temp);
|
|
||||||
SWAP(y1, y0, temp);
|
|
||||||
SWAP(z1, z0, temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top-left fill convention
|
|
||||||
float dxdy_left = (x2 - x0) / (y2 - y0);
|
|
||||||
float dxdy_right = (x2 - x1) / (y2 - y1);
|
|
||||||
int yStart = (int)ceilf(y0);
|
|
||||||
int yEnd = (int)ceilf(y2) - 1;
|
|
||||||
float xStart = x0 + dxdy_left * (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
|
|
||||||
for (int y = yStart; y <= yEnd; ++y)
|
|
||||||
{
|
|
||||||
float dzdx = (zEnd - zStart) / (xEnd - xStart);
|
|
||||||
float z = zStart;
|
|
||||||
|
|
||||||
int xStartInt = (int)xStart;
|
|
||||||
int xEndInt = (int)xEnd;
|
|
||||||
|
|
||||||
for (int x = xStartInt; x <= xEndInt; ++x)
|
|
||||||
{
|
|
||||||
int pixel = (y * width) + x;
|
|
||||||
|
|
||||||
if (z > zbuffer[pixel])
|
|
||||||
{
|
|
||||||
DrawPixel(buffer, width, color, x, y);
|
|
||||||
|
|
||||||
zbuffer[pixel] = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
z += dzdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
xStart += dxdy_left;
|
|
||||||
xEnd += dxdy_right;
|
|
||||||
|
|
||||||
zStart += dzdy_left;
|
|
||||||
zEnd += dzdy_right;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue