games101-hw/02/代码框架/rasterizer.cpp

243 lines
7.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// clang-format off
//
// Created by goksu on 4/6/19.
//
#include <algorithm>
#include <vector>
#include "rasterizer.hpp"
#include <opencv2/opencv.hpp>
#include <math.h>
rst::pos_buf_id rst::rasterizer::load_positions(const std::vector<Eigen::Vector3f> &positions)
{
auto id = get_next_id();
pos_buf.emplace(id, positions);
return {id};
}
rst::ind_buf_id rst::rasterizer::load_indices(const std::vector<Eigen::Vector3i> &indices)
{
auto id = get_next_id();
ind_buf.emplace(id, indices);
return {id};
}
rst::col_buf_id rst::rasterizer::load_colors(const std::vector<Eigen::Vector3f> &cols)
{
auto id = get_next_id();
col_buf.emplace(id, cols);
return {id};
}
auto to_vec4(const Eigen::Vector3f& v3, float w = 1.0f)
{
return Vector4f(v3.x(), v3.y(), v3.z(), w);
}
static bool insideTriangle(int x, int y, const Vector3f* _v)
{
//side vector
Eigen::Vector2f side1;
side1 << _v[0].x()-_v[1].x(),_v[0].y()-_v[1].y();
Eigen::Vector2f side2;
side2 << _v[2].x()-_v[0].x(),_v[2].y()-_v[0].y();
Eigen::Vector2f side3;
side3 << _v[1].x()-_v[2].x(),_v[1].y()-_v[2].y();
//vector between testPoint and vertex of triangle
Eigen::Vector2f po1;
po1 << x-_v[0].x(),y-_v[0].y();
Eigen::Vector2f po2;
po2 << x-_v[1].x(),y-_v[1].y();
Eigen::Vector2f po3;
po3 << x-_v[2].x(),y-_v[2].y();
//cross product
float z1 = side1.x()*po1.y()-side1.y()*po1.x();
float z2 = side2.x()*po2.y()-side2.y()*po2.x();
float z3 = side3.x()*po3.y()-side3.y()*po3.x();
//if they have the same character,the point is inside the triangle
if((z1<0 && z2<0 && z3<0 )||(z1>0 && z2>0 && z3>0))
{
return true;
}
else
{
return false;
}
// TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
}
static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector3f* v)
{
float c1 = (x*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*y + v[1].x()*v[2].y() - v[2].x()*v[1].y()) / (v[0].x()*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*v[0].y() + v[1].x()*v[2].y() - v[2].x()*v[1].y());
float c2 = (x*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*y + v[2].x()*v[0].y() - v[0].x()*v[2].y()) / (v[1].x()*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*v[1].y() + v[2].x()*v[0].y() - v[0].x()*v[2].y());
float c3 = (x*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*y + v[0].x()*v[1].y() - v[1].x()*v[0].y()) / (v[2].x()*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*v[2].y() + v[0].x()*v[1].y() - v[1].x()*v[0].y());
return {c1,c2,c3};
}
void rst::rasterizer::draw(pos_buf_id pos_buffer, ind_buf_id ind_buffer, col_buf_id col_buffer, Primitive type)
{
auto& buf = pos_buf[pos_buffer.pos_id];
auto& ind = ind_buf[ind_buffer.ind_id];
auto& col = col_buf[col_buffer.col_id];
float f1 = (50 - 0.1) / 2.0;
float f2 = (50 + 0.1) / 2.0;
Eigen::Matrix4f mvp = projection * view * model;
for (auto& i : ind)
{
Triangle t;
Eigen::Vector4f v[] = {
mvp * to_vec4(buf[i[0]], 1.0f),
mvp * to_vec4(buf[i[1]], 1.0f),
mvp * to_vec4(buf[i[2]], 1.0f)
};
//Homogeneous division
for (auto& vec : v) {
vec /= vec.w();
}
//Viewport transformation
for (auto & vert : v)
{
vert.x() = 0.5*width*(vert.x()+1.0);
vert.y() = 0.5*height*(vert.y()+1.0);
vert.z() = vert.z() * f1 + f2;
}
for (int i = 0; i < 3; ++i)
{
t.setVertex(i, v[i].head<3>());
t.setVertex(i, v[i].head<3>());
t.setVertex(i, v[i].head<3>());
}
auto col_x = col[i[0]];
auto col_y = col[i[1]];
auto col_z = col[i[2]];
t.setColor(0, col_x[0], col_x[1], col_x[2]);
t.setColor(1, col_y[0], col_y[1], col_y[2]);
t.setColor(2, col_z[0], col_z[1], col_z[2]);
rasterize_triangle(t);
}
}
//Screen space rasterization
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();
//bounding box
float max_x= std::max(v[0].x(),std::max(v[1].x(),v[2].x()));
float min_x= std::min(v[0].x(),std::min(v[1].x(),v[2].x()));
float max_y= std::max(v[0].y(),std::max(v[1].y(),v[2].y()));
float min_y= std::min(v[0].y(),std::min(v[1].y(),v[2].y()));
for(int x =min_x;x <= max_x;x++)
{
for(int y = min_y;y <= max_y;y++)
{
if(insideTriangle(x,y,t.v))
{
//以下是计算插值的内容,暂时看不懂,先抄别人博客补全
//最小深度,默认是无穷远
float min_depth = FLT_MAX;
//如果在三角形内部,计算当前深度,得到当前最小深度
auto tup = computeBarycentric2D(x, y, t.v);
float alpha , beta, gamma;
std::tie(alpha, beta, gamma) = tup;
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;
//如果x,y所在点的深度小于z-buffer的深度
if (z_interpolated<depth_buf[get_index(x,y)])
{
//获得最上层应该渲染的颜色
Vector3f color = t.getColor();
Vector3f point;
point << x, y, min_depth;
//更新深度
depth_buf[get_index(x, y)] = z_interpolated;
//更新所在点的颜色
set_pixel(point, color);
}
}
}
}
// 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.
//
//
//
//z_interpolated *= w_reciprocal;
// TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
}
void rst::rasterizer::set_model(const Eigen::Matrix4f& m)
{
model = m;
}
void rst::rasterizer::set_view(const Eigen::Matrix4f& v)
{
view = v;
}
void rst::rasterizer::set_projection(const Eigen::Matrix4f& p)
{
projection = p;
}
void rst::rasterizer::clear(rst::Buffers buff)
{
if ((buff & rst::Buffers::Color) == rst::Buffers::Color)
{
std::fill(frame_buf.begin(), frame_buf.end(), Eigen::Vector3f{0, 0, 0});
}
if ((buff & rst::Buffers::Depth) == rst::Buffers::Depth)
{
std::fill(depth_buf.begin(), depth_buf.end(), std::numeric_limits<float>::infinity());
}
}
rst::rasterizer::rasterizer(int w, int h) : width(w), height(h)
{
frame_buf.resize(w * h);
depth_buf.resize(w * h);
}
int rst::rasterizer::get_index(int x, int y)
{
return (height-1-y)*width + x;
}
void rst::rasterizer::set_pixel(const Eigen::Vector3f& point, const Eigen::Vector3f& color)
{
//old index: auto ind = point.y() + point.x() * width;
auto ind = (height-1-point.y())*width + point.x();
frame_buf[ind] = color;
}
// clang-format on