/// <summary> /// Renders a light. /// </summary> /// <param name="light">The light.</param> void IRenderer.Render(Light light) { if (light == null) { throw new ArgumentNullException(nameof(light)); } if (this.Phase == Phase.Lights) { this.lightShader.Use(light); if (light.Radius > 0) { var radius = light.Radius * 1.1f; // <- Grow the sphere slightly so that it fully encloses the light radius. const int Stacks = 8; const int Slices = 8; this.vertexBuffer.BeginTriangleStrip(Stacks * (Slices + 1) * 2); for (var stack = 0; stack < Stacks; stack++) { for (var slice = 0; slice <= Slices; slice++) { for (var i = 0; i < 2; i++) { var s = slice / (float)Slices; var t = (stack + i) / (float)Stacks; var sa = s * Math.PI * 2; var ta = (t * Math.PI) - (Math.PI / 2); var nx = (float)Math.Cos(sa) * (float)Math.Cos(ta); var ny = (float)Math.Sin(sa) * (float)Math.Cos(ta); var nz = (float)Math.Sin(ta); this.vertexBuffer.Vertex( light.Position.X + nx * radius, light.Position.Y + ny * radius, light.Position.Z + nz * radius); } } } this.vertexBuffer.End().Draw(); } else { this.vertexBuffer.FullSceneQuad().Draw(); } } }
/// <summary> /// Renders the scene. /// </summary> /// <param name="scene">The scene object.</param> /// <param name="primaryLight">The primary light. Only the primary light casts shadows.</param> public void Render(IScene scene, Light primaryLight) { if (scene == null) { throw new ArgumentNullException(nameof(scene)); } // Phase 1: Geometry { this.Phase = Phase.Geometry; GPU.Draw(ColorTarget, NormalTarget, PositionTarget, CompositionTarget); GPU.Use(Cull.Back, Depth.Test | Depth.Write, Stencil.None, Blend.None); GPU.Clear(null); scene.Render(this); } // Phase 2: Shadows if (primaryLight != null && primaryLight.Intensity > 0) { this.Phase = Phase.Shadows; this.shadowShader.Use(primaryLight); GPU.Draw(TargetBuffer.None); GPU.Use(Cull.None, Depth.Test | Depth.Clamp | Depth.Offset, Stencil.Shadows, Blend.None); scene.Render(this); } // Phase 3: Lights { this.Phase = Phase.Lights; this.lightShader.Use() .SetUniform("ColorBuffer", this.ColorBuffer) .SetUniform("NormalBuffer", this.NormalBuffer) .SetUniform("PositionBuffer", this.PositionBuffer) .SetUniform("BufferSize", this.Width, this.Height); GPU.Draw(CompositionTarget); if (primaryLight != null && primaryLight.Intensity > 0) { GPU.Use(Cull.Back, Depth.TestReversed, Stencil.Light, Blend.Additive); GPU.Transform(Matrix4x4.Identity); (this as IRenderer).Render(primaryLight); } GPU.Use(Cull.Back, Depth.TestReversed, Stencil.None, Blend.Additive); scene.Render(this); } // Phase 4: Effects { this.Phase = Phase.Effects; GPU.Use(Cull.None, Depth.Test, Stencil.None, Blend.Additive); scene.Render(this); } this.Phase = 0; }