~zjm/Moon3D

83b356e95461222db669c1436df9bfc2d24d441f — Zack Michener 4 months ago 86746c0
fix mysterious floating point bug
M src/3d/3d.c => src/3d/3d.c +1 -1
@@ 82,7 82,7 @@ Plane Pl(Vertex ref, Vector normal)

void PrintVec(Vector vec)
{
	printf("[ %+.10e %+.10e %+.10e %+.10e ]\n", vec.x, vec.y, vec.z, vec.w);
	printf("( %+.16e, %+.16e, %+.16e, %+.16e )\n", vec.x, vec.y, vec.z, vec.w);
}

void PrintVolume(Volume V)

M src/3d/clip.c => src/3d/clip.c +16 -0
@@ 90,9 90,25 @@ bool ClipPolygon(Polygon **polygon)
	ClipPolygonPlane(polygon, z_neg);
	ClipPolygonPlane(polygon, z_pos);

	// floating point errors can make some vertices still be out of bounds...
	ConstrainPolygon(*polygon);

	return NumVertices(*polygon) > 0;
}

void ConstrainPolygon(Polygon *polygon)
{
	for (int i = 0; i < NumVertices(polygon); i++) {
		Vertex *v = PolygonVertex(polygon, i);
		if (v->x < -v->w) v->x = -v->w;
		if (v->x > v->w) v->x = v->w;
		if (v->y < -v->w) v->y = -v->w;
		if (v->y > v->w) v->y = v->w;
		if (v->z < -v->w) v->z = -v->w;
		if (v->z > v->w) v->z = v->w;
	}
}

void ClipPolygonPlane(Polygon **polygon, Plane clipBoundary)
/* Sutherland-Hodgeman algorithm */
{

M src/3d/clip.h => src/3d/clip.h +1 -0
@@ 6,6 6,7 @@
bool ClipT(double den, double num, double *tE, double *tL);
bool ClipLine(Vector *v0, Vector *v1);
bool ClipPolygon(Polygon **polygon);
void ConstrainPolygon(Polygon *polygon);
void ClipPolygonPlane(Polygon **polygon, Plane clipBoundary);
bool VertexInside(Vertex *v, Plane clipBoundary);
Vertex ClipIntersect(Vertex *a, Vertex *b, Plane clipBoundary);

M src/3d/model.c => src/3d/model.c +4 -5
@@ 92,10 92,10 @@ int NumVertices(Polygon *polygon)
Vector PolygonNormal(Polygon *polygon)
{
	assert(NumVertices(polygon) >= 3);
	Vertex *a = PolygonVertex(polygon, 0);
	Vertex *b = PolygonVertex(polygon, 1);
	Vertex *c = PolygonVertex(polygon, 2);
	Vector n = NormalizeVector(CrossProd(VecSub(*b, *a), VecSub(*c, *b)));
	Vertex a = Homogenize(*PolygonVertex(polygon, 0));
	Vertex b = Homogenize(*PolygonVertex(polygon, 1));
	Vertex c = Homogenize(*PolygonVertex(polygon, 2));
	Vector n = NormalizeVector(CrossProd(VecSub(b, a), VecSub(c, b)));
	return n;
}



@@ 194,5 194,4 @@ void PrintPolygon(Polygon *polygon)
		v = PolygonVertex(polygon, i);
		PrintVec(*v);
	}
	printf("\n");
}

M src/3d/rasterize.c => src/3d/rasterize.c +0 -1
@@ 119,7 119,6 @@ void RasterLineSteep(Vertex a, Vertex b, uint32_t color)

	for (y = a.y; y < b.y; y++) {
		double z = MapRange(y, a.y, b.y, a.z, b.z);
		// printf("%f\n", z);
		if (UpdateDepthBuffer(x, y, z)) {
			WritePixel(x, y, color);
		}

M src/3d/render.c => src/3d/render.c +0 -3
@@ 74,11 74,8 @@ void DrawMesh(Mesh *mesh, uint32_t color)
void DrawPolygon(Polygon *polygon, uint32_t color)
{
	Polygon *image = ProjectPolygon(polygon);
	printf("-");
	PrintPolygon(image);
	if (ClipPolygon(&image)) {
		if (!BackfaceCulled(image)) {
			PrintPolygon(image);
			HomogenizePolygon(image);
			ViewmapPolygon(image);
			RasterPolygon(image, color);

M src/sketch.c => src/sketch.c +3 -3
@@ 12,7 12,7 @@ Polygon *ground;
Mesh *cube1, *cube2;
int debounce = 0;

int numCubes = 100;
int numCubes = 500;
Mesh **cubes = NULL;

int now, lastTime;


@@ 32,10 32,10 @@ void sketch_setup(uint32_t *pixels)

	SetViewport(pixels, 400, 240);
	// ShowZBuffer();
	ShowWireframes();
	// ShowWireframes();
	SetCamera(V(0, 0, 6));
	LookAt(V(0, 0, 0));
	SetPerspective(60, 1, 1000);
	SetPerspective(60, 1, 100);
	// SetOrtho(Vol(-5, 5, -5, 5, -10, 0.1));

	Transform *xf = RotateX(RotateZ(NewTransform(), 1), 1);

M test/clip.test.c => test/clip.test.c +16 -0
@@ 147,4 147,20 @@ void TestClipPolygon(void)
		AssertWithin(v.z, -1, 1);
	}
	FreePolygon(p);

	p = NewPolygon();
	AddVertex(p, NewVector4D( +2.1238925109378464e+00, +1.7320508075688776e+00, +9.4117255305726744e-01, +1.0587099095862040e+00 ));
	AddVertex(p, NewVector4D( -1.2739654549598711e+00, +1.7320508075688776e+00, +5.5113702891196237e-01, +1.4479661419749759e+00 ));
	AddVertex(p, NewVector4D( -1.2739654549598711e+00, -1.7320508075688776e+00, +5.5113702891196237e-01, +1.4479661419749759e+00 ));
	AddVertex(p, NewVector4D( +2.1238925109378464e+00, -1.7320508075688776e+00, +9.4117255305726744e-01, +1.0587099095862040e+00 ));
	visible = ClipPolygon(&p);
	AssertTrue(visible);
	for (int i = 0; i < NumVertices(p); i++) {
		Vertex v = Homogenize(*PolygonVertex(p, i));
		AssertEqual(v.w, 1);
		AssertWithin(v.x, -1, 1);
		AssertWithin(v.y, -1, 1);
		AssertWithin(v.z, -1, 1);
	}
	FreePolygon(p);
}

M test/endpoint.test.c => test/endpoint.test.c +11 -0
@@ 20,6 20,8 @@ void TestMakeEdgeTable(void)
	AddVertex(p, NewVertex(84.5299454, 115.051285, 0));
	Endpoint **table = MakeEdgeTable(240, p);
	AssertTrue(table);
	FreeEdgeTable(table, 240);
	FreePolygon(p);
}

void TestInsertEndpoints(void)


@@ 50,6 52,9 @@ void TestInsertEndpoints(void)
		InsertEndpoints(&list, table[i]);
		AssertEqual(ListLength(list), 4);
	}

	FreeEdgeTable(table, 240);
	FreePolygon(p);
}

void TestRemoveEndpoints(void)


@@ 72,6 77,9 @@ void TestRemoveEndpoints(void)
	AssertEqual(ListLength(list), 2);
	RemoveEndpoints(&list, 125);
	AssertEqual(ListLength(list), 0);

	FreeEdgeTable(table, 240);
	FreePolygon(p);
}

void TestIncrementEndpoints(void)


@@ 95,4 103,7 @@ void TestIncrementEndpoints(void)
	IncrementEndpoints(&list, 114);
	AssertWithin(list->x, 78, 79);
	AssertWithin(list->next->x, 78, 85);

	FreeEdgeTable(table, 240);
	FreePolygon(p);
}

M test/project.test.c => test/project.test.c +19 -0
@@ 5,6 5,7 @@
#include "../src/3d/project.h"
#include "../src/3d/model.h"
#include "../src/arraylist.h"
#include "../src/3d/clip.h"

void ProjectionTests(void)
{


@@ 71,4 72,22 @@ void TestViewmapPolygon(void)
		AssertTrue(v->y < 240);
	}
	FreePolygon(p);


	p = NewPolygon();
	AddVertex(p, NewVector(0.90350350893137943, 1.7320508075688776, 1.1582046473758254));
	AddVertex(p, NewVector(-2.0841785003064004, 1.7320508075688776, 0.14396012337173758));
	AddVertex(p, NewVector(-2.0841785003064004, -1.7320508075688776, 0.14396012337173758));
	AddVertex(p, NewVector(0.90350350893137943, -1.7320508075688776, 1.1582046473758254));
	ClipPolygon(&p);
	HomogenizePolygon(p);
	ViewmapPolygon(p);
	for (int i = 0; i < NumVertices(p); i++) {
		Vertex *v = PolygonVertex(p, i);
		AssertTrue(v->x >= 0);
		AssertTrue(v->x < 400);
		AssertTrue(v->y >= 0);
		AssertTrue(v->y < 240);
	}
	FreePolygon(p);
}

M test/rasterize.test.c => test/rasterize.test.c +5 -0
@@ 26,6 26,8 @@ void TestRasterLineShallow(void)
	AssertPixel(3, 0, BLACK);
	AssertPixel(4, 0, BLACK);
	AssertPixel(5, 0, WHITE);

	free(pixels);
}

void TestRasterPolygon(void)


@@ 48,4 50,7 @@ void TestRasterPolygon(void)
		AssertPixel(77, y, WHITE);
		AssertPixel(85, y, WHITE);
	}

	free(pixels);
	FreePolygon(p);
}

M test/render.test.c => test/render.test.c +1 -0
@@ 21,6 21,7 @@ void TestSetViewport(void)
			AssertPixel(x, y, WHITE);
		}
	}
	free(pixels);
}

void TestBackfaceCulled(void)

M test/tests.h => test/tests.h +1 -0
@@ 34,6 34,7 @@ void TestDeterminant(void);
void RenderTests(void);
void TestSetViewport(void);
void TestBackfaceCulled(void);
void TestDrawPolygon(void);

void ProjectionTests(void);
void TestPerspectiveProjection(void);