新项目开坑HDRP渲染管线,花了些时间把项目开发框架和图形工作流更新到最新版本,其间发现HDRP中深度信息和buildin渲染管线翻转了。
以前的buildin渲染管线,距离摄像机越近depth->0,越远depth->1,这也很好理解,离得越近距离越小,颜色值->(0,0,0,0)黑色,如下:
而新HDRP中,深度如下:
可以看的出来是反过来的,也就是距离摄像机越近depth->1,越远depth->0。
unity说是因为HDRP本身是为了支持高级图形硬件的图形语言比如hlsl设定的(比如dx和opengl的坐标系也是反的,同时uv也可能上下颠倒),当然这也不是什么大事,无非刚开始搞反了导致效果出问题,测试出来后改一改就好了。
接下来根据新的规范实现一个遮挡剔除和不剔除的外发光特效,因为以前写过外发光特效的原理,所以这里从简,只叙述一下大纲:
1.采样物体的轮廓纹理,进行纯色渲染。
2.高斯滤波进行后处理得到轮廓像素外扩的纯色渲染。
3.根据当前pixel片段所在的摄像机深度缓冲和物体轮廓纹理的深度相比较,如果片段轮廓纹理depth值更小,则代表距离摄像机更远,则被剔除渲染。
//滤波矩阵
static float _GaussMatrix[9] = { 0.07511362, 0.1238414, 0.07511362, 0.1238414, 0.20418, 0.1238414, 0.07511362, 0.1238414, 0.07511362 };
VaryingsEx VertBlur(AttributesEx input)
{
VaryingsEx output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
//必须采样屏幕坐标
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
//采样uv坐标,用于纹理采样
output.uv = GetFullScreenTriangleTexCoord(input.vertexID);
float c = 1;
for(int x=0;x<3;x++)
{
for(int y=0;y<3;y++)
{
output.uvs[x*3+y] = (output.uv+_CustomColorTexture_TexelSize.xy*float2((y-c)*_BlurSpread,(x-c)*_BlurSpread));
}
}
return output;
}
float4 FragBlur(VaryingsEx input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float4 col = float4(0,0,0,0);
for(int k=0;k<9;k++)
{
col+=(CustomPassSampleCustomColor(input.uvs[k])*_GaussMatrix[k]);
}
col*=_Brightness;
//采样上一个custompass纹理
//如果纹理有颜色数据,则剔除掉,就可以显示最底层的模型渲染纹理
float4 ocol = CustomPassSampleCustomColor(input.uv);
if(ocol.a>0)
{
discard;
}
return col;
}
以上是进行高斯滤波和原始纹理裁剪得到轮廓外发光效果。
void GetSurfaceAndBuiltinData(FragInputs fragInputs, float3 viewDirection, inout PositionInputs posInput, out SurfaceData surfaceData, out BuiltinData builtinData)
{
float2 colorMapUv = TRANSFORM_TEX(fragInputs.texCoord0.xy, _ColorMap);
float4 result = SAMPLE_TEXTURE2D(_ColorMap, s_trilinear_clamp_sampler, colorMapUv);
//hdrp摄像机深度值由近到远1->0深度图采样near=1,far=0
//通过像素坐标xy值采样深度信息
float camdepth = LoadCameraDepth(fragInputs.positionSS.xy);
//当前像素深度信息由近到远
//1->0
float vertexdepth = posInput.deviceDepth;
if(_OcclutionDiscard == 1)
{
//如果当前像素的深度值<深度图深度值
//则表示当前像素距离摄像机更远
//则被剔除渲染
if(vertexdepth<camdepth)
{
discard;
}
}
// Write back the data to the output structures
ZERO_BUILTIN_INITIALIZE(builtinData); // No call to InitBuiltinData as we don't have any lighting
ZERO_INITIALIZE(SurfaceData, surfaceData);
builtinData.opacity = result.a;
builtinData.emissiveColor = float3(0, 0, 0);
surfaceData.color = camdepth;
}
以上是根据深度缓冲进行剔除和非剔除采样。
可以看到添加物体外发光和选择遮挡剔除完成需要的效果。
ps:因为现在更加倾向于自身健康和家庭生活,所以博客只会偶尔花最多半个小时对一些技术要点(或坑点)进行说明。