2020-08-04 09:32:02 +00:00
|
|
|
|
using System.Collections.Generic;
|
2020-08-07 00:58:50 +00:00
|
|
|
|
using Microsoft.Xna.Framework;
|
2020-08-04 09:32:02 +00:00
|
|
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
|
|
|
|
|
|
|
|
namespace Kav
|
|
|
|
|
{
|
2020-08-07 00:58:50 +00:00
|
|
|
|
public class Renderer
|
2020-08-04 09:32:02 +00:00
|
|
|
|
{
|
2020-08-07 00:58:50 +00:00
|
|
|
|
private GraphicsDevice GraphicsDevice { get; }
|
|
|
|
|
private int RenderDimensionsX { get; }
|
|
|
|
|
private int RenderDimensionsY { get; }
|
|
|
|
|
|
2020-09-16 19:58:23 +00:00
|
|
|
|
private RenderTarget2D ShadowRenderTarget { get; }
|
2020-08-07 00:58:50 +00:00
|
|
|
|
private SimpleDepthEffect SimpleDepthEffect { get; }
|
|
|
|
|
|
2020-08-27 18:14:17 +00:00
|
|
|
|
private RenderTarget2D gPosition { get; }
|
|
|
|
|
private RenderTarget2D gNormal { get; }
|
|
|
|
|
private RenderTarget2D gAlbedo { get; }
|
|
|
|
|
private RenderTarget2D gMetallicRoughness { get; }
|
|
|
|
|
private RenderTarget2D deferredRenderTarget { get; }
|
|
|
|
|
|
|
|
|
|
private RenderTargetBinding[] GBuffer { get; }
|
|
|
|
|
|
|
|
|
|
private DeferredPBREffect DeferredPBREffect { get; }
|
|
|
|
|
|
|
|
|
|
private SpriteBatch SpriteBatch { get; }
|
|
|
|
|
|
2020-08-07 00:58:50 +00:00
|
|
|
|
public Renderer(GraphicsDevice graphicsDevice, int renderDimensionsX, int renderDimensionsY)
|
|
|
|
|
{
|
|
|
|
|
GraphicsDevice = graphicsDevice;
|
|
|
|
|
RenderDimensionsX = renderDimensionsX;
|
|
|
|
|
RenderDimensionsY = renderDimensionsY;
|
|
|
|
|
|
2020-09-16 19:58:23 +00:00
|
|
|
|
ShadowRenderTarget = new RenderTarget2D(
|
2020-08-07 00:58:50 +00:00
|
|
|
|
GraphicsDevice,
|
2020-09-16 19:58:23 +00:00
|
|
|
|
1024,
|
|
|
|
|
1024,
|
2020-08-07 00:58:50 +00:00
|
|
|
|
false,
|
2020-08-27 21:46:20 +00:00
|
|
|
|
SurfaceFormat.Single,
|
2020-08-07 00:58:50 +00:00
|
|
|
|
DepthFormat.Depth24
|
|
|
|
|
);
|
|
|
|
|
|
2020-08-27 18:14:17 +00:00
|
|
|
|
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)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
deferredRenderTarget = new RenderTarget2D(
|
|
|
|
|
GraphicsDevice,
|
|
|
|
|
renderDimensionsX,
|
|
|
|
|
renderDimensionsY
|
|
|
|
|
);
|
|
|
|
|
|
2020-08-07 00:58:50 +00:00
|
|
|
|
SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice);
|
2020-08-27 18:14:17 +00:00
|
|
|
|
DeferredPBREffect = new DeferredPBREffect(GraphicsDevice);
|
|
|
|
|
|
|
|
|
|
SpriteBatch = new SpriteBatch(GraphicsDevice);
|
|
|
|
|
|
|
|
|
|
GraphicsDevice.SetRenderTarget(deferredRenderTarget);
|
|
|
|
|
graphicsDevice.Clear(Color.White);
|
|
|
|
|
GraphicsDevice.SetRenderTarget(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DeferredRender(
|
|
|
|
|
Camera camera,
|
|
|
|
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
|
|
|
|
IEnumerable<PointLight> pointLights,
|
2020-09-16 19:58:23 +00:00
|
|
|
|
DirectionalLight directionalLight
|
2020-08-27 18:14:17 +00:00
|
|
|
|
) {
|
2020-09-16 19:58:23 +00:00
|
|
|
|
ShadowMapRender(camera, modelTransforms, directionalLight);
|
2020-08-27 21:46:20 +00:00
|
|
|
|
|
2020-08-27 18:14:17 +00:00
|
|
|
|
GraphicsDevice.SetRenderTargets(GBuffer);
|
|
|
|
|
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0);
|
|
|
|
|
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
|
|
|
|
GraphicsDevice.BlendState = BlendState.Opaque;
|
|
|
|
|
|
|
|
|
|
foreach (var (model, transform) in modelTransforms)
|
|
|
|
|
{
|
|
|
|
|
foreach (var modelMesh in model.Meshes)
|
|
|
|
|
{
|
|
|
|
|
foreach (var meshPart in modelMesh.MeshParts)
|
|
|
|
|
{
|
|
|
|
|
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
|
|
|
|
|
GraphicsDevice.Indices = meshPart.IndexBuffer;
|
|
|
|
|
|
|
|
|
|
if (meshPart.Effect is TransformEffect transformEffect)
|
|
|
|
|
{
|
|
|
|
|
transformEffect.World = transform;
|
|
|
|
|
transformEffect.View = camera.View;
|
|
|
|
|
transformEffect.Projection = camera.Projection;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var pass in meshPart.Effect.CurrentTechnique.Passes)
|
|
|
|
|
{
|
|
|
|
|
pass.Apply();
|
|
|
|
|
|
|
|
|
|
GraphicsDevice.DrawIndexedPrimitives(
|
|
|
|
|
PrimitiveType.TriangleList,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
meshPart.VertexBuffer.VertexCount,
|
|
|
|
|
0,
|
|
|
|
|
meshPart.Triangles.Length
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GraphicsDevice.SetRenderTarget(null);
|
|
|
|
|
GraphicsDevice.Clear(Color.CornflowerBlue);
|
|
|
|
|
|
|
|
|
|
DeferredPBREffect.GPosition = gPosition;
|
|
|
|
|
DeferredPBREffect.GAlbedo = gAlbedo;
|
|
|
|
|
DeferredPBREffect.GNormal = gNormal;
|
|
|
|
|
DeferredPBREffect.GMetallicRoughness = gMetallicRoughness;
|
2020-09-16 19:58:23 +00:00
|
|
|
|
DeferredPBREffect.ShadowMap = ShadowRenderTarget;
|
2020-08-27 18:14:17 +00:00
|
|
|
|
DeferredPBREffect.EyePosition = Matrix.Invert(camera.View).Translation;
|
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
foreach (var pointLight in pointLights)
|
|
|
|
|
{
|
|
|
|
|
if (i > DeferredPBREffect.MaxPointLights) { break; }
|
|
|
|
|
DeferredPBREffect.PointLights[i] = pointLight;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-16 19:58:23 +00:00
|
|
|
|
DeferredPBREffect.DirectionalLightColor = directionalLight.Color.ToVector3() * directionalLight.Intensity;
|
|
|
|
|
DeferredPBREffect.DirectionalLightDirection = directionalLight.Direction;
|
2020-08-27 18:14:17 +00:00
|
|
|
|
|
|
|
|
|
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, null, null, DeferredPBREffect);
|
|
|
|
|
SpriteBatch.Draw(deferredRenderTarget, Vector2.Zero, Color.White);
|
|
|
|
|
SpriteBatch.End();
|
2020-08-07 00:58:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for shadow mapping
|
2020-09-16 19:58:23 +00:00
|
|
|
|
public void ShadowMapRender(Camera camera, IEnumerable<(Model, Matrix)> modelTransforms, DirectionalLight directionalLight)
|
2020-08-04 09:32:02 +00:00
|
|
|
|
{
|
2020-09-16 19:58:23 +00:00
|
|
|
|
GraphicsDevice.SetRenderTarget(ShadowRenderTarget);
|
2020-08-27 21:46:20 +00:00
|
|
|
|
GraphicsDevice.Clear(Color.White);
|
|
|
|
|
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
|
|
|
|
GraphicsDevice.BlendState = BlendState.Opaque;
|
|
|
|
|
|
2020-09-16 19:58:23 +00:00
|
|
|
|
var right = Vector3.Cross(Vector3.Up, directionalLight.Direction);
|
|
|
|
|
var up = Vector3.Cross(directionalLight.Direction, right);
|
2020-09-16 23:49:08 +00:00
|
|
|
|
var cameraBoundingFrustum = new BoundingFrustum(camera.View * camera.Projection);
|
|
|
|
|
Vector3[] frustumCorners = cameraBoundingFrustum.GetCorners();
|
2020-09-16 19:58:23 +00:00
|
|
|
|
|
2020-09-16 23:49:08 +00:00
|
|
|
|
Vector3 frustumCenter = Vector3.Zero;
|
|
|
|
|
for (var i = 0; i < frustumCorners.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
frustumCenter += frustumCorners[i];
|
|
|
|
|
}
|
|
|
|
|
frustumCenter /= 8f;
|
2020-09-16 19:58:23 +00:00
|
|
|
|
|
2020-09-16 23:49:08 +00:00
|
|
|
|
var lightView = Matrix.CreateLookAt(frustumCenter, frustumCenter - directionalLight.Direction, camera.View.Right);
|
2020-09-16 19:58:23 +00:00
|
|
|
|
|
|
|
|
|
for (var i = 0; i < frustumCorners.Length; i++)
|
|
|
|
|
{
|
2020-09-16 23:49:08 +00:00
|
|
|
|
frustumCorners[i] = Vector3.Transform(frustumCorners[i], lightView);
|
2020-09-16 19:58:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BoundingBox lightBox = BoundingBox.CreateFromPoints(frustumCorners);
|
|
|
|
|
Vector3 boxSize = lightBox.Max - lightBox.Min;
|
|
|
|
|
Vector3 halfBoxSize = boxSize * 0.5f;
|
|
|
|
|
|
2020-09-16 23:49:08 +00:00
|
|
|
|
Vector3 lightPosition = frustumCenter + directionalLight.Direction * -lightBox.Min.Z;
|
|
|
|
|
//lightPosition.Z = lightBox.Min.Z;
|
|
|
|
|
//lightPosition = Vector3.Transform(lightPosition, Matrix.Invert(lightRotation));
|
|
|
|
|
|
|
|
|
|
SimpleDepthEffect.View = Matrix.CreateLookAt(lightPosition, frustumCenter, camera.View.Right);
|
|
|
|
|
SimpleDepthEffect.Projection = Matrix.CreateOrthographicOffCenter(lightBox.Min.X, lightBox.Max.X, lightBox.Min.Y, lightBox.Max.Y, 0, lightBox.Max.Z - lightBox.Min.Z);
|
2020-09-16 19:58:23 +00:00
|
|
|
|
|
2020-09-16 23:49:08 +00:00
|
|
|
|
//SimpleDepthEffect.View = directionalLight.View;
|
|
|
|
|
//SimpleDepthEffect.Projection = directionalLight.Projection;
|
2020-09-16 19:58:23 +00:00
|
|
|
|
DeferredPBREffect.LightSpaceMatrix = SimpleDepthEffect.View * SimpleDepthEffect.Projection;
|
2020-08-07 00:58:50 +00:00
|
|
|
|
|
2020-09-16 23:49:08 +00:00
|
|
|
|
var globalShadowView = Matrix.CreateLookAt(frustumCenter + directionalLight.Direction * -0.5f, frustumCenter, camera.View.Right);
|
|
|
|
|
var globalShadowProjection = Matrix.CreateOrthographic(1f, 1f, 0f, 1f);
|
|
|
|
|
//var texScaleBias = Matrix.CreateScale(0.5f, -0.5f, 1f) * Matrix.CreateTranslation(0.5f, 0.5f, 0f);
|
|
|
|
|
//DeferredPBREffect.LightSpaceMatrix = globalShadowView * globalShadowProjection; // * texScaleBias;
|
|
|
|
|
|
2020-08-07 00:58:50 +00:00
|
|
|
|
foreach (var (model, transform) in modelTransforms)
|
|
|
|
|
{
|
|
|
|
|
foreach (var modelMesh in model.Meshes)
|
|
|
|
|
{
|
|
|
|
|
foreach (var meshPart in modelMesh.MeshParts)
|
|
|
|
|
{
|
|
|
|
|
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
|
|
|
|
|
GraphicsDevice.Indices = meshPart.IndexBuffer;
|
|
|
|
|
|
|
|
|
|
SimpleDepthEffect.Model = transform;
|
2020-08-04 09:32:02 +00:00
|
|
|
|
|
2020-08-07 00:58:50 +00:00
|
|
|
|
foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes)
|
|
|
|
|
{
|
|
|
|
|
pass.Apply();
|
|
|
|
|
|
|
|
|
|
GraphicsDevice.DrawIndexedPrimitives(
|
|
|
|
|
PrimitiveType.TriangleList,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
meshPart.VertexBuffer.VertexCount,
|
|
|
|
|
0,
|
|
|
|
|
meshPart.Triangles.Length
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 21:46:20 +00:00
|
|
|
|
public void Render(
|
|
|
|
|
Camera camera,
|
|
|
|
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
|
|
|
|
IEnumerable<PointLight> pointLights,
|
|
|
|
|
IEnumerable<DirectionalLight> directionalLights
|
|
|
|
|
) {
|
|
|
|
|
Render(camera.View, camera.Projection, modelTransforms, pointLights, directionalLights);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-07 08:12:46 +00:00
|
|
|
|
private void Render(
|
|
|
|
|
Matrix view,
|
|
|
|
|
Matrix projection,
|
|
|
|
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
|
|
|
|
IEnumerable<PointLight> pointLights,
|
|
|
|
|
IEnumerable<DirectionalLight> directionalLights
|
|
|
|
|
) {
|
|
|
|
|
foreach (var (model, transform) in modelTransforms)
|
2020-08-04 09:32:02 +00:00
|
|
|
|
{
|
|
|
|
|
foreach (var modelMesh in model.Meshes)
|
|
|
|
|
{
|
|
|
|
|
foreach (var meshPart in modelMesh.MeshParts)
|
|
|
|
|
{
|
2020-08-07 00:58:50 +00:00
|
|
|
|
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
|
|
|
|
|
GraphicsDevice.Indices = meshPart.IndexBuffer;
|
2020-08-04 09:32:02 +00:00
|
|
|
|
|
|
|
|
|
if (meshPart.Effect is TransformEffect transformEffect)
|
|
|
|
|
{
|
2020-08-07 08:12:46 +00:00
|
|
|
|
transformEffect.World = transform;
|
2020-08-04 09:32:02 +00:00
|
|
|
|
transformEffect.View = view;
|
|
|
|
|
transformEffect.Projection = projection;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (meshPart.Effect is PointLightEffect pointLightEffect)
|
|
|
|
|
{
|
2020-08-05 03:50:44 +00:00
|
|
|
|
int i = 0;
|
|
|
|
|
foreach (var pointLight in pointLights)
|
2020-08-04 09:32:02 +00:00
|
|
|
|
{
|
2020-08-06 08:12:15 +00:00
|
|
|
|
if (i > pointLightEffect.MaxPointLights) { break; }
|
2020-08-05 03:50:44 +00:00
|
|
|
|
pointLightEffect.PointLights[i] = pointLight;
|
|
|
|
|
i++;
|
2020-08-04 09:32:02 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var pass in meshPart.Effect.CurrentTechnique.Passes)
|
|
|
|
|
{
|
|
|
|
|
pass.Apply();
|
|
|
|
|
|
2020-08-07 00:58:50 +00:00
|
|
|
|
GraphicsDevice.DrawIndexedPrimitives(
|
2020-08-04 09:32:02 +00:00
|
|
|
|
PrimitiveType.TriangleList,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
meshPart.VertexBuffer.VertexCount,
|
|
|
|
|
0,
|
|
|
|
|
meshPart.Triangles.Length
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|