triangle method written better; implemented bounding box; added wolf head model

This commit is contained in:
CJSatnarine
2025-05-22 20:15:20 -04:00
parent 47ee335fa1
commit c48c45450f
2 changed files with 2352 additions and 62 deletions

2284
obj/wolf_head.obj Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,6 @@
#include "geometry.h"
#include "model.h"
#include "tgaimage.h"
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <time.h>
#include <vector>
using namespace std;
@@ -15,88 +10,99 @@ const TGAColor red = TGAColor(255, 0, 0, 255);
const TGAColor purple = TGAColor(150, 47, 254, 255);
const int windowHeight = 800;
const int windowWidth = 800;
Model *model = NULL;
void line(Vec2i t0, Vec2i t1, TGAImage &image, TGAColor color) {
bool steep = false;
// if the line is steep, we transpose the image.
if (abs(t0.x - t1.x) < abs(t0.y - t1.y)) {
swap(t0.x, t0.y);
swap(t1.x, t1.y);
steep = true;
}
// Make it left to right.
if (t0.x > t1.x) {
swap(t0.x, t1.x);
swap(t0.y, t1.y);
}
for (int x = t0.x; x <= t1.x; x++) {
float t = (x - t0.x) / (float)(t1.x - t0.x);
int y = t0.y * (1.0 - t) + t1.y * t;
if (steep) {
image.set(y, x, color); // if transposed, de-transpose.
} else {
image.set(x, y, color);
}
}
Vec3f barycentric(Vec2i *pts, Vec2i P) {
Vec3f u = Vec3f(pts[2].x - pts[0].x, pts[1].x - pts[0].x, pts[0].x - P.x) ^
Vec3f(pts[2].y - pts[0].y, pts[1].y - pts[0].y, pts[0].y - P.y);
/*
* if `abs(u[2])` < 1 means `u[2]` is 0,
* that means the triangle is degenerate, in this case return something
* with negative coördinates.
*/
if (abs(u.z) < 1)
return Vec3f(-1, 1, 1);
return Vec3f(1.f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z);
}
void triangle(Vec2i t0, Vec2i t1, Vec2i t2, TGAImage &image, TGAColor colour) {
// Sorting the y-coördinates
void triangle(Vec2i t0, Vec2i t1, Vec2i t2, TGAImage &image, TGAColor color) {
if (t0.y == t1.y && t0.y == t2.y)
return;
if (t0.y > t1.y)
swap(t0, t1);
if (t0.y > t2.y)
swap(t0, t2);
if (t1.y > t2.y)
swap(t1, t2);
// Cut the triangle horizontally to render the bottom half.
int totalHeight = t2.y - t0.y;
for (int y = t0.y; y <= t1.y; y++) {
int segmentHeight = t1.y - t0.y + 1;
float alpha = (float)(y - t0.y) / totalHeight;
float beta = (float)(y - t0.y) / segmentHeight;
int total_height = t2.y - t0.y;
for (int i = 0; i < total_height; i++) {
bool second_half = i > t1.y - t0.y || t1.y == t0.y;
int segment_height = second_half ? t2.y - t1.y : t1.y - t0.y;
float alpha = (float)i / total_height;
float beta =
(float)(i - (second_half ? t1.y - t0.y : 0)) / segment_height;
Vec2i A = t0 + (t2 - t0) * alpha;
Vec2i B = t0 + (t1 - t0) * beta;
Vec2i B = second_half ? t1 + (t2 - t1) * beta : t0 + (t1 - t0) * beta;
if (A.x > B.x)
swap(A, B);
std::swap(A, B);
for (int j = A.x; j <= B.x; j++) {
image.set(j, y, colour);
image.set(j, t0.y + i, color);
}
}
}
// Render the top half.
for (int y = t1.y; y < t2.y; y++) {
int segmentHeight = t2.y - t1.y + 1;
float alpha = (float)(y - t0.y) / totalHeight;
float beta = (float)(y - t1.y) / segmentHeight;
void triangle(Vec2i *pts, TGAImage &image, TGAColor colour) {
Vec2i boundingBoxMinimum(image.get_width() - 1, image.get_height() - 1);
Vec2i boundingBoxMaximum(0, 0);
Vec2i clamp(image.get_width() - 1, image.get_height() - 1);
Vec2i A = t0 + (t2 - t0) * alpha;
Vec2i B = t1 + (t2 - t1) * beta;
for (int i = 0; i < 3; i++) {
boundingBoxMinimum.x = max(0, min(boundingBoxMinimum.x, pts[i].x));
boundingBoxMinimum.y = max(0, min(boundingBoxMinimum.y, pts[i].y));
if (A.x > B.x)
swap(A, B);
for (int j = A.x; j <= B.x; j++) {
image.set(j, y, colour);
boundingBoxMaximum.x =
min(clamp.x, max(boundingBoxMaximum.x, pts[i].x));
boundingBoxMaximum.y =
min(clamp.y, max(boundingBoxMaximum.y, pts[i].y));
}
Vec2i P;
for (P.x = boundingBoxMinimum.y; P.x <= boundingBoxMaximum.x; P.x++) {
for (P.y = boundingBoxMinimum.y; P.y <= boundingBoxMaximum.y; P.y++) {
Vec3f bc_screen = barycentric(pts, P);
if (bc_screen.x < 0 || bc_screen.y < 0 || bc_screen.z < 0)
continue;
image.set(P.x, P.y, colour);
}
}
}
int main(int argc, char **argv) {
TGAImage image(windowWidth, windowHeight, TGAImage::RGB);
Vec2i pts[3] = {Vec2i(30, 30), Vec2i(300, 90), Vec2i(570, 480)};
// triangle(pts, image, purple);
Vec2i t0[3] = {Vec2i(20, 140), Vec2i(100, 320), Vec2i(140, 160)};
Vec2i t1[3] = {Vec2i(360, 100), Vec2i(300, 2), Vec2i(140, 360)};
Vec2i t2[3] = {Vec2i(360, 300), Vec2i(240, 320), Vec2i(260, 360)};
triangle(t0[0], t0[1], t0[2], image, red);
triangle(t1[0], t1[1], t1[2], image, white);
triangle(t2[0], t2[1], t2[2], image, purple);
// Model stuff.
if (2 == argc)
model = new Model(argv[1]);
else
model = new Model("../obj/wolf_head.obj");
for (int i = 0; i < model->nfaces(); i++) {
vector<int> face = model->face(i);
Vec2i screenCoordinates[3];
for (int j = 0; j < 3; j++) {
Vec3f worldCoordinates = model->vert(face[j]);
screenCoordinates[j] =
Vec2i((worldCoordinates.x + 1) * windowWidth / 2.0,
(worldCoordinates.y + 1.0) * windowHeight / 2.0);
}
triangle(screenCoordinates[0], screenCoordinates[1],
screenCoordinates[2], image,
TGAColor(rand() % 255, rand() % 255, rand() % 255, 255));
}
image.flip_vertically();
image.write_tga_file("output.tga");
delete model;
return 0;
}