boxmoe_header_banner_img

菜就多练喵

文章导读

[C++][图形学]TinyRenderer第七课——描影


avatar
Ib_Mccf 2025年12月21日 31

渲染管线:

  • 顶点处理:处理单个顶点。
  • 原始装配:连接顶点形成原体。
  • 光栅化:将每个原体转换为一组片元。
  • 片元处理:处理单个片元。
  • 输出合并:将所有原体的片元(在三维空间中)合成显示的二维彩色像素。

片元与像素的区别:

像素是二维的点(x,y)且有颜色值,坐标与二维像素网格对齐。

片元是三维的(x,y,z),x和y与二维像素网格对齐,z轴代表深度。在片元处理阶段会为片元分配颜色和透明度等参数,在输出合并阶段整合。

渲染管线中的顶点处理和片元处理阶段是可以程序编辑的。

Phong反射模型

模型表面光照 = 环境光 + 漫反射 + 高光

\[三角面法线\vec{n} = \frac{\overrightarrow{AB} \times \overrightarrow{AC}}{\| \overrightarrow{AB} \times \overrightarrow{AC} \|}\]
\[光照方向\vec{l} * \vec{n} = cos\alpha \]
\[\vec{l} * \vec{n}是指\vec{l}在\vec{n}方向上的投影\]
\[反射方向\vec{r} = 2\vec{n}(\vec{l} * \vec{n}) – \vec{l}\]
\[其中2\vec{n}(\vec{l} * \vec{n}) = \vec{l} + \vec{r}\]
\[漫反射强度I_{\text{diff}} = k_d \cdot I_{\text{light}} \cdot \max(0, \vec{n} \cdot \vec{l})\]
\[高光强度I_{\text{spec}} = k_s \cdot I_{\text{light}} \cdot (\max(0, \vec{r} \cdot \vec{v}))^{e}\]
\[k_s和k_d为强度系数;I_{light}为光照强度;e为高光系数\]
e = 64
struct PhongShader : IShader {
    const Model &model;
    vec3 l;          // light direction in eye coordinates
    vec3 tri[3];     // triangle in eye coordinates

    PhongShader(const vec3 light, const Model &m) : model(m) {
        l = normalized((ModelView*vec4{light.x, light.y, light.z, 0.}).xyz()); // transform the light vector to view coordinates
    }

    virtual vec4 vertex(const int face, const int vert) {
        vec3 v = model.vert(face, vert);                          // current vertex in object coordinates
        vec4 gl_Position = ModelView * vec4{v.x, v.y, v.z, 1.};
        tri[vert] = gl_Position.xyz();                            // in eye coordinates
        return Perspective * gl_Position;                         // in clip coordinates
    }

    virtual std::pair<bool,TGAColor> fragment(const vec3 bar) const {
        TGAColor gl_FragColor = {255, 255, 255, 255};             // output color of the fragment
        //三角面法线
        vec3 n = normalized(cross(tri[1]-tri[0], tri[2]-tri[0])); // triangle normal in eye coordinates
        //反射向量, n * l 是l在n方向上的投影,2 * n * (n*l) = l + r 
        vec3 r = normalized(n * (n*l) * 2 - l);                   // reflected light direction
        //环境光
        double ambient = .3;                                      // ambient light intensity
        //漫反射
        double diff = std::max(0., n * l);                        // diffuse light intensity
        double e = 35;
        double spec = std::pow(std::max(r.z, 0.), e);            // specular intensity, note that the camera lies on the z-axis (in eye coordinates), therefore simple r.z, since (0,0,1)*(r.x, r.y, r.z) = r.z
        for (int channel : {0,1,2})
            gl_FragColor[channel] *= std::min(1., ambient + .4*diff + .9*spec);
            // gl_FragColor[channel] *= std::min(1., ambient + .75*diff);
        return {false, gl_FragColor};                             // do not discard the pixel
    }
};


评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字

插入代码