Skip to content

Commit

Permalink
Assignment2 down.
Browse files Browse the repository at this point in the history
  • Loading branch information
roeas committed Oct 21, 2023
1 parent 84912bd commit 8da5c62
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 70 deletions.
5 changes: 3 additions & 2 deletions Frame/Source/Assignment/Assignment1/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ Eigen::Matrix4f get_projection_matrix(float fov, float aspect, float near, float
0.0f, 0.0f, 0.0f, 1.0f;

Eigen::Matrix4f Morthographic = Mrotate * Mtrans;
Eigen::Matrix4f Mprojection = Morthographic * Mp2o;

return Morthographic * Mp2o;
return Mprojection;
}

Eigen::Matrix4f get_rotation(float angle, Vector3f n)
Expand Down Expand Up @@ -91,7 +92,7 @@ Eigen::Matrix4f get_rotation(float angle, Vector3f n)
return ret;
}

int main(int argc, const char **argv)
int main()
{
float angle = 0.0f;
rst::rasterizer r(700, 700);
Expand Down
111 changes: 54 additions & 57 deletions Frame/Source/Assignment/Assignment2/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,56 +28,71 @@ Eigen::Matrix4f get_model_matrix(float rotation_angle)
return model;
}

Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar)
Eigen::Matrix4f get_projection_matrix(float fov, float aspect, float near, float far)
{
// TODO: Copy-paste your implementation from the previous assignment.
Eigen::Matrix4f projection;

return projection;
// 由 frustum 的定义得 top 与 right
float top = std::tan(fov * 0.5f * MY_PI / 180.0f) * std::abs(near);
float right = aspect * top;
// 由相机此时的位置方向得 bottom = -top 与 left = -right
float bottom = -top;
float left = -right;

Eigen::Matrix4f Mp2o;
Mp2o <<
near, 0.0f, 0.0f, 0.0f,
0.0f, near, 0.0f, 0.0f,
0.0f, 0.0f, near + far, -near * far,
0.0f, 0.0f, 1.0f, 0.0f;

Eigen::Matrix4f Mtrans;
Mtrans <<
1.0f, 0.0f, 0.0f, (right + left) * -0.5f,
0.0f, 1.0f, 0.0f, (top + bottom) * -0.5f,
0.0f, 0.0f, 1.0f, (near + far) * -0.5f,
0.0f, 0.0f, 0.0f, 1.0f;

Eigen::Matrix4f Mrotate;
Mrotate <<
2.0f / (right - left), 0.0f, 0.0f, 0.0f,
0.0f, 2.0f / (top - bottom), 0.0f, 0.0f,
0.0f, 0.0f, 2.0f / (near - far), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f;

Eigen::Matrix4f Morthographic = Mrotate * Mtrans;
Eigen::Matrix4f Mprojection = Morthographic * Mp2o;

return Mprojection;
}

int main(int argc, const char** argv)
int main()
{
float angle = 0;
bool command_line = false;
std::string filename = "output.png";

if (argc == 2)
{
command_line = true;
filename = std::string(argv[1]);
}

rst::rasterizer r(700, 700);

Eigen::Vector3f eye_pos = {0,0,5};


std::vector<Eigen::Vector3f> pos
{
{2, 0, -2},
{0, 2, -2},
{-2, 0, -2},
{3.5, -1, -5},
{2.5, 1.5, -5},
{-1, 0.5, -5}
};

{
{2, 0, -2},
{0, 2, -2},
{-2, 0, -2},
{3.5, -1, -5},
{2.5, 1.5, -5},
{-1, 0.5, -5}
};
std::vector<Eigen::Vector3i> ind
{
{0, 1, 2},
{3, 4, 5}
};

{
{0, 1, 2},
{3, 4, 5}
};
std::vector<Eigen::Vector3f> cols
{
{217.0, 238.0, 185.0},
{217.0, 238.0, 185.0},
{217.0, 238.0, 185.0},
{185.0, 217.0, 238.0},
{185.0, 217.0, 238.0},
{185.0, 217.0, 238.0}
};
{
{217.0, 238.0, 185.0},
{217.0, 238.0, 185.0},
{217.0, 238.0, 185.0},
{185.0, 217.0, 238.0},
{185.0, 217.0, 238.0},
{185.0, 217.0, 238.0}
};

auto pos_id = r.load_positions(pos);
auto ind_id = r.load_indices(ind);
Expand All @@ -86,24 +101,6 @@ int main(int argc, const char** argv)
int key = 0;
int frame_count = 0;

if (command_line)
{
r.clear(rst::Buffers::Color | rst::Buffers::Depth);

r.set_model(get_model_matrix(angle));
r.set_view(get_view_matrix(eye_pos));
r.set_projection(get_projection_matrix(45, 1, 0.1, 50));

r.draw(pos_id, ind_id, col_id, rst::Primitive::Triangle);
cv::Mat image(700, 700, CV_32FC3, r.frame_buffer().data());
image.convertTo(image, CV_8UC3, 1.0f);
cv::cvtColor(image, image, cv::COLOR_RGB2BGR);

cv::imwrite(filename, image);

return 0;
}

while(key != 27)
{
r.clear(rst::Buffers::Color | rst::Buffers::Depth);
Expand Down
102 changes: 91 additions & 11 deletions Frame/Source/Assignment/Assignment2/rasterizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,27 @@ auto to_vec4(const Eigen::Vector3f& v3, float w = 1.0f)
}


static bool insideTriangle(int x, int y, const Vector3f* _v)
static bool insideTriangle(float x, float y, const Vector3f* v)
{
// TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
// 此时位于屏幕空间,保证 z 分量一致即可
Eigen::Vector3f point = { x, y, 0.0f };
Eigen::Vector3f vertex_a = { v[0].x(), v[0].y(), 0.0f };
Eigen::Vector3f vertex_b = { v[1].x(), v[1].y(), 0.0f };
Eigen::Vector3f vertex_c = { v[2].x(), v[2].y(), 0.0f };

Eigen::Vector3f vector_ab = vertex_b - vertex_a;
Eigen::Vector3f vector_bc = vertex_c - vertex_b;
Eigen::Vector3f vector_ca = vertex_a - vertex_c;
Eigen::Vector3f vector_ap = point - vertex_a;
Eigen::Vector3f vector_bp = point - vertex_b;
Eigen::Vector3f vector_cp = point - vertex_c;

float crossz1 = vector_ab.cross(vector_ap).z();
float crossz2 = vector_bc.cross(vector_bp).z();
float crossz3 = vector_ca.cross(vector_cp).z();

return (crossz1 <= 0.0f && crossz2 <= 0.0f && crossz3 <= 0.0f) ||
(crossz1 >= 0.0f && crossz2 >= 0.0f && crossz3 >= 0.0f);
}

static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector3f* v)
Expand Down Expand Up @@ -106,16 +124,78 @@ void rst::rasterizer::draw(pos_buf_id pos_buffer, ind_buf_id ind_buffer, col_buf
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();

// TODO : Find out the bounding box of current triangle.
// iterate through the pixel and find if the current pixel is inside the triangle

// If so, use the following code to get the interpolated z value.
//auto[alpha, beta, gamma] = computeBarycentric2D(x, y, t.v);
//float w_reciprocal = 1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
//float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
//z_interpolated *= w_reciprocal;
// AABB 应当由整数的像素下标索引定义
uint16_t min_x = std::numeric_limits<uint16_t>::max();
uint16_t max_x = std::numeric_limits<uint16_t>::min();
uint16_t min_y = std::numeric_limits<uint16_t>::max();
uint16_t max_y = std::numeric_limits<uint16_t>::min();
for (size_t i = 0; i < 3; ++i)
{
min_x = std::min(static_cast<uint16_t>(std::floor(v[i].x())), min_x);
max_x = std::max(static_cast<uint16_t>(std::ceil(v[i].x())), max_x);
min_y = std::min(static_cast<uint16_t>(std::floor(v[i].y())), min_y);
max_y = std::max(static_cast<uint16_t>(std::ceil(v[i].y())), max_y);
}

// TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
for (uint16_t pos_x = min_x; pos_x <= max_x; ++pos_x)
{
for (uint16_t pos_y = min_y; pos_y <= max_y; ++pos_y)
{
size_t index = static_cast<size_t>(get_index(static_cast<int>(pos_x), static_cast<int>(pos_y)));
float &depth = depth_buf[index];

// SSAA 所采样的四个子像素相对于像素左下角坐标的偏移量
static const std::vector<Eigen::Vector2f> s_offsets = { {0.25f, 0.25f}, {0.75f, 0.25f}, {0.25f, 0.75f}, {0.75f, 0.75f} };
constexpr uint8_t SubPixelCount = 4;
assert(s_offsets.size() == SubPixelCount);

// 用于计算子像素贡献值
uint8_t activeColor = 0;
uint8_t activeDepth = 0;
Eigen::Vector3f finalColor = { 0.0f, 0.0f , 0.0f };
float finalDepth = 0.0f;

for (const auto& offset : s_offsets)
{
float subPos_x = static_cast<float>(pos_x) + offset.x();
float subPos_y = static_cast<float>(pos_y) + offset.y();

// 获取子像素的深度插值
auto [alpha, beta, gamma] = computeBarycentric2D(subPos_x, subPos_y, t.v);
float w_reciprocal = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
z_interpolated *= w_reciprocal;

if (insideTriangle(subPos_x, subPos_y, t.v))
{
if (z_interpolated < depth)
{
// 只有同时通过了 inside 测试与深度测试才会对颜色有贡献
++activeColor;
finalColor += t.getColor();
}
// 只要通过 inside 测试就会对深度有贡献
++activeDepth;
finalDepth += z_interpolated;
}
}

finalColor /= static_cast<float>(activeColor);
finalDepth /= static_cast<float>(activeDepth);

// 没有通过测试的子像素依旧应当对颜色与深度产生贡献,
// 按理来说其值应从 frame_buf_ssaax4 与 depth_buf_ssaax4 中获取。
// 鉴于框架本身较为简陋,这里意思到位即可,没有必要魔改框架增加理解难度。
// finalColor += static_cast<float>(SubPixelCount - activeColor) / static_cast<float>(SubPixelCount) * frame_buf_ssaax4[subIndex];
// finalDepth += static_cast<float>(SubPixelCount - activeDepth) / static_cast<float>(SubPixelCount) * depth_buf_ssaax4[subIndex];

if (finalDepth < depth)
{
depth = finalDepth;
set_pixel(Eigen::Vector3f{ static_cast<float>(pos_x), static_cast<float>(pos_y), finalDepth }, finalColor);
}
}
}
}

void rst::rasterizer::set_model(const Eigen::Matrix4f& m)
Expand Down

0 comments on commit 8da5c62

Please sign in to comment.