看到HDRP源码中通过DrawProcedural绘制一个三角形来实现全屏绘制,代码是这样的:
m_CommandBuffer.DrawProcedural(Matrix4x4.identity, m_SharedMaterial, 1, MeshTopology.Triangles, 3, 1, null);
v2f vert(appdata v)
{
v2f o;
o.vertex = GetFullScreenTriangleVertexPosition(v.vertexID);
o.uv = GetFullScreenTriangleTexCoord(v.vertexID);
return o;
}
开始有点懵逼,后来计算了一下发现是用三角形内部的一个正方形来实现屏幕着色。
// 顶点位置转换到裁剪空间位置
// 只考虑xy,通过第一行代码得到,
// 索引0, x: 0<<1=00, 00&10=00 y: 00&10=0,所以0号位对应坐标为0,0
// 索引1, x: 1<<1=10, 10&10=10 y: 01&10=0, 所以1号位对应坐标为2,0
// 索引2, x: 2<<1=100, 100&010=000 y:10&10=10,所以2号位对应坐标为0,2
// *2-1映射后,顶点的坐标为
// v0:-1,-1
// v1:3,-1
// v2:-1,3
float4 GetFullScreenTriangleVertexPosition(uint vertexID, float z = UNITY_NEAR_CLIP_VALUE)
{
float2 uv = float2((vertexID << 1) & 2, vertexID & 2);
return float4(uv * 2.0 - 1.0, z, 1.0);
}
// UV坐标为:
// 索引0, x: 0<<1=00, 00&10=00 y: 00&10=0,所以0号位对应UV坐标为0,0
// 索引1, x: 1<<1=10, 10&10=10 y: 01&10=0, 所以1号位对应UV坐标为2,0
// 索引2, x: 2<<1=100, 100&010=000 y:10&10=10,所以2号位对应UV坐标为0,2
float2 GetFullScreenTriangleTexCoord(uint vertexID)
{
#if UNITY_UV_STARTS_AT_TOP
return float2((vertexID << 1) & 2, 1.0 - (vertexID & 2));
#else
return float2((vertexID << 1) & 2, vertexID & 2);
#endif
}
三个顶点在裁剪空间坐标:
v0:-1,1
v1:3,-1
v2:-1,3
三个顶点的UV坐标:
uv0:0,0
uv1:2,0
uv2:0,2
因为裁剪空间中进行齐次除法(w分量为1)后的值域范围是-1,1,所以在这个范围上的UV坐标为:
(0,0) (1,0)?(1,1) (0,1),是标准的屏幕UV值域,就可以正常的对屏幕上的各种buffer采样。
|