2021SC@SDUSC
一、简述
这一篇博客进一步看GPUShader部分,然后再看继承自GPUShaderProgram的几个类 ,也就是GPU着色器的功能。
二、分析
GPUShader接口继承自 GPUResource,是带有着色器程序的 GPU 资源,可以在 GPU 上运行,并能够使用纹理、顶点和其他资源执行渲染计算。
GPUShaderProgramsContainer _shaders;
GPUConstantBuffer* _constantBuffers[MAX_CONSTANT_BUFFER_SLOTS];
GPUShaderProgramsContainer表示具有排列和自定义名称的着色器程序集合。
GPUConstantBuffer用于将参数传递给 GPU 上的着色器的常量缓冲区对象。
接口内预定义的方法:
(1)
virtual bool Create(class MemoryReadStream& stream);
创建着色器资源并从字节加载其数据。
stream是带有已编译着色器数据的流。
返回值,如果不能创建状态则为真,否则为假
(2)
Get着色器的几个方法,这里只举其中一个例子:
API_FUNCTION() FORCE_INLINE GPUShaderProgramVS* GetVS(const StringAnsiView& name, int32 permutationIndex = 0) const
{
return static_cast<GPUShaderProgramVS*>(GetShader(ShaderStage::Vertex, name, permutationIndex));
}
获取顶点着色器。
name为着色器程序名, permutationIndex着色器排列索引,缺省值为0。
返回着色器对象。
(3)
FORCE_INLINE bool HasShader(const StringAnsiView& name, int32 permutationIndex = 0) const
{
return _shaders.Get(name, permutationIndex) != nullptr;
}
确定指定的着色器程序是否在着色器中。_shaders是上述声明的着色器集合。
name为着色器程序名, permutationIndex着色器排列索引,缺省值为0。
返回值,着色器有效返回真,否则为假。
接下来我们再继续深入,看一下着色器集合GPUShaderProgramsContainer:
Dictionary<int32, GPUShaderProgram*> _shaders;
首先是数据结构, Dictionary是带有映射键值对的无序字典模板。然后是主要方法:
void Add(GPUShaderProgram* shader, int32 permutationIndex);
GPUShaderProgram* Get(const StringAnsiView& name, int32 permutationIndex) const;
Add向集合中加入新的着色器,Get使用着色器名和索引获取集合中的着色器,查找失败时返回null 。然后是根据给定着色器程序名和排列索引计算哈希值:
static uint32 CalculateHash(const StringAnsiView& name, int32 permutationIndex);
GPUShader暂时介绍到这里,接下来我们看继承自GPUShaderProgram的几个类 。
Shader是运行在GPU上的一组指令,这里仅介绍各个着色器的功能,不涉及具体实现。
着色器:
- 着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。
- 在最简配置下,至少都得有两个着色器:一个叫顶点着色器(vertex shader),它将作用于每个顶点上;另一个叫片段着色器(fragment shader),它将作用于每一个采样点。我们采用4倍抗锯齿,因此每个像素有四个采样点。
- 如果我们打算从一个着色器向另一个着色器发送数据,我们必须在发送方着色器中声明一个输出,在接收方着色器中声明一个类似的输入。当类型和名字都一样的时候,OpenGL就会把两个变量链接到一起,它们之间就能发送数据了(这是在链接程序对象时完成的)。
(1)GPUShaderProgramVS* VS (Vertex Shader)顶点着色器程序
顶点着色器是一组指令代码,这组指令代码在顶点被渲染时执行。 同一时间内,只能激活一个顶点着色器。当渲染一个顶点时,API会执行你在顶点着色器中所写的指令。依靠这种方法,你可以自己控制每个顶点,包括渲染,确定位置,是否显示在屏幕上。
(2)GPUShaderProgramHS* HS 船体着色器程序(Hull Shader外壳着色器)
Hull Shader为曲面细分中的一种技术手段, 生成细分输出面片的顶点,更新所有逐顶点或逐面片的属性值; 设置细分层次因数,以控制生成图元的属性值。
(3)GPUShaderProgramDS* DS 域着色器程序(Domain Shader)
域着色器用于计算细分图元的顶点位置,它对Tessellator的每个输出点运行一次,能够只读访问其输出的uvw标量坐标,同时使用hull shader的两项输出数据。所有的顶点信息都会在这里计算,会涉及到大量运算。 域着色器同样为曲面细分的其中一部分,有关曲面细分着色器的相关知识可参考:https://blog.csdn.net/ifenghua135792468/article/details/106851708/
(4)GPUShaderProgramGS* GS 几何着色器程序(Geometry Shader)
一般只使用了顶点和片段着色器,这也是基本和必须的两个着色器,而几何着色器是一个可选的着色器,其位于顶点和片段着色器之间。
几何着色器接收来自顶点着色器的一个片元的一组顶点,然后可以对其进行变换,可以输出新的不同类型的片元,也可以增加顶点数,其功能非常强大。
(5)GPUShaderProgramPS* PS 像素着色器程序 (Pixel Shader,也叫Texture Shader纹理着色器,Fragment Shader片元着色器)
片元着色器的作用是处理由光栅化阶段生成的每个片元,最终计算出每个像素的最终颜色。归根结底,实际上就是数据的集合。这个数据集合包含每一个像素的各个颜色分量和像素透明度的值。
到这里,管道状态初始化过程中涉及到的部分基本分析完毕,接下来我们将继续回到2D渲染后面的部分。
2D渲染服务:
class Render2DService : public EngineService
首先看EngineService,引擎服务对象。首先看其主要方法;
static EngineServicesArray& GetServices();
获取所有已注册服务的列表,管理的对象是所有引擎提供的服务。返回对象如下:
typedef Array<EngineService*, FixedAllocation<128>> EngineServicesArray;
EngineService此外还有相关排序 ,这里不再赘述。
我们回到Render2DService,构造器继承自其父类EngineService,初始化服务名称。进行初始化工作以及关闭工作,主要是异步加载GUI着色器。
这篇博客暂时到这,后续将继续分析 2D渲染服务的其他部分