410 lines
14 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|