几何着色器简介
可以看d3d12龙书第146页。
对于本章内容来说,只有3个着色器。顶点着色器(VS)、几何着色器(GS)、像素着色器(PS)
VS ==> GS ==> PS
VS:拿到渲染目标的顶点,可以修改传入的顶点参数
GS:拿到完整的图元(如果是三角形渲染就是3个顶点,线段就是2个顶点,点就是一个顶点)。通过增减顶点来增减图元
PS:计算顶点的颜色值
公告板实现流程
跟渲染其他目标一样。这里呢采用几何着色器扩展图元来实现
渲染一个个离散的点,在GS中把每一个点扩展为一个矩形并设置该矩形4个顶点所需的其他参数
- 编写渲染点的VS,GS,PS
- 创建渲染点的PSO
- 创建点集合的渲染目标
2-3步前边做过很多了,只是改一个参数,由画三角形改为画点,这里就不再细说了。
公告板几何着色器解释
几何着色器是本章重点,详看注释
struct VertexOut
{
float3 CenterW : POSITION; // VS传过来的,这里也就是外边设置的点的世界坐标
float2 SizeW : SIZE; // 公告板的宽高数据
};
struct GeoOut
{
float4 PosH : SV_POSITION; // 顶点的齐次坐标
float3 PosW : POSITION; // 顶点的世界坐标
float3 NormalW : NORMAL; // 顶点的世界法向量
float2 TexC : TEXCOORD; // 顶点的纹理坐标
uint PrimID : SV_PrimitiveID; // 顶点ID
};
[maxvertexcount(4)]
void main(
point VertexOut gin[1], // 每次调用GS传入一个完整图元(一个点)
uint primID : SV_PrimitiveID, // 系统自动编号(本次是16个点,编号也就是0-15)
inout TriangleStream< GeoOut > triStream // 输出一个三角形带。三角形带就是每3个顶点作为一个三角形。例如4个顶点就是2个三角形。
)
{
// 计算up向量
float3 up = float3(0.0f, 1.0f, 0.0f);
// 计算目标点到观察点的向量
float3 look = gEyePosW - gin[0].CenterW;
// 保证目标点和观察点在通一个xz平面
look.y = 0.0f;
// 标准化
look = normalize(look);
// 计算右向量,这里的右以观察角度来看是左方向。龙书409页
float3 right = cross(up, look);
// 计算公告板树的宽和高
float halfWidth = 0.5f * gin[0].SizeW.x;
float halfHeight = 0.5f * gin[0].SizeW.y;
// 计算树的4个顶点
float4 v[4];
v[0] = float4(gin[0].CenterW + halfWidth * right - halfHeight * up, 1.0f); // 以观察角度来看,左下角
v[1] = float4(gin[0].CenterW + halfWidth * right + halfHeight * up, 1.0f); // 以观察角度来看,左上角
v[2] = float4(gin[0].CenterW - halfWidth * right - halfHeight * up, 1.0f); // 以观察角度来看,右下角
v[3] = float4(gin[0].CenterW - halfWidth * right + halfHeight * up, 1.0f); // 以观察角度来看,右上角
// 四个点对应的纹理坐标
float2 texC[4] =
{
float2(0.0f, 1.0f), // 左下
float2(0.0f, 0.0f), // 左上
float2(1.0f, 1.0f), // 右下
float2(1.0f, 0.0f) // 右上
};
// 输出图源
GeoOut gout;
[unroll]
for (int i = 0; i < 4; ++i)
{
gout.PosH = mul(v[i], gViewProj); // 顶点由世界坐标系转到投影坐标系
gout.PosW = v[i].xyz; // 顶点的世界坐标
gout.NormalW = look; // 顶点的法向量
gout.TexC = texC[i]; // 顶点的纹理
gout.PrimID = primID; // 该顶点所组成的面的ID
triStream.Append(gout);
}
}
看下效果
开启MSAA以及AlphaToCoverage之后的效果
// 公告板PSO
GraphicsPSO billboardPSO = defaultPSO;
billboardPSO.SetRasterizerState(Graphics::RasterizerDefaultCwMsaa);
blend = Graphics::BlendDisable;
blend.AlphaToCoverageEnable = true;
billboardPSO.SetBlendState(blend);
修改debug渲染效率过低的问题
visual studio =》 调试 =》 性能探查器(勾选CPU),运行几秒后关闭,会自动展示代码的热度。
发现水体的顶点update有很严重的效率问题。
这里稍微修改下。详见代码对比。
总结
本章主要是学习GS的概念和写法。
GS功能:通过对顶点的增减来增减图元。一个点传进来,我甚至可以在任意位置生成任意多个图元。
对于文中提到的纹理数组,MiniEngine很好的做了支持,毕竟这是DDS加载自带的支持,我本身也没有细看。