From 77e036e750dd48005fd3051509b6995f2f57109f Mon Sep 17 00:00:00 2001 From: dexy Date: Sat, 1 May 2021 21:17:43 +1000 Subject: [PATCH] Spot lights geometry improvement, LodLights cone angles and game crash fixes --- .../GameFiles/MetaTypes/MetaTypes.cs | 2 +- .../GameFiles/MetaTypes/PsoTypes.cs | 2 +- CodeWalker.Shaders/LightVS.hlsl | 6 +- CodeWalker.Shaders/LodLightsVS.hlsl | 6 +- CodeWalker/Rendering/Renderable.cs | 4 +- CodeWalker/Rendering/Renderer.cs | 10 +- CodeWalker/Rendering/Shaders/DeferredScene.cs | 6 +- CodeWalker/Rendering/Utils/UnitCone.cs | 166 +++++++++++++++++- Shaders/LightVS.cso | Bin 2356 -> 2500 bytes Shaders/LodLightsVS.cso | Bin 2436 -> 2580 bytes 10 files changed, 178 insertions(+), 24 deletions(-) diff --git a/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs b/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs index 830585e..7c5fe8d 100644 --- a/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs +++ b/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs @@ -589,7 +589,7 @@ namespace CodeWalker.GameFiles new MetaStructureEntryInfo_s((MetaName)MetaTypeName.ARRAYINFO, 0, MetaStructureEntryDataType.UnsignedInt, 0, 0, 0), new MetaStructureEntryInfo_s(MetaName.timeAndStateFlags, 56, MetaStructureEntryDataType.Array, 0, 6, 0), new MetaStructureEntryInfo_s((MetaName)MetaTypeName.ARRAYINFO, 0, MetaStructureEntryDataType.UnsignedInt, 0, 0, 0), - new MetaStructureEntryInfo_s((MetaName)MetaTypeName.HASH, 72, MetaStructureEntryDataType.Array, 0, 8, 0), + new MetaStructureEntryInfo_s(MetaName.hash, 72, MetaStructureEntryDataType.Array, 0, 8, 0), new MetaStructureEntryInfo_s((MetaName)MetaTypeName.ARRAYINFO, 0, MetaStructureEntryDataType.UnsignedByte, 0, 0, 0), new MetaStructureEntryInfo_s(MetaName.coneInnerAngle, 88, MetaStructureEntryDataType.Array, 0, 10, 0), new MetaStructureEntryInfo_s((MetaName)MetaTypeName.ARRAYINFO, 0, MetaStructureEntryDataType.UnsignedByte, 0, 0, 0), diff --git a/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs b/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs index 0dc1b9a..eb87923 100644 --- a/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs +++ b/CodeWalker.Core/GameFiles/MetaTypes/PsoTypes.cs @@ -14110,7 +14110,7 @@ namespace CodeWalker.GameFiles new PsoStructureEntryInfo((MetaName)MetaTypeName.ARRAYINFO, PsoDataType.UInt, 0, 0, 0), new PsoStructureEntryInfo(MetaName.timeAndStateFlags, PsoDataType.Array, 56, 0, (MetaName)6), new PsoStructureEntryInfo((MetaName)MetaTypeName.ARRAYINFO, PsoDataType.UInt, 0, 0, 0), - new PsoStructureEntryInfo((MetaName)MetaTypeName.HASH, PsoDataType.Array, 72, 0, (MetaName)8), + new PsoStructureEntryInfo(MetaName.hash, PsoDataType.Array, 72, 0, (MetaName)8), new PsoStructureEntryInfo((MetaName)MetaTypeName.ARRAYINFO, PsoDataType.UByte, 0, 0, 0), new PsoStructureEntryInfo(MetaName.coneInnerAngle, PsoDataType.Array, 88, 0, (MetaName)10), new PsoStructureEntryInfo((MetaName)MetaTypeName.ARRAYINFO, PsoDataType.UByte, 0, 0, 0), diff --git a/CodeWalker.Shaders/LightVS.hlsl b/CodeWalker.Shaders/LightVS.hlsl index 5949730..b5c4a18 100644 --- a/CodeWalker.Shaders/LightVS.hlsl +++ b/CodeWalker.Shaders/LightVS.hlsl @@ -49,9 +49,9 @@ VS_Output main(float4 ipos : POSITION, uint iid : SV_InstanceID) else if (InstType == 2)//spot (cone) { float arads = InstConeOuterAngle; - float3 cpos = ipos.xyz * (tan(arads) * extent); - cpos.y += ipos.w * extent; - opos = (cpos.x * InstTangentX) + (cpos.y * InstDirection) + (cpos.z * InstTangentY); + float3 tpos = (ipos.xyz * sin(arads)) + float3(0, 0, ipos.w * cos(arads)); + float3 cpos = ((ipos.w > 0) ? normalize(tpos) : tpos) * extent; + opos = (cpos.x * InstTangentX) + (cpos.y * InstTangentY) + (cpos.z * InstDirection); } else if (InstType == 4)//capsule { diff --git a/CodeWalker.Shaders/LodLightsVS.hlsl b/CodeWalker.Shaders/LodLightsVS.hlsl index 961cf43..8880a0f 100644 --- a/CodeWalker.Shaders/LodLightsVS.hlsl +++ b/CodeWalker.Shaders/LodLightsVS.hlsl @@ -47,9 +47,9 @@ VS_Output main(float4 ipos : POSITION, uint iid : SV_InstanceID) else if (LightType == 2)//spot (cone) { float arads = lodlight.OuterAngleOrCapExt; - 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); + float3 tpos = (ipos.xyz * sin(arads)) + float3(0, 0, ipos.w * cos(arads)); + float3 cpos = ((ipos.w>0) ? normalize(tpos) : tpos) * extent; + opos = (cpos.x * lodlight.TangentX.xyz) + (cpos.y * lodlight.TangentY.xyz) + (cpos.z * lodlight.Direction.xyz); } else if (LightType == 4)//capsule { diff --git a/CodeWalker/Rendering/Renderable.cs b/CodeWalker/Rendering/Renderable.cs index 567d581..2b1c54b 100644 --- a/CodeWalker/Rendering/Renderable.cs +++ b/CodeWalker/Rendering/Renderable.cs @@ -1513,8 +1513,8 @@ namespace CodeWalker.Rendering light.TangentY = new Vector4(l.TangentY, 0.0f); light.Falloff = l.Falloff; light.FalloffExponent = Math.Max(l.FalloffExponent*0.01f, 0.5f);//is this right? - light.InnerAngle = l.ConeInnerAngle * 0.0087266462f; //pi/360 - light.OuterAngleOrCapExt = l.ConeOuterAngleOrCapExt * 0.0087266462f; //pi/360 + light.InnerAngle = l.ConeInnerAngle * 0.012319971f; //pi/255 + light.OuterAngleOrCapExt = l.ConeOuterAngleOrCapExt * 0.012319971f; //pi/255 var type = l.Type; switch (type) { diff --git a/CodeWalker/Rendering/Renderer.cs b/CodeWalker/Rendering/Renderer.cs index ae606f6..04fe10e 100644 --- a/CodeWalker/Rendering/Renderer.cs +++ b/CodeWalker/Rendering/Renderer.cs @@ -1036,8 +1036,8 @@ namespace CodeWalker.Rendering var tx = lodlight.TangentX; var ty = lodlight.TangentY; var extent = lodlight.Falloff; - var innerAngle = lodlight.ConeInnerAngle * 0.0087266462f; //pi/360 - var outerAngle = lodlight.ConeOuterAngleOrCapExt * 0.0087266462f; //pi/360 + var innerAngle = lodlight.ConeInnerAngle * 0.012319971f; //pi/255 + var outerAngle = lodlight.ConeOuterAngleOrCapExt * 0.012319971f; //pi/255 var type = lodlight.Type; switch (type) { @@ -1047,10 +1047,8 @@ namespace CodeWalker.Rendering RenderSelectionCircle(pos, Vector3.UnitY, Vector3.UnitZ, extent, colwht); break; case LightType.Spot: - float coneouterrad = extent * (float)Math.Tan(outerAngle); - float coneinnerrad = extent * (float)Math.Tan(innerAngle); - RenderSelectionCone(pos, tx, ty, dir, coneouterrad, extent, colblu); - RenderSelectionCone(pos, tx, ty, dir, coneinnerrad, extent, colwht); + RenderSelectionCone(pos, tx, ty, dir, (float)Math.Sin(outerAngle)*extent, (float)Math.Cos(outerAngle)*extent, colblu); + RenderSelectionCone(pos, tx, ty, dir, (float)Math.Sin(innerAngle)*extent, (float)Math.Cos(innerAngle)*extent, colwht); break; case LightType.Capsule: outerAngle = lodlight.ConeOuterAngleOrCapExt * 0.25f; diff --git a/CodeWalker/Rendering/Shaders/DeferredScene.cs b/CodeWalker/Rendering/Shaders/DeferredScene.cs index e6a1ca6..153a9a2 100644 --- a/CodeWalker/Rendering/Shaders/DeferredScene.cs +++ b/CodeWalker/Rendering/Shaders/DeferredScene.cs @@ -90,7 +90,7 @@ namespace CodeWalker.Rendering VertexShader LightVS; PixelShader LightPS; PixelShader LightMSPS; - UnitCone LightCone; + LightCone LightCone; UnitSphere LightSphere; UnitCapsule LightCapsule; UnitQuad LightQuad; @@ -160,8 +160,8 @@ namespace CodeWalker.Rendering } - LightCone = new UnitCone(device, bLodLightVS, 4, false); - LightSphere = new UnitSphere(device, bLodLightVS, 4, true); + LightCone = new LightCone(device, bLodLightVS, 2); + LightSphere = new UnitSphere(device, bLodLightVS, 3, true); LightCapsule = new UnitCapsule(device, bLodLightVS, 4, false); LightQuad = new UnitQuad(device, true); LightQuadLayout = new InputLayout(device, bDirLightVS, new[] diff --git a/CodeWalker/Rendering/Utils/UnitCone.cs b/CodeWalker/Rendering/Utils/UnitCone.cs index 5bec8a3..1487ff4 100644 --- a/CodeWalker/Rendering/Utils/UnitCone.cs +++ b/CodeWalker/Rendering/Utils/UnitCone.cs @@ -20,12 +20,12 @@ namespace CodeWalker.Rendering private VertexBufferBinding vbbinding; private int indexcount; - private struct SphTri + private struct Tri { public int v1; public int v2; public int v3; - public SphTri(int i1, int i2, int i3) + public Tri(int i1, int i2, int i3) { v1 = i1; v2 = i2; @@ -46,7 +46,7 @@ namespace CodeWalker.Rendering List verts = new List(); Dictionary vdict = new Dictionary(); - List curtris = new List(); + List curtris = new List(); verts.Add(new Vector4(0.0f, 0.0f, 0.0f, 0.0f));//top end (translated by VS!) verts.Add(new Vector4(0.0f, -1.0f, 0.0f, 0.0f));//top normal @@ -82,8 +82,8 @@ namespace CodeWalker.Rendering i1 = 2; } - curtris.Add(new SphTri(0, i0, i1)); //fill the cone - curtris.Add(new SphTri(1, i1+1, i0+1)); //bottom cap triangles + curtris.Add(new Tri(0, i0, i1)); //fill the cone + curtris.Add(new Tri(1, i1+1, i0+1)); //bottom cap triangles } @@ -149,4 +149,160 @@ namespace CodeWalker.Rendering } + + public class LightCone + { + private Buffer VertexBuffer { get; set; } + private Buffer IndexBuffer { get; set; } + private InputLayout InputLayout { get; set; } + private VertexBufferBinding vbbinding; + private int indexcount; + + private struct Tri + { + public Vector4 v1; + public Vector4 v2; + public Vector4 v3; + public Tri(Vector4 i1, Vector4 i2, Vector4 i3) + { + v1 = i1; + v2 = i2; + v3 = i3; + } + } + + public LightCone(Device device, byte[] vsbytes, int detail) + { + + InputLayout = new InputLayout(device, vsbytes, new[] + { + new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0), + }); + + + var tris = new List(); + var newtris = new List(); + var curtris = new List(); + + curtris.Clear();//"cone" triangles + curtris.Add(new Tri(new Vector4(0, 0, 0, 0), new Vector4(-1, 0, 0, 1), new Vector4(0, -1, 0, 1))); + curtris.Add(new Tri(new Vector4(0, 0, 0, 0), new Vector4(0, 1, 0, 1), new Vector4(-1, 0, 0, 1))); + curtris.Add(new Tri(new Vector4(0, 0, 0, 0), new Vector4(1, 0, 0, 1), new Vector4(0, 1, 0, 1))); + curtris.Add(new Tri(new Vector4(0, 0, 0, 0), new Vector4(0, -1, 0, 1), new Vector4(1, 0, 0, 1))); + for (int i = 0; i < detail; i++) + { + foreach (var tri in curtris) + { + var v1 = tri.v1; + var v2 = tri.v2; + var v3 = tri.v3; + var v4 = new Vector4(Vector3.Normalize((v2 + v3).XYZ() * 0.5f), 1); + newtris.Add(new Tri(v1, v2, v4)); + newtris.Add(new Tri(v1, v4, v3)); + } + curtris = newtris; + newtris = new List(); + } + tris.AddRange(curtris); + + curtris.Clear();//hemisphere triangles + curtris.Add(new Tri(new Vector4(0, 0, 1, 1), new Vector4(0, -1, 0, 1), new Vector4(-1, 0, 0, 1))); + curtris.Add(new Tri(new Vector4(0, 0, 1, 1), new Vector4(-1, 0, 0, 1), new Vector4(0, 1, 0, 1))); + curtris.Add(new Tri(new Vector4(0, 0, 1, 1), new Vector4(0, 1, 0, 1), new Vector4(1, 0, 0, 1))); + curtris.Add(new Tri(new Vector4(0, 0, 1, 1), new Vector4(1, 0, 0, 1), new Vector4(0, -1, 0, 1))); + for (int i = 0; i < detail; i++) + { + foreach (var tri in curtris) + { + var v1 = tri.v1; + var v2 = tri.v2; + var v3 = tri.v3; + var v4 = new Vector4(Vector3.Normalize((v1 + v2).XYZ() * 0.5f), 1); + var v5 = new Vector4(Vector3.Normalize((v2 + v3).XYZ() * 0.5f), 1); + var v6 = new Vector4(Vector3.Normalize((v3 + v1).XYZ() * 0.5f), 1); + newtris.Add(new Tri(v1, v4, v6)); + newtris.Add(new Tri(v4, v2, v5)); + newtris.Add(new Tri(v4, v5, v6)); + newtris.Add(new Tri(v6, v5, v3)); + } + curtris = newtris; + newtris = new List(); + } + tris.AddRange(curtris); + + + + + var verts = new List(); + var vdict = new Dictionary(); + var idata = new List(); + uint addVert(Vector4 v) + { + if (vdict.TryGetValue(v, out int i)) return (uint)i; + var n = verts.Count; + verts.Add(v); + vdict[v] = n; + return (uint)n; + } + foreach (var tri in tris) + { + idata.Add(addVert(tri.v1)); + idata.Add(addVert(tri.v2)); + idata.Add(addVert(tri.v3)); + } + + + + VertexBuffer = Buffer.Create(device, BindFlags.VertexBuffer, verts.ToArray()); + vbbinding = new VertexBufferBinding(VertexBuffer, 16, 0); + + IndexBuffer = Buffer.Create(device, BindFlags.IndexBuffer, idata.ToArray()); + indexcount = idata.Count; + + } + + + public void Draw(DeviceContext context) + { + context.InputAssembler.InputLayout = InputLayout; + context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; + context.InputAssembler.SetVertexBuffers(0, vbbinding); + context.InputAssembler.SetIndexBuffer(IndexBuffer, Format.R32_UInt, 0); + + context.DrawIndexed(indexcount, 0, 0); + } + + public void DrawInstanced(DeviceContext context, int count) + { + context.InputAssembler.InputLayout = InputLayout; + context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; + context.InputAssembler.SetVertexBuffers(0, vbbinding); + context.InputAssembler.SetIndexBuffer(IndexBuffer, Format.R32_UInt, 0); + + context.DrawIndexedInstanced(indexcount, count, 0, 0, 0); + } + + + public void Dispose() + { + if (VertexBuffer != null) + { + VertexBuffer.Dispose(); + VertexBuffer = null; + } + if (IndexBuffer != null) + { + IndexBuffer.Dispose(); + IndexBuffer = null; + } + if (InputLayout != null) + { + InputLayout.Dispose(); + InputLayout = null; + } + } + + } + + } diff --git a/Shaders/LightVS.cso b/Shaders/LightVS.cso index 229cbfd116070a0528da4357349546ea60c130f0..c8d42a638ba9c21e12078975e043b73255038daa 100644 GIT binary patch delta 509 zcmdlYbVS(5CBn(sydy8V!|Cm@qbuTL479_)FfuSO9N}bOUooZPlOv z<^xS)uwYFG2E{cX-*CWP40X)6eu!^D z7Q*B~>@ZfS43quX#26VTr?Sa2GEHt}Q&&LN4hs-u<2SEi6JZim b02&SoS`c6cV$sPLIjmVhBFvK?awr1;v-2>W delta 349 zcmX>iyhX^!CBn(M?7QXLxA}*-)^POx zHX2=H;abDYz~I2Z$nctBvJh)fy)Od;hY*7RP%Q%khz6Np)t~^Tff^b37#P@L@?21L zAR4630!c4S4yG3>&z=O;!v>>;Aa;TDeqsc z$>c_;dA(1=`YQ;J{$nW zEZ~#epnL2BuXMLO;3@>}$ITfp>`9;l2YYJAJFAg`7LaKmq8A`K^!az5fUrP*N4w7FwroaA9MN&H8$Pw7xc?6H3zs zzbJu=|Ktp4sAW9`=5#oEN@hJp#^#LzjbjVic7>|Qa{Z6Gp=GIa%a(z)`3uBAjb+JM zQ}1$jWnx-lKc6@gfp(Ed9uZe!d{@25QY}5G$E?YqsvH@+TIZN#80y9^4^m^HnCUuJ z&19Hkg3kyB$#!k4G5WroP9WiDVr>ksit~8djAK?Ohs?CfCTx8C1$^qiu}&BX^v`8K_C`bR?)`=Xc?ux(ID0s;N}nwxR=X WrY=?fN(PxFJBT*|&aLc6T>k~PCO2dN