public void Render() { // Update hulls internal data structures. Hulls.Update(); // We want to use clamping sampler state throughout the lightmap rendering process. // This is required when drawing lights. Since light rendering and alpha clearing is done // in a single step, light is rendered with slightly larger quad where tex coords run out of the [0..1] range. Device.SamplerStates[0] = SamplerState.LinearClamp; // Switch render target to lightmap. Device.SetRenderTargets(Textures.LightmapBindings); // Clear lightmap color, depth and stencil data. Device.Clear(ClearOptions.DepthBuffer | ClearOptions.Stencil | ClearOptions.Target, _ambientColor, 1f, 0); // Set per frame shader data. ShadowRenderer.PreRender(); // Generate lightmap. For each light, mask the shadowed areas determined by hulls and render light. int lightCount = Lights.Count; for (int i = 0; i < lightCount; i++) { Light light = Lights[i]; // Continue only if light is enabled and not inside any hull. if (!light.Enabled || Hulls.Contains(light)) { continue; } // Update light's internal data structures. light.Update(); // Continue only if light is within camera view. if (!light.Intersects(Camera)) { continue; } // Set scissor rectangle to clip any shadows outside of light's range. BoundingRectangle scissor; Camera.GetScissorRectangle(light, out scissor); Device.SetScissorRectangle(ref scissor); // Mask shadowed areas by reducing alpha. ShadowRenderer.Render(light); // Draw light and clear alpha (reset it to 1 [fully lit] for next light). LightRenderer.Render(light); // Clear light's dirty flag. light.Dirty = false; } // Switch render target back to default. Device.SetRenderTargets(Textures.GetOriginalRenderTargetBindings()); // Blend original scene and lightmap and present to backbuffer. LightMapRenderer.Present(); // Clear hulls dirty flag. Hulls.Dirty = false; }
//-------------------------------------------------------------- #region Methods //-------------------------------------------------------------- public void Render(IList <SceneNode> lights, RenderContext context) { var graphicsService = context.GraphicsService; var graphicsDevice = graphicsService.GraphicsDevice; var renderTargetPool = graphicsService.RenderTargetPool; var target = context.RenderTarget; var viewport = context.Viewport; var width = viewport.Width; var height = viewport.Height; RenderTarget2D aoRenderTarget = null; if (_ssaoFilter != null) { // Render ambient occlusion info into a render target. aoRenderTarget = renderTargetPool.Obtain2D(new RenderTargetFormat( width / _ssaoDownsampleFactor, height / _ssaoDownsampleFactor, false, SurfaceFormat.Color, DepthFormat.None)); // PostProcessors require that context.SourceTexture is set. But since // _ssaoFilter.CombineWithSource is set to false, the SourceTexture is not // used and we can set it to anything except null. context.SourceTexture = aoRenderTarget; context.RenderTarget = aoRenderTarget; context.Viewport = new Viewport(0, 0, aoRenderTarget.Width, aoRenderTarget.Height); _ssaoFilter.Process(context); context.SourceTexture = null; } // The light buffer consists of two full-screen render targets into which we // render the accumulated diffuse and specular light intensities. var lightBufferFormat = new RenderTargetFormat(width, height, false, SurfaceFormat.HdrBlendable, DepthFormat.Depth24Stencil8); context.LightBuffer0 = renderTargetPool.Obtain2D(lightBufferFormat); context.LightBuffer1 = renderTargetPool.Obtain2D(lightBufferFormat); // Set the device render target to the light buffer. _renderTargetBindings[0] = new RenderTargetBinding(context.LightBuffer0); // Diffuse light accumulation _renderTargetBindings[1] = new RenderTargetBinding(context.LightBuffer1); // Specular light accumulation graphicsDevice.SetRenderTargets(_renderTargetBindings); context.RenderTarget = context.LightBuffer0; context.Viewport = graphicsDevice.Viewport; // Clear the light buffer. (The alpha channel is not used. We can set it to anything.) graphicsDevice.Clear(new Color(0, 0, 0, 255)); // Restore the depth buffer (which XNA destroys in SetRenderTarget). // (This is only needed if lights can use a clip geometry (LightNode.Clip).) var rebuildZBufferRenderer = (RebuildZBufferRenderer)context.Data[RenderContextKeys.RebuildZBufferRenderer]; rebuildZBufferRenderer.Render(context, true); // Render all lights into the light buffers. LightRenderer.Render(lights, context); if (aoRenderTarget != null) { // Render the ambient occlusion texture using multiplicative blending. // This will darken the light buffers depending on the ambient occlusion term. // Note: Theoretically, this should be done after the ambient light renderer // and before the directional light renderer because AO should not affect // directional lights. But doing this here has more impact. context.SourceTexture = aoRenderTarget; graphicsDevice.BlendState = GraphicsHelper.BlendStateMultiply; _copyFilter.Process(context); } // Clean up. graphicsService.RenderTargetPool.Recycle(aoRenderTarget); context.SourceTexture = null; context.RenderTarget = target; context.Viewport = viewport; _renderTargetBindings[0] = new RenderTargetBinding(); _renderTargetBindings[1] = new RenderTargetBinding(); }