(原)Unreal渲染模块 管线 - 着色器(1)

2023-03-10,,

@author: 白袍小道

转载悄悄说明下

随缘查看,施主开心就好

说明:

本篇继续Unreal搬山部分的渲染模块的Shader部分,

主要牵扯模块RenderCore, ShaderCore, RHI, Materia.

可能分成N篇。

(这里放入的UE的模块框)

(下一篇主要是UE灯光和着色简要[ush以及对应结构,和UE代码和DX部分],然后是巴拉巴拉)

前言:

部分算法和流程的实现原理,和细节(往往这部分会成为优化的处理口)。

梳理UEShader的结构,底层的接入,分层。

UE着色使用和细节部分。

对比反观差距和原因

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第一部分、渲染管线和着色

Shading Models

描述物体的颜色如何根据表面等因素而变化 (例如方向,视图方向,和照明)

1、通常具有控制外观变化的属性。

2、控制这些变化的属性而决定了变化。

评估

设计着色实现时,需要根据计算结果进行划分他们的评估频率。

首先,确定一个给定的结果在整个绘制调用中,计算总是不变的。在这种情况下,计算应用程序可以通过GPU计算(通常在CPU上)执行吗。着色器可以用于特别昂贵的计算。结果被传递给图形API通过统一着色器输入。

说明

、虚拟机

a\ 目前的着色语言都是 C-likelike 的着色语言,比如 HLSL,CG 和 GLSL GLSL,其被编译成独立于机器的汇语言 语言,也称为中间( IL )。

这些汇编语言在单独的阶段,通常是驱动中被转化成实际机器 )。

这些汇编语言在单独的阶段,通常是驱动中被转化成实际机器 语言。这样的安排可以兼容不同硬件实现些汇编被看做是定义一个作为着色译器.

b\ 着色语言虚拟机可以理解为一个处多种类型寄存器 和数据源、预编了一系列指令的处理器。

、单指令多数据( SIMD), 寄存器.

a\ 一次DrawCall会通过API做一次(一系列)的图元绘制,从而驱使图形管线运行。[如Draw,DrawInstance, …..]

b\ 输入,输出和交接。

c\ Shader的语句、加载和编译。

DX10 虚拟机

语法树

划分

、顶点着色

发生在图元装配后

顶点着色器(VS)阶段处理来自输入汇编器的顶点,执行每个顶点的操作,如转换、蒙皮、变形和每个顶点的光照,并编制到输出结构交付给下一个管道。

(顶点着色器总是操作单个输入顶点并产生单个输出顶点。顶点着色器阶段必须始终处于活动状态,以便管道执行。

如果不需要顶点修改或转换,则必须创建一个直通顶点着色器并将其设置为管道。)

a\ 输入和输出:

每个顶点着色器输入顶点可以由16个32位向量组成(每个顶点最多4个分量),每个输出顶点可以由16个32位4分量向量组成。

所有顶点着色器都必须至少有一个输入和一个输出,可以是一个标量值。

b\ vertexshader阶段可以使用输入汇编程序生成的两个系统值:VertexID和InstanceID(参见系统值和语义)。

由于VertexID和InstanceID在顶点级别都是有意义的,并且硬件生成的ID只能被输入到理解它们的第一阶段,因此这些ID值只能被输入到vertexshader阶段。

c\ 顶点着色器总是在所有顶点上运行,包括带有邻接的输入基元拓扑中的相邻顶点。

顶点着色器执行的次数可以使用VSInvocations管道统计从CPU查询。

、可选镶嵌

描述:

Direct3D 11运行时支持三个实现镶嵌的新阶段,它将低细节细分曲面转换为GPU上的高细节原语。

镶嵌瓷砖(或分解)高阶表面成适合渲染的结构。

通过在硬件中实现镶嵌,图形管道可以评估较低的细节(较低的多边形计数)模型和渲染较高的细节。

虽然可以进行软件镶嵌,但是由硬件实现的镶嵌可以生成大量的视觉细节(包括对位移映射的支持),而不需要向模型大小添加视觉细节和刷新率。

概括:镶嵌使用GPU计算更详细的表面从一个由四边形斑块,三角形斑块或等值线构成的表面。

HullShader:

一个可编程的着色器阶段,它产生一个几何贴片(和贴片常量),对应于每个输入贴片(四边形、三角形或直线).

外壳着色器(每个补加点调用一次)将定义低阶表面的输入控制点转换为构成补加的控制点。

ID3D11Device::

CreateHullShader

ID3D11DeviceContext::HSSetShader

Tessellator

一个固定的函数管道阶段,它创建表示几何patch的域的抽样模式,并生成一组较小的对象(三角形、点或线)来连接这些样本

将一个域(四边形、三边形或直线)细分为许多较小的对象(三角形、点或直线)。将uv(和可选的w)坐标和表面拓扑(归一化的坐标域)输出到域着色器阶段。

域着色器在每个tessellator阶段点调用一次,并计算表面位置。

Domain

一个可编程着色器阶段,计算对应于每个域样本的顶点位置

域着色器计算输出补丁中细分点的顶点位置,其中每个tesselator阶段输出点运行一次,并且对tesselators阶段输出UV坐标、船体着色器输出补丁和船体着色器输出补删常量具有只读访问权限。

ID3D11Device::

CreateDomainShader

、Geometry Shader

几何着色器(GS)阶段运行应用程序指定的着色器代码,将顶点作为输入,并能够在输出上生成顶点。

(不像顶点着色器操作单个顶点,几何着色器的输入是一个完整语义的顶点(两个顶点表示线,三个顶点表示三角形,或者单个顶点表示点)。

几何体着色器还可以将边缘相邻基元的顶点数据作为输入(对于一条直线,额外的两个顶点,对于三角形,额外的三个顶点)。

下图显示了一个三角形和一条有相邻顶点的直线。)

a\ 可以使用由IA自动生成的SV_PrimitiveID系统生成的值。

b\ 能够输出多个顶点,形成单个选定的拓扑(可用的GS阶段输出拓扑有:tristrip、linestrip和pointlist)。

c\ 输出可以通过流输出阶段反馈到光栅化阶段和/或内存中的顶点缓冲区。提供给内存的输出被扩展到单独的点/线/三角形列表(它们将被传递给光栅化器)。

、Pixel Shader

像素着色器阶段(PS)支持丰富的着色技术,例如逐像素光照和后期处理。

像素着色器是一个程序,它结合了常量变量、纹理数据、每个顶点值的插值和其他数据来产生每个像素的输出

对于一个原语覆盖的每个像素,rasterizer阶段只调用一次像素着色器,但是,可以指定一个空着色器来避免运行一个着色器。

a\ 当对纹理进行多采样时,每个覆盖的像素只调用一次像素着色器,同时对每个覆盖的多采样进行深度/模板测试。通过深度/模版测试的样本将使用像素着色器输出颜色进行更新。(所以适当减少)

b\ 像素着色器固有函数产生或使用屏幕空间x和y的数量导数,导数最常用的用途是计算纹理采样的详细程度计算,在各向异性滤波的情况下,选择沿各向异性轴的样本。

通常,硬件实现同时在多个像素(例如2x2网格)上运行一个像素着色器,以便在像素着色器中计算的量的导数可以合理地近似为相邻像素中同一执行点上的值的增量。

c\ 输入:

输入将被限制(超过会截取)在16(无配置Geo着色)or 32、 32位、4个组件。

关键词:顶点属性,插值,覆盖,抽样,

d\ 输出

像素着色器最多可以输出8 32位4分量的颜色,如果像素被丢弃,则不输出颜色。像素着色器输出寄存器组件在使用之前必须声明;每个寄存器都允许有一个不同的输出-写入掩码。

使用depth-write-enable状态(在输出合并阶段)来控制是否将深度数据写入深度缓冲区(或使用丢弃指令丢弃该像素的数据)。

像素着色器还可以输出可选的32位、1个组件、浮点数、深度值来进行深度测试(使用SV_Depth语义)。

深度值在深度寄存器中输出,并替换深度测试的插值深度值(假设启用深度测试)。无法在使用固定函数深度和着色器深度之间动态变化。

像素着色器不能输出模板值。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第二部分、Unreal 着色器相关

DX:

1、编译,读写

D3DCompileFromFile(_In_ LPCWSTR pFileName,

_In_reads_opt_(_Inexpressible_(pDefines->Name != NULL)) CONST D3D_SHADER_MACRO* pDefines,

_In_opt_ ID3DInclude* pInclude,

_In_ LPCSTR pEntrypoint,

_In_ LPCSTR pTarget,

_In_ UINT Flags1,

_In_ UINT Flags2,

_Out_ ID3DBlob** ppCode,

_Always_(_Outptr_opt_result_maybenull_) ID3DBlob** ppErrorMsgs);

D3DCompile(_In_reads_bytes_(SrcDataSize) LPCVOID pSrcData,

_In_ SIZE_T SrcDataSize,

_In_opt_ LPCSTR pSourceName,

_In_reads_opt_(_Inexpressible_(pDefines->Name != NULL)) CONST D3D_SHADER_MACRO* pDefines,

_In_opt_ ID3DInclude* pInclude,

_In_opt_ LPCSTR pEntrypoint,

_In_ LPCSTR pTarget,

_In_ UINT Flags1,

_In_ UINT Flags2,

_Out_ ID3DBlob** ppCode,

_Always_(_Outptr_opt_result_maybenull_) ID3DBlob** ppErrorMsgs);

D3DCompressShaders(_In_ UINT uNumShaders,

_In_reads_(uNumShaders) D3D_SHADER_DATA* pShaderData,

_In_ UINT uFlags,

_Out_ ID3DBlob** ppCompressedData)

D3DReadFileToBlob(_In_ LPCWSTR pFileName,_Out_ ID3DBlob** ppContents)

D3DWriteBlobToFile(_In_ ID3DBlob* pBlob,_In_ LPCWSTR pFileName, _In_ BOOL bOverwrite)

2、创建

CreateVertexShader(

_In_reads_(BytecodeLength) const void *pShaderBytecode,

_In_ SIZE_T BytecodeLength,

_In_opt_ ID3D11ClassLinkage *pClassLinkage,

_COM_Outptr_opt_ ID3D11VertexShader **ppVertexShader)

CreateXXXShader类似

Unreal

Unreal的Shader处理包括了:ush的包含,编译得到转储的着色器usf,平台编译器编译,创建和使用(绑定)。

1、Global Shaders

全局shader是用于操作固定几何体(如:full screen quad)的shader,并且它不需要与materials产生交互,例如:阴影过滤、后处理。

这种类型的shader在内存中只有一份实例.

2、Materia

材质由一些控制材质如何渲染的状态和一些控制材质如何与渲染Pass shader交互的材质输入(material inputs)组成。

3、Vertex Factories 和 MeshTypes

Material必须能够赋给各种类型的Mesh Types, 这个是通过和Vertex Factories 配合完成的。 一个FVertexFactoryType表示唯一的Mesh Type。

一个FVertexFactory的实例存有每个几何体的数据,以便支持特定的Mesh Type。

引擎内Shader位于:Engine\Shaders\Private(Public)下

(详细分析和说明在下一篇)

使用部分

ShaderCore:

FShader、FGlobalShader、

FShaderType, FVertexFactory

FShaderPipeline, FShaderTarget

材质的编译

过程说明:

1、生成材质的Shader代码【只是Shader文件】

2、构建编译环境,且添加相关文件路径

3、编译[可以异步],成功就缓存起来

3.1 创建了一个临时引用计数指针[主要是确保操作一个引用的着色器映射[或查找]将导致这个着色器映射被删除]

3.2 往ShaderMapsBeingCompiled添加[占个位置]

3.3 分配唯一编译ID,配置编译环境

3.4 迭代处理所有顶点工厂的类型,编译这个材质和顶点工厂类型组合的所有网格材质着色器。---------FVertexFactoryType

3.5 迭代处理所有材质Shader的类型 ------FShaderType

3.6 迭代处理所有材质Shader管线的类型 ------FShaderPipelineType

3.7 进入映射编译着色器

类关系:

(原)Unreal渲染模块 管线 - 着色器(1)的相关教程结束。

《(原)Unreal渲染模块 管线 - 着色器(1).doc》

下载本文的Word格式文档,以方便收藏与打印。