Chapter5 The Rendering Pipeline (Introduction to 3D Game Programming with DirectX 11)笔记

5.3.2 128-Bit Color  

用XMVECTOR 表示,128bit 可以利用SIMD的好处

另外,做 颜色调制或者说分量相乘,可以用

XMVECTOR XMColorModulate(// Returns (cr , cg , cb , ca ) ⊗ (kr , kg , kb , ka )

5.3.3 32-Bit Color

用 XMCOLOR 表示

128bit 范围是 0~1 ,32bit是 0~255,两者 XMCOLOR 和  XMVECTOR,可以通过 */ 255 来相互转化

XMCOLOR to XMVECTOR :  XMVECTOR XMLoadColor(CONST XMCOLOR* pSource);

XMVECTOR to XMCOLOR:  VOID XMStoreColor(XMCOLOR* pDestination, FXMVECTOR V);

注意32bit的表示是 ARGB

Typically, 128-bit colors values are used where many color operations will take place (e.g., in a pixel shader); in this way, we have many bits of accuracy for the calculations so arithmetic error does not accumulate too much. The final pixel color, however, is usually stored in a 32-bit color value in the back buffer; current physical display devices cannot take advantage of the higher resolution color

一般,128bit用于有很多计算的地方,可以利用SIMD,比如ps中,而32bit一般用于存储表示,比如 back buffer,当前一般物理设备表示不了256以上更高的像素颜色范围。

5.5 THE INPUT ASSEMBLER STAGE

5.5.2 Primitive Topology

顶点拓扑

Point List individual point

Line Strip n + 1 vertices induces n lines

Line List 2n vertices induces n lines

Triangle Strip n vertices induce n – 2 triangles

这里注意由于三角形面有正反,因此默认的三角形带在背面剔除下会有裁剪问题,比如第奇数个三角形左手顺时针朝上正面,第偶数个三角形左右逆时针朝下反面,因此GPU为了解决这个问题,处理第偶数个三角形时,会交换前两个顶点的位置,来满足顺时针的顺序

Triangle List 3n vertices induces n triangles

Primitives with Adjacency 邻接的顶点信息,每个三角形多记三个邻接三角形的顶点,主要用于 GS中的计算,因为GS中需要知道周围三角形的信息,line list , line strip ,triangle 都可能有邻接

Control Point Patch List 主要用于 TS(Tessalation Stage),vertex data should be interpreted as a patch lists with N control points。

5.5.3 Indices

为了防止,这种的顶点重复,不管是存储空间的重复,还是重复处理这些 vertex structure的消耗,因此用 IndexLists 代替,,int数组虽然还有重复,但相比vertex structure已经很小了。

5.6 THE VERTEX SHADER STAGE

5.6.1 Local Space and World Space

使用本地空间的好处:

1. 方便描述各个模型的远点,顶点坐标,一般可以根据对称等特性来描述

2.方便复用,一个模型可以用到多个世界空间

3.一个模型也可以在一个世界空间用不同的Transform画很多次

构建LocalToWorld Matrix,

1.If Qw = (Qx, Qy, Qz, 1), uw = (ux, uy, uz, 0), vw = (vx, vy, vz, 0), and ww = (wx, wy, wz, 0) describe, respectively, the origin, x-, y-, and z-axes of a local space ,注意这里点都是行向量,构建矩阵为

,矩阵为左乘,假如LocalSpace坐标,l=(lx,ly,lz,1),坐标会保留位置,因此w分量为1,

那世界坐标 w= l W=(ux*lx+vx*ly+wx*z+Qx , 。。。。,1),最后一个分量仍然为1

2.以上通过坐标轴构建矩阵,不太直观,还有一种构建方式 W = SRT

依次平移,旋转,缩放,构建矩阵

这样,也能反向得到本地空间的坐标轴及原点在世界空间的表示,

5.6.2 View Space

World到View的转换矩阵,就是 把相机LocalSpace到WorldSpace的转换矩阵的 逆矩阵,因为World到View的转换矩阵,把世界空间的坐标转换到 相机空间

,其中, u,v,w是相机空间x,y,z轴的世界空间表示,Q是相机空间原点在世界空间的坐标

那如何求 u,v,w?

,Q是原点,T是相机朝向点, j是世界空间 的 up 单位向量,则

the “right” of w,

如上计算方法,封装在,其中the “up” vector is almost always j = (0,1,0).。

5.6.3 Projection and Homogeneous Clip Space

投影和齐次裁剪空间

5.6.3.1 Defining a Frustum

projection plane z = d,near plane n, far plane f, vertical field of view angle α , and aspect ratio r,知道了垂直角度α 和长宽比,那水平的角度  β,可以求出来,而且这里真是画面的长宽 w h也是不重要的,重要的是 长宽比 r。

,那

5.6.3.2 Projecting Vertices

projection plane z = d

,那

并且(r is the aspect ratio)。

5.6.3.3 Normalized Device Coordinates (NDC)

在之后的阶段比如映射到back buffer等等,都需要计算 aspect retio,也就是r. 也就是为了能在之后摆脱对分辨率本身的依赖,因此需要将 x从 [-r,r]映射都[-1,1], 由于 y/x =r,因此各个轴的取值范围是

所以再接着以上 view space的表示,frustum下只要x‘ 再除以r即可,所以

,这个就是投影矩阵最主要要做的一个变换。

5.6.3.4 Writing the Projection Equation with a Matrix!!

以上的式子可以看到 从x,y到 x',y'的转化是非线性的,α 和 r这里都是常量,因此除了 除z,其他的相当于 k1 * x,k2 * y是线性的,因此这个转换分成了两部分,线性的投影矩阵转化,和非线性的透视除法,一般投影矩阵需要自己算,透视触发会在硬件中进行。

关于如何构建投影矩阵,

1.因为是3d到2d,所以最主要是保留 k1 * x,k2 * y的k值,另外矩阵做成,因此第一列是(k1,0,0,0),第二列(0,k2,0,0)

2.到2D,不意味着z值没有用了,还需要保留用于深度缓冲,判断遮挡,因此这里将z值移到结果的w分量,第四列是(0,0,1,0),这样相乘之后,结果的w分量便是原来的z值,之后实际做透视除法,也不是除z,而是除w

3.第三列的作用是把z值,归一化,映射到(n,f)远近平面的范围,这样除z之后,可以映射到(0,1)的范围,注意这里的映射,不是要完全保留差距,只要能保留先后次序,比如之前a比b远10,映射之后,可能只远了0.1,但没关系,只要a还是比b远就行,因此第三列不操作x,y,只操作z,因此先用 A,B系数代替,第三列为(0,0,A,B)。

因此整个投影矩阵为

矩阵相乘为,得到的值为

4.然后经过透视除法,除w

书中,这段表述很好

For uniformity, we would like to express the projection transformation by a matrix. However, Equation 5.1 is nonlinear, so it does not have a matrix representation. The “trick” is to separate it into two parts: a linear part and a nonlinear part. The nonlinear part is thedivide by z. As will be discussed in the next section, we are going to normalize the z-coordinate; this means we will not have theoriginal z-coordinate around for the divide. Therefore, we must save the input z-coordinate before it is transformed; to do this, we take advantage of homogeneous coordinates, and copy the input z-coordinate to the output w-coordinate. In terms of matrix multiplication,this is done by setting entry [2][3] = 1 and entry [3][3] = 0 (zero-based indices).

Note that we have placed constants (to be determined in the next section) A and B into the matrix; these constants will be used to transform the input z-coordinate into the normalized range。

5.6.3.5 Normalized Depth Value

接下来是如何计算A,B,正如上面说的,目的是为了映射及保留先后关系,因此

关系式,是为了 Mapping [n, f] onto [0, 1],因此

Condition 1: g(n) = A + B/n = 0 (the near plane gets mapped to zero) 。== B = –An
Condition 2: g(f) = A + B/f = 1 (the far plane gets mapped to one)

解得

正如之前提到的,转化之后,并不是线性的,g(z)的函数曲线,near远离一些0面,并且n和f近一点,这样g曲线会陡一些,g函数判断远近也会避免出现由于曲线太陡导致的精度判断问题。

所以最终的投影矩阵为

书中所述,

It may seem like after projection, we can discard the original 3D z-coordinate, as all the projected points now lay on the 2D projection window, which forms the 2D image seen by the eye. However, we still need 3D depth information around for the depth buffering algorithm. Just like Direct3D wants the projected x- and y-coordinates in a normalized range, Direct3D wants the depth coordinates in the normalized range [0, 1]. Therefore, we must construct an order preserving function g(z) that maps the interval [n, f] onto [0, 1]. Because the function is order preserving, if z1, z2 ∈ [n, f ] and z1 < z2, then g(z1) < g (z2); so even though the depth values have been transformed, the relative depth relationships remain intact, so we can still correctly compare depths in the normalized interval, which is all we need for the depth buffering algorithm.

5.6.3.6 XMMatrixPerspectiveFovLH

DirectX中用函数 表述以上过程

XMMATRIX XMMatrixPerspectiveFovLH( // returns projection matrix
FLOAT FovAngleY, // vertical field of view angle in radians
FLOAT AspectRatio, // aspect ratio = width / height
FLOAT NearZ, // distance to near plane
FLOAT FarZ); // distance to far plane

另外注意以上推导是基于由参数fovy,aspect,n,f定义的透视投影矩阵,

也可以由 投影参数l,r,b,t,n,f 定义透视投影矩阵

其实推导方法,同样是 第一列,第二列保留透视后的x,y

第三列保留先后次序,第四列保留z值。

具体可以搜索 投影矩阵或者透视矩阵

透视矩阵的推导(最直观、最深入、最还原,看完请点赞。)_hunterzone的专栏-CSDN博客

OpenGL学习脚印: 投影矩阵和视口变换矩阵(math-projection and viewport matrix)_王定桥的专栏-CSDN博客_视口变换矩阵

透视投影详解 - 翰墨小生 - 博客园

5.7 THE TESSELLATION STAGES

通过把三角形细分成更多的小三角形,获取更高的面数。这些新的小三角形可以通过添加offset偏移,获取更好的效果。

TS阶段的主要好处:

1.实现lod技术,只在需要的地方使用更高面数的mesh

2.内存中可以始终只存储低面数的模型,运行时计算额外的网格

3.在低面数的mesh上计算动画和物理,而用高面数的用于渲染

dx11之前ts阶段只能发生在cpu上,计算结束,再传输到gpu,因此非常慢,现在可以直接在gpu中计算,更详细的细节之后的章节再讨论。

5.8 THE GEOMETRY SHADER STAGE

GS阶段的输入是整个primitives信息,比如如果绘制三角形列表,那输入就是定义每个三角形的所有vertexlists,并且这些vertex都已经经过了vertex shader。

GS最主要的作用是可以创建新的或者删除已有的三角形,根据条件判断是否使用某些三角形。对比来看,VS阶段只是输入一个顶点就输出一个顶点,而TS阶段只是可以细分已有的三角形。

注意:GS阶段输出的三角形也必须是已经转化到了齐次裁剪空间。

5.9 CLIPPING

GS阶段输出后会执行 视锥体裁剪,只留视锥体内部的。

裁剪过后留下的多边形,会被三角形化,用三角形填充,这部分主要由硬件实现,是不可编程的。

具体实现可以参考 Sutherland-Hodgeman clipping algorithm 算法,主要实现时超着多边形和平面的交点,然后循环遍历构建新的多边形。

主要缘由是,见过透视除法的点,已经有限制,如果只是透视投影,不计算除法,那点的范围应该是

一旦得知这几个x,y,z裁剪面的范围,可以应用 Sutherland-Hodgeman clipping algorithm 进行裁剪。

5.10 THE RASTERIZATION STAGE

光栅化阶段最主要的作用是计算每个像素的颜色。

5.10.1 Viewport Transform

视口转换,经过clip裁剪之后,计算透视出发,将坐标从透视空间转换到NDC坐标系,此时的x,y坐标经过视口转换映射到长方形 viewport 的back buffer中,通常视口转换不会修改z值坐标,因为要用于计算深度缓冲,除非在声明D3D11_VIEWPORT时,传入了 MinDepth和MaxDepth,会修改掉这里的z值。

5.10.2 Backface Culling

背面剔除,计算面是正面还是背面的方法是,三角形的顶点顺序是v0,v1,v2.

那表面法线是,法线朝上的面是正面,否则是反面。、

By default, Direct3D treats triangles with a clockwise winding order (with respect to the viewer) as front-facing, and triangles

with a counterclockwise winding order (with respect to the viewer) as back-facing. However, this convention can be reversed with a

Direct3D render state setting. 默认DirectX顺时针的顶点顺序被认为是正面,逆时针是反面,当然,这个可以在render state setting中进行修改。

5.10.3 Vertex Attribute Interpolation

After the viewport transform, these attributes need to be interpolated for each pixel covering

the triangle. In addition to vertex attributes, vertex depth values need to get interpolated so that each pixel has a depth value for the

depth buffering algorithm. The vertex attributes are interpolated in screen space in such a way that the attributes are interpolated

linearly across the triangle in 3D space (Figure 5.33); this requires the so-called perspective correct interpolation. Essentially,

interpolation allows us to use the vertex values to compute values for the interior pixels.

经过适口转换,像素覆盖的位置的属性值需要经过三角形顶点之间的插值计算而来。插值时,不仅是vertex上的属性进行插值,包括这个顶点的深度也会进行插值,并用于之后的depth buffer计算。

顶点在屏幕空间的插值,和3d空间的三角形的线性插值类似。这种方法需要 叫做 透视正确插值法,可以用vertex数据进行内部像素的插值。

至于透视正确插值法,这是硬件内部实现的,不需要编程,内部大概原理是

这里有一点要注意的是由于透视关系,3d空间的插值是线性的,但2d空间上的是非线性的。

5.11 THE PIXEL SHADER STAGE

pixel shader是执行在gpu上的一个代码段,逐像素片段执行并且利用vertex数据计算这个像素的颜色,可以很简单的返回一个纯色,也可以做一些复杂的计算,比如逐像素光照,反射,阴影等。

5.12 THE OUTPUT MERGER STAGE

合并输出阶段,这个阶段可能会经过 depth test和 stencil test 抛弃一些像素片段,也可能不是丢弃,而是blend混合(比如透明等效果),这些都是可配置的阶段,但不可编程。

总的来说,就是 深度测试,模版测试,颜色混合blend等等。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值