Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
c2b683c
feat: add 3D scene rendering with Vulkan backend
yuto-trd Dec 25, 2025
44fc3a3
feat: add offscreen 3D rendering test and texture download support
yuto-trd Dec 25, 2025
85aca53
feat: Implement Vulkan backend for 3D rendering
yuto-trd Dec 25, 2025
53c5c92
refactor: abstract 3D renderer from Vulkan-specific implementation
yuto-trd Dec 25, 2025
35cef27
feat: expose graphics backend types as public API with abstraction layer
yuto-trd Dec 25, 2025
7fd8cfd
refactor: split Renderer3D into separate files for better organization
yuto-trd Dec 25, 2025
d14bc31
refactor: align 3D mesh architecture with 2D Geometry/Shape pattern
yuto-trd Dec 25, 2025
43c3034
refactor: abstract 3D rendering backend with material-based shader ma…
yuto-trd Dec 25, 2025
b470815
feat: move shader management to Material3D derived classes
yuto-trd Dec 25, 2025
8325f24
feat: PBR materials and multiple light types
yuto-trd Dec 25, 2025
dd926aa
feat: add SphereMesh and Sphere3D primitives, improve PBR test visual…
yuto-trd Dec 25, 2025
a3dbe27
refactor: abstract Vulkan types in Backend and move 3D renderer to Gr…
yuto-trd Dec 25, 2025
79dc9c1
feat: migrate materials to deferred rendering with G-Buffer output
yuto-trd Dec 25, 2025
80a4dc6
fix: add sampler support for G-Buffer texture sampling in deferred re…
yuto-trd Dec 25, 2025
847c026
refactor: externalize vertex input and pipeline options in CreatePipe…
yuto-trd Dec 25, 2025
3f7cade
refactor: extract GeometryPass and LightingPass into separate node cl…
yuto-trd Dec 25, 2025
8a2cb4a
feat: add FlipPass to correct vertical orientation in 3D rendering
yuto-trd Dec 25, 2025
4d8e7b3
feat(graphics): add support for texture cube and texture array creation
yuto-trd Dec 26, 2025
91c61c4
feat(graphics): add FrontFace property to PipelineOptions and update …
yuto-trd Dec 26, 2025
c2eb178
Implement shadow mapping system with ShadowPass and ShadowManager
yuto-trd Dec 26, 2025
819144d
fix: use texture array for 2D shadow maps and fix shadow bias values
yuto-trd Dec 26, 2025
7c8f931
feat(tests): add Graphics3DTests project to solution
yuto-trd Dec 27, 2025
d0802df
refactor(graphics): remove 3D renderer creation methods from context …
yuto-trd Dec 27, 2025
5910d3e
refactor(graphics): replace CoreList with IListProperty for Objects a…
yuto-trd Dec 27, 2025
fb4849e
feat(graphics): add Scene3DOperator and integrate with LibraryService
yuto-trd Dec 27, 2025
37115b8
fix(graphics): update texture copy method to use Vulkan image handle …
yuto-trd Dec 27, 2025
3cd2c69
feat(json): add Vector3 and Quaternion JSON converters
yuto-trd Dec 27, 2025
65bcbb4
feat(graphics): simplify Scene3DRenderNode by consolidating parameter…
yuto-trd Dec 27, 2025
ab5d24e
refactor(graphics): rename I3DRenderer to IRenderer3D for consistency
yuto-trd Dec 27, 2025
123152f
feat(graphics): update rotation property to use Euler angles instead …
yuto-trd Dec 27, 2025
93dbce3
feat(graphics): initialize default material in Object3D and simplify …
yuto-trd Dec 27, 2025
c82cc4f
feat(graphics): replace visibility checks with enabled state for rend…
yuto-trd Dec 27, 2025
4941798
feat(graphics): add 3D operators for Cube, Sphere, Directional Light,…
yuto-trd Dec 27, 2025
787d220
fix: update light properties to use IsEnabled instead of IsLightEnabled
yuto-trd Dec 28, 2025
a109a3b
feat(graphics): add support for cube map texture arrays and related o…
yuto-trd Dec 28, 2025
81d84d5
feat(graphics): implement cube shadow map arrays for improved shadow …
yuto-trd Dec 28, 2025
597a84f
feat(graphics): add 3D camera controls and mode switching in PlayerView
yuto-trd Dec 30, 2025
e99e3d8
feat(graphics): implement keyframe support for camera position and ta…
yuto-trd Dec 30, 2025
abc28ab
feat(graphics): add 3D hit testing functionality using ray casting
yuto-trd Dec 31, 2025
ff7a5ca
feat(graphics): implement recursive search for DrawableRenderNode in …
yuto-trd Dec 31, 2025
a204957
feat(graphics): enhance CreateRenderPass3D to support customizable lo…
yuto-trd Jan 1, 2026
ba1a043
feat(graphics): add 3D gizmo rendering support with customizable modes
yuto-trd Jan 1, 2026
0422fd5
feat(graphics): add gizmo hit testing functionality for 3D objects
yuto-trd Jan 1, 2026
34fa1c5
feat(graphics): implement gizmo mode selection and manipulation for 3…
yuto-trd Jan 1, 2026
5035d4a
feat(graphics): add plane indicators and scaling support for gizmo tr…
yuto-trd Jan 1, 2026
ce4474b
feat(graphics): enhance gizmo hit testing and rendering for scale mod…
yuto-trd Jan 1, 2026
e60f49f
feat(graphics): update gizmo hit testing and rendering comments for r…
yuto-trd Jan 1, 2026
19c97cf
feat(graphics): add render context parameter to geometry pass and rel…
yuto-trd Jan 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Beutl.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<File Path="version.json" />
</Folder>
<Folder Name="/Tests/">
<Project Path="tests/Beutl.Graphics3DTests/Beutl.Graphics3DTests.csproj" />
<Project Path="tests\Beutl.Benchmarks\Beutl.Benchmarks.csproj" />
<Project Path="tests\Beutl.UnitTests\Beutl.UnitTests.csproj" />
<Project Path="tests\DirectoryViewTest\DirectoryViewTest.csproj" />
Expand Down
2 changes: 2 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
<PackageVersion Include="Silk.NET.Vulkan.Loader.Native" Version="2024.10.25" />
<PackageVersion Include="Silk.NET.Vulkan.SwiftShader.Native" Version="2024.5.8" />
<PackageVersion Include="Silk.NET.Shaderc" Version="2.22.0" />
<PackageVersion Include="Silk.NET.Shaderc.Native" Version="2.22.0" />
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.6.2" />
<PackageVersion Include="Avalonia.Themes.Fluent" Version="11.3.9" />
<PackageVersion Include="Xaml.Behaviors.Avalonia" Version="11.3.9" />
Expand Down
28 changes: 28 additions & 0 deletions src/Beutl.Core/JsonConverters/QuaternionJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Numerics;
using System.Text.Json;
using System.Text.Json.Serialization;
using Beutl.Utilities;

namespace Beutl.JsonConverters;

internal sealed class QuaternionJsonConverter : JsonConverter<Quaternion>
{
public override Quaternion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string? s = reader.GetString();
if (s == null)
throw new Exception("Invalid Quaternion.");

var tokenizer = new RefStringTokenizer(s, exceptionMessage: "Invalid Quaternion.");
float x = tokenizer.ReadSingle();
float y = tokenizer.ReadSingle();
float z = tokenizer.ReadSingle();
float w = tokenizer.ReadSingle();
return new Quaternion(x, y, z, w);
}

public override void Write(Utf8JsonWriter writer, Quaternion value, JsonSerializerOptions options)
{
writer.WriteStringValue($"{value.X},{value.Y},{value.Z},{value.W}");
}
}
28 changes: 28 additions & 0 deletions src/Beutl.Core/JsonConverters/Vector3JsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Numerics;
using System.Text.Json;
using System.Text.Json.Serialization;

using Beutl.Utilities;

namespace Beutl.JsonConverters;

internal sealed class Vector3JsonConverter : JsonConverter<Vector3>
{
public override Vector3 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string? s = reader.GetString();
if (s == null)
throw new Exception("Invalid Vector3.");

var tokenizer = new RefStringTokenizer(s, exceptionMessage: "Invalid Quaternion.");
float x = tokenizer.ReadSingle();
float y = tokenizer.ReadSingle();
float z = tokenizer.ReadSingle();
return new Vector3(x, y, z);
}

public override void Write(Utf8JsonWriter writer, Vector3 value, JsonSerializerOptions options)
{
writer.WriteStringValue($"{value.X},{value.Y},{value.Z}");
}
}
2 changes: 2 additions & 0 deletions src/Beutl.Core/JsonHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public static class JsonHelper
new DirectoryInfoConverter(),
new FileInfoConverter(),
new CoreSerializableJsonConverter(),
new Vector3JsonConverter(),
new QuaternionJsonConverter()
//new CoreObjectJsonConverter()
}
};
Expand Down
6 changes: 6 additions & 0 deletions src/Beutl.Engine/Beutl.Engine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<PropertyGroup>
<RootNameSpace>Beutl</RootNameSpace>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="Beutl.Graphics3DTests" />
<InternalsVisibleTo Include="Beutl.UnitTests" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Graphics\VertexMode.cs" />
</ItemGroup>
Expand Down Expand Up @@ -38,5 +42,7 @@
<PackageReference Include="SkiaSharp" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" />
<PackageReference Include="Silk.NET.Shaderc" />
<PackageReference Include="Silk.NET.Shaderc.Native" />
</ItemGroup>
</Project>
22 changes: 22 additions & 0 deletions src/Beutl.Engine/Graphics/Backend/AttachmentLoadOp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Beutl.Graphics.Backend;

/// <summary>
/// Specifies the operation to perform on an attachment at the beginning of a render pass.
/// </summary>
public enum AttachmentLoadOp
{
/// <summary>
/// The previous contents of the attachment are preserved.
/// </summary>
Load = 0,

/// <summary>
/// The previous contents of the attachment are cleared.
/// </summary>
Clear = 1,

/// <summary>
/// The previous contents of the attachment are undefined.
/// </summary>
DontCare = 2
}
45 changes: 41 additions & 4 deletions src/Beutl.Engine/Graphics/Backend/BufferUsage.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,50 @@
namespace Beutl.Graphics.Backend;
using System;

namespace Beutl.Graphics.Backend;

/// <summary>
/// Specifies how a buffer will be used.
/// </summary>
[Flags]
internal enum BufferUsage
public enum BufferUsage
{
/// <summary>
/// No specific usage.
/// </summary>
None = 0,

/// <summary>
/// Buffer can be used as a vertex buffer.
/// </summary>
VertexBuffer = 1 << 0,

/// <summary>
/// Buffer can be used as an index buffer.
/// </summary>
IndexBuffer = 1 << 1,

/// <summary>
/// Buffer can be used as a uniform buffer.
/// </summary>
UniformBuffer = 1 << 2,

/// <summary>
/// Buffer can be used as a storage buffer.
/// </summary>
StorageBuffer = 1 << 3,
TransferSrc = 1 << 4,
TransferDst = 1 << 5

/// <summary>
/// Buffer can be used as a source for transfer operations.
/// </summary>
TransferSource = 1 << 4,

/// <summary>
/// Buffer can be used as a destination for transfer operations.
/// </summary>
TransferDestination = 1 << 5,

/// <summary>
/// Buffer can be used as an indirect buffer.
/// </summary>
IndirectBuffer = 1 << 6,
}
158 changes: 158 additions & 0 deletions src/Beutl.Engine/Graphics/Backend/Composite/CompositeContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
using System.Runtime.InteropServices;
using Beutl.Graphics.Backend.Metal;
using Beutl.Graphics.Backend.Vulkan;
using Beutl.Graphics3D;
using Silk.NET.Vulkan;
using SkiaSharp;

namespace Beutl.Graphics.Backend.Composite;

internal sealed class CompositeContext : IGraphicsContext
{
private bool _disposed;

public CompositeContext(VulkanInstance vulkanInstance, VulkanPhysicalDeviceInfo physicalDevice)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
throw new PlatformNotSupportedException("CompositeContext is only available on macOS");
}

// MoltenVKの場合はMetalコンテキストを使用する
if (physicalDevice.IsMoltenVK)
{
Metal = new MetalContext();
}

Vulkan = new VulkanContext(vulkanInstance, physicalDevice);
}

public GraphicsBackend Backend => GraphicsBackend.Metal;

public GRContext SkiaContext => Metal?.SkiaContext ?? Vulkan.SkiaContext!;

public MetalContext? Metal { get; }

public VulkanContext Vulkan { get; }

public bool Supports3DRendering => Vulkan.Supports3DRendering;

public ISharedTexture CreateTexture(int width, int height, TextureFormat format)
{
if (Metal == null)
return Vulkan.CreateTexture(width, height, format);

return new MetalVulkanSharedTexture(Metal, Vulkan, width, height, format);
}

public ITexture2D CreateTexture2D(int width, int height, TextureFormat format)
{
return Vulkan.CreateTexture2D(width, height, format);
}

public ITextureCube CreateTextureCube(int size, TextureFormat format)
{
return Vulkan.CreateTextureCube(size, format);
}

public ITextureArray CreateTextureArray(int width, int height, uint arraySize, TextureFormat format)
{
return Vulkan.CreateTextureArray(width, height, arraySize, format);
}

public ITextureCubeArray CreateTextureCubeArray(int size, uint arraySize, TextureFormat format)
{
return Vulkan.CreateTextureCubeArray(size, arraySize, format);
}

public IBuffer CreateBuffer(ulong size, BufferUsage usage, MemoryProperty memoryProperty)
{
return Vulkan.CreateBuffer(size, usage, memoryProperty);
}

public IShaderCompiler CreateShaderCompiler()
{
return Vulkan.CreateShaderCompiler();
}

public IRenderPass3D CreateRenderPass3D(
IReadOnlyList<TextureFormat> colorFormats,
TextureFormat depthFormat = TextureFormat.Depth32Float,
AttachmentLoadOp colorLoadOp = AttachmentLoadOp.Clear,
AttachmentLoadOp depthLoadOp = AttachmentLoadOp.Clear)
{
return Vulkan.CreateRenderPass3D(colorFormats, depthFormat, colorLoadOp, depthLoadOp);
}

public IFramebuffer3D CreateFramebuffer3D(IRenderPass3D renderPass, IReadOnlyList<ITexture2D> colorTextures, ITexture2D depthTexture)
{
return Vulkan.CreateFramebuffer3D(renderPass, colorTextures, depthTexture);
}

public IPipeline3D CreatePipeline3D(
IRenderPass3D renderPass,
byte[] vertexShaderSpirv,
byte[] fragmentShaderSpirv,
DescriptorBinding[] descriptorBindings,
VertexInputDescription vertexInput,
PipelineOptions? options = null)
{
return Vulkan.CreatePipeline3D(renderPass, vertexShaderSpirv, fragmentShaderSpirv, descriptorBindings, vertexInput, options);
}

public IDescriptorSet CreateDescriptorSet(IPipeline3D pipeline, DescriptorPoolSize[] poolSizes)
{
return Vulkan.CreateDescriptorSet(pipeline, poolSizes);
}

public ISampler CreateSampler(
SamplerFilter minFilter = SamplerFilter.Linear,
SamplerFilter magFilter = SamplerFilter.Linear,
SamplerAddressMode addressModeU = SamplerAddressMode.ClampToEdge,
SamplerAddressMode addressModeV = SamplerAddressMode.ClampToEdge)
{
return Vulkan.CreateSampler(minFilter, magFilter, addressModeU, addressModeV);
}

public void CopyBuffer(IBuffer source, IBuffer destination, ulong size)
{
Vulkan.CopyBuffer(source, destination, size);
}


public void CopyTexture(ITexture2D source, ISharedTexture destination)
{
Vulkan.CopyTexture(source, destination);
}

public void CopyTextureToCubeFace(ITexture2D source, ITextureCube destination, int faceIndex)
{
Vulkan.CopyTextureToCubeFace(source, destination, faceIndex);
}


public void CopyTextureToArrayLayer(ITexture2D source, ITextureArray destination, int layerIndex)
{
Vulkan.CopyTextureToArrayLayer(source, destination, layerIndex);
}

public void CopyTextureToCubeArrayFace(ITexture2D source, ITextureCubeArray destination, int arrayIndex, int faceIndex)
{
Vulkan.CopyTextureToCubeArrayFace(source, destination, arrayIndex, faceIndex);
}

public void WaitIdle()
{
Vulkan.WaitIdle();
Metal?.WaitIdle();
}

public void Dispose()
{
if (_disposed) return;
_disposed = true;

Vulkan.Dispose();
Metal?.Dispose();
}
}
57 changes: 0 additions & 57 deletions src/Beutl.Engine/Graphics/Backend/CompositeContext.cs

This file was deleted.

Loading
Loading