using System; using System.Collections.Generic; using Encompass; using Kav; using KavTest.Components; using KavTest.Extensions; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace KavTest.Renderers { public class SceneRenderer : GeneralRenderer { private GraphicsDevice GraphicsDevice { get; } private SpriteBatch SpriteBatch { get; } private InstancedModelContainer InstancedModelContainer { get; } private Kav.Renderer Renderer { get; } private RenderTargetBinding[] GBuffer { get; } private RenderTarget2D GPosition { get; } private RenderTarget2D GNormal { get; } private RenderTarget2D GAlbedo { get; } private RenderTarget2D GMetallicRoughness { get; } private RenderTarget2D DeferredTarget { get; } private RenderTarget2D BillboardTarget { get; } private readonly Dictionary> InstanceMap = new Dictionary>(); private IEnumerable CubeTransforms { get { foreach (var entity in ReadEntitiesAsEnumerable()) { if (HasComponent(entity)) { var transformComponent = GetComponent(entity); yield return transformComponent.Transform.TransformMatrix; } } } } private IEnumerable<(Kav.Model, Matrix)> ModelTransforms { get { foreach (var entity in ReadEntitiesAsEnumerable()) { /* FIXME: this transformation should definitely not go here */ var transformComponent = GetComponent(entity); var modelComponent = GetComponent(entity); if (HasComponent(entity)) { var overrideAlbedoComponent = GetComponent(entity); foreach (var mesh in modelComponent.Model.Meshes) { foreach (var meshPart in mesh.MeshParts) { meshPart.DisableAlbedoMap = true; meshPart.Albedo = overrideAlbedoComponent.Color; } } } yield return (modelComponent.Model, transformComponent.Transform.TransformMatrix); } } } private AmbientLight AmbientLight { get { if (SomeComponent()) { return new AmbientLight(ReadComponent().Color); } else { return new AmbientLight(Color.Black); } } } private IEnumerable PointLights { get { foreach (var entity in ReadEntitiesAsEnumerable()) { var transformComponent = GetComponent(entity); var pointLightComponent = GetComponent(entity); yield return new PointLight( transformComponent.Transform.Position, pointLightComponent.Color, pointLightComponent.Intensity ); } } } private Kav.DirectionalLight? DirectionalLight() { if (SomeComponent()) { var entity = ReadEntity(); var transformComponent = GetComponent(entity); var directionalLightComponent = GetComponent(entity); return new Kav.DirectionalLight( transformComponent.Transform.Forward, directionalLightComponent.Color, directionalLightComponent.Intensity ); } else { return null; } } private IEnumerable<(MeshSprite, Matrix)> MeshSpriteTransforms() { foreach (var entity in ReadEntitiesAsEnumerable()) { var transformComponent = GetComponent(entity); var spriteComponent = GetComponent(entity); yield return (spriteComponent.MeshSprite, transformComponent.Transform.TransformMatrix); } } public SceneRenderer( GraphicsDevice graphicsDevice, InstancedModelContainer instancedModelContainer ) { GraphicsDevice = graphicsDevice; InstancedModelContainer = instancedModelContainer; var renderDimensionsX = GraphicsDevice.PresentationParameters.BackBufferWidth; var renderDimensionsY = GraphicsDevice.PresentationParameters.BackBufferHeight; Renderer = new Kav.Renderer( GraphicsDevice, renderDimensionsX, renderDimensionsY, 4, 4096 ); DeferredTarget = new RenderTarget2D( GraphicsDevice, renderDimensionsX, renderDimensionsY, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8, 0, RenderTargetUsage.PreserveContents ); BillboardTarget = new RenderTarget2D( GraphicsDevice, renderDimensionsX, renderDimensionsY, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8, 0, RenderTargetUsage.PreserveContents ); GPosition = new RenderTarget2D( GraphicsDevice, renderDimensionsX, renderDimensionsY, false, SurfaceFormat.Vector4, DepthFormat.Depth24 ); GNormal = new RenderTarget2D( GraphicsDevice, renderDimensionsX, renderDimensionsY, false, SurfaceFormat.Vector4, DepthFormat.None ); GAlbedo = new RenderTarget2D( GraphicsDevice, renderDimensionsX, renderDimensionsY, false, SurfaceFormat.Color, DepthFormat.None ); GMetallicRoughness = new RenderTarget2D( GraphicsDevice, renderDimensionsX, renderDimensionsY, false, SurfaceFormat.HalfVector2, DepthFormat.None ); GBuffer = new RenderTargetBinding[4] { new RenderTargetBinding(GPosition), new RenderTargetBinding(GNormal), new RenderTargetBinding(GAlbedo), new RenderTargetBinding(GMetallicRoughness) }; SpriteBatch = new SpriteBatch(GraphicsDevice); } public override void Render() { if (SomeComponent()) { var cameraEntity = ReadEntity(); var transformComponent = GetComponent(cameraEntity); var cameraComponent = GetComponent(cameraEntity); var camera = new Kav.PerspectiveCamera( transformComponent.ArcballTransform.Position, transformComponent.ArcballTransform.Forward, transformComponent.ArcballTransform.Up, cameraComponent.FieldOfView, cameraComponent.AspectRatio, cameraComponent.NearPlane, cameraComponent.FarPlane ); GraphicsDevice.SetRenderTargets(GBuffer); GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); GraphicsDevice.DepthStencilState = DepthStencilState.Default; // Renderer.GBufferRender( // GBuffer, // camera, // ModelTransforms // ); Renderer.InstancedGBufferRender( GBuffer, camera, InstancedModelContainer.CubeModel, CubeTransforms ); GraphicsDevice.SetRenderTarget(DeferredTarget); GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); GraphicsDevice.DepthStencilState = DepthStencilState.Default; Renderer.DepthRender( DeferredTarget, camera, ModelTransforms ); Renderer.AmbientLightRender( DeferredTarget, GPosition, GAlbedo, AmbientLight ); foreach (var pointLight in PointLights) { Renderer.PointLightRender( DeferredTarget, GPosition, GAlbedo, GNormal, GMetallicRoughness, camera, ModelTransforms, pointLight ); } var directionalLight = DirectionalLight(); if (directionalLight.HasValue) { Renderer.DirectionalLightToonRender( DeferredTarget, GPosition, GAlbedo, GNormal, GMetallicRoughness, camera, ModelTransforms, directionalLight.Value, 4, false ); } Renderer.SkyboxRender( DeferredTarget, camera, ReadComponent().Skybox ); Renderer.MeshSpriteRender( BillboardTarget, camera, ModelTransforms, MeshSpriteTransforms(), AmbientLight, PointLights, DirectionalLight() ); GraphicsDevice.SetRenderTarget(null); SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null); SpriteBatch.Draw(DeferredTarget, Vector2.Zero, Color.White); SpriteBatch.Draw(BillboardTarget, Vector2.Zero, Color.White); SpriteBatch.End(); } } private void CollectInstances() { foreach (var list in InstanceMap.Values) { list.Clear(); } foreach (var modelEntity in ReadEntities()) { if (HasComponent(modelEntity)) { var modelComponent = GetComponent(modelEntity); if (modelComponent.Instanced) { var transformComponent = GetComponent(modelEntity); foreach (var mesh in modelComponent.Model.Meshes) { foreach (var meshPart in mesh.MeshParts) { if (!InstanceMap.ContainsKey(meshPart)) { InstanceMap.Add(meshPart, new List()); } else InstanceMap[meshPart].Add(transformComponent.Transform.TransformMatrix); } } } } } } } }