protected override void OnRenderFrame(FrameEventArgs e) { GL.Enable(EnableCap.ClipDistance0); GL.Enable(EnableCap.DepthTest); GL.Disable(EnableCap.Blend); // Shadow rendering shadows.ShadowBuffer.Bind(); GL.Clear(ClearBufferMask.DepthBufferBit); assets.RenderShadowMap(shadows, terrain); terrain.RenderShadowMap(camera, shadows, ClipPlane.ClipBottom); GL.ClipControl(ClipOrigin.LowerLeft, ClipDepthMode.ZeroToOne); // Water refraction rendering water.RefractionBuffer.Bind(); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); terrain.Render(camera, light, null, ClipPlane.ClipTop); assets.Render(camera, light, null, terrain, ClipPlane.ClipTop); // Water reflection rendering camera.InvertY(); water.ReflectionBuffer.Bind(); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); terrain.Render(camera, light, null, ClipPlane.ClipBottom); assets.Render(camera, light, null, terrain, ClipPlane.ClipBottom); sky.Render(camera, light); GL.Disable(EnableCap.ClipDistance0); camera.Reset(); // Main rendering multisampling.Bind(); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.PolygonMode(MaterialFace.FrontAndBack, State.PolygonMode); sky.Render(camera, light); terrain.Render(camera, light, shadows, ClipPlane.ClipBottom); water.Render(camera, light, shadows); GL.Enable(EnableCap.SampleShading); assets.Render(camera, light, shadows, terrain, ClipPlane.ClipBottom); GL.Disable(EnableCap.SampleShading); // UI and debug GL.Enable(EnableCap.Blend); GL.PolygonMode(MaterialFace.Front, PolygonMode.Fill); GL.Disable(EnableCap.DepthTest); GL4.GL.BlendFuncSeparate(GL4.BlendingFactorSrc.SrcAlpha, GL4.BlendingFactorDest.OneMinusSrcAlpha, GL4.BlendingFactorSrc.One, GL4.BlendingFactorDest.One); GL.ClipControl(ClipOrigin.LowerLeft, ClipDepthMode.NegativeOneToOne); ui.Render(); // shadows.ShadowBuffer.DrawDepthBuffer(); // Draw to screen multisampling.Draw(); SwapBuffers(); State.Time.CountFPS(); }
private RenderTarget2D RenderScene(CameraFrustumQuery frustumQuery, RenderContext context) { // Set an offscreen render target. The size is determined by the current viewport. RenderTarget2D sceneRenderTarget = GraphicsService.RenderTargetPool.Obtain2D( new RenderTargetFormat( context.Viewport.Width, context.Viewport.Height, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8)); var graphicsDevice = GraphicsService.GraphicsDevice; graphicsDevice.SetRenderTarget(sceneRenderTarget); // Update the info in the render context. Some renderers or effects might use this info. context.RenderTarget = sceneRenderTarget; context.Viewport = graphicsDevice.Viewport; graphicsDevice.Clear(Color.CornflowerBlue); // Render the meshes using the "Default" material. graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.Opaque; graphicsDevice.SamplerStates[0] = SamplerState.AnisotropicWrap; context.RenderPass = "******"; _meshRenderer.Render(frustumQuery.SceneNodes, context); context.RenderPass = null; // Render the sky. _skyRenderer.Render(frustumQuery.SceneNodes, context); // Set the render states for alpha blended objects and render BillboardNodes // and ParticleSystemNodes. graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; graphicsDevice.RasterizerState = RasterizerState.CullNone; graphicsDevice.BlendState = BlendState.NonPremultiplied; graphicsDevice.SamplerStates[0] = SamplerState.LinearWrap; _billboardRenderer.Render(frustumQuery.SceneNodes, context); return(sceneRenderTarget); }
// Renders the sky. This method is the RenderCallback of the SceneCaptureNode. private void RenderSky(RenderContext context) { var graphicsDevice = _graphicsService.GraphicsDevice; var renderTargetPool = _graphicsService.RenderTargetPool; // We have to render into this render target. var ldrTarget = context.RenderTarget; // Reset render states. graphicsDevice.BlendState = BlendState.Opaque; graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; // Use an intermediate HDR render target with the same resolution as the final target. var format = new RenderTargetFormat(ldrTarget) { SurfaceFormat = SurfaceFormat.HdrBlendable, DepthStencilFormat = DepthFormat.Depth24Stencil8 }; var hdrTarget = renderTargetPool.Obtain2D(format); graphicsDevice.SetRenderTarget(hdrTarget); context.RenderTarget = hdrTarget; graphicsDevice.Clear(Color.Black); // Render the sky. _skyRenderer.Render(_skyGroupNode.Children, context); // Convert the HDR image to RGBM image. context.SourceTexture = hdrTarget; context.RenderTarget = ldrTarget; _colorEncoder.Process(context); context.SourceTexture = null; // Clean up. renderTargetPool.Recycle(hdrTarget); context.RenderTarget = ldrTarget; }
protected internal void RenderScene(CustomSceneQuery sceneQuery, RenderContext context, bool doPostProcessing, bool renderLensFlares, bool renderDebugOutput, bool renderReticle) { var renderTargetPool = GraphicsService.RenderTargetPool; var graphicsDevice = GraphicsService.GraphicsDevice; var originalRenderTarget = context.RenderTarget; var originalViewport = context.Viewport; var originalSourceTexture = context.SourceTexture; // All intermediate render targets have the size of the target viewport. int width = context.Viewport.Width; int height = context.Viewport.Height; context.Viewport = new Viewport(0, 0, width, height); // The render context can be used to share any data, for example: // Store a shared RebuildZBufferRenderer in the context. context.Data[RenderContextKeys.RebuildZBufferRenderer] = _rebuildZBufferRenderer; // ----- G-Buffer Pass // The GBufferRenderer creates context.GBuffer0 and context.GBuffer1. _gBufferRenderer.Render(sceneQuery.RenderableNodes, sceneQuery.DecalNodes, context); // ----- Shadow Pass // The ShadowMapRenderer renders the shadow maps which are stored in the light nodes. context.RenderPass = "******"; ShadowMapRenderer.Render(sceneQuery.Lights, context); context.RenderPass = null; // The ShadowMaskRenderer renders the shadows and stores them in one or more render // targets ("shadows masks"). ShadowMaskRenderer.Render(sceneQuery.Lights, context); RecycleShadowMaps(sceneQuery.Lights); // ----- Light Buffer Pass // The LightBufferRenderer creates context.LightBuffer0 (diffuse light) and // context.LightBuffer1 (specular light). LightBufferRenderer.Render(sceneQuery.Lights, context); // Normally, we do not need the shadow masks anymore - except if we want to // display them for debugging. if (!VisualizeIntermediateRenderTargets) { ShadowMaskRenderer.RecycleShadowMasks(); } // ----- Material Pass if (DebugMode == DeferredGraphicsDebugMode.None) { // In the material pass we render all meshes and decals into a single full-screen // render target. The shaders combine the material properties (diffuse texture, etc.) // with the light buffer info. context.RenderTarget = renderTargetPool.Obtain2D(new RenderTargetFormat(width, height, false, SurfaceFormat.HdrBlendable, DepthFormat.Depth24Stencil8)); graphicsDevice.SetRenderTarget(context.RenderTarget); context.Viewport = graphicsDevice.Viewport; graphicsDevice.Clear(new Color(3, 3, 3, 255)); graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.Opaque; context.RenderPass = "******"; _opaqueMeshSceneRenderer.Render(sceneQuery.RenderableNodes, context); _decalRenderer.Render(sceneQuery.DecalNodes, context); context.RenderPass = null; } else { // For debugging: // Ignore the material pass. Keep rendering into one of the light buffers // to visualize only the lighting results. if (DebugMode == DeferredGraphicsDebugMode.VisualizeDiffuseLightBuffer) { context.RenderTarget = context.LightBuffer0; } else { context.RenderTarget = context.LightBuffer1; } } // The meshes rendered in the last step might use additional floating-point // textures (e.g. the light buffers) in the different graphics texture stages. // We reset the texture stages (setting all GraphicsDevice.Textures to null), // otherwise XNA might throw exceptions. graphicsDevice.ResetTextures(); // ----- Occlusion Queries if (renderLensFlares) { _lensFlareRenderer.UpdateOcclusion(sceneQuery.LensFlareNodes, context); } // ----- Sky _skyRenderer.Render(sceneQuery.SkyNodes, context); // ----- Fog _fogRenderer.Render(sceneQuery.FogNodes, context); // ----- Forward Rendering of Alpha-Blended Meshes and Particles graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.AlphaBlend; context.RenderPass = "******"; AlphaBlendSceneRenderer.Render(sceneQuery.RenderableNodes, context, RenderOrder.BackToFront); context.RenderPass = null; graphicsDevice.ResetTextures(); renderTargetPool.Recycle(context.SourceTexture); context.SourceTexture = null; _underwaterPostProcessor.Enabled = IsCameraUnderwater(sceneQuery, context.CameraNode); // ----- Post Processors context.SourceTexture = context.RenderTarget; context.RenderTarget = originalRenderTarget; context.Viewport = originalViewport; if (doPostProcessing) { // The post-processors modify the scene image and the result is written into // the final render target - which is usually the back buffer (but this could // also be another off-screen render target used in another graphics screen). PostProcessors.Process(context); } else { // Only copy the current render target to the final render target without post-processing. graphicsDevice.SetRenderTarget(originalRenderTarget); graphicsDevice.Viewport = originalViewport; SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone); SpriteBatch.Draw(context.SourceTexture, new Rectangle(0, 0, originalViewport.Width, originalViewport.Height), Color.White); SpriteBatch.End(); } renderTargetPool.Recycle((RenderTarget2D)context.SourceTexture); context.SourceTexture = null; // ----- Lens Flares if (renderLensFlares) { _lensFlareRenderer.Render(sceneQuery.LensFlareNodes, context); } // ----- Debug Output if (renderDebugOutput) { // ----- Optional: Restore the Z-Buffer // Currently, the hardware depth buffer is not initialized with useful data because // every time we change the render target, XNA deletes the depth buffer. If we want // the debug rendering to use correct depth buffer, we can restore the depth buffer // using the RebuildZBufferRenderer. If we remove this step, then the DebugRenderer // graphics will overlay the whole 3D scene. _rebuildZBufferRenderer.Render(context, true); // Render debug info added by game objects. DebugRenderer.Render(context); // Render intermediate render targets for debugging. // We do not use the public DebugRenderer here because the public DebugRenderer // might not be cleared every frame (the game logic can choose how it wants to // use the public renderer). if (VisualizeIntermediateRenderTargets) { _internalDebugRenderer.DrawTexture(context.GBuffer0, new Rectangle(0, 0, 200, 200)); _internalDebugRenderer.DrawTexture(context.GBuffer1, new Rectangle(200, 0, 200, 200)); _internalDebugRenderer.DrawTexture(context.LightBuffer0, new Rectangle(400, 0, 200, 200)); _internalDebugRenderer.DrawTexture(context.LightBuffer1, new Rectangle(600, 0, 200, 200)); for (int i = 0; i < ShadowMaskRenderer.ShadowMasks.Count; i++) { var shadowMask = ShadowMaskRenderer.ShadowMasks[i]; if (shadowMask != null) { _internalDebugRenderer.DrawTexture(shadowMask, new Rectangle((i) * 200, 200, 200, 200)); } } _internalDebugRenderer.Render(context); _internalDebugRenderer.Clear(); } } // ----- Draw Reticle if (renderReticle && _sampleFramework.IsGuiVisible) { SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend); SpriteBatch.Draw( _reticle, new Vector2(originalViewport.Width / 2 - _reticle.Width / 2, originalViewport.Height / 2 - _reticle.Height / 2), Color.Black); SpriteBatch.End(); } // ----- Clean-up // It is very important to give every intermediate render target back to the // render target pool! renderTargetPool.Recycle(context.GBuffer0); context.GBuffer0 = null; renderTargetPool.Recycle(context.GBuffer1); context.GBuffer1 = null; renderTargetPool.Recycle((RenderTarget2D)context.Data[RenderContextKeys.DepthBufferHalf]); context.Data.Remove(RenderContextKeys.DepthBufferHalf); if (DebugMode != DeferredGraphicsDebugMode.VisualizeDiffuseLightBuffer) { renderTargetPool.Recycle(context.LightBuffer0); } context.LightBuffer0 = null; if (DebugMode != DeferredGraphicsDebugMode.VisualizeSpecularLightBuffer) { renderTargetPool.Recycle(context.LightBuffer1); } context.LightBuffer1 = null; ShadowMaskRenderer.RecycleShadowMasks(); context.Data.Remove(RenderContextKeys.RebuildZBufferRenderer); context.SourceTexture = originalSourceTexture; }
// Renders the graphics screen. - This method is called in GraphicsManager.Render(). protected override void OnRender(RenderContext context) { // Abort if no active camera is set. if (ActiveCameraNode == null) { return; } var renderTargetPool = GraphicsService.RenderTargetPool; var graphicsDevice = GraphicsService.GraphicsDevice; var screenRenderTarget = context.RenderTarget; var viewport = context.Viewport; // All intermediate render targets have the size of the target viewport. int width = context.Viewport.Width; int height = context.Viewport.Height; context.Viewport = new Viewport(0, 0, width, height); // Our scene and the camera must be set in the render context. This info is // required by many renderers. context.Scene = Scene; context.CameraNode = ActiveCameraNode; // LOD (level of detail) settings are also specified in the context. context.LodCameraNode = ActiveCameraNode; context.LodHysteresis = 0.5f; context.LodBias = EnableLod ? 1.0f : 0.0f; context.LodBlendingEnabled = false; // Get all scene nodes which overlap the camera frustum. CustomSceneQuery sceneQuery = Scene.Query <CustomSceneQuery>(ActiveCameraNode, context); // Generate cloud maps. // (Note: Only necessary if LayeredCloudMaps are used. If the cloud maps are // static and the settings do not change, it is not necessary to generate the // cloud maps in every frame. But in this example we use animated cloud maps.) _cloudMapRenderer.Render(sceneQuery.SkyNodes, context); // ----- G-Buffer Pass // The GBufferRenderer creates context.GBuffer0 and context.GBuffer1. _gBufferRenderer.Render(sceneQuery.RenderableNodes, sceneQuery.DecalNodes, context); // ----- Shadow Pass // The ShadowMapRenderer renders the shadow maps which are stored in the light nodes. context.RenderPass = "******"; _shadowMapRenderer.Render(sceneQuery.Lights, context); context.RenderPass = null; // The ShadowMaskRenderer renders the shadows and stores them in one or more render // targets ("shadows masks"). _shadowMaskRenderer.Render(sceneQuery.Lights, context); // In this render pipeline we do not need most shadow maps anymore and can // recycle them. The exception is the DirectionalLight shadow map which // might still be needed for forward rendering of alpha-blended objects. foreach (var node in sceneQuery.Lights) { var lightNode = (LightNode)node; if (lightNode.Shadow != null && !(lightNode.Light is DirectionalLight)) { renderTargetPool.Recycle(lightNode.Shadow.ShadowMap); lightNode.Shadow.ShadowMap = null; } } // ----- Light Buffer Pass // The LightBufferRenderer creates context.LightBuffer0 (diffuse light) and // context.LightBuffer1 (specular light). LightBufferRenderer.Render(sceneQuery.Lights, context); // ----- Material Pass // In the material pass we render all meshes and decals into a single full-screen // render target. The shaders combine the material properties (diffuse texture, etc.) // with the light buffer info. context.RenderTarget = renderTargetPool.Obtain2D(new RenderTargetFormat(width, height, false, SurfaceFormat.HdrBlendable, DepthFormat.Depth24Stencil8)); graphicsDevice.SetRenderTarget(context.RenderTarget); context.Viewport = graphicsDevice.Viewport; graphicsDevice.Clear(Color.Black); graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.Opaque; context.RenderPass = "******"; _meshRenderer.Render(sceneQuery.RenderableNodes, context); _decalRenderer.Render(sceneQuery.DecalNodes, context); context.RenderPass = null; // The meshes rendered in the last step might use additional floating-point // textures (e.g. the light buffers) in the different graphics texture stages. // We reset the texture stages (setting all GraphicsDevice.Textures to null), // otherwise XNA might throw exceptions. graphicsDevice.ResetTextures(); // ----- Occlusion Queries _lensFlareRenderer.UpdateOcclusion(sceneQuery.LensFlareNodes, context); // ----- Sky _skyRenderer.Render(sceneQuery.SkyNodes, context); // ----- Fog _fogRenderer.Render(sceneQuery.FogNodes, context); // ----- Forward Rendering of Alpha-Blended Meshes and Particles graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.AlphaBlend; context.RenderPass = "******"; AlphaBlendSceneRenderer.Render(sceneQuery.RenderableNodes, context, RenderOrder.BackToFront); context.RenderPass = null; graphicsDevice.ResetTextures(); // The shadow maps could be used by some shaders of the alpha-blended // objects - but now, we can recycle all shadow maps. foreach (var node in sceneQuery.Lights) { var lightNode = (LightNode)node; if (lightNode.Shadow != null) { renderTargetPool.Recycle(lightNode.Shadow.ShadowMap); lightNode.Shadow.ShadowMap = null; } } // ----- Post Processors // The post-processors modify the scene image and the result is written into // the final render target - which is usually the back buffer (but this could // also be another off-screen render target used in another graphics screen). context.SourceTexture = context.RenderTarget; context.RenderTarget = screenRenderTarget; context.Viewport = viewport; PostProcessors.Process(context); renderTargetPool.Recycle((RenderTarget2D)context.SourceTexture); context.SourceTexture = null; // ----- Lens Flares _lensFlareRenderer.Render(sceneQuery.LensFlareNodes, context); // ----- Optional: Restore the Z-Buffer // Currently, the hardware depth buffer is not initialized with useful data because // every time we change the render target, XNA deletes the depth buffer. If we want // the debug rendering to use correct depth buffer, we can restore the depth buffer // using the RebuildZBufferRenderer. If we remove this step, then the DebugRenderer // graphics will overlay the whole 3D scene. _rebuildZBufferRenderer.Render(context, true); // ----- Debug Output // Render debug info added by game objects. DebugRenderer.Render(context); // ----- Draw Reticle if (DrawReticle) { _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend); _spriteBatch.Draw( _reticle, new Vector2(viewport.Width / 2 - _reticle.Width / 2, viewport.Height / 2 - _reticle.Height / 2), Color.Black); _spriteBatch.End(); } // Render intermediate render targets for debugging. // We do not use the public DebugRenderer here because the public DebugRenderer // might not be cleared every frame (the game logic can choose how it wants to // use the public renderer). if (VisualizeIntermediateRenderTargets) { _internalDebugRenderer.DrawTexture(context.GBuffer0, new Rectangle(0, 0, 200, 200)); _internalDebugRenderer.DrawTexture(context.GBuffer1, new Rectangle(200, 0, 200, 200)); _internalDebugRenderer.DrawTexture(context.LightBuffer0, new Rectangle(400, 0, 200, 200)); _internalDebugRenderer.DrawTexture(context.LightBuffer1, new Rectangle(600, 0, 200, 200)); for (int i = 0; i < _shadowMaskRenderer.ShadowMasks.Count; i++) { var shadowMask = _shadowMaskRenderer.ShadowMasks[i]; if (shadowMask != null) { _internalDebugRenderer.DrawTexture(shadowMask, new Rectangle((i) * 200, 200, 200, 200)); } } _internalDebugRenderer.Render(context); _internalDebugRenderer.Clear(); } // ----- Clean-up // It is very important to give every intermediate render target back to the // render target pool! renderTargetPool.Recycle(context.GBuffer0); context.GBuffer0 = null; renderTargetPool.Recycle(context.GBuffer1); context.GBuffer1 = null; renderTargetPool.Recycle((RenderTarget2D)context.Data[RenderContextKeys.DepthBufferHalf]); context.Data.Remove(RenderContextKeys.DepthBufferHalf); renderTargetPool.Recycle(context.LightBuffer0); context.LightBuffer0 = null; renderTargetPool.Recycle(context.LightBuffer1); context.LightBuffer1 = null; _shadowMaskRenderer.RecycleShadowMasks(); context.Scene = null; context.CameraNode = null; context.LodHysteresis = 0; context.LodCameraNode = null; context.RenderPass = null; }
private void Render(RenderContext context) { var originalRenderTarget = context.RenderTarget; var originalViewport = context.Viewport; var graphicsDevice = context.GraphicsService.GraphicsDevice; if (_updateCubeMap) { _updateCubeMap = false; _cloudMapRenderer.Render(_skyNodes, context); // Create a camera with 45° FOV for a single cube map face. var perspectiveProjection = new PerspectiveProjection(); perspectiveProjection.SetFieldOfView(ConstantsF.PiOver2, 1, 1, 100); context.CameraNode = new CameraNode(new Camera(perspectiveProjection)); var size = _skybox.Texture.Size; var hdrFormat = new RenderTargetFormat(size, size, false, SurfaceFormat.HdrBlendable, DepthFormat.None); var hdrTarget = context.GraphicsService.RenderTargetPool.Obtain2D(hdrFormat); var ldrFormat = new RenderTargetFormat(size, size, false, SurfaceFormat.Color, DepthFormat.None); var ldrTarget = context.GraphicsService.RenderTargetPool.Obtain2D(ldrFormat); var spriteBatch = GraphicsService.GetSpriteBatch(); for (int side = 0; side < 6; side++) { // Rotate camera to face the current cube map face. var cubeMapFace = (CubeMapFace)side; context.CameraNode.View = Matrix44F.CreateLookAt( new Vector3F(), GraphicsHelper.GetCubeMapForwardDirection(cubeMapFace), GraphicsHelper.GetCubeMapUpDirection(cubeMapFace)); // Render sky into HDR render target. graphicsDevice.SetRenderTarget(hdrTarget); context.RenderTarget = hdrTarget; context.Viewport = graphicsDevice.Viewport; graphicsDevice.Clear(Color.Black); _skyRenderer.Render(_skyNodes, context); graphicsDevice.BlendState = BlendState.Opaque; // Convert HDR to RGBM. context.SourceTexture = hdrTarget; context.RenderTarget = ldrTarget; _colorEncoder.Process(context); context.SourceTexture = null; // Copy RGBM texture into cube map face. graphicsDevice.SetRenderTarget((RenderTargetCube)_skybox.Texture, cubeMapFace); spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, null, null, null); spriteBatch.Draw(ldrTarget, new Vector2(0, 0), Color.White); spriteBatch.End(); } context.GraphicsService.RenderTargetPool.Recycle(ldrTarget); context.GraphicsService.RenderTargetPool.Recycle(hdrTarget); } graphicsDevice.BlendState = BlendState.Opaque; graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; context.CameraNode = _cameraObject.CameraNode; var tempFormat = new RenderTargetFormat(originalRenderTarget); tempFormat.SurfaceFormat = SurfaceFormat.HdrBlendable; var tempTarget = context.GraphicsService.RenderTargetPool.Obtain2D(tempFormat); graphicsDevice.SetRenderTarget(tempTarget); graphicsDevice.Viewport = originalViewport; context.RenderTarget = tempTarget; context.Viewport = originalViewport; _skyRenderer.Render(_skybox, context); context.SourceTexture = tempTarget; context.RenderTarget = originalRenderTarget; _hdrFilter.Process(context); context.SourceTexture = null; context.GraphicsService.RenderTargetPool.Recycle(tempTarget); RenderDebugInfo(context); context.CameraNode = null; }
protected override void OnRender(RenderContext context) { // This screen expects two cameras. if (ActiveCameraNodeA == null || ActiveCameraNodeB == null) { return; } var renderTargetPool = GraphicsService.RenderTargetPool; var graphicsDevice = GraphicsService.GraphicsDevice; var originalRenderTarget = context.RenderTarget; var fullViewport = context.Viewport; // Get a render target for the first camera. Use half the width because we split // the screen horizontally. var format = new RenderTargetFormat(context.RenderTarget) { Width = fullViewport.Width / 2 }; var renderTargetA = renderTargetPool.Obtain2D(format); context.Scene = Scene; context.LodHysteresis = 0.5f; context.LodBias = 1.0f; context.LodBlendingEnabled = true; for (int i = 0; i < 2; i++) { Viewport halfViewport; RenderTarget2D currentRenderTarget; if (i == 0) { // The first camera renders into renderTargetA. context.CameraNode = ActiveCameraNodeA; halfViewport = new Viewport(0, 0, fullViewport.Width / 2, fullViewport.Height); currentRenderTarget = renderTargetA; } else { // The second camera renders into the right half of the final render target. context.CameraNode = ActiveCameraNodeB; halfViewport = new Viewport(fullViewport.X + fullViewport.Width / 2, fullViewport.Y, fullViewport.Width / 2, fullViewport.Height); currentRenderTarget = originalRenderTarget; } context.LodCameraNode = context.CameraNode; CustomSceneQuery sceneQuery = Scene.Query <CustomSceneQuery>(context.CameraNode, context); // Cloud maps need to be updated only once. if (i == 0) { _cloudMapRenderer.Render(sceneQuery.SkyNodes, context); } // ----- G-Buffer Pass _gBufferRenderer.Render(sceneQuery.RenderableNodes, sceneQuery.DecalNodes, context); // ----- Shadow Pass context.RenderPass = "******"; _shadowMapRenderer.Render(sceneQuery.Lights, context); context.RenderPass = null; context.Viewport = halfViewport; _shadowMaskRenderer.Render(sceneQuery.Lights, context); // Recycle shadow maps. foreach (var node in sceneQuery.Lights) { var lightNode = (LightNode)node; if (lightNode.Shadow != null) { renderTargetPool.Recycle(lightNode.Shadow.ShadowMap); lightNode.Shadow.ShadowMap = null; } } // ----- Light Buffer Pass _lightBufferRenderer.Render(sceneQuery.Lights, context); // ----- Material Pass context.RenderTarget = renderTargetPool.Obtain2D(new RenderTargetFormat( context.Viewport.Width, context.Viewport.Height, false, SurfaceFormat.HdrBlendable, DepthFormat.Depth24Stencil8)); graphicsDevice.SetRenderTarget(context.RenderTarget); context.Viewport = graphicsDevice.Viewport; graphicsDevice.Clear(Color.Black); graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.Opaque; context.RenderPass = "******"; _meshRenderer.Render(sceneQuery.RenderableNodes, context); _decalRenderer.Render(sceneQuery.DecalNodes, context); context.RenderPass = null; graphicsDevice.ResetTextures(); // ----- Occlusion Queries _lensFlareRenderer.UpdateOcclusion(sceneQuery.LensFlareNodes, context); // ----- Sky _skyRenderer.Render(sceneQuery.SkyNodes, context); // ----- Fog _fogRenderer.Render(sceneQuery.FogNodes, context); // ----- Forward Rendering of Alpha-Blended Meshes and Particles graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.AlphaBlend; context.RenderPass = "******"; _transparentSceneRenderer.Render(sceneQuery.RenderableNodes, context, RenderOrder.BackToFront); context.RenderPass = null; graphicsDevice.ResetTextures(); // ----- Lens Flares _lensFlareRenderer.Render(sceneQuery.LensFlareNodes, context); // ----- Post Processors context.SourceTexture = context.RenderTarget; context.RenderTarget = currentRenderTarget; context.Viewport = halfViewport; PostProcessors.Process(context); renderTargetPool.Recycle((RenderTarget2D)context.SourceTexture); context.SourceTexture = null; // ----- Optional: Restore the Z-Buffer _rebuildZBufferRenderer.Render(context, true); // ----- Debug Output DebugRenderer.Render(context); // ----- Draw Reticle if (DrawReticle) { _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend); _spriteBatch.Draw( _reticle, new Vector2(halfViewport.Width / 2 - _reticle.Width / 2, halfViewport.Height / 2 - _reticle.Height / 2), Color.Black); _spriteBatch.End(); } // ----- Clean-up renderTargetPool.Recycle(context.GBuffer0); context.GBuffer0 = null; renderTargetPool.Recycle(context.GBuffer1); context.GBuffer1 = null; renderTargetPool.Recycle((RenderTarget2D)context.Data[RenderContextKeys.DepthBufferHalf]); context.Data.Remove(RenderContextKeys.DepthBufferHalf); renderTargetPool.Recycle(context.LightBuffer0); context.LightBuffer0 = null; renderTargetPool.Recycle(context.LightBuffer1); context.LightBuffer1 = null; _shadowMaskRenderer.RecycleShadowMasks(); // ----- Copy image of first camera. if (i == 1) { // Copy the upper screen from the temporary render target back into the back buffer. context.Viewport = fullViewport; graphicsDevice.Viewport = fullViewport; _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone); _spriteBatch.Draw( renderTargetA, new Rectangle(0, 0, fullViewport.Width / 2, fullViewport.Height), Color.White); _spriteBatch.End(); renderTargetPool.Recycle(renderTargetA); } } context.Scene = null; context.CameraNode = null; context.LodCameraNode = null; context.RenderPass = null; }
private void UpdateCubeMap(TimeSpan deltaTime) { if (_cloudMapRenderer == null) { // This is the first call of UpdateCubeMap. Create the renderers which // we need to render the cube map. // The CloudMapRenderer creates and animates the LayeredCloudMaps. _cloudMapRenderer = new CloudMapRenderer(_graphicsService); // The SkyRenderer renders SkyNodes. _skyRenderer = new SkyRenderer(_graphicsService); // We use a ColorEncoder to encode a HDR image in a normal Color texture. _colorEncoder = new ColorEncoder(_graphicsService) { SourceEncoding = ColorEncoding.Rgb, TargetEncoding = SkyboxNode.Encoding, }; // The SceneCaptureRenderer handles SceneCaptureNodes. We need to specify // a delegate which is called in SceneCaptureNode.Render(). _sceneCaptureRenderer = new SceneCaptureRenderer(context => { var graphicsDevice = _graphicsService.GraphicsDevice; var renderTargetPool = _graphicsService.RenderTargetPool; // We have to render into this render target. var ldrTarget = context.RenderTarget; // Reset render states. graphicsDevice.BlendState = BlendState.Opaque; graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; // Use an intermediate HDR render target with the same resolution as the final target. var format = new RenderTargetFormat(ldrTarget) { SurfaceFormat = SurfaceFormat.HdrBlendable, DepthStencilFormat = DepthFormat.Depth24Stencil8 }; var hdrTarget = renderTargetPool.Obtain2D(format); graphicsDevice.SetRenderTarget(hdrTarget); context.RenderTarget = hdrTarget; graphicsDevice.Clear(Color.Black); // Render the sky. _skyRenderer.Render(_skyGroupNode.Children, context); // Convert the HDR image to RGBM image. context.SourceTexture = hdrTarget; context.RenderTarget = ldrTarget; _colorEncoder.Process(context); context.SourceTexture = null; // Clean up. renderTargetPool.Recycle(hdrTarget); context.RenderTarget = ldrTarget; }); // Normally, the render context is managed by the graphics service. // When we call renderer outside of a GraphicsScreen, we have to use our // own context instance. _context = new RenderContext(_graphicsService); } // Update render context. // Frame needs to be updated to tell the renderers that this is a new "frame". // (Otherwise, they might abort early to avoid duplicate work in the same frame.) _context.Frame++; // DeltaTime is relevant for renderers such as the CloudMapRenderer because it // might have to animate the clouds. _context.DeltaTime = deltaTime; // Create cloud maps. _cloudMapRenderer.Render(_skyGroupNode.Children, _context); // Capture sky in cube map. _sceneCaptureRenderer.Render(_sceneCaptureNode, _context); }
protected override void OnRender(RenderContext context) { if (ActiveCameraNode == null) { return; } var renderTargetPool = GraphicsService.RenderTargetPool; var graphicsDevice = GraphicsService.GraphicsDevice; var originalRenderTarget = context.RenderTarget; var fullViewport = context.Viewport; // Get a render target for the first camera. Use half the width and height. int halfWidth = fullViewport.Width / 2; int halfHeight = fullViewport.Height / 2; var format = new RenderTargetFormat(context.RenderTarget) { Width = halfWidth, Height = halfHeight }; var renderTarget0 = renderTargetPool.Obtain2D(format); var renderTarget1 = renderTargetPool.Obtain2D(format); var renderTarget2 = renderTargetPool.Obtain2D(format); var viewport0 = new Viewport(0, 0, halfWidth, halfHeight); var viewport1 = new Viewport(halfWidth, 0, halfWidth, halfHeight); var viewport2 = new Viewport(0, halfHeight, halfWidth, halfHeight); context.Scene = Scene; context.CameraNode = ActiveCameraNode; context.LodCameraNode = context.CameraNode; context.LodHysteresis = 0.5f; // Reduce detail level by increasing the LOD bias. context.LodBias = 2.0f; for (int i = 0; i < 4; i++) { Viewport halfViewport; RenderTarget2D currentRenderTarget; if (i == 0) { // TOP, LEFT currentRenderTarget = renderTarget0; halfViewport = new Viewport(0, 0, viewport0.Width, viewport0.Height); context.LodBlendingEnabled = false; } else if (i == 1) { // TOP, RIGHT currentRenderTarget = renderTarget1; halfViewport = new Viewport(0, 0, viewport1.Width, viewport1.Height); context.LodBlendingEnabled = true; } else if (i == 2) { // BOTTOM, LEFT currentRenderTarget = renderTarget2; halfViewport = new Viewport(0, 0, viewport2.Width, viewport2.Height); context.LodBlendingEnabled = false; } else { // BOTTOM, RIGHT currentRenderTarget = originalRenderTarget; halfViewport = new Viewport(fullViewport.X + halfWidth, fullViewport.Y + halfHeight, halfWidth, halfHeight); context.LodBlendingEnabled = true; } var sceneQuery = Scene.Query <SceneQueryWithLodBlending>(context.CameraNode, context); if (i == 0 || i == 1) { // TOP for (int j = 0; j < sceneQuery.RenderableNodes.Count; j++) { if (sceneQuery.RenderableNodes[j].UserFlags == 1) { sceneQuery.RenderableNodes[j] = null; } } } else { // BOTTOM for (int j = 0; j < sceneQuery.RenderableNodes.Count; j++) { if (sceneQuery.RenderableNodes[j].UserFlags == 2) { sceneQuery.RenderableNodes[j] = null; } } } // Cloud maps need to be updated only once. if (i == 0) { _cloudMapRenderer.Render(sceneQuery.SkyNodes, context); } // ----- G-Buffer Pass _gBufferRenderer.Render(sceneQuery.RenderableNodes, sceneQuery.DecalNodes, context); // ----- Shadow Pass context.RenderPass = "******"; _shadowMapRenderer.Render(sceneQuery.Lights, context); context.RenderPass = null; context.Viewport = halfViewport; _shadowMaskRenderer.Render(sceneQuery.Lights, context); // Recycle shadow maps. foreach (var node in sceneQuery.Lights) { var lightNode = (LightNode)node; if (lightNode.Shadow != null) { renderTargetPool.Recycle(lightNode.Shadow.ShadowMap); lightNode.Shadow.ShadowMap = null; } } // ----- Light Buffer Pass _lightBufferRenderer.Render(sceneQuery.Lights, context); // ----- Material Pass context.RenderTarget = renderTargetPool.Obtain2D(new RenderTargetFormat( context.Viewport.Width, context.Viewport.Height, false, SurfaceFormat.HdrBlendable, DepthFormat.Depth24Stencil8)); graphicsDevice.SetRenderTarget(context.RenderTarget); context.Viewport = graphicsDevice.Viewport; graphicsDevice.Clear(Color.Black); graphicsDevice.DepthStencilState = DepthStencilState.Default; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.Opaque; context.RenderPass = "******"; _meshRenderer.Render(sceneQuery.RenderableNodes, context); _decalRenderer.Render(sceneQuery.DecalNodes, context); context.RenderPass = null; graphicsDevice.ResetTextures(); // ----- Occlusion Queries _lensFlareRenderer.UpdateOcclusion(sceneQuery.LensFlareNodes, context); // ----- Sky _skyRenderer.Render(sceneQuery.SkyNodes, context); // ----- Fog _fogRenderer.Render(sceneQuery.FogNodes, context); // ----- Forward Rendering of Alpha-Blended Meshes and Particles graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; graphicsDevice.BlendState = BlendState.AlphaBlend; context.RenderPass = "******"; _transparentSceneRenderer.Render(sceneQuery.RenderableNodes, context, RenderOrder.BackToFront); context.RenderPass = null; graphicsDevice.ResetTextures(); // ----- Lens Flares _lensFlareRenderer.Render(sceneQuery.LensFlareNodes, context); // ----- Post Processors context.SourceTexture = context.RenderTarget; context.RenderTarget = currentRenderTarget; context.Viewport = halfViewport; PostProcessors.Process(context); renderTargetPool.Recycle((RenderTarget2D)context.SourceTexture); context.SourceTexture = null; // ----- Optional: Restore the Z-Buffer _rebuildZBufferRenderer.Render(context, true); // ----- Debug Output DebugRenderer.Render(context); // ----- Draw Reticle if (DrawReticle) { _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend); _spriteBatch.Draw( _reticle, new Vector2(halfViewport.Width / 2 - _reticle.Width / 2, halfViewport.Height / 2 - _reticle.Height / 2), Color.Black); _spriteBatch.End(); } // ----- Clean-up renderTargetPool.Recycle(context.GBuffer0); context.GBuffer0 = null; renderTargetPool.Recycle(context.GBuffer1); context.GBuffer1 = null; renderTargetPool.Recycle((RenderTarget2D)context.Data[RenderContextKeys.DepthBufferHalf]); context.Data.Remove(RenderContextKeys.DepthBufferHalf); renderTargetPool.Recycle(context.LightBuffer0); context.LightBuffer0 = null; renderTargetPool.Recycle(context.LightBuffer1); context.LightBuffer1 = null; _shadowMaskRenderer.RecycleShadowMasks(); sceneQuery.Reset(); } // ----- Copy screens. // Copy the previous screens from the temporary render targets into the back buffer. context.Viewport = fullViewport; graphicsDevice.Viewport = fullViewport; _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone); _spriteBatch.Draw(renderTarget0, viewport0.Bounds, Color.White); _spriteBatch.Draw(renderTarget1, viewport1.Bounds, Color.White); _spriteBatch.Draw(renderTarget2, viewport2.Bounds, Color.White); _spriteBatch.End(); renderTargetPool.Recycle(renderTarget0); renderTargetPool.Recycle(renderTarget1); renderTargetPool.Recycle(renderTarget2); context.Scene = null; context.CameraNode = null; context.LodCameraNode = null; context.RenderPass = null; }