KavTest/KavTest/Renderers/SceneRenderer.cs

410 lines
14 KiB
C#

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 RenderTargetCube ShadowCubeMap { get; }
private DirectionalShadowMapData DirectionalShadowMapData { get; }
private readonly Dictionary<Kav.MeshPart, List<Matrix>> InstanceMap = new Dictionary<MeshPart, List<Matrix>>();
private IEnumerable<Matrix> CubeTransforms
{
get
{
foreach (var entity in ReadEntitiesAsEnumerable<InstancedCubeComponent>())
{
if (HasComponent<Transform3DComponent>(entity))
{
var transformComponent = GetComponent<Transform3DComponent>(entity);
yield return transformComponent.Transform.TransformMatrix;
}
}
}
}
private IEnumerable<(Kav.MeshPart, Matrix)> MeshPartTransforms
{
get
{
foreach (var entity in ReadEntitiesAsEnumerable<ModelComponent>())
{
/* FIXME: this transformation should definitely not go here */
var transformComponent = GetComponent<Transform3DComponent>(entity);
var modelComponent = GetComponent<ModelComponent>(entity);
foreach (var mesh in modelComponent.Model.Meshes)
{
foreach (var meshPart in mesh.MeshParts)
{
if (HasComponent<OverrideAlbedoComponent>(entity))
{
var overrideAlbedoComponent = GetComponent<OverrideAlbedoComponent>(entity);
meshPart.DisableAlbedoMap = true;
meshPart.Albedo = overrideAlbedoComponent.Color;
}
yield return (meshPart, transformComponent.Transform.TransformMatrix);
}
}
}
}
}
private AmbientLight AmbientLight
{
get
{
if (SomeComponent<AmbientLightComponent>())
{
return new AmbientLight(ReadComponent<AmbientLightComponent>().Color);
}
else
{
return new AmbientLight(Color.Black);
}
}
}
private IEnumerable<PointLight> PointLights
{
get
{
foreach (var entity in ReadEntitiesAsEnumerable<PointLightComponent>())
{
var transformComponent = GetComponent<Transform3DComponent>(entity);
var pointLightComponent = GetComponent<PointLightComponent>(entity);
yield return new PointLight(
transformComponent.Transform.Position,
pointLightComponent.Color,
pointLightComponent.Intensity
);
}
}
}
private Kav.DirectionalLight? DirectionalLight()
{
if (SomeComponent<DirectionalLightComponent>())
{
var entity = ReadEntity<DirectionalLightComponent>();
var transformComponent = GetComponent<Transform3DComponent>(entity);
var directionalLightComponent = GetComponent<DirectionalLightComponent>(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<MeshSpriteComponent>())
{
var transformComponent = GetComponent<Transform3DComponent>(entity);
var spriteComponent = GetComponent<MeshSpriteComponent>(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
);
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,
0,
RenderTargetUsage.PreserveContents
);
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)
};
ShadowCubeMap = Kav.Renderer.CreateShadowCubeMap(
GraphicsDevice,
2048
);
DirectionalShadowMapData = Kav.Renderer.CreateDirectionalShadowMaps(
graphicsDevice,
2048,
4
);
SpriteBatch = new SpriteBatch(GraphicsDevice);
}
public override void Render()
{
if (SomeComponent<PerspectiveCameraComponent>())
{
var cameraEntity = ReadEntity<PerspectiveCameraComponent>();
var transformComponent = GetComponent<ArcballTransformComponent>(cameraEntity);
var cameraComponent = GetComponent<PerspectiveCameraComponent>(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.SetRenderTarget(DeferredTarget);
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0);
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
Renderer.RenderGBufferInstanced(
GBuffer,
DeferredTarget,
camera,
InstancedModelContainer.CubeModel,
CubeTransforms
);
Renderer.RenderGBufferIndexed(
GBuffer,
camera,
MeshPartTransforms
);
Renderer.RenderDepthIndexed(
DeferredTarget,
camera,
MeshPartTransforms
);
Renderer.RenderAmbientLight(
DeferredTarget,
GPosition,
GAlbedo,
AmbientLight
);
foreach (var pointLight in PointLights)
{
foreach (CubeMapFace face in Enum.GetValues(typeof(CubeMapFace)))
{
GraphicsDevice.SetRenderTarget(ShadowCubeMap, face);
GraphicsDevice.Clear(Color.White);
}
Renderer.RenderPointShadowMapIndexed(
ShadowCubeMap,
camera,
MeshPartTransforms,
pointLight
);
Renderer.RenderPointLight(
DeferredTarget,
GPosition,
GAlbedo,
GNormal,
GMetallicRoughness,
ShadowCubeMap,
camera,
pointLight
);
}
var directionalLight = DirectionalLight();
if (directionalLight.HasValue)
{
DirectionalShadowMapData.Clear(GraphicsDevice);
Renderer.PrepareDirectionalShadowData(
DirectionalShadowMapData,
camera,
directionalLight.Value
);
Renderer.RenderDirectionalShadowsIndexed(
DirectionalShadowMapData,
MeshPartTransforms
);
Renderer.RenderDirectionalShadowsInstanced(
DirectionalShadowMapData,
InstancedModelContainer.CubeModel,
CubeTransforms
);
Renderer.RenderDirectionalLight(
DeferredTarget,
GPosition,
GAlbedo,
GNormal,
GMetallicRoughness,
DirectionalShadowMapData,
camera,
directionalLight.Value
);
}
Renderer.RenderSkybox(
DeferredTarget,
camera,
ReadComponent<SkyboxComponent>().Skybox
);
Renderer.MeshSpriteRender(
DeferredTarget,
camera,
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<ModelComponent>())
{
if (HasComponent<Transform3DComponent>(modelEntity))
{
var modelComponent = GetComponent<ModelComponent>(modelEntity);
if (modelComponent.Instanced)
{
var transformComponent = GetComponent<Transform3DComponent>(modelEntity);
foreach (var mesh in modelComponent.Model.Meshes)
{
foreach (var meshPart in mesh.MeshParts)
{
if (!InstanceMap.ContainsKey(meshPart))
{
InstanceMap.Add(meshPart, new List<Matrix>());
}
else
InstanceMap[meshPart].Add(transformComponent.Transform.TransformMatrix);
}
}
}
}
}
}
}
}