开始学习
console.log("first learning");
参考:
- 《UnityShader入门精要》冯乐乐
- 《learn OpenGL》
- 《realtime rendering》
- 原文在本地站点
http://localhost:8888/wordpress/2020/03/27/shaderlearning_1/
渲染流水线
首先我们应该了解一下渲染流水线。在《Render-Time Rendering》中将一个渲染流程分为3个阶段:Application Stage-Geometry Stage-Rasterizer Stage。
图
2.2
显
示
了
3
个
阶
段
图2.2 显示了3个阶段
图2.2显示了3个阶段
其中applicationStage通常由CPU负责,在这一阶段我们要做culling(粗粒度剔除)工作,将不可见的物体剔除;然后我们需要设置好每个模型的渲染装态,这些状态包括但不限于它使用的材质(diffuse,specular),使用的texture,shader等。最后要输出rendering primitives,即渲染所需的几何信息,通俗来讲就是点,线三角面这些primitives,需要传递给下一个阶段——几何阶段。
GeometryStage用于处理所有和我们要绘制的几何相关的事情,这个阶段在GPU上进行,要把顶点坐标变换到屏幕空间中,再交给光栅器处理。通过将primitives处理后,该阶段输出屏幕空间的二维顶点坐标,每个顶点对应的深度值,着色等相关信息,并传递给下一个阶段。
RasterizerStage使用上一个Stage传递的数据产生最终的pixel,这一阶段在GPU上进行。这一阶段的任务决定每个primitives中哪些pixel应该被绘制在screen上。他需要对上一个阶段得到的逐顶点数据(纹理坐标,颜色顶点)进行插值,然后绘制。
注意上面说的3个流水线阶段不是GPU流水线阶段。
CPU和GPU通信
ApplicationState可以分为3个阶段工作:1.将数据加载到显存中。2.设置渲染状态。3.调用DrawCall。 其中要注意渲染数据先从hdd加载到ram中,其中mesh和texture又被加载到显卡上的存储空间——Video Random Access Memory,VRAM(显存)中。
GPU流水线
在GeometryStage中和RasterizerStage中进行GPU流水线处理,注意集合阶段的最后一个流水线阶段是Screen Mapping(屏幕映射),这一阶段不可配置和编程,负责把每个图元的坐标转换到屏幕坐标系中,可以参考下图:
↑
图
2.3.2
其
中
可
见
V
e
r
t
e
x
S
h
a
d
e
r
,
G
e
o
m
e
t
r
y
S
h
a
d
e
r
,
F
r
a
g
m
e
n
t
S
h
a
d
e
r
是
可
编
程
渲
染
管
线
↑图2.3.2 其中可见VertexShader,GeometryShader,FragmentShader是可编程渲染管线
↑图2.3.2其中可见VertexShader,GeometryShader,FragmentShader是可编程渲染管线
VertexShader是流水线的第一步,它的输入来自于CPU,VS处理的单位是顶点,意味着每个进来的Vertex都会调用一次VS。VS采用并行计算,它完成的主要任务有:坐标变换和逐顶点光照以及输出后续阶段所需要的数据。
坐标变换:改变顶点位置,基本思想:将顶点坐标从模型空间转换到齐次裁剪空间。就如通常在VS中看到的代码:
o.pos = mul(UNITY_MVP, v.position);
上面代码就是将Vertex转换到齐次裁剪坐标系下,接着再由硬件做透视除法后得到Normalized Device Coordinates,NDC(归一化的设备坐标)。
FragmentShader是另一个可编程shader,在它之前的操作实际上并不会影响Screen上每个pixel的color的呈现,实际上这些操作只是会产生一系列数据信息,用来表述一个三角网格是怎样覆盖每个像素的。而每个primitive负责存储这样一系列数据,真正对pixel产生影响的是在per-FragmentOperations阶段。同VS一样FS也是并行计算,因此Primitive无法将数据传递给它的邻居们且也不能影响它们(导数信息除外)。