https://haqr.eu/tinyrenderer/shading/

首先回顾渲染管线,目前我们有了 Model View Perspective Projection Viewport zbuffer draw_trangle 等等,我们把文件拆分一下,一些不会再修改的内容放入一个 gl Module 中。把我们顶点坐标变换的部分放在 Vertex Shader 中,Fragment Shader 部分就应用一下 Random Color 就可以。


main :: () {
model = rotate_y(30.0);
view = lookat(eye, center, up);
projection = make_perspective(radian_to_angle(45), 1.0, 0.1, 100.0);
viewport = make_viewport(0, 0, width, height);
zbuffer = make_zbuffer(width, height);
load_obj("./assets/african_head.obj", *vertices, *indices);
defer array_free(vertices);
defer array_free(indices);
framebuffer := make_image(width, height, BLACK);
defer free_image(*framebuffer);
shader := Shader.{vertex_pass, fragment_pass};
for indices {
triangle := make_triangle(vertices, it, shader); // vertex shader
draw_triangle(*framebuffer, *zbuffer, triangle, shader); // fragment shasder
}
ppm.write_p3("061.ppm", *framebuffer);
}
简化版的全局光照: Ambient + Duffuse + Specular


环境光 + 漫反射 + 高光
GAMES 101 07 Shading 1 (Illumination, Shading)
$$ \begin{aligned} L & =L_a+L_d+L_s \\ & =k_a I_a+k_d\left(I / r^2\right) \max (0, \mathbf{n} \cdot \mathbf{l})+k_s\left(I / r^2\right) \max (0, \mathbf{n} \cdot \mathbf{h})^p \end{aligned} $$
环境光:恒定的背景光,直接调整一个百分比就可以。
漫反射

计算三角形ABC的法向量 $\vec{n} =\frac{\overrightarrow{AB} \times \overrightarrow{AC}}{\left\lVert \overrightarrow{AB} \times \overrightarrow{AC} \right\rVert}$, $\cos \alpha = \vec{n} \cdot \vec{l}$
Diffuse = $\text{max}(0, \vec{n} \cdot \vec{l})$

高光项

首先图里的向量都是单位向量, $\vec{v}$ 是片元到摄像机。$\vec{l}$ 是入射平行光的方向(反过来了,把向量起点放在了入射点位置), $\vec{r}$ 是高光反射的方向。向量加法很容易得到 $\vec{l} + \vec{r} = 2\vec{n}(\vec{n} \cdot \vec{l})$,那么 $\vec{r} = 2\vec{n}(\vec{n} \cdot \vec{l}) - \vec{l}$。
specular := pow(max(dot(r, v), 0.0), shininess);
其中 shininess = 8 -> 宽而柔和的高光 = 32 -> 比较明显的高光 = 128 -> 很小、很亮、很尖锐的高光

fragment_pass :: () -> Vector4 {
ambient := 0.3;
l := l_dir; using triangle_world;
n := normalize(cross(b - a, c - a)); // triangle normal
r := normalize(n * dot(n, l) * 2.0 - l); // reflected light direction
diffuse := max(0.0, dot(n, l));
specular := pow(max(r.z, 0.0), 35);
color := make_vector4(min(1.0, ambient + 0.4 * diffuse + 0.9 * specular));
color.w = 1.0;
return color;
}