1.透视投影变换

投影接口的参数是张角fov,横纵比为aspect时,透视投影的变换矩阵如下:

image-20231203092505302

1
2
3
4
5
6
7
8
9
10
11
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar)
{
Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();
projection(0, 0) = -(1 / (aspect_ratio * tan(eye_fov / 180.0 * MY_PI)));
projection(1, 1) = -(1 / (tan(eye_fov / 180.0 * MY_PI)));
projection(2, 2) = (zNear + zFar) / (zNear - zFar);
projection(2, 3) = (2 * zFar * zNear) / (zNear - zFar);
projection(3, 2) = 1;
projection(3, 3) = 0;
return projection;
}

2.判断点是否在三角形内

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static bool insideTriangle(int x, int y, const Vector4f* _v){
Eigen::Vector2f AB, BC, CA, AP, BP, CP, p;
float a, b, c;//用于保存叉乘的结果(是正还是负)
p << x ,y;
AB = _v[1].head(2) - _v[0].head(2);
AP = p - _v[0].head(2);
BC = _v[2].head(2) - _v[1].head(2);
BP = p - _v[1].head(2);
CA = _v[0].head(2) - _v[2].head(2);
CP = p - _v[2].head(2);
//分别计算叉乘,x,y方向为0,故只计算z方向的结果
a = AB[0] * AP[1] - AB[1] * AP[0];
b = BC[0] * BP[1] - BC[1] * BP[0];
c = CA[0] * CP[1] - CA[1] * CP[0];
if (a > 0 && b > 0 && c > 0)
return true;
else if (a < 0 && b < 0 && c < 0)
return true;
return false;
}

3.光栅化

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
//屏幕空间光栅化
//view_pos:顶点在屏幕空间的坐标
void rst::rasterizer::rasterize_triangle(const Triangle& t, const std::array<Eigen::Vector3f, 3>& view_pos)
{
auto v = t.toVector4();
float x_max = std::max(std::max(v[0].x(), v[1].x()), v[2].x());
float x_min = std::min(std::min(v[0].x(), v[1].x()), v[2].x());
float y_min = std::min(std::min(v[0].y(), v[1].y()), v[2].y());
float y_max = std::max(std::max(v[0].y(), v[1].y()), v[2].y());
for (int i = x_min; i < x_max+1; i++)
{
for (int j = y_min; j < y_max+1; j++)
{
if (insideTriangle(i, j, t.v))
{
//计算当前像素在三角形内的重心坐标
auto [alpha, beta, gamma] = computeBarycentric2D(i, j, t.v);

//通过重心插值得到深度值z_interpolated
//w_reciprocal为透视修正系数
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;

//Z-Buffer
if (depth_buf[get_index(i, j)] > z_interpolated)
{
//利用重心坐标插值颜色、法线、纹理、shadingcoords(像素位置)
auto interpolated_color = interpolate(alpha, beta, gamma, t.color[0], t.color[1], t.color[2], 1);
auto interpolated_normal = interpolate(alpha, beta, gamma, t.normal[0], t.normal[1], t.normal[2], 1);
auto interpolated_texcoords = interpolate(alpha, beta, gamma, t.tex_coords[0], t.tex_coords[1], t.tex_coords[2], 1);
auto interpolated_shadingcoords = interpolate(alpha, beta, gamma, view_pos[0], view_pos[1], view_pos[2], 1);
// 初始化 payload,用于传递给片段着色器
fragment_shader_payload payload(interpolated_color, interpolated_normal.normalized(), interpolated_texcoords, texture ? &*texture : nullptr);
payload.view_pos = interpolated_shadingcoords;

// 更新深度缓存
depth_buf[get_index(i, j)] = z_interpolated;

// 设置像素颜色,调用片段着色器
Vector2i temp(i, j);
set_pixel(temp, fragment_shader(payload));
}
}
}
}
}

4.Blinn-Phong反射模型

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
Eigen::Vector3f phong_fragment_shader(const fragment_shader_payload& payload)
{
Eigen::Vector3f ka = Eigen::Vector3f(0.005, 0.005, 0.005);//环境光反射率
Eigen::Vector3f kd = payload.color;//漫反射项系数
Eigen::Vector3f ks = Eigen::Vector3f(0.7937, 0.7937, 0.7937);//高光项
//定义了两个光源
auto l1 = light{{20, 20, 20}, {500, 500, 500}};
auto l2 = light{{-20, 20, 0}, {500, 500, 500}};

std::vector<light> lights = {l1, l2};
Eigen::Vector3f amb_light_intensity{10, 10, 10};//环境光
Eigen::Vector3f eye_pos{0, 0, 10};//观察点的位置
float p = 150;

Eigen::Vector3f color = payload.color;
Eigen::Vector3f point = payload.view_pos;
Eigen::Vector3f normal = payload.normal;

Eigen::Vector3f result_color = {0, 0, 0};
for (auto& light : lights)
{
//计算光源到物体距离的平方r2
float r2 = (light.position - point).dot((light.position - point));//a.dot(a)=|a|^2

Eigen::Vector3f l = (light.position - point).normalized();//光线方向
Eigen::Vector3f v = (eye_pos - point).normalized();//观察方向
Eigen::Vector3f h = (l + v).normalized();//半程向量

//.cwiseProduct()用于向量对应位置的点相乘
//漫反射
Eigen::Vector3f diffuse = kd.cwiseProduct(light.intensity / r2) * std::max(0.0f, normal.normalized().dot(l));
//环境光
Eigen::Vector3f ambient = ka.cwiseProduct(amb_light_intensity);
//高光
Eigen::Vector3f specular = ks.cwiseProduct(light.intensity / r2) * pow(std::max(0.0f, normal.normalized().dot(h)), p);

result_color += ambient + diffuse + specular;
}
return result_color * 255.f;
}

5.纹理映射

修改漫反射系数 kd即可,kd 是一个颜色向量,它表示了表面对漫反射光的反应程度,环境光和镜面反射成分通常是不受纹理映射直接影响。

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
50
Eigen::Vector3f texture_fragment_shader(const fragment_shader_payload& payload)
{
Eigen::Vector3f return_color = {0, 0, 0};
if (payload.texture)
{
//获取纹理坐标处的颜色
return_color = payload.texture->getColor(payload.tex_coords.x(), payload.tex_coords.y());
}
Eigen::Vector3f texture_color;
texture_color << return_color.x(), return_color.y(), return_color.z();

Eigen::Vector3f ka = Eigen::Vector3f(0.005, 0.005, 0.005);
Eigen::Vector3f kd = texture_color / 255.f;
Eigen::Vector3f ks = Eigen::Vector3f(0.7937, 0.7937, 0.7937);

auto l1 = light{{20, 20, 20}, {500, 500, 500}};
auto l2 = light{{-20, 20, 0}, {500, 500, 500}};

std::vector<light> lights = {l1, l2};
Eigen::Vector3f amb_light_intensity{10, 10, 10};
Eigen::Vector3f eye_pos{0, 0, 10};

float p = 150;
Eigen::Vector3f color = texture_color;
Eigen::Vector3f point = payload.view_pos;
Eigen::Vector3f normal = payload.normal;

Eigen::Vector3f result_color = {0, 0, 0};

for (auto& light : lights)
{
//计算光源到物体距离的平方r2
float r2 = (light.position - point).dot((light.position - point));//a.dot(a)=|a|^2

Eigen::Vector3f l = (light.position - point).normalized();//光线方向
Eigen::Vector3f v = (eye_pos - point).normalized();//观察方向
Eigen::Vector3f h = (l + v).normalized();//半程向量

//.cwiseProduct()用于向量对应位置的点相乘
//漫反射
Eigen::Vector3f diffuse = kd.cwiseProduct(light.intensity / r2) * std::max(0.0f, normal.normalized().dot(l));
//环境光
Eigen::Vector3f ambient = ka.cwiseProduct(amb_light_intensity);
//高光
Eigen::Vector3f specular = ks.cwiseProduct(light.intensity / r2) * pow(std::max(0.0f, normal.normalized().dot(h)), p);

result_color += ambient + diffuse + specular;
}
return result_color * 255.f;
}

6.凹凸贴图

pass

7.位移贴图

pass