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 0000000..aa53f03
Binary files /dev/null and b/Models/UnitCube.glb differ
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())
{