/// <summary> /// Generate the shadow map for a given spot light /// </summary> /// <param name="renderer"></param> /// <param name="meshes"></param> /// <param name="light"></param> /// <param name="shadowMap"></param> public void GenerateShadowTextureSpotLight(Renderer renderer, BaseSceneGraph renderWorld, Light light, SpotShadowMapEntry shadowMap) { //bind the render target renderer.GraphicsDevice.SetRenderTarget(shadowMap.Texture); //clear it to white, ie, far far away renderer.GraphicsDevice.Clear(Color.White); renderer.GraphicsDevice.BlendState = BlendState.Opaque; renderer.GraphicsDevice.DepthStencilState = DepthStencilState.Default; Matrix viewProj = light.ViewProjection; shadowMap.LightViewProjection = viewProj; BoundingFrustum frustum = light.Frustum; _visibleMeshes.Clear(); //cull meshes outside the light volume renderWorld.GetShadowCasters(frustum, _visibleMeshes); renderer.InstancingGroupManager.Reset(); for (int index = 0; index < _visibleMeshes.Count; index++) { Mesh.SubMesh subMesh = _visibleMeshes[index]; //render it if (!subMesh.InstanceEnabled) subMesh.RenderShadowMap(ref viewProj, renderer.GraphicsDevice); else renderer.InstancingGroupManager.AddInstancedSubMesh(subMesh); } renderer.InstancingGroupManager.GenerateInstanceInfo(renderer.GraphicsDevice); renderer.InstancingGroupManager.RenderShadowMap(ref viewProj, renderer.GraphicsDevice); }
public override void SetLightDelegate(BaseSceneGraph.AddLightDelegate lightD) { addLightFunc = lightD; }
public override void SetSubMeshDelegate(BaseSceneGraph.AddSubMeshDelegate subMeshD) { addSubMeshFunc = subMeshD; }
/// <summary> /// Generate the shadow maps and matrixes for the visible lights. We should limit /// our shadow-casters based on number of available shadow maps (we could use some /// performance-related heuristic here too) /// </summary> /// <param name="camera"></param> /// <param name="meshes"></param> /// <param name="renderWorld"></param> private void GenerateShadows(Camera camera, BaseSceneGraph sceneGraph) { for (int index = 0; index < _lightShadowCasters.Count; index++) { LightEntry light = _lightShadowCasters[index]; //only spot if (light.light.LightType == Light.Type.Spot) { _shadowRenderer.GenerateShadowTextureSpotLight(this, sceneGraph, light.light, light.spotShadowMap); } } }
/// <summary> /// Do a frustum culling test on each sub mesh, adding the visible ones to our list /// </summary> /// <param name="camera"></param> /// <param name="meshes"></param> private void CullVisibleMeshes(Camera camera, BaseSceneGraph sceneGraph) { for (int index = 0; index < _visibleMeshes.Length; index++) { _visibleMeshes[index].Clear(); } sceneGraph.GetVisibleMeshes(camera.Frustum, _visibleMeshes); }
/// <summary> /// Render the current scene. The culling will be performed inside this method, /// because we need all meshes here to compute the shadow maps. /// </summary> /// <param name="camera">Current camera</param> /// <param name="visibleLights"></param> /// <param name="meshes">All meshes</param> /// <param name="sceneGraph"></param> /// <param name="particleSystems"></param> /// <param name="gameTime"></param> /// <param name="lights">Visible lights</param> /// <returns></returns> public RenderTarget2D RenderScene(Camera camera, BaseSceneGraph sceneGraph) { InstancingGroupManager.Reset(); sceneGraph.DoPreFrameWork(camera.Frustum); _depthDownsampledThisFrame = false; _currentCamera = camera; //compute the frustum corners for this camera ComputeFrustumCorners(camera); //this resets the free shadow maps _shadowRenderer.InitFrame(); _visibleLights.Clear(); sceneGraph.GetVisibleLights(camera.Frustum, _visibleLights); //sort lights, choose the shadow casters BuildLightEntries(camera); SelectShadowCasters(); //generate all shadow maps GenerateShadows(camera, sceneGraph); //first of all, we must bind our GBuffer and reset all states GraphicsDevice.SetRenderTargets(_gBufferBinding); GraphicsDevice.Clear(ClearOptions.DepthBuffer | ClearOptions.Stencil, Color.Black, 1.0f, 0); GraphicsDevice.BlendState = BlendState.Opaque; GraphicsDevice.DepthStencilState = DepthStencilState.None; GraphicsDevice.RasterizerState = RasterizerState.CullNone; //bind the effect that outputs the default GBuffer values _clearGBuffer.CurrentTechnique.Passes[0].Apply(); //draw a full screen quad for clearing our GBuffer _quadRenderer.RenderQuad(GraphicsDevice, -Vector2.One, Vector2.One); GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; //select the visible meshes CullVisibleMeshes(camera, sceneGraph); //now, render them to the G-Buffer RenderToGbuffer(camera); //resolve our GBuffer and render the lights //clear the light buffer with black GraphicsDevice.SetRenderTargets(_lightAccumBinding); //dont be fooled by Color.Black, as its alpha is 255 (or 1.0f) GraphicsDevice.Clear(new Color(0, 0, 0, 0)); //dont use depth/stencil test...we dont have a depth buffer, anyway GraphicsDevice.DepthStencilState = DepthStencilState.None; GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; //draw using additive blending. //At first I was using BlendState.additive, but it seems to use alpha channel for modulation, //and as we use alpha channel as the specular intensity, we have to create our own blend state here GraphicsDevice.BlendState = _lightAddBlendState; RenderLights(camera); //reconstruct each object shading, using the light texture as input (and another specific parameters too) GraphicsDevice.SetRenderTarget(_outputTexture); GraphicsDevice.Clear(ClearOptions.DepthBuffer | ClearOptions.Stencil | ClearOptions.Target, Color.Black, 1.0f, 0); GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; //reconstruct the shading, using the already culled list ReconstructShading(camera); //render objects that doesn't need the lightbuffer information, such as skyboxes, pure reflective meshes, etc DrawOpaqueObjects(camera); //draw objects with transparency DrawBlendObjects(camera); //draw SSAO texture. It's not correct to do it here, because ideally the SSAO should affect only //the ambient light, but it looks good this way //unbind our final buffer and return it GraphicsDevice.SetRenderTarget(null); return _outputTexture; }
public abstract void SetLightDelegate(BaseSceneGraph.AddLightDelegate lightD);
public abstract void SetSubMeshDelegate(BaseSceneGraph.AddSubMeshDelegate subMeshD);