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 b92ff1a..eb4c2b7 100644 Binary files a/Shaders/LightPS.cso and b/Shaders/LightPS.cso differ diff --git a/Shaders/LightPS_MS.cso b/Shaders/LightPS_MS.cso new file mode 100644 index 0000000..0877aac Binary files /dev/null and b/Shaders/LightPS_MS.cso differ diff --git a/Shaders/LightVS.cso b/Shaders/LightVS.cso index eea120a..6fdaf6d 100644 Binary files a/Shaders/LightVS.cso and b/Shaders/LightVS.cso differ diff --git a/Shaders/LodLightsPS.cso b/Shaders/LodLightsPS.cso index b95822b..5bfe0f6 100644 Binary files a/Shaders/LodLightsPS.cso and b/Shaders/LodLightsPS.cso differ diff --git a/Shaders/LodLightsPS_MS.cso b/Shaders/LodLightsPS_MS.cso index 5e54009..ff6ed20 100644 Binary files a/Shaders/LodLightsPS_MS.cso and b/Shaders/LodLightsPS_MS.cso differ