From c6f87cce5547857f5d7eabd8c978922bba59dde1 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Fri, 26 Jan 2024 22:29:20 -0800 Subject: [PATCH] more sprite batch implementation --- .../InstancedSpriteBatch.frag.refresh | Bin 0 -> 745 bytes .../InstancedSpriteBatch.vert.refresh | Bin 5344 -> 3293 bytes .../Shaders/Source/InstancedSpriteBatch.frag | 13 ++ .../Shaders/Source/InstancedSpriteBatch.vert | 16 +-- MoonWorks.Test.Common/CopyMoonlibs.targets | 22 +--- SpriteBatch/SpriteBatchGame.cs | 116 +++++++++++++++--- 6 files changed, 126 insertions(+), 41 deletions(-) create mode 100644 MoonWorks.Test.Common/Content/Shaders/Compiled/InstancedSpriteBatch.frag.refresh create mode 100644 MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.frag diff --git a/MoonWorks.Test.Common/Content/Shaders/Compiled/InstancedSpriteBatch.frag.refresh b/MoonWorks.Test.Common/Content/Shaders/Compiled/InstancedSpriteBatch.frag.refresh new file mode 100644 index 0000000000000000000000000000000000000000..ec6a133b3856233023633176c72720d5add0b58e GIT binary patch literal 745 zcmYk2%Syvw6ogMN(b}q2tF0o4mwj=eB8YB^jf+6R3NAxwf&^k((kl7@zL-zqW4IBV zFHIpoOwO74C+G4%_JF#hS1!>BzpzR^0x97X~#lG z|MNz0_BqzKrpQa9-{hQ`&<-?RT@gR^i)YCXCVYOPUQ8YbPPOP4R;aoA0yj`+N+e|(dYy;j&`eMs__=;R@c_5wY$wuzuz1tzeGVZ3VT7b8xDd_68;q6cQEG{_BzpiH}6oA zN4^&9Y3>2Cd#O z%EC(8g|okiO}dJ(hjBNEq)X~;Rr*QPtOtXwV2}jQWD3o2)^PDKOiP(^2U34}p5kFI zX@tLWBt>K#y%e_`h5b9>FlqHV!HDC=;P#_v#Bnz6hmU${(wn_-J09%aj^fT!@F_9i zd|P4gGnyK~sHHxLcexw7MZQNk=%WYR`{)23YfH!b$wu&OIgSV2G={m@+{$WTK2&Gc zkkww7u2377p|}iRj-yz^%3U%?-c*0GyX8JPFE(?CO>eNd7i?-@Q3mdSZzfYC3?3}+ zM-DJ@TP$lZX09rReE6*hvA&g3`*|N1W%H54eDnz2krd0~*f$@COQNR-sV26kMP_BHhnmzDyU;#HPIi|C$yT9 zE=x|zi@LG#Kc&A1rNOYv`umc%!SQEr{K*ABD?KIwzvgY;HP~_4ho#FBzVqJBeyOr} zdW|nR;nBw=eCGeE*7z8I64L#Cll|Y+%Fe+4BF!G~9)iVaAS1m~&?Ny7pv7UXg&C&vC8sVRp>tgx277 zRYN_eB*ZcECdR$yF=C3`>p6_~0B><`MU!`JDSzW zINQ90-rIX7hMt03%%ax$m@~48p$Blp(06c)d0T7pnEj5{_?Z2!w}10Jeor=-@#nNA z-p+nrYjTpO*t7SA5l>8!`yhuE`?-|kiv9dh9D9 zu6UpPynG@I+m4?fcx+1li9l^0Wx#sDzR(&!aD4bbs`>DrvrO7cX9Z9w&aKz0>?@7SP+4eRZb^Ivld#>m0|McpwO8y6RPVE=~ literal 5344 zcmbW5+jkU25XJ{`0Rs^gxp>0?L^lv(E-RvlA^}4rn2^hgBCN}15(hRradsDj9*@5J zq|g2}{#Cwsj^A&lYqxiZJUE<6ch&b*b#--3Gs*I2D>wH1c`yhD_MYAs1bc!5!D#S( zkUuX5du0h^8_veLg_VVgR(pM-{N5yt=YxTa2C z*^(rZ0sY&n@h=4#3`T;vh3eem;@raZYJGdV+G;;(MAb&zjH>H#8r9qJV+9xt_Itdz zS#NaKeZr6!ejex}T4SYNYp^~#x%Kpc;Dq#gh7DyoFDLCQa6WGY7K} z!@<6cPrWmH+-$GJKe8oxEwPw7L zq+3@TN&OM_VIkOgDsl7!BROItm!&j$$k|XW;w?hZLk&3dq|;uFc4m_#UC(e5UaREm z(F@8c-~4=YoeGf0R_>SEXOl*fVjs+U#;K}BevX_S`$nhV(8&v(GeGCLp$OEQ=RiJm zZSb)%8jqORsGHfCW23+3gb)wj4Oy&4Lz&*I*=gxK#4yf2=`Uoq+>dpAKXm-ANX!qL z`LQ;!Y~R%UR6#!}orgNqG+G_dIRo^3AA{LD$-d4?z^T7qN8VL*_J3HbvhGP~=**95 zHmos}9FsqJq7(nPe(u+Z4L#J)=bVlmK5N4#7PzjY>@2Wfa{8#V9g)s$6H0i_IsH(s zX8zQ6kA#@ujE5yW#(!CJIEEhs41WED_21CU_Q3kYqqpFb@03PjvVZu~8o{u`N2m8J zKKWjhu)o)Zf2I+CayX&coJLy@3?c3fjjRDqTy)-7Y}Da%jiJQWLBA>CIU$@Lp~eXD zzR*Yx*olWu?^xZJ+#Ei2A>OKl`1s$~$lBzJ{;kvPoX~5|W_5lbopWd3b&YVb;lHkN zj|4mUpwpY!z&G5SJiyU6oz3!#r4t{V{ODbB#J{PLSmX=kFjr-;4k+30_8^Lx$1u!Doq8?Q@Pli0+7`>`rWy}&HbP;=g! zgW4H;J1L>|&r3oHKGYPu`JC3=_jyY?KGXmVAL@?XeBRcaIHtd&Ih)N4uOZONkKro=eQ&TcVRq~nL({MIzbZ&hM`70t1m-iyaRChuo3ONN#I= z-kYzSO+(lAwX^YV81JsL?bT>C|3-8C;e&Igzbh{H#ytt^!y)JU8mp3d345hB=@%VLR!{(@L+@+*DQvBBw|uW)E#u*RXFmmJpWCvsm$XxFhbv3- z%a!VEnzUNg`Q~<~-7S2!lU{DB+3NK>vx|$%*CrK!qsbWEU3r8lpWuq&!P7om4zrv* zc*cjP!)%`(Ty}8h>0=OUrDErDO}zY2ciHM_y8Ppsw`lNvmY--H*0}wzRulQQl?)cHL%uJUrjpJ$IRf_Hx@j z>;JneGV}fhu*(VbB3l-Az!N*gTzqbq^`yx1&!Nluad%da+kYD5o&8Nh8EJ}+^%!z)2^>X$W zDHWfY+1zDhRV`4=>{wRD0?W*fwN@$MYZZs&H)VeoRvaql-6hV$uZpWyz6BLob#W}; qL;)-z<>6_&krl@N93--*{Ri3mzbWT?2IrDS?M~WsmF}jgv;P-7c52-K diff --git a/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.frag b/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.frag new file mode 100644 index 0000000..5e44f9b --- /dev/null +++ b/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.frag @@ -0,0 +1,13 @@ +#version 450 + +layout(location = 0) in vec2 inTexCoord; +layout(location = 1) in vec4 inColor; + +layout(location = 0) out vec4 FragColor; + +layout(binding = 0, set = 1) uniform sampler2D Sampler; + +void main() +{ + FragColor = texture(Sampler, inTexCoord) * inColor; +} diff --git a/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.vert b/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.vert index 43031a4..5134748 100644 --- a/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.vert +++ b/MoonWorks.Test.Common/Content/Shaders/Source/InstancedSpriteBatch.vert @@ -27,19 +27,19 @@ void main() float c = cos(Rotation); float s = sin(Rotation); mat4 Rotation = mat4( - c, -s, 0, 0, - s, c, 0, 0, + c, s, 0, 0, + -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); mat4 Translation = mat4( - 1, 0, 0, Position.x, - 0, 1, 0, Position.y, - 0, 0, 1, Position.z, - 0, 0, 0, 1 + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + Translation.x, Translation.y, Translation.z, 1 ); - mat4 Model = Scale * Rotation * Translation; - gl_Position = Model * View * Projection * vec4(Position, 1); + mat4 Model = Translation * Rotation * Scale; + gl_Position = Projection * View * Model * vec4(Position, 1); outTexCoord = UV[gl_VertexIndex % 4]; outVertexColor = Color; } diff --git a/MoonWorks.Test.Common/CopyMoonlibs.targets b/MoonWorks.Test.Common/CopyMoonlibs.targets index 89671bc..599dc52 100644 --- a/MoonWorks.Test.Common/CopyMoonlibs.targets +++ b/MoonWorks.Test.Common/CopyMoonlibs.targets @@ -5,32 +5,20 @@ - - - %(RecursiveDir)%(Filename)%(Extension) - PreserveNewest - - - - %(RecursiveDir)%(Filename)%(Extension) - PreserveNewest - - - - + %(RecursiveDir)%(Filename)%(Extension) PreserveNewest - + %(RecursiveDir)%(Filename)%(Extension) PreserveNewest - + %(RecursiveDir)%(Filename)%(Extension) PreserveNewest - + %(RecursiveDir)%(Filename)%(Extension) PreserveNewest @@ -48,7 +36,7 @@ %(RecursiveDir)%(Filename)%(Extension) PreserveNewest - + %(RecursiveDir)%(Filename)%(Extension) PreserveNewest diff --git a/SpriteBatch/SpriteBatchGame.cs b/SpriteBatch/SpriteBatchGame.cs index 8ff102a..712434b 100644 --- a/SpriteBatch/SpriteBatchGame.cs +++ b/SpriteBatch/SpriteBatchGame.cs @@ -1,5 +1,6 @@ using System; using MoonWorks.Graphics; +using MoonWorks.Math; using MoonWorks.Math.Float; namespace MoonWorks.Test @@ -10,14 +11,23 @@ namespace MoonWorks.Test Graphics.Buffer quadVertexBuffer; Graphics.Buffer quadIndexBuffer; SpriteBatch SpriteBatch; + Texture Texture; + Sampler Sampler; + + Matrix4x4 View; + Matrix4x4 Projection; + + Random Random; public unsafe SpriteBatchGame() : base(TestUtils.GetStandardWindowCreateInfo(), TestUtils.GetStandardFrameLimiterSettings(), 60, true) { + Random = new Random(); + ShaderModule vertShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("InstancedSpriteBatch.vert")); ShaderModule fragShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("InstancedSpriteBatch.frag")); var vertexBufferDescription = VertexBindingAndAttributes.Create(0); - var instanceBufferDescription = VertexBindingAndAttributes.Create(1, VertexInputRate.Instance); + var instanceBufferDescription = VertexBindingAndAttributes.Create(1, 1, VertexInputRate.Instance); GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( MainWindow.SwapchainFormat, @@ -25,6 +35,9 @@ namespace MoonWorks.Test fragShaderModule ); + pipelineCreateInfo.VertexShaderInfo = GraphicsShaderInfo.Create(vertShaderModule, "main", 0); + pipelineCreateInfo.FragmentShaderInfo = GraphicsShaderInfo.Create(fragShaderModule, "main", 1); + pipelineCreateInfo.VertexInputState = new VertexInputState([ vertexBufferDescription, instanceBufferDescription @@ -32,6 +45,9 @@ namespace MoonWorks.Test spriteBatchPipeline = new GraphicsPipeline(GraphicsDevice, pipelineCreateInfo); + Texture = Texture.CreateTexture2D(GraphicsDevice, 1, 1, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler); + Sampler = new Sampler(GraphicsDevice, SamplerCreateInfo.PointClamp); + quadVertexBuffer = Graphics.Buffer.Create(GraphicsDevice, BufferUsageFlags.Vertex, 4); quadIndexBuffer = Graphics.Buffer.Create(GraphicsDevice, BufferUsageFlags.Index, 6); @@ -50,9 +66,40 @@ namespace MoonWorks.Test var cmdbuf = GraphicsDevice.AcquireCommandBuffer(); cmdbuf.SetBufferData(quadVertexBuffer, new Span(vertices, 4)); cmdbuf.SetBufferData(quadIndexBuffer, new Span(indices, 6)); + cmdbuf.SetTextureData(Texture, new Color[1] { Color.White }); GraphicsDevice.Submit(cmdbuf); SpriteBatch = new SpriteBatch(GraphicsDevice); + + // View = Matrix4x4.CreateLookAt( + // new Vector3(0, 0, -1), + // Vector3.Zero, + // Vector3.Up + // ); + + //View = Matrix4x4.Identity; + + View = Matrix4x4.CreateLookAt( + new Vector3(0, 0, 1), + Vector3.Zero, + Vector3.Up + ); + + Projection = Matrix4x4.CreateOrthographicOffCenter( + 0, + MainWindow.Width, + MainWindow.Height, + 0, + 0.01f, + 10 + ); + + // Projection = Matrix4x4.CreatePerspectiveFieldOfView( + // MathHelper.ToRadians(75f), + // (float) MainWindow.Width / MainWindow.Height, + // 0.01f, + // 1000 + // ); } protected override void Update(TimeSpan delta) @@ -66,21 +113,25 @@ namespace MoonWorks.Test Texture? swapchain = cmdbuf.AcquireSwapchainTexture(MainWindow); if (swapchain != null) { + SpriteBatch.Reset(); + for (var i = 0; i < 1024; i += 1) { - SpriteBatch.Add() + var position = new Vector3(Random.Next((int) MainWindow.Width), Random.Next((int) MainWindow.Height), 1); + SpriteBatch.Add( + position, + 0f, + new Vector2(100, 100), + new Color(Random.Next(255), Random.Next(255), Random.Next(255)), + new Vector2(0, 0), + new Vector2(1, 1) + ); } SpriteBatch.Upload(cmdbuf); cmdbuf.BeginRenderPass(new ColorAttachmentInfo(swapchain, Color.Black)); - cmdbuf.BindGraphicsPipeline(spriteBatchPipeline); - cmdbuf.BindVertexBuffers( - new BufferBinding(quadVertexBuffer, 0), - new BufferBinding(SpriteBatch.BatchBuffer, 0) - ); - cmdbuf.BindIndexBuffer(quadIndexBuffer, IndexElementSize.Sixteen); - cmdbuf.DrawInstancedPrimitives(0, 0, SpriteBatch.Index * 2, SpriteBatch.Index, ); + SpriteBatch.Render(cmdbuf, spriteBatchPipeline, Texture, Sampler, quadVertexBuffer, quadIndexBuffer, new ViewProjectionMatrices(View, Projection)); cmdbuf.EndRenderPass(); } GraphicsDevice.Submit(cmdbuf); @@ -93,6 +144,8 @@ namespace MoonWorks.Test } } + public readonly record struct ViewProjectionMatrices(Matrix4x4 View, Matrix4x4 Projection); + public struct SpriteInstanceData : IVertexType { public Vector3 Translation; @@ -122,7 +175,9 @@ namespace MoonWorks.Test GraphicsDevice GraphicsDevice; public Graphics.Buffer BatchBuffer; SpriteInstanceData[] InstanceDatas; - int Index; + uint Index; + + public uint InstanceCount => Index; public SpriteBatch(GraphicsDevice graphicsDevice) { @@ -132,23 +187,52 @@ namespace MoonWorks.Test Index = 0; } - public void Add(Vector3 position, float rotation, Vector2 size, Color color) + public void Reset() { + Index = 0; + } + + public void Add( + Vector3 position, + float rotation, + Vector2 size, + Color color, + Vector2 leftTopUV, + Vector2 dimensionsUV + ) { + var left = leftTopUV.X; + var top = leftTopUV.Y; + var right = leftTopUV.X + dimensionsUV.X; + var bottom = leftTopUV.Y + dimensionsUV.Y; + InstanceDatas[Index].Translation = position; InstanceDatas[Index].Rotation = rotation; InstanceDatas[Index].Scale = size; InstanceDatas[Index].Color = color; - InstanceDatas[Index].UV0 = new Vector2(0, 0); - InstanceDatas[Index].UV1 = new Vector2(0, 1); - InstanceDatas[Index].UV2 = new Vector2(1, 0); - InstanceDatas[Index].UV3 = new Vector2(1, 1); + InstanceDatas[Index].UV0 = leftTopUV; + InstanceDatas[Index].UV1 = new Vector2(left, bottom); + InstanceDatas[Index].UV2 = new Vector2(right, top); + InstanceDatas[Index].UV3 = new Vector2(right, bottom); Index += 1; } public void Upload(CommandBuffer commandBuffer) { commandBuffer.SetBufferData(BatchBuffer, InstanceDatas, 0, 0, (uint) Index); - Index = 0; + } + + public void Render(CommandBuffer commandBuffer, GraphicsPipeline pipeline, Texture texture, Sampler sampler, Graphics.Buffer quadVertexBuffer, Graphics.Buffer quadIndexBuffer, ViewProjectionMatrices viewProjectionMatrices) + { + commandBuffer.BindGraphicsPipeline(pipeline); + commandBuffer.BindFragmentSamplers(new TextureSamplerBinding(texture, sampler)); + commandBuffer.BindVertexBuffers( + new BufferBinding(quadVertexBuffer, 0), + new BufferBinding(BatchBuffer, 0) + ); + commandBuffer.BindIndexBuffer(quadIndexBuffer, IndexElementSize.Sixteen); + var vertParamOffset = commandBuffer.PushVertexShaderUniforms(viewProjectionMatrices); + commandBuffer.DrawInstancedPrimitives(0, 0, 2, InstanceCount, vertParamOffset, 0); + } } }