304 lines
10 KiB
C#
304 lines
10 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 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 IEnumerable<(Kav.Model, Matrix)> ModelTransforms
|
|
{
|
|
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);
|
|
if (HasComponent<OverrideAlbedoComponent>(entity))
|
|
{
|
|
var overrideAlbedoComponent = GetComponent<OverrideAlbedoComponent>(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<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)
|
|
{
|
|
GraphicsDevice = graphicsDevice;
|
|
|
|
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<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);
|
|
|
|
Renderer.GBufferRender(
|
|
GBuffer,
|
|
camera,
|
|
ModelTransforms
|
|
);
|
|
|
|
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<SkyboxComponent>().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();
|
|
}
|
|
}
|
|
}
|
|
}
|