CG4 - 3D 流水线

07 Jul 2015

0、概述

流水线又称为装配线,一种工业上的生产方式,指每一个生产单位只专注处理某一个片段的工作,以提高工作效率及产量。(引自百度百科

3D 流水线(3D pipeline,也称 3D 管线)是指将软件渲染器实现渲染的整个过程按功能分割成各个部分,将每个部分只处理其相应的内容,然后将整个过程串联起来。流水线的优势在于,每个部分只需要关注其职责范围内的工作,不会产生业务交叉,只有各部分的处理结果对后续工序有影响。

3D 流水线的实现存放在 Pipeline.h 中,这里先介绍一个最粗略的 3D 流水线,随着每一部分的深入再对其细化和完善。

pipeline1

1、物体

从一个纯粹的物体出发,考虑要将一个物体绘制出来,需要几个基本属性:

1
2
3
4
5
6
7
8
9
10
11
12
struct Object4D 
{
    ...
    // 世界坐标,用于变换
    Point4D world_pos;
    // 初始化为局部坐标顶点
    // 此处用了两个数组,一个数组存储原始的顶点数据,一个数组存储坐标变换后的数据
    Vertex4D vlist_local[OBJECT4D_MAX_VERTICES];
    Vertex4D vlist_trans[OBJECT4D_MAX_VERTICES];
    Poly4D plist[OBJECT4D_MAX_POLYS];
    ...
};

一个物体存储了许多个面与许多个顶点,两个面可能有 1 - 2 个公用顶点,如果存储面的结构中依然使用顶点数组进行存储,会造成比较大的资源浪费。实际实现中,只需要存储指向顶点数组的指针和对应顶点的偏移信息即可。

1
2
3
4
5
6
struct Poly4D
{
    ...
    PVertex4D vlist = NULL;
    int vert[3];
};

2、渲染列表

从世界坐标系的整体出发,渲染列表代表着实际空间中的多个物体。实际上,在渲染列表中已经没有了物体的表示,保留下来的是物体的面的信息。

1
2
3
4
5
6
struct RenderList4D
{
    ...
    PPolyList4D poly_ptrs[RENDERLIST4D_MAX_POLYS];
    PolyList4D poly_data[RENDERLIST4D_MAX_POLYS];
};

渲染列表中的面与物体中的面数据格式并不完全相同,因为在物体中,面的顶点是用指针表示的,若渲染列表中的面的顶点仍使用指针,会出现从渲染列表指向物体的指针,若物体在渲染过程中被回收或改变,那指针指向的内容可能也被对应改变了。所以在渲染列表的面结构中,需要真实地创建面的数组空间。

1
2
3
4
5
6
7
8
9
10
11
struct PolyList4D
{
    ...
    // vlist 用于存储变换前的顶点,tvlist 用于存储变换后的顶点
    Vertex4D vlist[3];
    Vertex4D tvlist[3];

    // 将渲染面列表设计成双向链表,此处也可以设计成数组
    PolyList4D* prev = NULL;
    PolyList4D* next = NULL;
};

3、坐标变换

物体和渲染列表均支持两种操作:旋转和平移。

1
2
3
4
5
6
7
8
9
10
11
12
struct Object4D
{
    ...
    void rotate(PMatrix4x4 m, TransformMode mode, int basis);
    void to_World(TransformMode mode = TRANSFORM_LOCAL_TO_TRANS);
};
struct RenderList4D
{
    ...
    void rotate(PMatrix4x4 m, TransformMode mode);
    void to_World(PPoint4D pos, TransformMode mode);
};

triangleDemo

此时再看 3D 流水线,在物体变换到顶点之前,加入了“局部坐标=>世界坐标”的变换过程:

pipeline2

事实上,这部分实现得并不好: 1)两个 to_World 没有统一接口,Object4D 中的 world_pos 并不是必须的,需要时创建即可; 2)rotate 实际效果取决于 PMatrix4x4,若变换矩阵为平移矩阵,这里的 rotate 将出现“旋转导致了平移效果”的二义性。

添加更多的 API wrapper 和校验或许是一个不错的选择,当然,就目前而言这并不影响继续前行。


如果你发现我文章中的问题或希望与我交流,可以给我发邮件:plinux@qq.com

如果你读后有些许收获,也可以到我的 Github 点赞支持

© 2015 plinx