From c6aa4c7baf655f9e42814d17ee1357635dbde561 Mon Sep 17 00:00:00 2001 From: dexy Date: Thu, 5 Dec 2019 03:40:52 +1100 Subject: [PATCH] HD lights rendering in interiors --- CodeWalker.Shaders/CodeWalker.Shaders.vcxproj | 10 ++ .../CodeWalker.Shaders.vcxproj.filters | 3 + CodeWalker.Shaders/LightPS.hlsl | 35 +---- CodeWalker.Shaders/LightPS.hlsli | 68 ++++++++- CodeWalker.Shaders/LightPS_MS.hlsl | 52 +++++++ CodeWalker.Shaders/LightVS.hlsl | 79 +++++------ Rendering/Renderable.cs | 72 +++++++++- Rendering/Renderer.cs | 26 +++- Rendering/ShaderManager.cs | 23 ++- Rendering/Shaders/DeferredScene.cs | 131 +++++++++++++++++- Shaders/LightPS.cso | Bin 10696 -> 5100 bytes Shaders/LightPS_MS.cso | Bin 0 -> 25920 bytes Shaders/LightVS.cso | Bin 2548 -> 2436 bytes Shaders/LodLightsPS.cso | Bin 5264 -> 5264 bytes Shaders/LodLightsPS_MS.cso | Bin 28272 -> 28272 bytes 15 files changed, 412 insertions(+), 87 deletions(-) create mode 100644 CodeWalker.Shaders/LightPS_MS.hlsl create mode 100644 Shaders/LightPS_MS.cso diff --git a/CodeWalker.Shaders/CodeWalker.Shaders.vcxproj b/CodeWalker.Shaders/CodeWalker.Shaders.vcxproj index 2af5424..e972b36 100644 --- a/CodeWalker.Shaders/CodeWalker.Shaders.vcxproj +++ b/CodeWalker.Shaders/CodeWalker.Shaders.vcxproj @@ -434,6 +434,16 @@ Pixel 4.0 + + Pixel + 4.1 + Pixel + 4.1 + Pixel + 4.1 + Pixel + 4.1 + Vertex 4.0 diff --git a/CodeWalker.Shaders/CodeWalker.Shaders.vcxproj.filters b/CodeWalker.Shaders/CodeWalker.Shaders.vcxproj.filters index b6bf4d5..136dd7b 100644 --- a/CodeWalker.Shaders/CodeWalker.Shaders.vcxproj.filters +++ b/CodeWalker.Shaders/CodeWalker.Shaders.vcxproj.filters @@ -268,6 +268,9 @@ Lights + + Lights + diff --git a/CodeWalker.Shaders/LightPS.hlsl b/CodeWalker.Shaders/LightPS.hlsl index 0f7d3c6..7096c76 100644 --- a/CodeWalker.Shaders/LightPS.hlsl +++ b/CodeWalker.Shaders/LightPS.hlsl @@ -1,9 +1,6 @@ #include "LightPS.hlsli" -//currently unused - TODO: implement individual HD lights here - - Texture2D DepthTex : register(t0); Texture2D DiffuseTex : register(t2); Texture2D NormalTex : register(t3); @@ -14,11 +11,10 @@ struct VS_Output { float4 Pos : SV_POSITION; float4 Screen : TEXCOORD0; - uint IID : SV_INSTANCEID; }; -PS_OUTPUT main(VS_Output input) +float4 main(VS_Output input) : SV_TARGET { uint3 ssloc = uint3(input.Pos.xy, 0); //pixel location float depth = DepthTex.Load(ssloc).r; @@ -29,39 +25,14 @@ PS_OUTPUT main(VS_Output input) float4 specular = SpecularTex.Load(ssloc); float4 irradiance = IrradianceTex.Load(ssloc); - - PS_OUTPUT output; - output.Depth = input.Pos.z; - - switch (RenderMode) - { - case 5: output.Colour = float4(diffuse.rgb, 1); return output; - case 6: output.Colour = float4(normal.rgb, 1); return output; - case 7: output.Colour = float4(specular.rgb, 1); return output; - } - - float4 spos = float4(input.Screen.xy/input.Screen.w, depth, 1); float4 cpos = mul(spos, ViewProjInv); float3 camRel = cpos.xyz * (1/cpos.w); float3 norm = normal.xyz * 2 - 1; - - if (LightType == 0) //directional light - { - float3 c = DeferredDirectionalLight(camRel, norm, diffuse, specular, irradiance); - - PS_OUTPUT output; - output.Colour = float4(c, 1); - output.Depth = depth; - return output; - } - - - float4 lcol = DeferredLODLight(camRel, norm, diffuse, specular, irradiance, input.IID); + float4 lcol = DeferredLight(camRel, norm, diffuse, specular, irradiance); if (lcol.a <= 0) discard; - output.Colour = lcol; - return output; + return lcol; } diff --git a/CodeWalker.Shaders/LightPS.hlsli b/CodeWalker.Shaders/LightPS.hlsli index 7bb7002..f284acf 100644 --- a/CodeWalker.Shaders/LightPS.hlsli +++ b/CodeWalker.Shaders/LightPS.hlsli @@ -22,6 +22,23 @@ cbuffer PSLightVars : register(b0) float SampleMult;//for MSAA } +cbuffer PSLightInstVars : register(b2) +{ + float3 InstPosition;//camera relative + float InstIntensity; + float3 InstColour; + float InstFalloff; + float3 InstDirection; + float InstFalloffExponent; + float3 InstTangentX; + float InstConeInnerAngle; + float3 InstTangentY; + float InstConeOuterAngle; + float3 InstCapsuleExtent; + uint InstType; + float3 InstCullingPlaneNormal; + float InstCullingPlaneOffset; +} @@ -52,8 +69,6 @@ float3 GetReflectedDir(float3 camRel, float3 norm) } - - float3 DeferredDirectionalLight(float3 camRel, float3 norm, float4 diffuse, float4 specular, float4 irradiance) { float3 refl = GetReflectedDir(camRel, norm); @@ -88,7 +103,7 @@ float4 DeferredLODLight(float3 camRel, float3 norm, float4 diffuse, float4 specu else if (LightType == 2)//spot (cone) { float ang = acos(-dot(ldir, lodlight.Direction)); - float iang = lodlight.InnerAngle * 0.01745329; + float iang = lodlight.InnerAngle * 0.01745329 * 0.5; float oang = lodlight.OuterAngleOrCapExt * 0.01745329 * 0.5; if (ang > oang) return 0; lamt *= saturate(1 - ((ang - iang) / (oang - iang))); @@ -113,5 +128,52 @@ float4 DeferredLODLight(float3 camRel, float3 norm, float4 diffuse, float4 specu return float4(lcol, 1); } +float4 DeferredLight(float3 camRel, float3 norm, float4 diffuse, float4 specular, float4 irradiance) +{ + float3 srpos = InstPosition - camRel; //light position relative to surface position + float ldist = length(srpos); + if (ldist > InstFalloff) return 0; //out of range of the light... TODO: capsules! + if (ldist <= 0) return 0; + + float4 rgbi = float4(InstColour, InstIntensity); + float3 lcol = rgbi.rgb;// * rgbi.a; // * 5.0f; + float3 ldir = srpos / ldist; + float pclit = saturate(dot(ldir, norm)); + float lamt = 1; + + if (InstType == 1)//point (sphere) + { + lamt *= pow(saturate(1 - (ldist / InstFalloff)), InstFalloffExponent); + } + else if (InstType == 2)//spot (cone) + { + float ang = acos(-dot(ldir, InstDirection)); + float iang = InstConeInnerAngle * 0.01745329 * 0.5; + float oang = InstConeOuterAngle * 0.01745329 * 0.5; + if (ang > oang) return 0; + lamt *= saturate(1 - ((ang - iang) / (oang - iang))); + lamt *= pow(saturate(1 - (ldist / InstFalloff)), InstFalloffExponent); + } + else if (InstType == 4)//capsule + { + lamt *= pow(saturate(1 - (ldist / InstFalloff)), InstFalloffExponent); //TODO! proper capsule lighting... (use point-line dist!) + } + + pclit *= lamt; + + if (pclit <= 0) return 0; + + float3 refl = GetReflectedDir(camRel, norm); + float specb = saturate(dot(refl, ldir)); + float specp = max(exp(specb * 10) - 1, 0); + float3 spec = lcol * (0.00006 * specp * specular.r * lamt); + + lcol = lcol * diffuse.rgb * pclit + spec; + + return float4(lcol, 1); +} + + + diff --git a/CodeWalker.Shaders/LightPS_MS.hlsl b/CodeWalker.Shaders/LightPS_MS.hlsl new file mode 100644 index 0000000..ebfab23 --- /dev/null +++ b/CodeWalker.Shaders/LightPS_MS.hlsl @@ -0,0 +1,52 @@ +#include "LightPS.hlsli" + + +Texture2DMS DepthTex : register(t0); +Texture2DMS DiffuseTex : register(t2); +Texture2DMS NormalTex : register(t3); +Texture2DMS SpecularTex : register(t4); +Texture2DMS IrradianceTex : register(t5); + +struct VS_Output +{ + float4 Pos : SV_POSITION; + float4 Screen : TEXCOORD0; +}; + +float4 main(VS_Output input) : SV_TARGET +{ + uint2 ssloc = uint2(input.Pos.xy); //pixel location + float2 spos = float2(input.Screen.xy / input.Screen.w); + float4 c = 0; + float d = 0; + int sc = min(SampleCount, 8); + + [unroll] + for (int i = 0; i < sc; i++) + { + float depth = DepthTex.Load(ssloc, i); + if (depth == 0) continue; //no existing subpixel rendered here + + float4 diffuse = DiffuseTex.Load(ssloc, i); + float4 normal = NormalTex.Load(ssloc, i); + float4 specular = SpecularTex.Load(ssloc, i); + float4 irradiance = IrradianceTex.Load(ssloc, i); + + float4 cpos = mul(float4(spos, depth, 1), ViewProjInv); + float3 camRel = cpos.xyz * (1 / cpos.w); + float3 norm = normal.xyz * 2 - 1; + + float4 colour = DeferredLight(camRel, norm, diffuse, specular, irradiance); + + c += colour; + d += depth; + } + + c *= SampleMult; + d *= SampleMult; + + if (d <= 0) discard; + + return c; +} + diff --git a/CodeWalker.Shaders/LightVS.hlsl b/CodeWalker.Shaders/LightVS.hlsl index 59af1f9..07d4254 100644 --- a/CodeWalker.Shaders/LightVS.hlsl +++ b/CodeWalker.Shaders/LightVS.hlsl @@ -1,28 +1,10 @@ #include "Common.hlsli" -//currently unused - TODO: implement individual HD lights here - - - -struct LODLight -{ - float3 Position; - uint Colour; - float3 Direction; - uint TimeAndStateFlags; - float4 TangentX; - float4 TangentY; - float Falloff; - float FalloffExponent; - float InnerAngle; //for cone - float OuterAngleOrCapExt; //outer angle for cone, cap extent for capsule -}; struct VS_Output { float4 Pos : SV_POSITION; float4 Screen : TEXCOORD0; - uint IID : SV_INSTANCEID; }; @@ -36,44 +18,51 @@ cbuffer VSLightVars : register(b0) uint Pad1; } -StructuredBuffer LODLights : register(t0); +cbuffer VSLightInstVars : register(b1) +{ + float3 InstPosition;//camera relative + float InstIntensity; + float3 InstColour; + float InstFalloff; + float3 InstDirection; + float InstFalloffExponent; + float3 InstTangentX; + float InstConeInnerAngle; + float3 InstTangentY; + float InstConeOuterAngle; + float3 InstCapsuleExtent; + uint InstType; + float3 InstCullingPlaneNormal; + float InstCullingPlaneOffset; +} VS_Output main(float4 ipos : POSITION, uint iid : SV_InstanceID) { float3 opos = 0; - if (LightType > 0) + + float extent = InstFalloff; + if (InstType == 1)//point (sphere) { - LODLight lodlight = LODLights[iid]; - float extent = lodlight.Falloff; - - if (LightType == 1)//point (sphere) - { - opos = ipos.xyz * extent; - } - else if (LightType == 2)//spot (cone) - { - float arads = lodlight.OuterAngleOrCapExt * 0.01745329 * 0.5; // deg -> rad - float3 cpos = ipos.xyz * (tan(arads) * extent); - cpos.y += ipos.w * extent; - opos = (cpos.x * lodlight.TangentX.xyz) + (cpos.y * lodlight.Direction.xyz) + (cpos.z * lodlight.TangentY.xyz); - } - else if (LightType == 4)//capsule - { - float3 cpos = ipos.xyz * extent; - cpos.y += (ipos.w*2-1) * lodlight.OuterAngleOrCapExt * 0.1; - opos = (cpos.x * lodlight.TangentX.xyz) + (cpos.y * lodlight.Direction.xyz) + (cpos.z * lodlight.TangentY.xyz); - } - opos += (lodlight.Position - CameraPos.xyz); + opos = ipos.xyz * extent; } - else + else if (InstType == 2)//spot (cone) { - opos = ipos.xyz; + float arads = InstConeOuterAngle * 0.01745329 * 0.5; // deg -> rad + float3 cpos = ipos.xyz * (tan(arads) * extent); + cpos.y += ipos.w * extent; + opos = (cpos.x * InstTangentX) + (cpos.y * InstDirection) + (cpos.z * InstTangentY); } - float4 spos = mul(float4(opos, 1), ViewProj); + else if (InstType == 4)//capsule + { + float3 cpos = ipos.xyz * extent; + cpos += InstCapsuleExtent * (ipos.w * 2 - 1) * 0.1; + opos = (cpos.x * InstTangentX.xyz) + (cpos.y * InstDirection.xyz) + (cpos.z * InstTangentY.xyz); + } + + float4 spos = mul(float4(opos + InstPosition, 1), ViewProj); VS_Output output; output.Pos = spos; output.Screen = spos; - output.IID = iid; return output; } diff --git a/Rendering/Renderable.cs b/Rendering/Renderable.cs index 5358b9a..4a360be 100644 --- a/Rendering/Renderable.cs +++ b/Rendering/Renderable.cs @@ -26,12 +26,19 @@ namespace CodeWalker.Rendering public Quaternion Orientation; public Vector3 Scale; public uint TintPaletteIndex; + public bool CastShadow; } public struct RenderableGeometryInst { public RenderableGeometry Geom; public RenderableInst Inst; } + public struct RenderableLightInst + { + public RenderableLight Light; + public Vector3 EntityPosition; + public Quaternion EntityRotation; + } public struct RenderableBoundCompositeInst { @@ -83,6 +90,10 @@ namespace CodeWalker.Rendering public ClothInstance Cloth; + public RenderableLight[] Lights; + + + public override void Init(DrawableBase drawable) { Key = drawable; @@ -146,6 +157,8 @@ namespace CodeWalker.Rendering + var fd = drawable as FragDrawable; + var dd = drawable as Drawable; bool hasskeleton = false; @@ -164,7 +177,6 @@ namespace CodeWalker.Rendering modeltransforms = skeleton.Transformations; //for fragments, get the default pose from the root fragment... - var fd = drawable as FragDrawable; if (fd != null) { var frag = fd.OwnerFragment; @@ -306,6 +318,23 @@ namespace CodeWalker.Rendering + var lights = dd?.LightAttributes?.data_items; + if ((lights == null) && (fd != null) && (fd?.OwnerFragment?.Drawable == fd)) + { + lights = fd.OwnerFragment.LightAttributes?.data_items; + } + if (lights != null) + { + var rlights = new RenderableLight[lights.Length]; + for (int i = 0; i < lights.Length; i++) + { + var rlight = new RenderableLight(); + rlight.Owner = this; + rlight.Init(ref lights[i]); + rlights[i] = rlight; + } + Lights = rlights; + } UpdateBoneTransforms(); @@ -1300,6 +1329,47 @@ namespace CodeWalker.Rendering } } + public class RenderableLight + { + public Renderable Owner; + public Vector3 Position; + public Vector3 Colour; + public Vector3 Direction; + public Vector3 TangentX; + public Vector3 TangentY; + public LightType Type; + public float Intensity; + public float Falloff; + public float FalloffExponent; + public float ConeInnerAngle; + public float ConeOuterAngle; + public Vector3 CapsuleExtent; + public Vector3 CullingPlaneNormal; + public float CullingPlaneOffset; + public uint TimeFlags; + public MetaHash TextureHash; + + public void Init(ref LightAttributes_s l) + { + Position = l.Position; + Colour = new Vector3(l.ColorR, l.ColorG, l.ColorB) * ((l.Intensity * 5.0f) / 255.0f); + Direction = l.Direction; + TangentX = l.Tangent; + TangentY = Vector3.Cross(l.Direction, l.Tangent); + Type = l.Type; + Intensity = l.Intensity; + Falloff = l.Falloff; + FalloffExponent = l.FalloffExponent; + ConeInnerAngle = l.ConeInnerAngle; + ConeOuterAngle = l.ConeOuterAngle; + CapsuleExtent = l.Extent; + CullingPlaneNormal = l.CullingPlaneNormal; + CullingPlaneOffset = l.CullingPlaneOffset; + TimeFlags = l.TimeFlags; + TextureHash = l.ProjectedTextureHash; + } + } + public class RenderableInstanceBatch : RenderableCacheItem { diff --git a/Rendering/Renderer.cs b/Rendering/Renderer.cs index af04ba5..4ff5c02 100644 --- a/Rendering/Renderer.cs +++ b/Rendering/Renderer.cs @@ -102,7 +102,7 @@ namespace CodeWalker.Rendering public bool renderchildents = false;//when rendering single ymap, render root only or not... public bool renderentities = true; public bool rendergrass = true; - public bool renderlights = false; //render individual drawable lights (TODO!) + public bool renderlights = true; //render individual drawable lights public bool renderlodlights = true; //render LOD lights from ymaps public bool renderdistlodlights = true; //render distant lod lights (coronas) public bool rendercars = false; @@ -1292,6 +1292,7 @@ namespace CodeWalker.Rendering rinst.Orientation = Quaternion.Identity; rinst.Scale = Vector3.One; rinst.TintPaletteIndex = 0; + rinst.CastShadow = false; rinst.Renderable = sdrnd; shader.SetShader(context); shader.SetInputLayout(context, VertexType.PTT); @@ -1383,6 +1384,7 @@ namespace CodeWalker.Rendering rinst.Orientation = Quaternion.Identity; rinst.Scale = frag.Scale;// Vector3.One; rinst.TintPaletteIndex = 0; + rinst.CastShadow = false; rinst.Renderable = rnd; shader.SetEntityVars(context, ref rinst); @@ -2599,6 +2601,9 @@ namespace CodeWalker.Rendering Vector3 bscen = (arche != null) ? arche.BSCenter : rndbl.Key.BoundingCenter; float radius = (arche != null) ? arche.BSRadius : rndbl.Key.BoundingSphereRadius; float distance = 0;// (camrel + bscen).Length(); + bool interiorent = false; + bool castshadow = true; + if (entity != null) { position = entity.Position; @@ -2610,6 +2615,8 @@ namespace CodeWalker.Rendering bscen = entity.BSCenter; camrel += position; distance = entity.Distance; + castshadow = (entity.MloParent == null);//don't cast sun/moon shadows if this is an interior entity - optimisation! + interiorent = (entity.MloParent != null); } else { @@ -2663,8 +2670,22 @@ namespace CodeWalker.Rendering RenderSkeleton(rndbl, entity); } + + if (renderlights && shaders.deferred && (rndbl.Lights != null) && interiorent)//only interior ents making lights! todo: fix LOD lights + { + var linst = new RenderableLightInst(); + for (int i = 0; i < rndbl.Lights.Length; i++) + { + linst.EntityPosition = position; + linst.EntityRotation = orientation; + linst.Light = rndbl.Lights[i]; + shaders.Enqueue(ref linst); + } + } + + bool retval = true;// false; - if (rndbl.IsLoaded && (rndbl.AllTexturesLoaded || !waitforchildrentoload)) + if ((rndbl.AllTexturesLoaded || !waitforchildrentoload)) { RenderableGeometryInst rginst = new RenderableGeometryInst(); rginst.Inst.Renderable = rndbl; @@ -2678,6 +2699,7 @@ namespace CodeWalker.Rendering rginst.Inst.BSCenter = bscen; rginst.Inst.Radius = radius; rginst.Inst.Distance = distance; + rginst.Inst.CastShadow = castshadow; RenderableModel[] models = isselected ? rndbl.AllModels : rndbl.HDModels; diff --git a/Rendering/ShaderManager.cs b/Rendering/ShaderManager.cs index 0d4b348..34394df 100644 --- a/Rendering/ShaderManager.cs +++ b/Rendering/ShaderManager.cs @@ -71,6 +71,7 @@ namespace CodeWalker.Rendering public List RenderBuckets = new List(); public List RenderBoundGeoms = new List(); public List RenderInstBatches = new List(); + public List RenderLights = new List(); public List RenderLODLights = new List(); public List RenderDistLODLights = new List(); public List RenderPathBatches = new List(); @@ -326,6 +327,7 @@ namespace CodeWalker.Rendering RenderBoundGeoms.Clear(); RenderInstBatches.Clear(); + RenderLights.Clear(); RenderLODLights.Clear(); RenderDistLODLights.Clear(); RenderPathBatches.Clear(); @@ -583,6 +585,14 @@ namespace CodeWalker.Rendering context.OutputMerger.DepthStencilState = dsDisableWriteRev;//only render parts behind or at surface DefScene.RenderLights(context, camera, RenderLODLights); } + + if (RenderLights.Count > 0) + { + context.Rasterizer.State = rsSolid; + context.OutputMerger.BlendState = bsAdd; //additive blend for lights... + context.OutputMerger.DepthStencilState = dsDisableWriteRev;//only render parts behind or at surface + DefScene.RenderLights(context, camera, RenderLights); + } } Basic.Deferred = false; @@ -682,10 +692,13 @@ namespace CodeWalker.Rendering for (int g = 0; g < sbgeoms.Count; g++) { var sbgeom = sbgeoms[g]; - float idist = sbgeom.Inst.Distance - sbgeom.Inst.Radius; - if (idist <= maxdist) + if (sbgeom.Inst.CastShadow) { - shadowcasters.Add(sbgeom); + float idist = sbgeom.Inst.Distance - sbgeom.Inst.Radius; + if (idist <= maxdist) + { + shadowcasters.Add(sbgeom); + } } } } @@ -853,6 +866,10 @@ namespace CodeWalker.Rendering batch.Geometries.Add(geom); } + public void Enqueue(ref RenderableLightInst light) + { + RenderLights.Add(light); + } public void Enqueue(ref RenderableBoundGeometryInst geom) { RenderBoundGeoms.Add(geom); diff --git a/Rendering/Shaders/DeferredScene.cs b/Rendering/Shaders/DeferredScene.cs index 92b8b3e..879f089 100644 --- a/Rendering/Shaders/DeferredScene.cs +++ b/Rendering/Shaders/DeferredScene.cs @@ -40,6 +40,23 @@ namespace CodeWalker.Rendering public uint SampleCount;//for MSAA public float SampleMult;//for MSAA } + public struct DeferredLightInstVars + { + public Vector3 InstPosition; + public float InstIntensity; + public Vector3 InstColour; + public float InstFalloff; + public Vector3 InstDirection; + public float InstFalloffExponent; + public Vector3 InstTangentX; + public float InstConeInnerAngle; + public Vector3 InstTangentY; + public float InstConeOuterAngle; + public Vector3 InstCapsuleExtent; + public uint InstType; + public Vector3 InstCullingPlaneNormal; + public float InstCullingPlaneOffset; + } public struct DeferredSSAAPSVars { @@ -70,6 +87,9 @@ namespace CodeWalker.Rendering VertexShader LodLightVS; PixelShader LodLightPS; PixelShader LodLightMSPS; + VertexShader LightVS; + PixelShader LightPS; + PixelShader LightMSPS; UnitCone LightCone; UnitSphere LightSphere; UnitCapsule LightCapsule; @@ -79,6 +99,7 @@ namespace CodeWalker.Rendering GpuVarsBuffer LightVSVars; GpuVarsBuffer LightPSVars; + GpuVarsBuffer LightInstVars; @@ -113,6 +134,9 @@ namespace CodeWalker.Rendering byte[] bLodLightVS = File.ReadAllBytes("Shaders\\LodLightsVS.cso"); byte[] bLodLightPS = File.ReadAllBytes("Shaders\\LodLightsPS.cso"); byte[] bLodLightMSPS = File.ReadAllBytes("Shaders\\LodLightsPS_MS.cso"); + byte[] bLightVS = File.ReadAllBytes("Shaders\\LightVS.cso"); + byte[] bLightPS = File.ReadAllBytes("Shaders\\LightPS.cso"); + byte[] bLightMSPS = File.ReadAllBytes("Shaders\\LightPS_MS.cso"); byte[] bFinalVS = File.ReadAllBytes("Shaders\\PPFinalPassVS.cso"); byte[] bSSAAPS = File.ReadAllBytes("Shaders\\PPSSAAPS.cso"); @@ -120,12 +144,15 @@ namespace CodeWalker.Rendering DirLightPS = new PixelShader(device, bDirLightPS); LodLightVS = new VertexShader(device, bLodLightVS); LodLightPS = new PixelShader(device, bLodLightPS); + LightVS = new VertexShader(device, bLightVS); + LightPS = new PixelShader(device, bLightPS); try { //error could happen here if the device isn't supporting feature level 10.1 DirLightMSPS = new PixelShader(device, bDirLightMSPS); LodLightMSPS = new PixelShader(device, bLodLightMSPS); + LightMSPS = new PixelShader(device, bLightMSPS); } catch { @@ -145,6 +172,7 @@ namespace CodeWalker.Rendering LightVSVars = new GpuVarsBuffer(device); LightPSVars = new GpuVarsBuffer(device); + LightInstVars = new GpuVarsBuffer(device); FinalVS = new VertexShader(device, bFinalVS); @@ -190,6 +218,11 @@ namespace CodeWalker.Rendering LightPSVars.Dispose(); LightPSVars = null; } + if (LightInstVars != null) + { + LightInstVars.Dispose(); + LightInstVars = null; + } if (LightQuadLayout != null) { LightQuadLayout.Dispose(); @@ -245,6 +278,21 @@ namespace CodeWalker.Rendering LodLightVS.Dispose(); LodLightVS = null; } + if (LightPS != null) + { + LightPS.Dispose(); + LightPS = null; + } + if (LightMSPS != null) + { + LightMSPS.Dispose(); + LightMSPS = null; + } + if (LightVS != null) + { + LightVS.Dispose(); + LightVS = null; + } if (SSAAPSVars != null) { SSAAPSVars.Dispose(); @@ -376,7 +424,6 @@ namespace CodeWalker.Rendering context.PixelShader.SetSamplers(0, null, null); } - public void RenderLights(DeviceContext context, Camera camera, List lodlights) { //instanced rendering of all other lights, using appropriate shapes @@ -456,8 +503,90 @@ namespace CodeWalker.Rendering context.PixelShader.SetSamplers(0, null, null); } + public void RenderLights(DeviceContext context, Camera camera, List lights) + { + //instanced rendering of all other lights, using appropriate shapes + //blend mode: additive + var ps = (MSAASampleCount > 1) ? LightMSPS : LightPS; + + context.VertexShader.Set(LightVS); + context.PixelShader.Set(ps); + + LightVSVars.Vars.ViewProj = Matrix.Transpose(camera.ViewProjMatrix); + LightVSVars.Vars.CameraPos = new Vector4(camera.Position, 0.0f); + LightVSVars.Vars.LightType = 0; + LightVSVars.Vars.IsLOD = 0; + LightVSVars.Vars.Pad0 = 0; + LightVSVars.Vars.Pad1 = 0; + LightVSVars.Update(context); + LightVSVars.SetVSCBuffer(context, 0); + + LightPSVars.Vars.ViewProjInv = Matrix.Transpose(camera.ViewProjInvMatrix); + LightPSVars.Vars.CameraPos = new Vector4(camera.Position, 0.0f); + LightPSVars.Vars.EnableShadows = 0; + LightPSVars.Vars.RenderMode = 0; + LightPSVars.Vars.RenderModeIndex = 1; + LightPSVars.Vars.RenderSamplerCoord = 0; + LightPSVars.Vars.LightType = 0; + LightPSVars.Vars.IsLOD = 0; + LightPSVars.Vars.SampleCount = (uint)MSAASampleCount; + LightPSVars.Vars.SampleMult = 1.0f / MSAASampleCount; + LightPSVars.Update(context); + LightPSVars.SetPSCBuffer(context, 0); + + context.PixelShader.SetShaderResources(0, GBuffers.DepthSRV); + context.PixelShader.SetShaderResources(2, GBuffers.SRVs); + + + for (int i = 0; i < lights.Count; i++) + { + var li = lights[i]; + var rl = li.Light; + + LightInstVars.Vars.InstPosition = li.EntityPosition + li.EntityRotation.Multiply(rl.Position) - camera.Position; + LightInstVars.Vars.InstDirection = li.EntityRotation.Multiply(rl.Direction); + LightInstVars.Vars.InstTangentX = li.EntityRotation.Multiply(rl.TangentX); + LightInstVars.Vars.InstTangentY = li.EntityRotation.Multiply(rl.TangentY); + LightInstVars.Vars.InstCapsuleExtent = li.EntityRotation.Multiply(rl.CapsuleExtent); + LightInstVars.Vars.InstCullingPlaneNormal = li.EntityRotation.Multiply(rl.CullingPlaneNormal); + LightInstVars.Vars.InstColour = rl.Colour; + LightInstVars.Vars.InstIntensity = rl.Intensity; + LightInstVars.Vars.InstFalloff = rl.Falloff; + LightInstVars.Vars.InstFalloffExponent = rl.FalloffExponent; + LightInstVars.Vars.InstConeInnerAngle = rl.ConeInnerAngle; + LightInstVars.Vars.InstConeOuterAngle = rl.ConeOuterAngle; + LightInstVars.Vars.InstType = (uint)rl.Type; + LightInstVars.Vars.InstCullingPlaneOffset = rl.CullingPlaneOffset; + LightInstVars.Update(context); + LightInstVars.SetVSCBuffer(context, 1); + LightInstVars.SetPSCBuffer(context, 2); + + switch (rl.Type) + { + case LightType.Point: + LightSphere.Draw(context); + break; + case LightType.Spot: + LightCone.Draw(context); + break; + case LightType.Capsule: + LightCapsule.Draw(context); + break; + default: + break; + } + + } + + + context.VertexShader.Set(null); + context.PixelShader.Set(null); + context.PixelShader.SetShaderResources(0, null, null, null); + context.PixelShader.SetSamplers(0, null, null); + } + public void SSAAPass(DeviceContext context) { diff --git a/Shaders/LightPS.cso b/Shaders/LightPS.cso index b92ff1a5c1b1045b12539f116f43aeb3fd05bcc7..eb4c2b709cd3cb0653d571f964b30a5da2a86ca5 100644 GIT binary patch literal 5100 zcma)9O=w(I6uz1KHA(Yhic*WxXDO()wrLw;tkujklSzlBNz6<`Diu3P-XtS0?+x=~ zQ$&fOJ3%TG(OnlVglvkq5sHn{MU^h3bWyN^6kP~iNEfXXp?=?e_sqOJp0yWl?z!hX z|M%ScCdrw@!*BI>-MIAWx6ge%x_KRPc^zfm={yZ4Buq93#O_&ccun<}9e3hE)drcVUx7&_!WlJ;@+2gm;!nW1PoIUL2Dm7YzR*){EHpU~*hC z{A*a(v1d&PdJ&W7 zwr*$(^mRk`f&SglanOGodJ=Re(x>hz(7ay_`u1&7JHekW*rz8;-n(h{JyfF+b*<++ zoLjO>xk;~Ft79D-adWedomtGyd#8yjwFP$TwVbludAoGXo3~Y+OoO*<_L!XpE0jG`v{kx1Hjz|5IP6v3ilL8Hol4Z1eaVC{SRs_Z6nRQmX9r>JoJY<)x6()ZBj;W0A>5Z@M3WYg~rQDwcZ6zo2hQ!Ug|@C-3n}n z!P?E*5cdsqs;0(mhKFxuEB!Jr`lYRV+x->(n-3dIY>>BVc)q=rp(hY$ud$cvGPX=@ z@zX{Tmsr9$&yP6$=sZIDZ3d^$D7+mwa%dMk76(JE3Gple2GxT=49vCm4G%h*4HBkcwxaSM&^JQG@Q=%nqZa&F979-02a=Up-^|tH;V^ z)LBpVQJ{VsYS&}=^E!f&&_~Be=i@9twII^$F zN=;I$es53~L*EJdfX>SISnK{)hS+C^jjdf~#rf%bAUYofbo$&cE-}{UpZfgupd5QE zO8#vBiSHgq?#s>}hj_1851yOEB6eY;O)$P8a<&j%XFR`jr{n1PS}mAs0-%Y>&l&cm zuD~@m6W=+xpB9f|uDoZBkmVNIlNg0b$5r}uyE6ze2!g3dQOZ+*WF zu4_qJe8`&+)R%q;^1`_?_8=b2NAh4^L0?ht#*+wz6FzI-6zZ|2Tv?w-eG~AG)N0Ik zgnF_jagIA+gLRUa=!frgP;R=}mx;0^?=(!*{D>`C(ZlVxVUuIpd{bbv*0=nY&>!vd zEg&s+Wo4{_wHq168n)YFFn&{*8;97Cca(a9F-8ua_fI$S3BKoH3~;18dhjxBF)j|V z#rQaa*g^1kR#BMn7{lsU?+-$66VHHy`EbbF&wde{G;^ZeAdY&siN54q`<()L4*8u% zntpkoU{C*EdL^#KfM7#qlRJM2~k9J~oL?EFKcXmVN!Wa(rWZ;lF-g z{Qjp^{$6Dbi7_wv?JTjp0Y8~+B3l8@|JC?=nnTyktfcwvVP5|=!We&hQjdNgHU0%1 C5gHl* literal 10696 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 B!wdib diff --git a/Shaders/LightPS_MS.cso b/Shaders/LightPS_MS.cso new file mode 100644 index 0000000000000000000000000000000000000000..0877aac222a2b39f365dbf351abf8e01566f3524 GIT binary patch literal 25920 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 iRT_5QE`yrtIX3;#bW9Oj& literal 0 HcmV?d00001 diff --git a/Shaders/LightVS.cso b/Shaders/LightVS.cso index eea120a951b34da894f91704ee99d00479dff08e..6fdaf6d43f44a4b4638ad47bc63dee4e7156ef0f 100644 GIT binary patch literal 2436 zcma)8-)j_C6h6CA6Vs4bErk{qK>^bPC`$X7WR2?TTt4g zP}%p_--5$`jNlCS8N%4q_5b0>H)`c}YrWTSqpq$?K{wem_5tY6&{e1kV@^VUK!A>d zuyYIuDL`3k(d_H6#126zs|N4DRJ6V>ZMz<5BD>r(t;y5eI_Db5!2b5zTXa7Ro@M~r7+rX{r|v~ zX0z+{O&x)JpYIWl3s{Ypm4`*1S?t`jwZ&<+(vztcy?; z;^dKz;Rd1Wiz{}evW%$xe(h3m`57Dw@Z5vnRXhXdTMMh?J?Nfs`2D$tbi0T6s}X6z zW!Fm90Q(7AV(^Hgf-`^@tvI{1~J4K zzi09`_9r=#PvgeV#Nj7fqiB5sCN+aLp}1W_DG&RrsHUj#4M3F zG@s6cb>|CsFSJnlQ?MT$?uD_L?>z2`9EEigV^0+AJMF{ysSoq0FP8Cr>bcnNBs1iC z7XMw)ndAyYwm*K;y!SZHq{(T1PxK&v9Qm?%V&pHrglGTcnKSD=dtgoan{<$$ev0WC h+K+IBwfaK6hxL0OKclu5FW>_^PnWb6bV%YR;UMhAh-SW}OA|-^5DYs?pyv`Tk3Z%mcRFz{Jk&G)^q=ywO6G!Dl`Y=k9u zSec9w;9KV(9!T#8KY3GVntvhwg>A8DeXqAG4VSfN&W9{17>l^v} z+SQF~o9n2(=DfSD`?7#Yykknb3o9!kMWZAJt;7tW*>GyDT4P(B_U)QK8oU0kS1ZeL z195p58G}B|L89+8E@YlbCF*HMI`LF#bZAdf%fd9%l&wmq)M)IKqukq0tGHdNFt<~! zbe_d<3W#PS;N7aEZsO?M_pK-@@9Ss03PbKpT-$Awb-Eh=-+?U$nYFO?F8)ug*hU>{ zOY>jl9Awtl!|^8m1<7QVjx0#=9(^gY7)Cc6J7wag3XxgtFpjGj#!O;poy9O$5@Vf# z;VhGw{0t_CdiWM3F$Mf*%}iJiF+5{Q49}fna8~B;X;-`uEcZ8=HivMQ`i_QYcTfnvF%m#qIF(0d#o|J(ue-P zL1w?%#dvQu2mQY>G27?j{Pse;=btcJ<$nP=5cxy^ diff --git a/Shaders/LodLightsPS.cso b/Shaders/LodLightsPS.cso index b95822b37c5a370d22c5361cf55b433bcc3a061d..5bfe0f6bc089084492b010f3767434bc4f11e395 100644 GIT binary patch delta 42 zcmV+_0M-AHDUc}?L|8&Y{EXtYOzarQeYm5Sy*hEeu@qts0S=RQ4p#vVv(FB}1&|#P Ai~s-t delta 42 zcmV+_0M-AHDUc}?L|8&YOMpy7Jh|<_>a?z(I#VFvu@qts0gjV*4p#w=v(FB}1#d4A AH2?qr diff --git a/Shaders/LodLightsPS_MS.cso b/Shaders/LodLightsPS_MS.cso index 5e54009c446831a4fbdbf11045a00617ed36580c..ff6ed2083cdadd4421e66e141c14d5e7579d7ee2 100644 GIT binary patch delta 145 zcmexxhw;N5MiG|?Cucd$PkUC+-yU`(QzCo$--w?ZMQ-si@=bov7tYAH*`2?c2go@s z4dN)vgd;eYHIO*XrbrxPCnU~eKP1lN=wOfm&(ovX`E0Zp1Q^&S`|`_g&dA_k0{{s9 BFChQ` delta 145 zcmexxhw;N5MiG|?C+9h@d(GUtr~T(DzPbKLtJaH+BDeS$`zF8V3uo-x?9SiJ1LT~R z262>S!V#Ry8c3XGQzVYD6B6gK9};JBbTG((=jqYxeKuMQ0u1bvefi}#XJl}&0RSM+ BH$eaZ