Batched Billboard Implementation #5
|
@ -0,0 +1,39 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace Kav
|
||||||
|
{
|
||||||
|
public struct Sprite
|
||||||
|
{
|
||||||
|
public Texture2D Texture { get; }
|
||||||
|
public Vector3 Position { get; }
|
||||||
|
public Vector2 Origin { get; }
|
||||||
|
public float Rotation { get; }
|
||||||
|
public Vector2 Scale { get; }
|
||||||
|
|
||||||
|
public Sprite(
|
||||||
|
Texture2D texture,
|
||||||
|
Vector3 position,
|
||||||
|
Vector2 origin,
|
||||||
|
float rotation,
|
||||||
|
Vector2 scale
|
||||||
|
) {
|
||||||
|
Texture = texture;
|
||||||
|
Position = position;
|
||||||
|
Origin = origin;
|
||||||
|
Rotation = rotation;
|
||||||
|
Scale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sprite(
|
||||||
|
Texture2D texture,
|
||||||
|
Vector3 position
|
||||||
|
) {
|
||||||
|
Texture = texture;
|
||||||
|
Position = position;
|
||||||
|
Origin = Vector2.Zero;
|
||||||
|
Rotation = 0f;
|
||||||
|
Scale = Vector2.One;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
Renderer.cs
91
Renderer.cs
|
@ -33,6 +33,7 @@ namespace Kav
|
||||||
private LinearDepthEffect LinearDepthEffect { get; }
|
private LinearDepthEffect LinearDepthEffect { get; }
|
||||||
private Effect ToneMapEffect { get; }
|
private Effect ToneMapEffect { get; }
|
||||||
private SkyboxEffect SkyboxEffect { get; }
|
private SkyboxEffect SkyboxEffect { get; }
|
||||||
|
private BasicEffect BasicEffect { get; }
|
||||||
|
|
||||||
private RenderTarget2D gPosition { get; }
|
private RenderTarget2D gPosition { get; }
|
||||||
private RenderTarget2D gNormal { get; }
|
private RenderTarget2D gNormal { get; }
|
||||||
|
@ -159,6 +160,7 @@ namespace Kav
|
||||||
ToneMapEffect = new Effect(graphicsDevice, Resources.ToneMapEffect);
|
ToneMapEffect = new Effect(graphicsDevice, Resources.ToneMapEffect);
|
||||||
Deferred_ToonEffect = new Deferred_ToonEffect(GraphicsDevice);
|
Deferred_ToonEffect = new Deferred_ToonEffect(GraphicsDevice);
|
||||||
SkyboxEffect = new SkyboxEffect(GraphicsDevice);
|
SkyboxEffect = new SkyboxEffect(GraphicsDevice);
|
||||||
|
BasicEffect = new BasicEffect(GraphicsDevice);
|
||||||
|
|
||||||
FullscreenTriangle = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 3, BufferUsage.WriteOnly);
|
FullscreenTriangle = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 3, BufferUsage.WriteOnly);
|
||||||
FullscreenTriangle.SetData(new VertexPositionTexture[3] {
|
FullscreenTriangle.SetData(new VertexPositionTexture[3] {
|
||||||
|
@ -176,6 +178,7 @@ namespace Kav
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeferredRender(
|
public void DeferredRender(
|
||||||
|
RenderTarget2D renderTarget,
|
||||||
PerspectiveCamera camera,
|
PerspectiveCamera camera,
|
||||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
AmbientLight ambientLight,
|
AmbientLight ambientLight,
|
||||||
|
@ -198,21 +201,21 @@ namespace Kav
|
||||||
|
|
||||||
DirectionalLightRender(camera, modelTransforms, directionalLight);
|
DirectionalLightRender(camera, modelTransforms, directionalLight);
|
||||||
|
|
||||||
GraphicsDevice.SetRenderTarget(null);
|
GraphicsDevice.SetRenderTarget(renderTarget);
|
||||||
GraphicsDevice.Clear(Color.Black);
|
|
||||||
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, ToneMapEffect);
|
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, ToneMapEffect);
|
||||||
SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White);
|
SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White);
|
||||||
SpriteBatch.End();
|
SpriteBatch.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeferredToonRender(
|
public void DeferredToonRender(
|
||||||
|
RenderTarget2D renderTarget,
|
||||||
PerspectiveCamera camera,
|
PerspectiveCamera camera,
|
||||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
AmbientLight ambientLight,
|
AmbientLight ambientLight,
|
||||||
IEnumerable<PointLight> pointLights,
|
IEnumerable<PointLight> pointLights,
|
||||||
DirectionalLight directionalLight,
|
DirectionalLight directionalLight,
|
||||||
TextureCube skybox
|
TextureCube skybox
|
||||||
) {
|
) {
|
||||||
GBufferRender(camera, modelTransforms);
|
GBufferRender(camera, modelTransforms);
|
||||||
|
|
||||||
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
||||||
|
@ -230,12 +233,64 @@ namespace Kav
|
||||||
DirectionalLightToonRender(camera, modelTransforms, directionalLight);
|
DirectionalLightToonRender(camera, modelTransforms, directionalLight);
|
||||||
SkyboxRender(camera, skybox);
|
SkyboxRender(camera, skybox);
|
||||||
|
|
||||||
GraphicsDevice.SetRenderTarget(null);
|
GraphicsDevice.SetRenderTarget(renderTarget);
|
||||||
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, null);
|
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, null);
|
||||||
SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White);
|
SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White);
|
||||||
SpriteBatch.End();
|
SpriteBatch.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// billboards sprites into the scene
|
||||||
|
// FIXME: we can frustum cull the sprites probably
|
||||||
|
public void BillboardSpriteRender(
|
||||||
|
RenderTarget2D renderTarget,
|
||||||
|
PerspectiveCamera camera,
|
||||||
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
|
IEnumerable<Sprite> sprites
|
||||||
|
) {
|
||||||
|
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
||||||
|
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0);
|
||||||
|
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
||||||
|
|
||||||
|
DepthRender(camera, modelTransforms);
|
||||||
|
GraphicsDevice.Clear(ClearOptions.Target, new Color(0, 0, 0, 0), 1f, 0);
|
||||||
|
|
||||||
|
Matrix invertY = Matrix.CreateScale(1, -1, 1);
|
||||||
|
|
||||||
|
BasicEffect.World = invertY;
|
||||||
|
BasicEffect.View = Matrix.Identity;
|
||||||
|
BasicEffect.Projection = camera.Projection;
|
||||||
|
BasicEffect.TextureEnabled = true;
|
||||||
|
BasicEffect.VertexColorEnabled = true;
|
||||||
|
|
||||||
|
SpriteBatch.Begin(0, null, null, DepthStencilState.DepthRead, RasterizerState.CullNone, BasicEffect);
|
||||||
|
|
||||||
|
foreach (var sprite in sprites)
|
||||||
|
{
|
||||||
|
// transform view space on CPU so we don't have to break the batch
|
||||||
|
Vector3 viewSpacePosition = Vector3.Transform(sprite.Position, camera.View * invertY);
|
||||||
|
|
||||||
|
SpriteBatch.Draw(
|
||||||
|
sprite.Texture,
|
||||||
|
new Vector2(viewSpacePosition.X, viewSpacePosition.Y),
|
||||||
|
null,
|
||||||
|
Color.White,
|
||||||
|
0,
|
||||||
|
sprite.Origin,
|
||||||
|
sprite.Scale / new Vector2(sprite.Texture.Width, sprite.Texture.Height),
|
||||||
|
0,
|
||||||
|
viewSpacePosition.Z
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpriteBatch.End();
|
||||||
|
|
||||||
|
GraphicsDevice.SetRenderTarget(renderTarget);
|
||||||
|
GraphicsDevice.Clear(new Color(0, 0, 0, 0));
|
||||||
|
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null);
|
||||||
|
SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White);
|
||||||
|
SpriteBatch.End();
|
||||||
|
}
|
||||||
|
|
||||||
private void DepthRender(
|
private void DepthRender(
|
||||||
PerspectiveCamera camera,
|
PerspectiveCamera camera,
|
||||||
IEnumerable<(Model, Matrix)> modelTransforms
|
IEnumerable<(Model, Matrix)> modelTransforms
|
||||||
|
@ -386,11 +441,11 @@ namespace Kav
|
||||||
DeferredPointLightEffect.GPosition = gPosition;
|
DeferredPointLightEffect.GPosition = gPosition;
|
||||||
DeferredPointLightEffect.GAlbedo = gAlbedo;
|
DeferredPointLightEffect.GAlbedo = gAlbedo;
|
||||||
DeferredPointLightEffect.GNormal = gNormal;
|
DeferredPointLightEffect.GNormal = gNormal;
|
||||||
DeferredPointLightEffect.GMetallicRoughness = gMetallicRoughness;
|
DeferredPointLightEffect.GMetallicRoughness = gMetallicRoughness;
|
||||||
DeferredPointLightEffect.ShadowMap = PointShadowCubeMap;
|
DeferredPointLightEffect.ShadowMap = PointShadowCubeMap;
|
||||||
|
|
||||||
DeferredPointLightEffect.PointLightPosition = pointLight.Position;
|
DeferredPointLightEffect.PointLightPosition = pointLight.Position;
|
||||||
DeferredPointLightEffect.PointLightColor =
|
DeferredPointLightEffect.PointLightColor =
|
||||||
pointLight.Color.ToVector3() * pointLight.Intensity;
|
pointLight.Color.ToVector3() * pointLight.Intensity;
|
||||||
|
|
||||||
DeferredPointLightEffect.FarPlane = 25f; // FIXME: magic value
|
DeferredPointLightEffect.FarPlane = 25f; // FIXME: magic value
|
||||||
|
@ -428,11 +483,11 @@ namespace Kav
|
||||||
{
|
{
|
||||||
DeferredDirectionalLightEffect.ShadowMapFour = ShadowRenderTargets[3];
|
DeferredDirectionalLightEffect.ShadowMapFour = ShadowRenderTargets[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
DeferredDirectionalLightEffect.DirectionalLightDirection = directionalLight.Direction;
|
DeferredDirectionalLightEffect.DirectionalLightDirection = directionalLight.Direction;
|
||||||
DeferredDirectionalLightEffect.DirectionalLightColor =
|
DeferredDirectionalLightEffect.DirectionalLightColor =
|
||||||
directionalLight.Color.ToVector3() * directionalLight.Intensity;
|
directionalLight.Color.ToVector3() * directionalLight.Intensity;
|
||||||
|
|
||||||
DeferredDirectionalLightEffect.ViewMatrix = camera.View;
|
DeferredDirectionalLightEffect.ViewMatrix = camera.View;
|
||||||
DeferredDirectionalLightEffect.EyePosition = camera.Position;
|
DeferredDirectionalLightEffect.EyePosition = camera.Position;
|
||||||
|
|
||||||
|
@ -467,7 +522,7 @@ namespace Kav
|
||||||
|
|
||||||
Deferred_ToonEffect.EyePosition = camera.Position;
|
Deferred_ToonEffect.EyePosition = camera.Position;
|
||||||
Deferred_ToonEffect.DirectionalLightDirection = directionalLight.Direction;
|
Deferred_ToonEffect.DirectionalLightDirection = directionalLight.Direction;
|
||||||
Deferred_ToonEffect.DirectionalLightColor =
|
Deferred_ToonEffect.DirectionalLightColor =
|
||||||
directionalLight.Color.ToVector3() * directionalLight.Intensity;
|
directionalLight.Color.ToVector3() * directionalLight.Intensity;
|
||||||
|
|
||||||
Deferred_ToonEffect.ShadowMapOne = ShadowRenderTargets[0];
|
Deferred_ToonEffect.ShadowMapOne = ShadowRenderTargets[0];
|
||||||
|
@ -483,7 +538,7 @@ namespace Kav
|
||||||
{
|
{
|
||||||
Deferred_ToonEffect.ShadowMapFour = ShadowRenderTargets[3];
|
Deferred_ToonEffect.ShadowMapFour = ShadowRenderTargets[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
Deferred_ToonEffect.ViewMatrix = camera.View;
|
Deferred_ToonEffect.ViewMatrix = camera.View;
|
||||||
|
|
||||||
foreach (EffectPass pass in Deferred_ToonEffect.CurrentTechnique.Passes)
|
foreach (EffectPass pass in Deferred_ToonEffect.CurrentTechnique.Passes)
|
||||||
|
@ -506,7 +561,7 @@ namespace Kav
|
||||||
{
|
{
|
||||||
var farPlane = camera.FarPlane / (MathHelper.Max((NumShadowCascades - i - 1) * 2f, 1f));
|
var farPlane = camera.FarPlane / (MathHelper.Max((NumShadowCascades - i - 1) * 2f, 1f));
|
||||||
|
|
||||||
// divide the view frustum
|
// divide the view frustum
|
||||||
var shadowCamera = new PerspectiveCamera(
|
var shadowCamera = new PerspectiveCamera(
|
||||||
camera.Position,
|
camera.Position,
|
||||||
camera.Forward,
|
camera.Forward,
|
||||||
|
@ -516,7 +571,7 @@ namespace Kav
|
||||||
previousFarPlane,
|
previousFarPlane,
|
||||||
farPlane
|
farPlane
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: This is tightly coupled to the effect and it sucks
|
// TODO: This is tightly coupled to the effect and it sucks
|
||||||
RenderDirectionalShadowMap(shadowCamera, modelTransforms, directionalLight, effect, i);
|
RenderDirectionalShadowMap(shadowCamera, modelTransforms, directionalLight, effect, i);
|
||||||
|
|
||||||
|
@ -526,8 +581,8 @@ namespace Kav
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderDirectionalShadowMap(
|
private void RenderDirectionalShadowMap(
|
||||||
PerspectiveCamera camera,
|
PerspectiveCamera camera,
|
||||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
DirectionalLight directionalLight,
|
DirectionalLight directionalLight,
|
||||||
ShadowCascadeEffect effect,
|
ShadowCascadeEffect effect,
|
||||||
int shadowCascadeIndex
|
int shadowCascadeIndex
|
||||||
|
@ -536,7 +591,7 @@ namespace Kav
|
||||||
GraphicsDevice.Clear(Color.White);
|
GraphicsDevice.Clear(Color.White);
|
||||||
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
||||||
GraphicsDevice.BlendState = BlendState.Opaque;
|
GraphicsDevice.BlendState = BlendState.Opaque;
|
||||||
|
|
||||||
var cameraBoundingFrustum = new BoundingFrustum(camera.View * camera.Projection);
|
var cameraBoundingFrustum = new BoundingFrustum(camera.View * camera.Projection);
|
||||||
Vector3[] frustumCorners = cameraBoundingFrustum.GetCorners();
|
Vector3[] frustumCorners = cameraBoundingFrustum.GetCorners();
|
||||||
|
|
||||||
|
@ -555,7 +610,7 @@ namespace Kav
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBox lightBox = BoundingBox.CreateFromPoints(frustumCorners);
|
BoundingBox lightBox = BoundingBox.CreateFromPoints(frustumCorners);
|
||||||
|
|
||||||
SimpleDepthEffect.View = lightView;
|
SimpleDepthEffect.View = lightView;
|
||||||
SimpleDepthEffect.Projection = Matrix.CreateOrthographicOffCenter(
|
SimpleDepthEffect.Projection = Matrix.CreateOrthographicOffCenter(
|
||||||
lightBox.Min.X,
|
lightBox.Min.X,
|
||||||
|
@ -586,7 +641,7 @@ namespace Kav
|
||||||
}
|
}
|
||||||
|
|
||||||
var boundingFrustum = new BoundingFrustum(lightSpaceMatrix);
|
var boundingFrustum = new BoundingFrustum(lightSpaceMatrix);
|
||||||
|
|
||||||
foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms))
|
foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms))
|
||||||
{
|
{
|
||||||
foreach (var modelMesh in model.Meshes)
|
foreach (var modelMesh in model.Meshes)
|
||||||
|
|
Loading…
Reference in New Issue