HLSL重点知识梳理
2024-11-21
23
0
本文源于对DirectX11—HLSL语法入门(https://www.cnblogs.com/X-Jun/p/12246859.html ) 一文的总结
浮点
类型 | 描述 |
---|---|
bool | 32位整数值用于存放逻辑值true和false |
int | 32位有符号整数 |
uint | 32位无符号整数 |
half | 16位浮点数(仅提供用于向后兼容) |
float | 32位浮点数 |
double | 64位浮点数 |
注意:一些平台可能不支持int, half和double,如果出现这些情况将会使用float来模拟
此外,浮点数还有规格化的形式:
- snorm float是IEEE 32位有符号且规格化的浮点数,表示范围为-1到1
- unorm float是IEEE 32位无符号且规格化的浮点数,表示范围为0到1
语义
语义通常是附加在着色器输入/输出参数上的字符串。它在着色器程序的用途如下:
- 用于描述传递给着色器程序的变量参数的含义
- 允许着色器程序接受由渲染管线生成的特殊系统值
- 允许着色器程序传递由渲染管线解释的特殊系统值
语义有三种类型:顶点着色器语义,像素着色器语义和系统着色器语义
顶点着色器语义
输入 | 描述 | 类型 |
---|---|---|
BINORMAL[n] | 副法线(副切线)向量 | float4 |
BLENDINDICES[n] | 混合索引 | uint |
BLENDWEIGHT[n] | 混合权重 | float |
COLOR[n] | 漫反射/镜面反射颜色 | float4 |
NORMAL[n] | 法向量 | float4 |
POSITION[n] | 物体坐标系下的顶点坐标 | float4 |
POSITIONT | 变换后的顶点坐标 | float4 |
PSIZE[n] | 点的大小 | float |
TANGENT[n] | 切线向量 | float4 |
TEXCOORD[n] | 纹理坐标 | float4 |
Output | 仅描述输出 | Type |
FOG | 顶点雾 | float |
n是一个可选的整数,从0开始。比如POSITION0, TEXCOORD1等等。
像素着色器语义
输入 | 描述 | 类型 |
---|---|---|
COLOR[n] | 漫反射/镜面反射颜色 | float4 |
TEXCOORD[n] | 纹理坐标 | float4 |
Output | 仅描述输出 | Type |
DEPTH[n] | 深度值 | float |
系统值语义
所有的系统值都包含前缀SV_。这些系统值将用于某些着色器的特定用途(并未全部列出)
系统值 | 描述 | 类型 |
---|---|---|
SV_Depth | 深度缓冲区数据,可以被任何着色器写入/读取 | float |
SV_InstanceID | 每个实例都会在运行期间自动生成一个ID。在任何着色器阶段都能读取 | uint |
SV_IsFrontFace | 指定该三角形是否为正面。可以被几何着色器写入,以及可以被像素着色器读取 | bool |
SV_Position | 若被声明用于输入到着色器,它描述的是像素位置,在所有着色器中都可用,可能会有0.5的偏移值 | float4 |
SV_PrimitiveID | 每个原始拓扑都会在运行期间自动生成一个ID。可用在几何/像素着色器中写入,也可以在像素/几何/外壳/域着色器中读取 | uint |
SV_StencilRef | 代表当前像素着色器的模板引用值。只可以被像素着色器写入 | uint |
SV_VertexID | 每个实例都会在运行期间自动生成一个ID。仅允许作为顶点着色器的输入 | uint |
常量缓冲区
着色器常量存在内存中的一个或多个缓冲区资源当中。他们可以被组织成两种类型的缓冲区:常量缓冲区(cbuffers)和纹理缓冲区(tbuffers)。
不同的常量缓冲区使用不同的常量缓冲区声明。如常量缓冲区使用cbuffers
cbuffer VSConstants
{
float4x4 g_WorldViewProj;
fioat3 g_Color;
uint g_EnableFog;
float2 g_ViewportXY;
float2 g_ViewportWH;
}
为了进一步优化,可以为常量缓冲区在HLSL的声明中使用关键字register手动指定对应的寄存器索引,然后编译器会为对应的着色器阶段自动将其映射到15个常量缓冲寄存器的其中一个位置。这些寄存器的名字为b0到b14:
cbuffer VSConstants : register(b0)
{
float4x4 g_WorldViewProj;
fioat3 g_Color;
uint g_EnableFog;
float2 g_ViewportXY;
float2 g_ViewportWH;
}
在C++端是通过ID3D11DeviceContext::*SSetConstantBuffers指定特定的槽(slot)来给某一着色器阶段对应的寄存器索引提供常量缓冲区的数据。
如果是存在多个不同的着色器阶段使用同一个常量缓冲区,那就需要分别给这两个着色器阶段设置好相同的数据。
综合前面几节内容,下面演示了顶点着色器和常量缓冲区的用法:
cbuffer ConstantBuffer : register(b0)
{
float4x4 g_WorldViewProj;
}
void VS_Main(
in float4 inPos : POSITION, //POSITION语义:绑定变量到输入装配器
in uint VID : SV_VertexID, // SV_VertexID语义:绑定变量到系统生成值
out float4 outPos : SV_Position) // SV_Position语义:告诉管线将该值解释为输出的顶点位置
{
outPos = mul(inPos, g_WorldViewProj);
}
`
上面的代码也可以写成:
cbuffer ConstantBuffer : register(b0)
{
float4x4 g_WorldViewProj;
}
struct VertexIn
{
float4 inPos : POSITION; // 源自输入装配器
uint VID : SV_VertexID; // 源自系统生成的调用实例ID
};
float4 VS_Main(VertexIn vIn) : SV_Position
{
return mul(vIn.inPos, g_WorldViewProj);//默认返回值为输出顶点位置
}