private void AttachPostProcessing(CommandBuffer commandBuffer, Material material, int w, int h, RenderTextureFormat defaultFormat, RenderTargetIdentifier renderedImageId, WeatherMakerTemporalReprojectionState reprojState, Camera camera, ref int postSourceId, ref RenderTargetIdentifier postSource) { if (material.passCount > 2) { if (renderedImageId == CameraTargetIdentifier()) { Debug.LogError("Weather Maker command buffer post processing cannot blit directly to camera target"); } else { int downsampleMain = WMS._MainTex2; float postScale = (float)Mathf.Max((int)DownsampleScale, (int)DownsampleScalePostProcess); commandBuffer.SetGlobalFloat(WMS._WeatherMakerDownsampleScale, postScale); postSourceId = WMS._MainTex4; postSource = new RenderTargetIdentifier(WMS._MainTex4); commandBuffer.GetTemporaryRT(postSourceId, GetRenderTextureDescriptor((int)postScale, 0, 1, defaultFormat, 0, camera), FilterMode.Bilinear); if (reprojState == null) { if ((int)DownsampleScale < (int)DownsampleScalePostProcess) { // downsample main texture commandBuffer.GetTemporaryRT(downsampleMain, GetRenderTextureDescriptor((int)postScale, 0, 1, defaultFormat, 0, camera), FilterMode.Bilinear); commandBuffer.GetTemporaryRT(postSourceId, GetRenderTextureDescriptor((int)postScale, 0, 1, defaultFormat, 0, camera), FilterMode.Bilinear); commandBuffer.SetGlobalTexture(WMS._MainTex2, downsampleMain); commandBuffer.Blit(renderedImageId, downsampleMain); commandBuffer.Blit(downsampleMain, postSourceId, material, 2); commandBuffer.ReleaseTemporaryRT(downsampleMain); } else { commandBuffer.SetGlobalTexture(WMS._MainTex2, renderedImageId); commandBuffer.Blit(renderedImageId, postSourceId, material, 2); } } else if ((int)DownsampleScale * (int)reprojState.ReprojectionSize < (int)DownsampleScalePostProcess) { commandBuffer.GetTemporaryRT(downsampleMain, GetRenderTextureDescriptor((int)postScale, 0, 1, defaultFormat, 0, camera), FilterMode.Bilinear); commandBuffer.GetTemporaryRT(postSourceId, GetRenderTextureDescriptor((int)postScale, 0, 1, defaultFormat, 0, camera), FilterMode.Bilinear); commandBuffer.SetGlobalTexture(WMS._MainTex2, downsampleMain); commandBuffer.Blit(reprojState.PrevFrameTexture, downsampleMain); commandBuffer.Blit(downsampleMain, postSourceId, material, 2); commandBuffer.ReleaseTemporaryRT(downsampleMain); } else { commandBuffer.SetGlobalTexture(WMS._MainTex2, reprojState.PrevFrameTexture); commandBuffer.Blit(reprojState.PrevFrameTexture, postSourceId, material, 2); } commandBuffer.SetGlobalFloat(WMS._WeatherMakerDownsampleScale, (float)DownsampleScale); commandBuffer.SetGlobalTexture(WMS._MainTex4, postSourceId); commandBuffer.Blit(postSourceId, renderedImageId, material, 3); // pass index 3 is post process blit pass commandBuffer.ReleaseTemporaryRT(postSourceId); } } }
/// <summary> /// Post render event /// </summary> /// <param name="camera">Camera</param> public void PostRenderCamera(Camera camera) { if (camera != null && Enabled) { WeatherMakerTemporalReprojectionState reprojState = temporalStates.Find(b => b.Camera == camera); if (reprojState != null) { reprojState.PostRenderFrame(camera); } } }
private void AttachTemporalReprojection(CommandBuffer commandBuffer, WeatherMakerTemporalReprojectionState reprojState, RenderTargetIdentifier depthTarget, RenderTargetIdentifier renderedImageId, Material material, int scale, RenderTextureFormat defaultFormat) { if (reprojState.NeedsFirstFrameHandling) { // do a more expensive render once to get the image looking nice, only happens once on first frame commandBuffer.Blit(depthTarget, reprojState.PrevFrameTexture, material, 0); // copy to sub frame so it's ready for next pass commandBuffer.Blit(reprojState.PrevFrameTexture, reprojState.SubFrameTexture); // copy to final image commandBuffer.Blit(reprojState.PrevFrameTexture, renderedImageId); } else if (reprojState.IntegratedTemporalReprojection) { // render fast pass with offset temporal reprojection so it is available in the full pass commandBuffer.SetGlobalFloat(WMS._WeatherMakerTemporalReprojectionEnabled, 1.0f); commandBuffer.Blit(depthTarget, reprojState.SubFrameTexture, material, 0); // perform full pass with full temporal reprojection commandBuffer.SetGlobalFloat(WMS._WeatherMakerTemporalReprojectionEnabled, 2.0f); commandBuffer.Blit(reprojState.SubFrameTexture, renderedImageId, material, 0); // copy to previous frame so we can re-use it next frame if (reprojState.BlendMode == WeatherMakerTemporalReprojectionState.TemporalReprojectionBlendMode.Blur) { commandBuffer.Blit(reprojState.SubFrameTexture, reprojState.PrevFrameTexture); } else { commandBuffer.Blit(renderedImageId, reprojState.PrevFrameTexture); } } else { // render to sub frame (fast, this is a small texture) commandBuffer.SetGlobalFloat(WMS._WeatherMakerTemporalReprojectionEnabled, 1.0f); commandBuffer.Blit(depthTarget, reprojState.SubFrameTexture, material, 0); // combine sub frame and prev frame to final image commandBuffer.Blit(reprojState.PrevFrameTexture, renderedImageId, reprojState.TemporalReprojectionMaterial, 0); // copy combined to previous frame for re-use next frame commandBuffer.Blit(renderedImageId, reprojState.PrevFrameTexture); } commandBuffer.SetGlobalFloat(WMS._WeatherMakerTemporalReprojectionEnabled, 0.0f); }
/// <summary> /// Update the full screen effect, usually called from OnPreRender or OnPreCull /// </summary> /// <param name="camera">Camera</param> /// <param name="integratedTemporalReprojection">Whether to use integrated temporal reprojection (if temporal reprojection is enabled)</param> public void PreCullCamera(Camera camera, bool integratedTemporalReprojection = true) { //integratedTemporalReprojection = false; if (WeatherMakerScript.Instance != null && WeatherMakerScript.Instance.CommandBufferManager != null && (Enabled || preSetupCommandBuffer != null) && Material != null && clonedMaterial != null && camera != null) { WeatherMakerCameraType cameraType = WeatherMakerScript.GetCameraType(camera); if (cameraType == WeatherMakerCameraType.Other) { return; } WeatherMakerTemporalReprojectionState reprojState = null; WeatherMakerDownsampleScale downsampleScale = DownsampleScale; if (cameraType != WeatherMakerCameraType.Normal) { if (camera.pixelWidth > 2000) { downsampleScale = WeatherMakerDownsampleScale.QuarterResolution; } else if (camera.pixelWidth > 1000) { downsampleScale = WeatherMakerDownsampleScale.HalfResolution; } } if (Enabled) { // setup temporal reprojection state reprojState = temporalStates.Find(b => b.Camera == camera); if (reprojState == null) { // temporal reprojection is not currently possible with cubemap if (TemporalReprojection != WeatherMakerTemporalReprojectionSize.None && TemporalReprojectionMaterial != null && (cameraType == WeatherMakerCameraType.Normal || cameraType == WeatherMakerCameraType.Reflection)) { reprojState = new WeatherMakerTemporalReprojectionState(camera, TemporalReprojectionMaterial, integratedTemporalReprojection); temporalStates.Add(reprojState); } } else if (TemporalReprojection == WeatherMakerTemporalReprojectionSize.None || TemporalReprojectionMaterial == null) { reprojState.Dispose(); temporalStates.Remove(reprojState); reprojState = null; } if (reprojState != null) { WeatherMakerTemporalReprojectionSize reprojSize = (cameraType == WeatherMakerCameraType.Normal ? TemporalReprojection : WeatherMakerTemporalReprojectionSize.FourByFour); reprojState.PreCullFrame(camera, downsampleScale, reprojSize); } } WeatherMakerCommandBuffer cmdBuffer = CreateCommandBuffer(camera, reprojState, downsampleScale, preSetupCommandBuffer); if (reprojState != null) { reprojState.CommandBuffer = cmdBuffer; } } }
private WeatherMakerCommandBuffer CreateCommandBuffer(Camera camera, WeatherMakerTemporalReprojectionState reprojState, WeatherMakerDownsampleScale downsampleScale, System.Action <WeatherMakerCommandBuffer> preSetupCommandBuffer) { if (WeatherMakerScript.Instance == null) { Debug.LogError("Cannot create command buffer, WeatherMakerScript.Instance is null"); return(null); } // Debug.Log("Creating command buffer " + CommandBufferName); WeatherMakerCommandBuffer weatherMakerCommandBuffer = GetOrCreateWeatherMakerCommandBuffer(camera); // multi-pass vr uses one command buffer for each eye if (camera.stereoTargetEye == StereoTargetEyeMask.Right) { weatherMakerCommandBuffer.Camera = camera; return(weatherMakerCommandBuffer); } else if (weatherMakerCommandBuffer != null && weatherMakerCommandBuffer.CommandBuffer != null) { camera.RemoveCommandBuffer(RenderQueue, weatherMakerCommandBuffer.CommandBuffer); weatherMakerCommandBuffer.CommandBuffer.Clear(); } RenderTextureFormat defaultFormat = (camera.allowHDR ? RenderTextureFormat.DefaultHDR : RenderTextureFormat.Default); CommandBuffer commandBuffer = weatherMakerCommandBuffer.CommandBuffer; int postSourceId = -1; RenderTargetIdentifier postSource = postSourceId; WeatherMakerCameraType cameraType = weatherMakerCommandBuffer.CameraType; // setup reprojection state if (reprojState != null) { reprojState.PreRenderFrame(camera, WeatherMakerCommandBufferManagerScript.BaseCamera, commandBuffer); if (!reprojState.NeedsFirstFrameHandling && reprojState.BlendMode == WeatherMakerTemporalReprojectionState.TemporalReprojectionBlendMode.Sharp) { float xo = reprojState.TemporalOffsetX; float yo = reprojState.TemporalOffsetY; commandBuffer.SetGlobalVector(WMS._WeatherMakerTemporalUV, new Vector4(xo, yo, 1.0f, 1.0f)); } else { commandBuffer.SetGlobalVector(WMS._WeatherMakerTemporalUV, Vector4.zero); } } int scale = (int)downsampleScale; if (reprojState != null && reprojState.BlendMode == WeatherMakerTemporalReprojectionState.TemporalReprojectionBlendMode.Blur) { int totalDownScale = (scale * reprojState.ReprojectionSize); switch (totalDownScale) { case 0: case 1: totalDownScale = 1; break; case 2: case 3: totalDownScale = 2; break; case 4: case 5: totalDownScale = 4; break; case 6: case 7: case 8: case 9: case 10: case 11: totalDownScale = 8; break; default: totalDownScale = 16; break; } //Debug.LogFormat("Total down scale: {0}, {1}, {2}", totalDownScale, scale, reprojState.ReprojectionSize); commandBuffer.SetGlobalFloat(WMS._WeatherMakerDownsampleScale, (float)totalDownScale); } else { commandBuffer.SetGlobalFloat(WMS._WeatherMakerDownsampleScale, scale); } if (preSetupCommandBuffer != null) { preSetupCommandBuffer.Invoke(weatherMakerCommandBuffer); } if (Enabled) { commandBuffer.SetGlobalFloat(WMS._WeatherMakerTemporalReprojectionEnabled, 0.0f); commandBuffer.SetGlobalVector(WMS._WeatherMakerTemporalUV_VertexShaderProjection, Vector4.zero); commandBuffer.SetGlobalVector(WMS._WeatherMakerTemporalUV_FragmentShader, Vector4.zero); if (DownsampleRenderBufferScale != WeatherMakerDownsampleScale.Disabled) { // render camera target to texture, performing separate down-sampling commandBuffer.GetTemporaryRT(WMS._MainTex5, GetRenderTextureDescriptor((int)DownsampleRenderBufferScale, 0, 1, defaultFormat, 0, camera), FilterMode.Bilinear); commandBuffer.Blit(CameraTargetIdentifier(), WMS._MainTex5); } commandBuffer.SetGlobalFloat(WMS._ZTest, (float)ZTest); // if no blur, no downsample, no temporal reprojection and no post processing (pass count > 2) then we can just draw directly to camera target if (BlurShaderType == BlurShaderType.None && DownsampleScale == WeatherMakerDownsampleScale.FullResolution && reprojState == null && clonedMaterial.passCount < 3) { // set blend mode for blitting to camera target commandBuffer.SetGlobalFloat(WMS._SrcBlendMode, (float)SourceBlendMode); commandBuffer.SetGlobalFloat(WMS._DstBlendMode, (float)DestBlendMode); commandBuffer.Blit(CameraTargetIdentifier(), CameraTargetIdentifier(), clonedMaterial, 0); } else { // render to texture, using current image target as input _MainTex, no blend // alpha or blue will use _MainTex to render the final result int renderTargetRenderedImageId = WMS._MainTex3; int renderTargetDepthTextureId = WMS._WeatherMakerTemporaryDepthTexture; RenderTargetIdentifier renderTargetRenderedImage = new RenderTargetIdentifier(renderTargetRenderedImageId); RenderTargetIdentifier renderTargetDepthTexture = new RenderTargetIdentifier(renderTargetDepthTextureId); BlurShaderType blur = BlurShaderType; if (cameraType != WeatherMakerCameraType.Normal) { if (BlurMaterial.passCount > 3) { blur = BlurShaderType.Bilateral; } else { blur = BlurShaderType.GaussianBlur17; } } int mod = (reprojState == null ? 0 : reprojState.ReprojectionSize); commandBuffer.GetTemporaryRT(renderTargetRenderedImageId, GetRenderTextureDescriptor(scale, mod, 1, defaultFormat, 0, camera), FilterMode.Bilinear); commandBuffer.GetTemporaryRT(renderTargetDepthTextureId, GetRenderTextureDescriptor(scale, mod, 1, RenderTextureFormat.RFloat, 0, camera), FilterMode.Point); // set blend mode for blitting to render texture commandBuffer.SetGlobalFloat(WMS._SrcBlendMode, (float)BlendMode.One); commandBuffer.SetGlobalFloat(WMS._DstBlendMode, (float)BlendMode.Zero); if (reprojState == null || reprojState.TemporalReprojectionMaterial == null) { // render to final destination commandBuffer.Blit(renderTargetDepthTextureId, renderTargetRenderedImage, clonedMaterial, 0); } else { AttachTemporalReprojection(commandBuffer, reprojState, renderTargetDepthTextureId, renderTargetRenderedImage, clonedMaterial, scale, defaultFormat); } if (cameraType == WeatherMakerCameraType.Normal && DownsampleScalePostProcess != WeatherMakerDownsampleScale.Disabled) { AttachPostProcessing(commandBuffer, clonedMaterial, 0, 0, defaultFormat, renderTargetRenderedImage, reprojState, camera, ref postSourceId, ref postSource); //AttachPostProcessing(commandBuffer, material, w, h, defaultFormat, renderTargetRenderedImageId, reprojState, ref postSourceId, ref postSource); } AttachBlurBlit(commandBuffer, renderTargetRenderedImage, renderTargetDepthTexture, CameraTargetIdentifier(), clonedMaterial, blur, defaultFormat, camera); // cleanup commandBuffer.ReleaseTemporaryRT(renderTargetRenderedImageId); commandBuffer.ReleaseTemporaryRT(renderTargetDepthTextureId); commandBuffer.SetGlobalTexture(WMS._MainTex2, new RenderTargetIdentifier(BuiltinRenderTextureType.None)); } if (DownsampleRenderBufferScale != WeatherMakerDownsampleScale.Disabled) { // cleanup commandBuffer.ReleaseTemporaryRT(WMS._MainTex5); } } weatherMakerCommandBuffer.Material = clonedMaterial; weatherMakerCommandBuffer.ReprojectionState = reprojState; weatherMakerCommandBuffer.RenderQueue = RenderQueue; camera.AddCommandBuffer(RenderQueue, commandBuffer); if (WeatherMakerCommandBufferManagerScript.Instance != null) { WeatherMakerCommandBufferManagerScript.Instance.AddCommandBuffer(weatherMakerCommandBuffer); } return(weatherMakerCommandBuffer); }