早几年学习后处理Shader的时候,遇到编辑器视口中的渲染结果与视口大小不匹配的问题: ![](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/PostProcessMaterialError.png) PS.该问题不会在使用SceneTexture节点制作的后处理效果材质中发生。但它不易于维护与修改。所以我花了些时间来解决这个问题。 ## 问题成因与解决方法 可以看得出这个问题是因为ViewSize与BufferSize不一造成的。经过一系列测试使用ViewportUVToBufferUV()对UV坐标进行转换就可以解决问题,该函数位于Common.h。 ```c# float2 ViewportUVToBufferUV(float2 ViewportUV) { float2 PixelPos = ViewportUV * View.ViewSizeAndInvSize.xy; return (PixelPos + View.ViewRectMin.xy) * View.BufferSizeAndInvSize.zw; } ``` ScreenUV使用GetViewportUV(Parameters)来获取,Step为ResolvedView.ViewSizeAndInvSize.zw,用法大致如下: ```c# float GetDepthTestWeight(float2 ScreenUV,float Stepx, float Stepy, float3x3 KernelX, float3x3 KernelY,float DepthTestThreshold) { float3x3 image; float CurrentPixelDepth=GetScreenSpaceData(ViewportUVToBufferUV(ScreenUV)).GBuffer.Depth; image = float3x3( length(GetScreenSpaceData(ViewportUVToBufferUV(ScreenUV + float2(-Stepx,Stepy))).GBuffer.Depth-CurrentPixelDepth), length(GetScreenSpaceData(ViewportUVToBufferUV(ScreenUV + float2(0,Stepy))).GBuffer.Depth-CurrentPixelDepth), length(GetScreenSpaceData(ViewportUVToBufferUV(ScreenUV + float2(Stepx,Stepy))).GBuffer.Depth-CurrentPixelDepth), length(GetScreenSpaceData(ViewportUVToBufferUV(ScreenUV + float2(-Stepx,0))).GBuffer.Depth-CurrentPixelDepth), 0, length(GetScreenSpaceData(ViewportUVToBufferUV(ScreenUV + float2(Stepx,0))).GBuffer.Depth-CurrentPixelDepth), length(GetScreenSpaceData(ViewportUVToBufferUV(ScreenUV + float2(-Stepx,-Stepy))).GBuffer.Depth-CurrentPixelDepth), length(GetScreenSpaceData(ViewportUVToBufferUV(ScreenUV + float2(0,-Stepy))).GBuffer.Depth-CurrentPixelDepth), length(GetScreenSpaceData(ViewportUVToBufferUV(ScreenUV + float2(Stepx,-Stepy))).GBuffer.Depth-CurrentPixelDepth) ); UNROLL for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { // image[i][j] = image[i][j] > CurrentPixelDepth * DepthTestThreshold ? 1 : 0; image[i][j] = saturate(image[i][j] / (CurrentPixelDepth * DepthTestThreshold)); } } float2 StrokeWeight; StrokeWeight.x = convolve(KernelX, image); StrokeWeight.y = convolve(KernelY, image); return length(StrokeWeight); } ``` 当然如果是直接在渲染管线里添加渲染Pass的方式来实现后处理效果,那也不会出现这个问题,因为每帧都会按照View大小创建新的buffer,所以不会出现这个问题。 ## 材质编辑器的相关大小节点。 - ScreenPosition:代码为GetViewportUV(FMaterialVertexParameters Parameters)。 - ViewSize:可视视口的大小。代码为View.ViewSizeAndInvSize.xy,zw为倒数值。 - MF_ScreenResolution:具体有VisibleResolution(就是ViewSize节点输出结果) 与BufferResolution(ViewProperty的RenderTargetSize) - SceneTexelSize(场景纹素大小):这是一个float2的值,对应着UV,(u,v),uv均为正数。 - MF_ScreenAlignedPixelToPixelUVs:RenderTargetSize / TextureSize。 其中TextureSize可以是ViewSize。可以用来实现一些修改View大小后,后处理尺寸不变得效果。 - 后处理节点的Size:ClampSceneTextureUV(ViewportUVToSceneTextureUV,SceneTextureId)