diff --git a/MoonWorks.Test.Common/Content/Shaders/Compiled/TexturedQuad3DFrag.refresh b/MoonWorks.Test.Common/Content/Shaders/Compiled/TexturedQuad3DFrag.refresh new file mode 100644 index 0000000..a94da74 Binary files /dev/null and b/MoonWorks.Test.Common/Content/Shaders/Compiled/TexturedQuad3DFrag.refresh differ diff --git a/MoonWorks.Test.Common/Content/Shaders/Source/TexturedQuad3DFrag.frag b/MoonWorks.Test.Common/Content/Shaders/Source/TexturedQuad3DFrag.frag new file mode 100644 index 0000000..8a9119e --- /dev/null +++ b/MoonWorks.Test.Common/Content/Shaders/Source/TexturedQuad3DFrag.frag @@ -0,0 +1,17 @@ +#version 450 + +layout (location = 0) in vec2 TexCoord; + +layout (location = 0) out vec4 FragColor; + +layout(binding = 0, set = 1) uniform sampler3D Sampler; + +layout (binding = 0, set = 3) uniform UniformBlock +{ + float depth; +}; + +void main() +{ + FragColor = texture(Sampler, vec3(TexCoord, depth)); +} diff --git a/MoonWorks.Test.Common/Content/Textures/tex3d_0.png b/MoonWorks.Test.Common/Content/Textures/tex3d_0.png new file mode 100644 index 0000000..6ab7f80 Binary files /dev/null and b/MoonWorks.Test.Common/Content/Textures/tex3d_0.png differ diff --git a/MoonWorks.Test.Common/Content/Textures/tex3d_1.png b/MoonWorks.Test.Common/Content/Textures/tex3d_1.png new file mode 100644 index 0000000..ce7f777 Binary files /dev/null and b/MoonWorks.Test.Common/Content/Textures/tex3d_1.png differ diff --git a/MoonWorks.Test.Common/Content/Textures/tex3d_2.png b/MoonWorks.Test.Common/Content/Textures/tex3d_2.png new file mode 100644 index 0000000..4e0984a Binary files /dev/null and b/MoonWorks.Test.Common/Content/Textures/tex3d_2.png differ diff --git a/MoonWorks.Test.Common/Content/Textures/tex3d_3.png b/MoonWorks.Test.Common/Content/Textures/tex3d_3.png new file mode 100644 index 0000000..923e8e8 Binary files /dev/null and b/MoonWorks.Test.Common/Content/Textures/tex3d_3.png differ diff --git a/MoonWorks.Test.Common/Content/Textures/tex3d_4.png b/MoonWorks.Test.Common/Content/Textures/tex3d_4.png new file mode 100644 index 0000000..3278d86 Binary files /dev/null and b/MoonWorks.Test.Common/Content/Textures/tex3d_4.png differ diff --git a/MoonWorks.Test.Common/Content/Textures/tex3d_5.png b/MoonWorks.Test.Common/Content/Textures/tex3d_5.png new file mode 100644 index 0000000..f0d75e4 Binary files /dev/null and b/MoonWorks.Test.Common/Content/Textures/tex3d_5.png differ diff --git a/MoonWorks.Test.Common/Content/Textures/tex3d_6.png b/MoonWorks.Test.Common/Content/Textures/tex3d_6.png new file mode 100644 index 0000000..bf980b2 Binary files /dev/null and b/MoonWorks.Test.Common/Content/Textures/tex3d_6.png differ diff --git a/MoonWorksGraphicsTests.sln b/MoonWorksGraphicsTests.sln index 7a8f480..b6f6e58 100644 --- a/MoonWorksGraphicsTests.sln +++ b/MoonWorksGraphicsTests.sln @@ -41,6 +41,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VideoPlayer", "VideoPlayer\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InstancingAndOffsets", "Instancing\InstancingAndOffsets.csproj", "{01427BDA-45E2-46C0-B116-024EBE541D45}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Texture3D", "Texture3D\Texture3D.csproj", "{9D0F0573-7FD4-4480-8F9B-CDD52120A170}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -123,6 +125,10 @@ Global {01427BDA-45E2-46C0-B116-024EBE541D45}.Debug|x64.Build.0 = Debug|x64 {01427BDA-45E2-46C0-B116-024EBE541D45}.Release|x64.ActiveCfg = Release|x64 {01427BDA-45E2-46C0-B116-024EBE541D45}.Release|x64.Build.0 = Release|x64 + {9D0F0573-7FD4-4480-8F9B-CDD52120A170}.Debug|x64.ActiveCfg = Debug|x64 + {9D0F0573-7FD4-4480-8F9B-CDD52120A170}.Debug|x64.Build.0 = Debug|x64 + {9D0F0573-7FD4-4480-8F9B-CDD52120A170}.Release|x64.ActiveCfg = Release|Any CPU + {9D0F0573-7FD4-4480-8F9B-CDD52120A170}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index 82a60e8..05e3033 100644 --- a/README.md +++ b/README.md @@ -67,3 +67,7 @@ Loads an image, then makes three copies of the image. One is a 1:1 scale image, **VideoPlayer** Plays a sample Ogg Theora video file. Tests YUV textures and video rendering. + +**Texture3D** + +Displays 2D slices of a 3D texture. Tests creating and drawing 3D textures. diff --git a/Texture3D/Texture3D.csproj b/Texture3D/Texture3D.csproj new file mode 100644 index 0000000..2868e63 --- /dev/null +++ b/Texture3D/Texture3D.csproj @@ -0,0 +1,17 @@ + + + + + + + + + Exe + net7.0 + enable + x64 + + + + + diff --git a/Texture3D/Texture3DGame.cs b/Texture3D/Texture3DGame.cs new file mode 100644 index 0000000..db7a9d4 --- /dev/null +++ b/Texture3D/Texture3DGame.cs @@ -0,0 +1,162 @@ +using MoonWorks; +using MoonWorks.Graphics; +using MoonWorks.Math.Float; +using RefreshCS; + +namespace MoonWorks.Test +{ + class Texture3DGame : Game + { + private GraphicsPipeline pipeline; + private Buffer vertexBuffer; + private Buffer indexBuffer; + private Texture texture; + private Sampler sampler; + + private int currentDepth = 0; + + struct FragUniform + { + public float Depth; + + public FragUniform(float depth) + { + Depth = depth; + } + } + + public Texture3DGame() : base(TestUtils.GetStandardWindowCreateInfo(), TestUtils.GetStandardFrameLimiterSettings(), 60, true) + { + Logger.LogInfo("Press Left and Right to cycle between depth slices"); + + // Load the shaders + ShaderModule vertShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("TexturedQuadVert")); + ShaderModule fragShaderModule = new ShaderModule(GraphicsDevice, TestUtils.GetShaderPath("TexturedQuad3DFrag")); + + // Create the graphics pipeline + GraphicsPipelineCreateInfo pipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo( + MainWindow.SwapchainFormat, + vertShaderModule, + fragShaderModule + ); + pipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding(); + pipelineCreateInfo.FragmentShaderInfo = GraphicsShaderInfo.Create(fragShaderModule, "main", 1); + pipeline = new GraphicsPipeline(GraphicsDevice, pipelineCreateInfo); + + // Create samplers + sampler = new Sampler(GraphicsDevice, SamplerCreateInfo.PointClamp); + + // Create and populate the GPU resources + vertexBuffer = Buffer.Create(GraphicsDevice, BufferUsageFlags.Vertex, 4); + indexBuffer = Buffer.Create(GraphicsDevice, BufferUsageFlags.Index, 6); + texture = new Texture(GraphicsDevice, new TextureCreateInfo + { + Width = 16, + Height = 16, + Depth = 7, + Format = TextureFormat.R8G8B8A8, + IsCube = false, + LevelCount = 1, + UsageFlags = TextureUsageFlags.Sampler + }); + + CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); + cmdbuf.SetBufferData( + vertexBuffer, + new PositionTextureVertex[] + { + new PositionTextureVertex(new Vector3(-1, -1, 0), new Vector2(0, 0)), + new PositionTextureVertex(new Vector3(1, -1, 0), new Vector2(4, 0)), + new PositionTextureVertex(new Vector3(1, 1, 0), new Vector2(4, 4)), + new PositionTextureVertex(new Vector3(-1, 1, 0), new Vector2(0, 4)), + } + ); + cmdbuf.SetBufferData( + indexBuffer, + new ushort[] + { + 0, 1, 2, + 0, 2, 3, + } + ); + + // Load each depth subimage of the 3D texture + for (uint i = 0; i < texture.Depth; i += 1) + { + TextureSlice slice = new TextureSlice( + texture, + new Rect(0, 0, (int) texture.Width, (int) texture.Height), + i + ); + + var pixels = Refresh.Refresh_Image_Load( + TestUtils.GetTexturePath($"tex3d_{i}.png"), + out var width, + out var height, + out var channels + ); + + var byteCount = (uint) (width * height * channels); + cmdbuf.SetTextureData(slice, pixels, byteCount); + + Refresh.Refresh_Image_Free(pixels); + } + + GraphicsDevice.Submit(cmdbuf); + } + + protected override void Update(System.TimeSpan delta) + { + int prevDepth = currentDepth; + + if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Left)) + { + currentDepth -= 1; + if (currentDepth < 0) + { + currentDepth = (int) texture.Depth - 1; + } + } + + if (TestUtils.CheckButtonPressed(Inputs, TestUtils.ButtonType.Right)) + { + currentDepth += 1; + if (currentDepth >= texture.Depth) + { + currentDepth = 0; + } + } + + if (prevDepth != currentDepth) + { + Logger.LogInfo("Setting depth to: " + currentDepth); + } + } + + protected override void Draw(double alpha) + { + FragUniform fragUniform = new FragUniform((float) currentDepth / texture.Depth); + + CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer(); + Texture? backbuffer = cmdbuf.AcquireSwapchainTexture(MainWindow); + if (backbuffer != null) + { + cmdbuf.BeginRenderPass(new ColorAttachmentInfo(backbuffer, Color.Black)); + cmdbuf.BindGraphicsPipeline(pipeline); + cmdbuf.BindVertexBuffers(vertexBuffer); + cmdbuf.BindIndexBuffer(indexBuffer, IndexElementSize.Sixteen); + cmdbuf.BindFragmentSamplers(new TextureSamplerBinding(texture, sampler)); + uint fragParamOffset = cmdbuf.PushFragmentShaderUniforms(fragUniform); + cmdbuf.DrawIndexedPrimitives(0, 0, 2, 0, fragParamOffset); + cmdbuf.EndRenderPass(); + } + GraphicsDevice.Submit(cmdbuf); + } + + public static void Main(string[] args) + { + Texture3DGame game = new Texture3DGame(); + game.Run(); + } + } +}