57 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			57 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								早几年学习后处理Shader的时候,遇到编辑器视口中的渲染结果与视口大小不匹配的问题:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								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)
							 |