From 0b6e5b8501b75537c37b5c4c3c96a6b429aab44d Mon Sep 17 00:00:00 2001 From: Misaki Date: Wed, 1 Apr 2026 00:06:31 +0900 Subject: [PATCH] feat(mesh): update Vertex layout, add mesh loader Refactored Vertex to use float3 position/normal, float2 uv, float4 tangent, and Color128 color, updating all mesh generation and HLSL code accordingly. Added MeshUtility for loading .obj/.fbx meshes with deduplication and normal/tangent computation. Updated GraphicsTestWindow to use the new loader and improved resource management. Fixed D3D12ResourceAllocator resource creation logic, improved camera projection math, and simplified RenderingLayerMask. Updated package references and app display name. BREAKING CHANGE: Vertex struct layout changed; all mesh code and shaders must use the new format. --- src/Runtime/Ghost.Core/Ghost.Core.csproj | 7 +- .../D3D12ResourceAllocator.cs | 5 +- src/Runtime/Ghost.Graphics.RHI/Common.cs | 10 +- src/Runtime/Ghost.Graphics/Core/Mesh.cs | 22 ++- .../Ghost.Graphics/Core/RenderingLayerMask.cs | 24 --- .../Shaders/Includes/Common.hlsl | 8 +- .../Ghost.Graphics/Utilities/MeshBuilder.cs | 50 ++--- .../Utilities/MeshletUtility.cs | 2 +- src/Runtime/Ghost.Graphics/test.gshdr | 7 +- .../Ghost.Graphics.Test.csproj | 1 + .../Ghost.Graphics.Test/Package.appxmanifest | 2 +- .../RenderPasses/TestRenderPipeline.cs | 10 +- .../Ghost.Graphics.Test/UnitTestApp.xaml.cs | 12 +- .../Utilities/MeshUtility.cs | 176 ++++++++++++++++++ .../Windows/GraphicsTestWindow.xaml.cs | 55 ++++-- 15 files changed, 282 insertions(+), 109 deletions(-) create mode 100644 src/Test/Ghost.Graphics.Test/Utilities/MeshUtility.cs diff --git a/src/Runtime/Ghost.Core/Ghost.Core.csproj b/src/Runtime/Ghost.Core/Ghost.Core.csproj index 7cbe6bf..b334eca 100644 --- a/src/Runtime/Ghost.Core/Ghost.Core.csproj +++ b/src/Runtime/Ghost.Core/Ghost.Core.csproj @@ -9,19 +9,20 @@ True - $(DefineConstants);MHP_ENABLE_SAFETY_CHECKS + $(DefineConstants);MHP_ENABLE_SAFETY_CHECKS;MHP_ENABLE_STACKTRACE True True + True - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Runtime/Ghost.Graphics.D3D12/D3D12ResourceAllocator.cs b/src/Runtime/Ghost.Graphics.D3D12/D3D12ResourceAllocator.cs index 90704ee..be6a02f 100644 --- a/src/Runtime/Ghost.Graphics.D3D12/D3D12ResourceAllocator.cs +++ b/src/Runtime/Ghost.Graphics.D3D12/D3D12ResourceAllocator.cs @@ -740,7 +740,10 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator else { hr = CreateResource(&allocationDesc, &resourceDesc, initialState, options, null, (void**)&pAllocation); - pResource = pAllocation->GetResource(); + if (hr.SUCCEEDED) + { + pResource = pAllocation->GetResource(); + } } if (hr.FAILED) diff --git a/src/Runtime/Ghost.Graphics.RHI/Common.cs b/src/Runtime/Ghost.Graphics.RHI/Common.cs index 59ff5f9..3d2535a 100644 --- a/src/Runtime/Ghost.Graphics.RHI/Common.cs +++ b/src/Runtime/Ghost.Graphics.RHI/Common.cs @@ -132,7 +132,7 @@ public struct Color128 : IEquatable [StructLayout(LayoutKind.Sequential)] -public struct Vertex +public record struct Vertex { public static class Semantic { @@ -145,11 +145,11 @@ public struct Vertex public static readonly FixedText32 Color = new("COLOR"u8); } - public float4 position; - public float4 normal; - public float4 tangent; - public float4 uv; public Color128 color; + public float4 tangent; + public float3 position; + public float3 normal; + public float2 uv; } public readonly struct ShaderVariant; diff --git a/src/Runtime/Ghost.Graphics/Core/Mesh.cs b/src/Runtime/Ghost.Graphics/Core/Mesh.cs index ea36c58..db662b7 100644 --- a/src/Runtime/Ghost.Graphics/Core/Mesh.cs +++ b/src/Runtime/Ghost.Graphics/Core/Mesh.cs @@ -210,18 +210,20 @@ public struct Mesh : IResourceReleasable maxVertices = 64, minTriangles = 32, maxTriangles = 124, - partitionSize = 128, - clusterSpatial = true, + partitionSpatial = true, + partitionSize = 16, + clusterSpatial = false, + clusterSplitFactor = 2.0f, clusterFillWeight = 1.0f, - clusterSplitFactor = 1.0f, simplifyRatio = 0.5f, - simplifyThreshold = 0.5f, - simplifyErrorMergePrevious = 0.5f, - simplifyErrorMergeAdditive = 0.5f, - simplifyErrorFactorSloppy = 1.0f, - simplifyErrorEdgeLimit = 1.0f, - optimizeBounds = true, - optimizeClusters = true + simplifyThreshold = 0.85f, + simplifyErrorMergePrevious = 1.0f, + simplifyErrorFactorSloppy = 2.0f, + simplifyPermissive = true, + simplifyFallbackPermissive = false, + simplifyFallbackSloppy = true, + //optimizeBounds = true, + //optimizeClusters = true }; // 2. Map Mesh to ClodMesh diff --git a/src/Runtime/Ghost.Graphics/Core/RenderingLayerMask.cs b/src/Runtime/Ghost.Graphics/Core/RenderingLayerMask.cs index 0144ad1..975bc8c 100644 --- a/src/Runtime/Ghost.Graphics/Core/RenderingLayerMask.cs +++ b/src/Runtime/Ghost.Graphics/Core/RenderingLayerMask.cs @@ -1,31 +1,7 @@ -using System.Diagnostics; - namespace Ghost.Graphics.Core; public readonly struct RenderingLayerMask : IEquatable { - private static readonly Dictionary s_layerNameToBit = new(32); - private static readonly Dictionary s_bitToLayerName = new(32); - - internal static void SetLayerName(int layerIndex, string name) - { - Debug.Assert(layerIndex >= 0 && layerIndex < 32, "Layer index must be between 0 and 31."); - - var bit = 1u << layerIndex; - s_layerNameToBit[name] = bit; - s_bitToLayerName[bit] = name; - } - - public static uint GetLayerBit(string name) - { - if (s_layerNameToBit.TryGetValue(name, out var bit)) - { - return bit; - } - - return 0u; - } - private readonly uint _value; public static readonly RenderingLayerMask Empty = new(0); diff --git a/src/Runtime/Ghost.Graphics/Shaders/Includes/Common.hlsl b/src/Runtime/Ghost.Graphics/Shaders/Includes/Common.hlsl index 4497ba8..8b6bddb 100644 --- a/src/Runtime/Ghost.Graphics/Shaders/Includes/Common.hlsl +++ b/src/Runtime/Ghost.Graphics/Shaders/Includes/Common.hlsl @@ -3,11 +3,11 @@ struct Vertex { - float4 position; - float4 normal; - float4 tangent; - float4 uv; float4 color; + float4 tangent; + float3 position; + float3 normal; + float2 uv; }; struct Meshlet diff --git a/src/Runtime/Ghost.Graphics/Utilities/MeshBuilder.cs b/src/Runtime/Ghost.Graphics/Utilities/MeshBuilder.cs index d765140..b080836 100644 --- a/src/Runtime/Ghost.Graphics/Utilities/MeshBuilder.cs +++ b/src/Runtime/Ghost.Graphics/Utilities/MeshBuilder.cs @@ -17,12 +17,12 @@ public static unsafe class MeshBuilder vertices = new UnsafeList(24, allocator); indices = new UnsafeList(36, allocator); - var corners = new float4[] + var corners = new float3[] { - new (-half, -half, -half, 1.0f), new (half, -half, -half, 1.0f), - new (half, half, -half, 1.0f), new (-half, half, -half, 1.0f), - new (-half, -half, half, 1.0f), new (half, -half, half, 1.0f), - new (half, half, half, 1.0f), new (-half, half, half, 1.0f) + new (-half, -half, -half), new (half, -half, -half), + new (half, half, -half), new (-half, half, -half), + new (-half, -half, half), new (half, -half, half), + new (half, half, half), new (-half, half, half) }; var faces = stackalloc int[] @@ -46,10 +46,10 @@ public static unsafe class MeshBuilder var vertex = new Vertex { position = corners[face[i]], - normal = float4.zero, + normal = float3.zero, tangent = float4.zero, color = color, - uv = new(uvs[i], 0.0f, 0.0f) + uv = uvs[i] }; vertices.Add(vertex); @@ -81,38 +81,38 @@ public static unsafe class MeshBuilder vertices.Add(new Vertex() { - position = new(-hw, 0.0f, -hd, 0.0f), - normal = float4.zero, + position = new float3(-hw, 0.0f, -hd), + normal = float3.zero, tangent = float4.zero, color = color, - uv = new(0.0f) + uv = float2.zero }); vertices.Add(new Vertex() { - position = new(hw, 0.0f, -hd, 0.0f), - normal = float4.zero, + position = new float3(hw, 0.0f, -hd), + normal = float3.zero, tangent = float4.zero, color = color, - uv = new(1.0f, 0.0f, 0.0f, 0.0f) + uv = new float2(1.0f, 0.0f) }); vertices.Add(new Vertex() { - position = new(hw, 0.0f, hd, 0.0f), - normal = float4.zero, + position = new float3(hw, 0.0f, hd), + normal = float3.zero, tangent = float4.zero, color = color, - uv = new(1.0f, 1.0f, 0.0f, 0.0f) + uv = new float2(1.0f, 1.0f) }); vertices.Add(new Vertex() { - position = new(-hw, 0.0f, hd, 0.0f), - normal = float4.zero, + position = new float3(-hw, 0.0f, hd), + normal = float3.zero, tangent = float4.zero, color = color, - uv = new(0.0f, 1.0f, 0.0f, 0.0f) + uv = new float2(0.0f, 1.0f) }); indices.Add(0); @@ -153,11 +153,11 @@ public static unsafe class MeshBuilder vertices.Add(new Vertex { - position = new float4(x, y, z, 0.0f) * radius, - normal = float4.zero, + position = new float3(x, y, z) * radius, + normal = float3.zero, tangent = float4.zero, color = color, - uv = new float4((float)lon / longitudeSegments, (float)lat / latitudeSegments, 0.0f, 0.0f) + uv = new float2((float)lon / longitudeSegments, (float)lat / latitudeSegments) }); } } @@ -231,7 +231,7 @@ public static unsafe class MeshBuilder public static void ComputeTangents(UnsafeList vertices, UnsafeList indices) { using var scope = AllocationManager.CreateStackScope(); - var bitangents = new UnsafeArray(vertices.Count, scope.AllocationHandle); + var bitangents = new UnsafeArray(vertices.Count, scope.AllocationHandle, AllocationOption.Clear); for (var i = 0; i < indices.Count; i += 3) { @@ -269,7 +269,7 @@ public static unsafe class MeshBuilder for (var i = 0; i < vertices.Count; i++) { var n = vertices[i].normal; - var t = vertices[i].tangent; + var t = vertices[i].tangent.xyz; var proj = n * math.dot(n, t); t = math.normalize(t - proj); @@ -277,7 +277,7 @@ public static unsafe class MeshBuilder var b = bitangents[i]; var w = math.dot(math.cross(n.xyz, t.xyz), b.xyz) < 0.0f ? -1.0f : 1.0f; - vertices[i].tangent = new float4(t.x, t.y, t.z, w); + vertices[i].tangent = new float4(t.xyz, w); } } } diff --git a/src/Runtime/Ghost.Graphics/Utilities/MeshletUtility.cs b/src/Runtime/Ghost.Graphics/Utilities/MeshletUtility.cs index 3150141..a774a6f 100644 --- a/src/Runtime/Ghost.Graphics/Utilities/MeshletUtility.cs +++ b/src/Runtime/Ghost.Graphics/Utilities/MeshletUtility.cs @@ -582,7 +582,7 @@ public static unsafe class MeshletUtility } } - var targetSize = ((nuint)merged.Count / 3) * (nuint)config.simplifyRatio * 3; + var targetSize = (nuint)(merged.Count / 3 * config.simplifyRatio * 3.0f); var bounds = MergeBounds(clusters, groups[i]); var error = 0.0f; diff --git a/src/Runtime/Ghost.Graphics/test.gshdr b/src/Runtime/Ghost.Graphics/test.gshdr index af6209a..8afea0f 100644 --- a/src/Runtime/Ghost.Graphics/test.gshdr +++ b/src/Runtime/Ghost.Graphics/test.gshdr @@ -29,11 +29,12 @@ shader "MyShader/Standard" hlsl { + #line 31 "MyShader_Standard_Forward_hlsl_block" struct PixelInput { float4 position : SV_POSITION; float4 color : COLOR; - float4 uv : TEXCOORD0; + float2 uv : TEXCOORD0; nointerpolation uint meshletID : MESHLET_ID; }; @@ -72,9 +73,9 @@ shader "MyShader/Standard" float4 worldPos = mul(instanceData.localToWorld, float4(v.position.xyz, 1.0f)); float4 viewPos = mul(viewData.viewMatrix, worldPos); - // outVerts[groupThreadID.x].position = mul(viewData.projectionMatrix, viewPos); + outVerts[groupThreadID.x].position = mul(viewData.projectionMatrix, viewPos); // For testing. - outVerts[groupThreadID.x].position = float4(v.position.xyz, 1.0f); + // outVerts[groupThreadID.x].position = v.position.xyz; outVerts[groupThreadID.x].color = v.color; outVerts[groupThreadID.x].uv = v.uv; diff --git a/src/Test/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj b/src/Test/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj index 2eb85fa..c5b7443 100644 --- a/src/Test/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj +++ b/src/Test/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj @@ -53,6 +53,7 @@ +