deferred skybox

pull/3/head
cosmonaut 2020-10-17 13:53:26 -07:00
parent 19a61985ca
commit 06e5523996
8 changed files with 264 additions and 18 deletions

BIN
Effects/FXB/SkyboxEffect.fxb (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,45 @@
#include "Macros.fxh"
DECLARE_CUBEMAP(skybox, 0);
BEGIN_CONSTANTS
float4x4 ViewProjection _vs(c0) _cb(c0);
END_CONSTANTS
struct VertexShaderInput
{
float3 Position : POSITION;
};
struct VertexShaderOutput
{
float4 Position : SV_POSITION;
float3 TexCoord : TEXCOORD;
};
VertexShaderOutput main_vs(VertexShaderInput input)
{
VertexShaderOutput output;
output.Position = mul(float4(input.Position, 1.0), ViewProjection);
output.Position = output.Position.xyww;
output.TexCoord = input.Position;
return output;
}
float4 main_ps(VertexShaderOutput input) : SV_TARGET0
{
return SAMPLE_CUBEMAP(skybox, input.TexCoord);
}
Technique Skybox
{
Pass
{
VertexShader = compile vs_3_0 main_vs();
PixelShader = compile ps_3_0 main_ps();
}
}

77
Effects/SkyboxEffect.cs Normal file
View File

@ -0,0 +1,77 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Kav
{
public class SkyboxEffect : Effect
{
EffectParameter viewProjectionParam;
EffectParameter skyboxParam;
Matrix view;
Matrix projection;
TextureCube skybox;
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
public Matrix View
{
get { return view; }
set
{
view = value;
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
}
}
public Matrix Projection
{
get { return projection; }
set
{
projection = value;
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
}
}
public TextureCube Skybox
{
get { return skybox; }
set
{
skybox = value;
dirtyFlags |= EffectDirtyFlags.World; // hack flag but whatever
}
}
public SkyboxEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.SkyboxEffect)
{
CacheEffectParameters();
}
protected override void OnApply()
{
if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
{
Matrix.Multiply(ref view, ref projection, out Matrix viewProjection);
viewProjectionParam.SetValue(viewProjection);
dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
}
if ((dirtyFlags & EffectDirtyFlags.World) != 0)
{
skyboxParam.SetValue(skybox);
dirtyFlags &= ~EffectDirtyFlags.World;
}
}
private void CacheEffectParameters()
{
viewProjectionParam = Parameters["ViewProjection"];
skyboxParam = Parameters["skybox"];
}
}
}

View File

@ -42,6 +42,12 @@
<EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb">
<LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Effects\FXB\SkyboxEffect.fxb">
<LogicalName>Kav.Resources.SkyboxEffect.fxb</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Models\UnitCube.glb">
<LogicalName>Kav.Resources.UnitCube.glb</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@ -42,6 +42,12 @@
<EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb">
<LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Effects\FXB\SkyboxEffect.fxb">
<LogicalName>Kav.Resources.SkyboxEffect.fxb</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Models\UnitCube.glb">
<LogicalName>Kav.Resources.UnitCube.glb</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project>

BIN
Models/UnitCube.glb Normal file

Binary file not shown.

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@ -29,6 +30,7 @@ namespace Kav
private Deferred_ToonEffect Deferred_ToonEffect { get; }
private SimpleDepthEffect SimpleDepthEffect { get; }
private Effect ToneMapEffect { get; }
private SkyboxEffect SkyboxEffect { get; }
private RenderTarget2D gPosition { get; }
private RenderTarget2D gNormal { get; }
@ -37,6 +39,8 @@ namespace Kav
private RenderTargetBinding[] GBuffer { get; }
private Kav.Model UnitCube { get; }
private SpriteBatch SpriteBatch { get; }
public Renderer(
@ -73,7 +77,7 @@ namespace Kav
renderDimensionsY,
false,
SurfaceFormat.Color,
DepthFormat.None,
DepthFormat.Depth24,
0,
RenderTargetUsage.PreserveContents
);
@ -142,6 +146,7 @@ namespace Kav
DeferredDirectionalLightEffect.ShadowMapSize = ShadowMapSize;
ToneMapEffect = new Effect(graphicsDevice, Resources.ToneMapEffect);
Deferred_ToonEffect = new Deferred_ToonEffect(GraphicsDevice);
SkyboxEffect = new SkyboxEffect(GraphicsDevice);
FullscreenTriangle = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 3, BufferUsage.WriteOnly);
FullscreenTriangle.SetData(new VertexPositionTexture[3] {
@ -150,6 +155,11 @@ namespace Kav
new VertexPositionTexture(new Vector3(3, 1, 0), new Vector2(2, 0))
});
UnitCube = Kav.ModelLoader.Load(
GraphicsDevice,
Smuggler.Importer.ImportGLB(GraphicsDevice, new MemoryStream(Resources.UnitCubeModel))
);
SpriteBatch = new SpriteBatch(graphicsDevice);
}
@ -187,23 +197,95 @@ namespace Kav
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms,
AmbientLight ambientLight,
DirectionalLight directionalLight
) {
DirectionalLight directionalLight,
TextureCube skybox
) {
GBufferRender(camera, modelTransforms);
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
GraphicsDevice.Clear(Color.Black);
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0);
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
DepthRender(camera, modelTransforms);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
AmbientLightRender(ambientLight);
DirectionalLightToonRender(camera, modelTransforms, directionalLight);
SkyboxRender(camera, skybox);
GraphicsDevice.SetRenderTarget(null);
GraphicsDevice.Clear(Color.Black);
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, null);
SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White);
SpriteBatch.End();
}
private void DepthRender(
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms
) {
foreach (var (model, transform) in modelTransforms)
{
foreach (var modelMesh in model.Meshes)
{
foreach (var meshPart in modelMesh.MeshParts)
{
SimpleDepthEffect.Model = transform;
SimpleDepthEffect.View = camera.View;
SimpleDepthEffect.Projection = camera.Projection;
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
GraphicsDevice.Indices = meshPart.IndexBuffer;
foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
meshPart.VertexBuffer.VertexCount,
0,
meshPart.Triangles.Length
);
}
}
}
}
}
private void SkyboxRender(
PerspectiveCamera camera,
TextureCube skybox
) {
GraphicsDevice.RasterizerState.CullMode = CullMode.CullClockwiseFace;
SkyboxEffect.Skybox = skybox;
var view = camera.View;
view.Translation = Vector3.Zero;
SkyboxEffect.View = view;
SkyboxEffect.Projection = camera.Projection;
GraphicsDevice.SetVertexBuffer(UnitCube.Meshes[0].MeshParts[0].VertexBuffer);
GraphicsDevice.Indices = UnitCube.Meshes[0].MeshParts[0].IndexBuffer;
foreach (var pass in SkyboxEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
UnitCube.Meshes[0].MeshParts[0].VertexBuffer.VertexCount,
0,
UnitCube.Meshes[0].MeshParts[0].Triangles.Length
);
}
GraphicsDevice.RasterizerState.CullMode = CullMode.CullCounterClockwiseFace;
}
private void GBufferRender(
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms
@ -255,8 +337,7 @@ namespace Kav
private void AmbientLightRender(AmbientLight ambientLight)
{
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
GraphicsDevice.BlendState = BlendState.Additive;
GraphicsDevice.DepthStencilState = DepthStencilState.None;
GraphicsDevice.BlendState = BlendState.Opaque;
DeferredAmbientLightEffect.GPosition = gPosition;
DeferredAmbientLightEffect.GAlbedo = gAlbedo;
@ -341,6 +422,7 @@ namespace Kav
RenderShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect);
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
GraphicsDevice.BlendState = BlendState.Additive;
Deferred_ToonEffect.GPosition = gPosition;

View File

@ -10,7 +10,7 @@ namespace Kav
{
if (ambientLightEffect == null)
{
ambientLightEffect = GetResource("DeferredPBR_AmbientLightEffect");
ambientLightEffect = GetResource("DeferredPBR_AmbientLightEffect.fxb");
}
return ambientLightEffect;
}
@ -21,7 +21,7 @@ namespace Kav
{
if (pointLightEffect == null)
{
pointLightEffect = GetResource("DeferredPBR_PointLightEffect");
pointLightEffect = GetResource("DeferredPBR_PointLightEffect.fxb");
}
return pointLightEffect;
}
@ -33,7 +33,7 @@ namespace Kav
{
if (directionalLightEffect == null)
{
directionalLightEffect = GetResource("DeferredPBR_DirectionalLightEffect");
directionalLightEffect = GetResource("DeferredPBR_DirectionalLightEffect.fxb");
}
return directionalLightEffect;
}
@ -45,7 +45,7 @@ namespace Kav
{
if (gBufferEffect == null)
{
gBufferEffect = GetResource("DeferredPBR_GBufferEffect");
gBufferEffect = GetResource("DeferredPBR_GBufferEffect.fxb");
}
return gBufferEffect;
}
@ -57,7 +57,7 @@ namespace Kav
{
if (toneMapEffect == null)
{
toneMapEffect = GetResource("ToneMapEffect");
toneMapEffect = GetResource("ToneMapEffect.fxb");
}
return toneMapEffect;
}
@ -69,7 +69,7 @@ namespace Kav
{
if (deferredToonEffect == null)
{
deferredToonEffect = GetResource("Deferred_ToonEffect");
deferredToonEffect = GetResource("Deferred_ToonEffect.fxb");
}
return deferredToonEffect;
}
@ -81,7 +81,7 @@ namespace Kav
{
if (deferredPBREffect == null)
{
deferredPBREffect = GetResource("DeferredPBREffect");
deferredPBREffect = GetResource("DeferredPBREffect.fxb");
}
return deferredPBREffect;
}
@ -93,7 +93,7 @@ namespace Kav
{
if (pbrEffect == null)
{
pbrEffect = GetResource("PBREffect");
pbrEffect = GetResource("PBREffect.fxb");
}
return pbrEffect;
}
@ -105,12 +105,36 @@ namespace Kav
{
if (simpleDepthEffect == null)
{
simpleDepthEffect = GetResource("SimpleDepthEffect");
simpleDepthEffect = GetResource("SimpleDepthEffect.fxb");
}
return simpleDepthEffect;
}
}
public static byte[] SkyboxEffect
{
get
{
if (skyboxEffect == null)
{
skyboxEffect = GetResource("SkyboxEffect.fxb");
}
return skyboxEffect;
}
}
public static byte[] UnitCubeModel
{
get
{
if (unitCubeModel == null)
{
unitCubeModel = GetResource("UnitCube.glb");
}
return unitCubeModel;
}
}
private static byte[] ambientLightEffect;
private static byte[] pointLightEffect;
private static byte[] directionalLightEffect;
@ -120,11 +144,14 @@ namespace Kav
private static byte[] deferredPBREffect;
private static byte[] pbrEffect;
private static byte[] simpleDepthEffect;
private static byte[] skyboxEffect;
private static byte[] unitCubeModel;
private static byte[] GetResource(string name)
{
Stream stream = typeof(Resources).Assembly.GetManifestResourceStream(
"Kav.Resources." + name + ".fxb"
"Kav.Resources." + name
);
using (MemoryStream ms = new MemoryStream())
{