Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions src/color_space.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@ ColorSpace::~ColorSpace()

void ColorSpace::DrawScene()
{


for (unsigned short x = 0; x < width; x++) {
for (unsigned short y = 0; y < height; y++) {
SetPixel(x, y, color{
static_cast<unsigned char>(y * 255. / height),
static_cast<unsigned char>(x * 255. / width),
0
});
}
}
}

void ColorSpace::SetPixel(unsigned short x, unsigned short y, color color)
{

void ColorSpace::SetPixel(unsigned short x, unsigned short y, color color) {
auto ind = x + y * width;
if (ind >= 0 && ind < frame_buffer.size())
frame_buffer[ind] = color;
}

63 changes: 57 additions & 6 deletions src/draw_line.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,69 @@ LineDrawing::LineDrawing(unsigned short width, unsigned short height): ColorSpac

}

LineDrawing::~LineDrawing()
{
LineDrawing::~LineDrawing() {
}

void LineDrawing::DrawLine(unsigned short x_begin, unsigned short y_begin, unsigned short x_end, unsigned short y_end, color color)
{
template<typename T>
int sign(T x) {
if (x < 0) return -1;
if (x > 0) return 1;
return 0;
}

void LineDrawing::DrawLine(unsigned short x_begin, unsigned short y_begin, unsigned short x_end, unsigned short y_end,
color color) {
bool rotate = abs(x_end - x_begin) < abs(y_begin - y_end);

if (rotate) {
std::swap(x_begin, y_begin);
std::swap(x_end, y_end);
}

if (x_end < x_begin) {
std::swap(x_begin, x_end);
std::swap(y_begin, y_end);
}


auto deltax = static_cast<float>(x_end - x_begin);
auto deltay = static_cast<float>(y_end - y_begin);
float deltaerr = abs(deltay / deltax);
float error = 0.0;
int y = y_begin;
for (auto x = x_begin; x <= x_end; x++) {
if (rotate)
SetPixel(y, x, color);
else
SetPixel(x, y, color);
error += deltaerr;
if (error >= 0.5) {
y += sign(deltay);
error -= 1.f;
}
}
}

void LineDrawing::DrawScene()
{
void LineDrawing::DrawScene() {

for (auto angle = 0; angle < 360; angle += 5) {
int radius = std::min(width, height) / 2 - 40;

int x_center = width / 2;
int y_center = height / 2;

auto x_end = static_cast<int>(cos(angle * M_PI / 180.) * radius + x_center);
auto y_end = static_cast<int>(sin(angle * M_PI / 180.) * radius + y_center);

DrawLine(static_cast<unsigned short>(x_center),
static_cast<unsigned short>(y_center),
static_cast<unsigned short>(x_end),
static_cast<unsigned short>(y_end),
color{
static_cast<unsigned char>(255 * sin(angle * M_PI / 180.0)),
static_cast<unsigned char>(255 * cos(angle * M_PI / 180.0)),
255
});
}
}

83 changes: 81 additions & 2 deletions src/projection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,88 @@ Projection::~Projection()
{
}

void Projection::DrawScene()
{
void Projection::DrawScene() {
parser->Parse();
auto faces = parser->GetFaces();


float3 eye = {0, 0, 2};
float3 at{0, 0, 0};
float3 up{0, 1, 0};

for (auto &f: project(faces, getWorld(), getView(eye, at, up), getProjection())) {
DrawTriangle(f);
}
}

float4x4 Projection::getProjection() {
float radius = static_cast<float>(std::min(width, height) / 2);
float zf = 100;
float zn = 1;
float fov_coef = 1 / 0.8;

return {
{radius / fov_coef, 0, 0, 0},
{0, radius / fov_coef, 0, 0},
{0, 0, (zf + zn) / (zf - zn), zf * zn / (zn - zf)},
{0, 0, -1, 0}
};
}

float4x4 Projection::getView(float3 eye, float3 at, float3 up) {
float3 z = linalg::normalize(eye - at);
float3 x = linalg::normalize(linalg::cross(up, z));
float3 y = linalg::cross(z, x);

return linalg::transpose(float4x4{
{x, -linalg::dot(x, eye)},
{y, -linalg::dot(y, eye)},
{z, -linalg::dot(z, eye)},
{0, 0, 0, 1}
});
}

float4x4 Projection::getWorld() {
return linalg::identity_t(4);
}

std::vector<face> Projection::project(std::vector<face> &faces, float4x4 world, float4x4 view, float4x4 projection) {
std::vector<face> proj;

auto transform = mul(projection, view, world);
for (auto f: faces) {
float4 v[3];

for (int i = 0; i < 3; i++) {
v[i] = mul(transform, f.vertexes[i]);
}
proj.emplace_back();
std::copy_n(v, 3, proj.back().vertexes);
}

return proj;
}

void Projection::DrawTriangle(face f) {
linalg::vec<unsigned short, 2> center{static_cast<uint16_t>(width/2), static_cast<uint16_t>(height/2)};


DrawLine(center.x + f.vertexes[0].x / f.vertexes[0].w,
center.y + f.vertexes[0].y / f.vertexes[0].w,
center.x + f.vertexes[1].x / f.vertexes[1].w,
center.y + f.vertexes[1].y / f.vertexes[1].w,
color{255, 0, 0});

DrawLine(center.x + f.vertexes[1].x / f.vertexes[1].w,
center.y + f.vertexes[1].y / f.vertexes[1].w,
center.x + f.vertexes[2].x / f.vertexes[2].w,
center.y + f.vertexes[2].y / f.vertexes[2].w,
color{0, 255, 0});

DrawLine(center.x + f.vertexes[2].x / f.vertexes[2].w,
center.y + f.vertexes[2].y / f.vertexes[2].w,
center.x + f.vertexes[0].x / f.vertexes[0].w,
center.y + f.vertexes[0].y / f.vertexes[0].w,
color{0, 0, 255});

}
8 changes: 8 additions & 0 deletions src/projection.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,12 @@ class Projection: public ReadObj

void DrawScene();

protected:
virtual float4x4 getWorld();
virtual float4x4 getView(float3 eye, float3 at, float3 up);
virtual float4x4 getProjection();
virtual std::vector<face> project(std::vector<face> &faces, float4x4 world, float4x4 view, float4x4 projection);

private:
void DrawTriangle(face f);
};
90 changes: 80 additions & 10 deletions src/read_obj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,55 @@ ObjParser::~ObjParser()

int ObjParser::Parse()
{

return 0;
std::ifstream file(filename, std::ifstream::in);

if (file.fail())
return -1;

std::string line;
while (std::getline(file, line)) {
if (line.rfind("v ", 0) == 0) {
auto tokens = Split(line, ' ');

float4 ver{0, 0, 0, 1};
for (auto i = 1; i < tokens.size(); i++) {
if (!tokens[i].empty()) {
float v = std::stof(tokens[i]);
ver[i - 1] = v;
}
}
vertexes.push_back(ver);
} else if (line.rfind("f ", 0) == 0) {
auto tokens = Split(line, ' ');

float4 first;
auto ind0 = std::stoi(Split(tokens[1], '/')[0]);
first = vertexes[vertexes.size() + ind0];

float4 last;
bool was = false;
float4 curr;

for (auto i = 2; i < tokens.size(); i++) {
if (!tokens[i].empty()) {
auto ind = std::stoi(Split(tokens[i], '/')[0]);

curr = vertexes[vertexes.size() + ind];

if (was) {
faces.emplace_back<face>({
first, last, curr
});
}
last = curr;
was = true;
}
}

}
}

return 0;
}

const std::vector<face>& ObjParser::GetFaces()
Expand All @@ -42,18 +89,41 @@ std::vector<std::string> ObjParser::Split(const std::string& s, char delimiter)
}


ReadObj::ReadObj(unsigned short width, unsigned short height, std::string obj_file): LineDrawing(width, height)
{
parser = new ObjParser(obj_file);
ReadObj::ReadObj(unsigned short width, unsigned short height, std::string obj_file) : LineDrawing(width, height) {
parser = new ObjParser(obj_file);
}

ReadObj::~ReadObj()
{
delete parser;
ReadObj::~ReadObj() {
delete parser;
}

void ReadObj::DrawScene()
{
void ReadObj::DrawTriangle(face const &f, color c) {
auto x_center = width / 2;
auto y_center = height / 2;
auto radius = std::min(width, height) / 2;

float4 vertices[3];

for (int i = 0; i < 3; i++) {
vertices[i] = float4{
f.vertexes[i].x * radius + x_center,
f.vertexes[i].y * radius + y_center,
0,
1
};
}

DrawLine(vertices[0].x, vertices[0].y, vertices[1].x, vertices[1].y, color{255, 0, 0});
DrawLine(vertices[0].x, vertices[0].y, vertices[2].x, vertices[2].y, color{0, 0, 255});
DrawLine(vertices[2].x, vertices[2].y, vertices[1].x, vertices[1].y, color{0, 255, 0});
}

void ReadObj::DrawScene() {
parser->Parse();
auto faces = parser->GetFaces();

for (auto const &f: faces) {
DrawTriangle(f, color{255, 255, 255});
}
}

2 changes: 2 additions & 0 deletions src/read_obj.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ class ReadObj: public LineDrawing

protected:
ObjParser* parser;

void DrawTriangle(face const &f, color c);
};
62 changes: 59 additions & 3 deletions src/triangle_rasterization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,72 @@ TriangleRasterization::~TriangleRasterization()

void TriangleRasterization::DrawScene()
{
parser->Parse();
auto faces = parser->GetFaces();

float2 center = {float(width) / 2, float(height) / 2};

float3 eye = {0, 0, 2};
float3 at{0, 0, 0};
float3 up{0, 1, 0};
auto proj = project(faces, getWorld(), getView(eye, at, up), getProjection());

for (auto &f: proj) {

float2 triangle[3];
for (int i = 0; i < 3; i++) {
triangle[i] = f.vertexes[i].xy() / f.vertexes[i].w + center;
}

DrawTriangle(triangle);
}

for (auto &f: proj) {

float2 triangle[3];
for (int i = 0; i < 3; i++) {
triangle[i] = f.vertexes[i].xy() / f.vertexes[i].w + center;
}
DrawLine(triangle[0].x, triangle[0].y, triangle[1].x, triangle[1].y, color{255, 255, 255});
DrawLine(triangle[1].x, triangle[1].y, triangle[2].x, triangle[2].y, color{255, 255, 255});
DrawLine(triangle[2].x, triangle[2].y, triangle[0].x, triangle[0].y, color{255, 255, 255});
}
}

void TriangleRasterization::DrawTriangle(float4 triangle[3])
{

void TriangleRasterization::DrawTriangle(float2 triangle[3]) {
float2 begin{
std::min(triangle[0].x, std::min(triangle[1].x, triangle[2].x)),
std::min(triangle[0].y, std::min(triangle[1].y, triangle[2].y))
};
float2 end{
std::max(triangle[0].x, std::max(triangle[1].x, triangle[2].x)),
std::max(triangle[0].y, std::max(triangle[1].y, triangle[2].y))
};

auto ef = EdgeFunction(triangle[0], triangle[1], triangle[2]);

for (int x = begin.x; x < int(ceil(end.x)); x++) {
for (int y = begin.y; y < int(ceil(end.y)); y++) {
auto ef01 = EdgeFunction({ static_cast<float>(x), static_cast<float>(y)}, triangle[0], triangle[1]);
auto ef12 = EdgeFunction({static_cast<float>(x), static_cast<float>(y)}, triangle[1], triangle[2]);
auto ef20 = EdgeFunction({ static_cast<float>(x), static_cast<float>(y)}, triangle[2], triangle[0]);

auto w0 = std::abs(ef12 / ef);
auto w1 = std::abs(ef20 / ef);
auto w2 = std::abs(ef01 / ef);

if ((ef01 >= 0 && ef12 >= 0 && ef20 >= 0) || (ef01 <= 0 && ef12 <= 0 && ef20 <= 0)) {
SetPixel(x, y, color{
255, 0, 0
});
}
}
}
}

float TriangleRasterization::EdgeFunction(float2 a, float2 b, float2 c)
{
return (a.x - b.x) * (c.y - b.y) - (a.y - b.y) * (c.x - b.x);
}


Loading