diff --git a/Effects/DeferredPBR_PointLightEffect.cs b/Effects/DeferredPBR_PointLightEffect.cs index 82a73ea..b792ae0 100644 --- a/Effects/DeferredPBR_PointLightEffect.cs +++ b/Effects/DeferredPBR_PointLightEffect.cs @@ -18,6 +18,8 @@ namespace Kav EffectParameter farPlaneParam; + EffectParameter worldViewProjectionParam; + public Texture2D GPosition { get; set; } public Texture2D GAlbedo { get; set; } public Texture2D GNormal { get; set; } @@ -31,6 +33,42 @@ namespace Kav public float FarPlane { get; set; } + Matrix world = Matrix.Identity; + Matrix view = Matrix.Identity; + Matrix projection = Matrix.Identity; + + EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; + + public Matrix World + { + get { return world; } + set + { + world = value; + dirtyFlags |= EffectDirtyFlags.WorldViewProj; + } + } + + 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 DeferredPBR_PointLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_PointLightEffect) { CacheEffectParameters(); @@ -73,6 +111,13 @@ namespace Kav pointLightColorParam.SetValue(PointLightColor); farPlaneParam.SetValue(FarPlane); + + if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0) + { + worldViewProjectionParam.SetValue(world * view * projection); + + dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; + } } void CacheEffectParameters() @@ -89,6 +134,8 @@ namespace Kav pointLightColorParam = Parameters["PointLightColor"]; farPlaneParam = Parameters["FarPlane"]; + + worldViewProjectionParam = Parameters["WorldViewProjection"]; } } } diff --git a/Effects/FXB/DeferredPBR_PointLightEffect.fxb b/Effects/FXB/DeferredPBR_PointLightEffect.fxb index 9511784..a05cd21 100644 --- a/Effects/FXB/DeferredPBR_PointLightEffect.fxb +++ b/Effects/FXB/DeferredPBR_PointLightEffect.fxb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:033598dc2f22c2766a8b0d46215e5a9764b5445a520d67bc68f1566dbdd15035 -size 3740 +oid sha256:9a30fb7bc8d5af4490f415509711762aa45ee8d5ef4c67d01eb8ae6af10778a0 +size 4076 diff --git a/Effects/HLSL/DeferredPBR_PointLightEffect.fx b/Effects/HLSL/DeferredPBR_PointLightEffect.fx index d6e1933..0195594 100644 --- a/Effects/HLSL/DeferredPBR_PointLightEffect.fx +++ b/Effects/HLSL/DeferredPBR_PointLightEffect.fx @@ -1,3 +1,5 @@ +// Assumes you are drawing a sphere!! + #include "Macros.fxh" //from FNA #include "Lighting.fxh" #include "Shadow.fxh" @@ -19,26 +21,27 @@ BEGIN_CONSTANTS MATRIX_CONSTANTS + float4x4 WorldViewProjection _vs(c0) _cb(c4); + END_CONSTANTS struct VertexInput { float4 Position : POSITION; - float2 TexCoord : TEXCOORD; }; struct PixelInput { float4 Position : SV_POSITION; - float2 TexCoord : TEXCOORD0; + float4 ScreenPosition : TEXCOORD0; }; PixelInput main_vs(VertexInput input) { PixelInput output; - output.Position = input.Position; - output.TexCoord = input.TexCoord; + output.Position = mul(input.Position, WorldViewProjection); + output.ScreenPosition = output.Position; return output; } @@ -73,10 +76,13 @@ float4 ComputeColor( float4 main_ps(PixelInput input) : SV_TARGET0 { - float3 worldPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb; - float3 normal = SAMPLE_TEXTURE(gNormal, input.TexCoord).xyz; - float3 albedo = SAMPLE_TEXTURE(gAlbedo, input.TexCoord).rgb; - float2 metallicRoughness = SAMPLE_TEXTURE(gMetallicRoughness, input.TexCoord).rg; + input.ScreenPosition.xy /= input.ScreenPosition.w; + float2 texCoord = 0.5f * float2(input.ScreenPosition.x,-input.ScreenPosition.y) + 0.5f; + + float3 worldPosition = SAMPLE_TEXTURE(gPosition, texCoord).rgb; + float3 normal = SAMPLE_TEXTURE(gNormal, texCoord).xyz; + float3 albedo = SAMPLE_TEXTURE(gAlbedo, texCoord).rgb; + float2 metallicRoughness = SAMPLE_TEXTURE(gMetallicRoughness, texCoord).rg; return ComputeColor( worldPosition, diff --git a/Kav.Core.csproj b/Kav.Core.csproj index 541feb0..676e7c2 100644 --- a/Kav.Core.csproj +++ b/Kav.Core.csproj @@ -64,6 +64,9 @@ Kav.Resources.UnitCube.glb + + Kav.Resources.UnitSphere.glb + diff --git a/Kav.Framework.csproj b/Kav.Framework.csproj index 1cf665d..2263772 100644 --- a/Kav.Framework.csproj +++ b/Kav.Framework.csproj @@ -64,6 +64,9 @@ Kav.Resources.UnitCube.glb + + Kav.Resources.UnitSphere.glb + diff --git a/Lights/PointLight.cs b/Lights/PointLight.cs index 6d3fb90..50f32ca 100644 --- a/Lights/PointLight.cs +++ b/Lights/PointLight.cs @@ -4,15 +4,23 @@ namespace Kav { public struct PointLight { + public static double ATTENUATION_EPSILON = 0.1; + public Vector3 Position { get; } public Color Color { get; } public float Intensity { get; } + public float EffectiveRadius { get; } + public BoundingSphere BoundingSphere { get; } + public PointLight(Vector3 position, Color color, float intensity = 1f) { Position = position; Color = color; Intensity = intensity; + + EffectiveRadius = (float) System.Math.Sqrt(Intensity); + BoundingSphere = new BoundingSphere(position, EffectiveRadius); } } } diff --git a/Models/UnitSphere.glb b/Models/UnitSphere.glb new file mode 100644 index 0000000..b495e77 Binary files /dev/null and b/Models/UnitSphere.glb differ diff --git a/Renderer.cs b/Renderer.cs index 59da550..594f0fb 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -26,8 +26,9 @@ namespace Kav private Effect ToneMapEffect { get; } private SkyboxEffect SkyboxEffect { get; } private DiffuseLitSpriteEffect DiffuseLitSpriteEffect { get; } - + private Kav.Model UnitCube { get; } + private Kav.Model UnitSphere { get; } public Renderer( GraphicsDevice graphicsDevice @@ -61,6 +62,11 @@ namespace Kav GraphicsDevice, Smuggler.Importer.ImportGLB(GraphicsDevice, new MemoryStream(Resources.UnitCubeModel)) ); + + UnitSphere = Kav.ModelLoader.Load( + graphicsDevice, + Smuggler.Importer.ImportGLB(graphicsDevice, new MemoryStream(Resources.UnitSphereModel)) + ); } public static (T[], DynamicVertexBuffer) CreateInstanceVertexBuffer( @@ -461,7 +467,16 @@ namespace Kav PointLight pointLight ) { GraphicsDevice.SetRenderTarget(renderTarget); - GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; + if (Vector3.Distance(camera.Position, pointLight.Position) < pointLight.EffectiveRadius) + { + GraphicsDevice.RasterizerState = RasterizerState.CullClockwise; + } + else + { + GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; + } + + GraphicsDevice.DepthStencilState = DepthStencilState.None; GraphicsDevice.BlendState = BlendState.Additive; DeferredPointLightEffect.GPosition = gPosition; @@ -478,7 +493,17 @@ namespace Kav DeferredPointLightEffect.FarPlane = 25f; // FIXME: magic value - RenderFullscreenEffect(DeferredPointLightEffect); + DeferredPointLightEffect.World = + Matrix.CreateScale(pointLight.EffectiveRadius) * + Matrix.CreateTranslation(pointLight.Position); + DeferredPointLightEffect.View = camera.View; + DeferredPointLightEffect.Projection = camera.Projection; + + RenderIndexed( + GraphicsDevice, + UnitSphere.Meshes[0].MeshParts[0], + DeferredPointLightEffect + ); } public void RenderDirectionalLight( @@ -492,6 +517,7 @@ namespace Kav DirectionalLight directionalLight ) { GraphicsDevice.SetRenderTarget(renderTarget); + GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.BlendState = BlendState.Additive; diff --git a/Resources.cs b/Resources.cs index ae53a3d..05d2a1b 100644 --- a/Resources.cs +++ b/Resources.cs @@ -195,6 +195,18 @@ namespace Kav } } + public static byte[] UnitSphereModel + { + get + { + if (unitSphereModel == null) + { + unitSphereModel = GetResource("UnitSphere.glb"); + } + return unitSphereModel; + } + } + private static byte[] ambientLightEffect; private static byte[] pointLightEffect; private static byte[] directionalLightEffect; @@ -212,6 +224,7 @@ namespace Kav private static byte[] paletteCrushEffect; private static byte[] unitCubeModel; + private static byte[] unitSphereModel; private static byte[] GetResource(string name) {