绘制一个可旋转的三角形

model

1
2
3
4
5
6
7
8
9
Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
model<<cos(rotation_angle/180*MY_PI),-sin(rotation_angle/180*MY_PI),0,0,
sin(rotation_angle/180*MY_PI),cos(rotation_angle/180*MY_PI),0,0,
0,0,1,0,
0,0,0,1;
return model;
}

view

1
2
3
4
5
6
7
8
9
10
11
Eigen::Matrix4f get_view_matrix(Eigen::Vector3f eye_pos)
{
Eigen::Matrix4f view = Eigen::Matrix4f::Identity();
Eigen::Matrix4f translate;
translate << 1, 0, 0, -eye_pos[0],
0, 1, 0, -eye_pos[1],
0, 0, 1, -eye_pos[2],
0, 0, 0, 1;
view = translate * view;
return view;
}

projection

透视矩阵正交矩阵:Transformation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar)
{
Eigen::Matrix4f projection;
Eigen::Matrix4f orthotrans1;
Eigen::Matrix4f orthotrans2;
Eigen::Matrix4f persptrans;
float f, n, l, r, b, t, fov;
n = -zNear;
f = -zFar;
t = tan(eye_fov / 2) * abs(n);
b = -t;
r = t * aspect_ratio;
l = -r;
persptrans << n, 0, 0, 0,
0, n, 0, 0,
0, 0, n + f, -n * f,
0, 0, 1, 0;
orthotrans1 << 2 / (r - l), 0, 0, 0,
0, 2 / (t - b), 0, 0,
0, 0, 2 / (n - f), 0,
0, 0, 0, 1;
orthotrans2 << 1, 0, 0, -(r + l) / 2,
0, 1, 0, -(t + b) / 2,
0, 0, 1, -(n + f) / 2,
0, 0, 0, 1;
projection = orthotrans1 * orthotrans2 * persptrans;
return projection;
}

draw

视口变换:Rasterization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void rst::rasterizer::draw(rst::pos_buf_id pos_buffer, rst::ind_buf_id ind_buffer, rst::Primitive type)
{
if (type != rst::Primitive::Triangle)
{
throw std::runtime_error("Drawing primitives other than triangle is not implemented yet!");
}
auto& buf = pos_buf[pos_buffer.pos_id];
auto& ind = ind_buf[ind_buffer.ind_id];

float f1 = (100 - 0.1) / 2.0;
float f2 = (100 + 0.1) / 2.0;

Eigen::Matrix4f mvp = projection * view * model;
for (auto& i : ind)
{
Triangle t;
//三维增加一维w以实现运算 1表示向量 0表示点
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)
};
//w统一成1 x,y,z跟着变换
for (auto& vec : v) {
vec /= vec.w();
}

for (auto & vert : v)
{
//将x,y转换到屏幕上 从[-1,1]转到[0,windowsize]
vert.x() = 0.5*width*(vert.x()+1.0);
vert.y() = 0.5*height*(vert.y()+1.0);
vert.z() = vert.z() * f1 + f2;
}
//取x,y,z舍弃w
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>());
}

t.setColor(0, 255.0, 0.0, 0.0);
t.setColor(1, 0.0 ,255.0, 0.0);
t.setColor(2, 0.0 , 0.0,255.0);

rasterize_wireframe(t);
}
}

rasterize_wirefram

1
2
3
4
5
6
void rst::rasterizer::rasterize_wireframe(const Triangle& t)
{
draw_line(t.c(), t.a());
draw_line(t.c(), t.b());
draw_line(t.b(), t.a());
}

绕任意过原点轴的旋转矩阵

Rodrigues’ rotation formula

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Eigen::Matrix4f get_rotation(Vector3f axis, float angle)
{
Matrix4f rotation = Matrix4f::Identity();
float x = axis.x();
float y = axis.y();
float z = axis.z();
float cosAngle = cos(angle / 180 * MY_PI);
float sinAngle = sin(angle / 180 * MY_PI);
rotation << cosAngle + (1 - cosAngle) * x * x, (1 - cosAngle)* x* y - sinAngle * z, (1 - cosAngle)* x* z + sinAngle * y, 0,
(1 - cosAngle)* x* y + sinAngle * z, cosAngle + (1 - cosAngle) * y * y, (1 - cosAngle)* y* z - sinAngle * x, 0,
(1 - cosAngle)* x* z - sinAngle * y, (1 - cosAngle)* y* z + sinAngle * x, cosAngle + (1 - cosAngle) * z * z, 0,
0, 0, 0, 1;
return rotation;
}

结果

绘制两个有颜色、有重叠的三角形

insideTriangle

判断点在三角形内:Shading

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static bool insideTriangle(int x, int y, const Vector3f* _v)
{
//假设0,1,2对应A,B,C 判断点P
//AB AC AP两两叉乘 看法向量是否是同一方向
Vector3f v[3];
for (int i = 0; i < 3; i++)
v[i] = { _v[i].x(),_v[i].y(), 1.0 };
Vector3f ab = v[1] - v[0];
Vector3f bc = v[2] - v[1];
Vector3f ca = v[0] - v[2];
Vector3f ap = Vector3f(x, y, 1.0) - v[0];
Vector3f bp = Vector3f(x, y, 1.0) - v[1];
Vector3f cp = Vector3f(x, y, 1.0) - v[2];
if (ab.cross(ap).z() > 0 && bc.cross(bp).z() > 0 && ca.cross(cp).z() > 0)
return true;
return false;
}

computeBarycentric2D

重心坐标:Shading

1
2
3
4
5
6
7
8
9
10
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};
}

rasterize_triangle

深度测试:Rasterization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();

int x_min = std::min({ v[0].x(), v[1].x(), v[2].x() });
int x_max = std::max({ v[0].x(), v[1].x(), v[2].x() });
int y_min = std::min({ v[0].y(), v[1].y(), v[2].y() });
int y_max = std::max({ v[0].y(), v[1].y(), v[2].y() });

for (int x = x_min; x <= x_max; x++) {
for (int y = y_min; y <= y_max; y++) {
if (insideTriangle(x, y, t.v)) {
auto [alpha, beta, gamma] = computeBarycentric2D(x, y, t.v);
if (alpha >= 0 && beta >= 0 && gamma >= 0) {
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;

int index = get_index(x, y);
if (z_interpolated < depth_buf[index]) {
depth_buf[index] = z_interpolated;
Eigen::Vector3f point(x, y, 0);
set_pixel(point, t.getColor());
}
}
}
}
}
}

MSAA

MSAA:Rasterization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int rst::rasterizer::MSAA(int x, int y, const Vector3f* _v, int n, int m, float z, Eigen::Vector3f color)
{
//n*m超采样 每个大点细分成n*m小点 对小点深度测试 若可见 则记录小点的color
//返回大点数量
float size_x = 1.0 / n; // the size_x of every super sample pixel
float size_y = 1.0 / m;

int blocksinTriangle = 0;
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j) {
if (z < msaa_depth_buf[get_index(x, y) * 4 + i * 2 + j] && insideTriangle_MSAA(x + i * size_x, y + j * size_y, _v, size_x, size_y)) {
msaa_depth_buf[get_index(x, y) * 4 + i * 2 + j] = z;
msaa_frame_buf[get_index(x, y) * 4 + i * 2 + j] = color;
blocksinTriangle++;
}
}
return blocksinTriangle;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void rst::rasterizer::rasterize_triangle_MSAA(const Triangle& t) {
auto v = t.toVector4();

int x_min = std::min({ v[0].x(), v[1].x(), v[2].x() });
int x_max = std::max({ v[0].x(), v[1].x(), v[2].x() });
int y_min = std::min({ v[0].y(), v[1].y(), v[2].y() });
int y_max = std::max({ v[0].y(), v[1].y(), v[2].y() });

int m = 2;
int n = 2;

for (int x = x_min; x <= x_max; x++) {
for (int y = y_min; y <= y_max; y++) {
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;
int blocksinTriangle = MSAA(x, y, t.v, n, m, z_interpolated, t.getColor());
//点在三角形内
if (blocksinTriangle > 0) {
int idx = get_index(x, y);
//颜色平均
set_pixel(Eigen::Vector3f(x, y, z_interpolated), (msaa_frame_buf[idx * 4] + msaa_frame_buf[idx * 4 + 1] + msaa_frame_buf[idx * 4 + 2] + msaa_frame_buf[idx * 4 + 3]) / 4.0);
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static bool insideTriangle_MSAA(float x, float y, const Vector3f* _v, float size_x, float size_y)
{
//x+0.25是小点中心 用这个判断是否在三角形内
float x_mid = x + size_x / 2.0;
float y_mid = y + size_y / 2.0;

Vector3f v[3];
for (int i = 0; i < 3; i++)
v[i] = { _v[i].x(),_v[i].y(), 1.0 };
Vector3f ab = v[1] - v[0];
Vector3f bc = v[2] - v[1];
Vector3f ca = v[0] - v[2];
Vector3f ap = Vector3f(x_mid, y_mid, 1.0) - v[0];
Vector3f bp = Vector3f(x_mid, y_mid, 1.0) - v[1];
Vector3f cp = Vector3f(x_mid, y_mid, 1.0) - v[2];
if (ab.cross(ap).z() > 0 && bc.cross(bp).z() > 0 && ca.cross(cp).z() > 0)
return true;
return false;
}

结果