From 06e552399600be4b706249bab54740eae4fd8e6b Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Sat, 17 Oct 2020 13:53:26 -0700 Subject: [PATCH] deferred skybox --- Effects/FXB/SkyboxEffect.fxb | 3 ++ Effects/HLSL/SkyboxEffect.fx | 45 ++++++++++++++++ Effects/SkyboxEffect.cs | 77 +++++++++++++++++++++++++++ Kav.Core.csproj | 6 +++ Kav.Framework.csproj | 6 +++ Models/UnitCube.glb | Bin 0 -> 1684 bytes Renderer.cs | 98 ++++++++++++++++++++++++++++++++--- Resources.cs | 47 +++++++++++++---- 8 files changed, 264 insertions(+), 18 deletions(-) create mode 100644 Effects/FXB/SkyboxEffect.fxb create mode 100644 Effects/HLSL/SkyboxEffect.fx create mode 100644 Effects/SkyboxEffect.cs create mode 100644 Models/UnitCube.glb diff --git a/Effects/FXB/SkyboxEffect.fxb b/Effects/FXB/SkyboxEffect.fxb new file mode 100644 index 0000000..10d5b22 --- /dev/null +++ b/Effects/FXB/SkyboxEffect.fxb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:847ffdb1472a2c6ca32b7bbf0f41e2b972d2435d8fe4d72e82d97bc8c88b4b59 +size 1072 diff --git a/Effects/HLSL/SkyboxEffect.fx b/Effects/HLSL/SkyboxEffect.fx new file mode 100644 index 0000000..88ac7f3 --- /dev/null +++ b/Effects/HLSL/SkyboxEffect.fx @@ -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(); + } +} diff --git a/Effects/SkyboxEffect.cs b/Effects/SkyboxEffect.cs new file mode 100644 index 0000000..b4f4427 --- /dev/null +++ b/Effects/SkyboxEffect.cs @@ -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"]; + } + } +} diff --git a/Kav.Core.csproj b/Kav.Core.csproj index b018e72..fc78de4 100644 --- a/Kav.Core.csproj +++ b/Kav.Core.csproj @@ -42,6 +42,12 @@ Kav.Resources.SimpleDepthEffect.fxb + + Kav.Resources.SkyboxEffect.fxb + + + Kav.Resources.UnitCube.glb + diff --git a/Kav.Framework.csproj b/Kav.Framework.csproj index c2d9079..4b72a58 100644 --- a/Kav.Framework.csproj +++ b/Kav.Framework.csproj @@ -42,6 +42,12 @@ Kav.Resources.SimpleDepthEffect.fxb + + Kav.Resources.SkyboxEffect.fxb + + + Kav.Resources.UnitCube.glb + diff --git a/Models/UnitCube.glb b/Models/UnitCube.glb new file mode 100644 index 0000000000000000000000000000000000000000..aa53f03fbf6f8808cb355c0302381eb28e1ee265 GIT binary patch literal 1684 zcmb7FZEq4m5FT5tTD5A``jyP*6OW_3cptPBYebPVKpK;#(E}EGNx36;2ig!4euV!= zf0{GPE?lsoaLMd5v(GcLGkZtqT{b^#0l@Da0COAQQ^To^(TySzqdmr+@I~mxL5Mbf zz6b+9h*CXDNgZDbzazp_<+YO8>` zX%8EcGtdt@f(i3{a=wVh*cZ`-OjY{wuqBWsOvsFRDW=ki`w@5j@Rat>_j%@wke8&aMpio z*zJn&)Du5top#V41itX&=GB1a%4Mv)f$d=E(+ygO)UNxBr%UGyWjumMmvr`uH|7g% z$Fc&Ro|Ln6dt*$VL~Y)5(yDZ8lXUC9)3ev5%S}0FmPS^mH_D}IsV-mCqW$E>$xCZp z#iA1PIK%po8}mk#yTCdziF&N@`O!M&Sr00Yk@d`LWM1nSdH+WOnZE`6U$O<;a2xKx4y`+I7w*A* k*rjzB9>7C*1bejZ!DDy=Php?deRu}X;RPJfdH^rsABk>Wv;Y7A literal 0 HcmV?d00001 diff --git a/Renderer.cs b/Renderer.cs index d48a36a..2e11a73 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -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; diff --git a/Resources.cs b/Resources.cs index 9badc01..251b820 100644 --- a/Resources.cs +++ b/Resources.cs @@ -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()) {