forked from Misaki/GhostEngine
- Added `<IsTrimmable>` property in project files for trimming. - Replaced bindless texture types with non-bindless equivalents. - Refactored `ShaderDescriptor` and `ShaderPass` for better modularity. - Introduced `ShaderDescriptorExtensions` for property size calculations. - Simplified constant buffer handling in `Material.cs`. - Improved resource management in `D3D12` components. - Added support for static meshes and optimized resource barriers. - Refactored shader code generation and property merging in `SDLCompiler`. - Removed unused or redundant code (e.g., `IncludesBlock` parser). - Updated comments, documentation, and error handling for clarity.
283 lines
9.0 KiB
C#
283 lines
9.0 KiB
C#
using Misaki.HighPerformance.LowLevel.Buffer;
|
|
using Misaki.HighPerformance.LowLevel.Collections;
|
|
using Misaki.HighPerformance.Mathematics;
|
|
using Ghost.Graphics.Core;
|
|
|
|
namespace Ghost.Graphics.Utilities;
|
|
|
|
public unsafe static class MeshBuilder
|
|
{
|
|
/// <summary>
|
|
/// Creates a unit cube centered at the origin with size 1.
|
|
/// </summary>
|
|
public static void CreateCube(float size, Color128 color, Allocator allocator, out UnsafeList<Vertex> vertices, out UnsafeList<uint> indices)
|
|
{
|
|
var half = size * 0.5f;
|
|
|
|
vertices = new UnsafeList<Vertex>(24, allocator);
|
|
indices = new UnsafeList<uint>(36, allocator);
|
|
|
|
var corners = new float4[]
|
|
{
|
|
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)
|
|
};
|
|
|
|
var faces = stackalloc int[]
|
|
{
|
|
0,1,2,3,
|
|
5,4,7,6,
|
|
4,0,3,7,
|
|
1,5,6,2,
|
|
3,2,6,7,
|
|
4,5,1,0
|
|
};
|
|
|
|
var uvs = stackalloc float2[] { new(0, 0), new(1, 0), new(1, 1), new(0, 1) };
|
|
|
|
for (var f = 0; f < 6; f++)
|
|
{
|
|
var face = &faces[f * 4];
|
|
var baseIndex = (uint)vertices.Count;
|
|
for (var i = 0; i < 4; i++)
|
|
{
|
|
var vertex = new Vertex
|
|
{
|
|
position = corners[face[i]],
|
|
normal = float4.zero,
|
|
tangent = float4.zero,
|
|
color = color,
|
|
uv = new(uvs[i], 0.0f, 0.0f)
|
|
};
|
|
|
|
vertices.Add(vertex);
|
|
}
|
|
|
|
indices.Add(baseIndex + 0);
|
|
indices.Add(baseIndex + 1);
|
|
indices.Add(baseIndex + 2);
|
|
indices.Add(baseIndex + 0);
|
|
indices.Add(baseIndex + 2);
|
|
indices.Add(baseIndex + 3);
|
|
}
|
|
|
|
ComputeNormal(vertices, indices);
|
|
ComputeTangents(vertices, indices);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Creates a plane on the XZ axis centered at the origin.
|
|
/// </summary>
|
|
public static void CreatePlane(float width, float depth, Color128 color, Allocator allocator, out UnsafeList<Vertex> vertices, out UnsafeList<uint> indices)
|
|
{
|
|
var hw = width * 0.5f;
|
|
var hd = depth * 0.5f;
|
|
|
|
vertices = new UnsafeList<Vertex>(4, allocator);
|
|
indices = new UnsafeList<uint>(6, allocator);
|
|
|
|
vertices.Add(new Vertex()
|
|
{
|
|
position = new(-hw, 0.0f, -hd, 0.0f),
|
|
normal = float4.zero,
|
|
tangent = float4.zero,
|
|
color = color,
|
|
uv = new(0.0f)
|
|
});
|
|
|
|
vertices.Add(new Vertex()
|
|
{
|
|
position = new(hw, 0.0f, -hd, 0.0f),
|
|
normal = float4.zero,
|
|
tangent = float4.zero,
|
|
color = color,
|
|
uv = new(1.0f, 0.0f, 0.0f, 0.0f)
|
|
});
|
|
|
|
vertices.Add(new Vertex()
|
|
{
|
|
position = new(hw, 0.0f, hd, 0.0f),
|
|
normal = float4.zero,
|
|
tangent = float4.zero,
|
|
color = color,
|
|
uv = new(1.0f, 1.0f, 0.0f, 0.0f)
|
|
});
|
|
|
|
vertices.Add(new Vertex()
|
|
{
|
|
position = new(-hw, 0.0f, hd, 0.0f),
|
|
normal = float4.zero,
|
|
tangent = float4.zero,
|
|
color = color,
|
|
uv = new(0.0f, 1.0f, 0.0f, 0.0f)
|
|
});
|
|
|
|
indices.Add(0);
|
|
indices.Add(1);
|
|
indices.Add(2);
|
|
indices.Add(0);
|
|
indices.Add(2);
|
|
indices.Add(3);
|
|
|
|
ComputeNormal(vertices, indices);
|
|
ComputeTangents(vertices, indices);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a UV sphere centered at the origin.
|
|
/// </summary>
|
|
public static void CreateSphere(int latitudeSegments, int longitudeSegments, float radius, Color128 color, Allocator allocator, out UnsafeList<Vertex> vertices, out UnsafeList<uint> indices)
|
|
{
|
|
vertices = new UnsafeList<Vertex>((latitudeSegments + 1) * (longitudeSegments + 1), allocator);
|
|
indices = new UnsafeList<uint>(latitudeSegments * longitudeSegments * 6, allocator);
|
|
|
|
// Vertices
|
|
for (var lat = 0; lat <= latitudeSegments; lat++)
|
|
{
|
|
var theta = (float)lat / latitudeSegments * MathF.PI;
|
|
var sinTheta = MathF.Sin(theta);
|
|
var cosTheta = MathF.Cos(theta);
|
|
|
|
for (var lon = 0; lon <= longitudeSegments; lon++)
|
|
{
|
|
var phi = (float)lon / longitudeSegments * 2 * MathF.PI;
|
|
var sinPhi = MathF.Sin(phi);
|
|
var cosPhi = MathF.Cos(phi);
|
|
|
|
var x = cosPhi * sinTheta;
|
|
var y = cosTheta;
|
|
var z = sinPhi * sinTheta;
|
|
|
|
vertices.Add(new Vertex
|
|
{
|
|
position = new float4(x, y, z, 0.0f) * radius,
|
|
normal = float4.zero,
|
|
tangent = float4.zero,
|
|
color = color,
|
|
uv = new float4((float)lon / longitudeSegments, (float)lat / latitudeSegments, 0.0f, 0.0f)
|
|
});
|
|
}
|
|
}
|
|
|
|
// Indices
|
|
for (var lat = 0; lat < latitudeSegments; lat++)
|
|
{
|
|
for (var lon = 0; lon < longitudeSegments; lon++)
|
|
{
|
|
var i0 = lat * (longitudeSegments + 1) + lon;
|
|
var i1 = i0 + longitudeSegments + 1;
|
|
var i2 = i1 + 1;
|
|
var i3 = i0 + 1;
|
|
|
|
indices.Add((uint)i0);
|
|
indices.Add((uint)i1);
|
|
indices.Add((uint)i2);
|
|
indices.Add((uint)i0);
|
|
indices.Add((uint)i2);
|
|
indices.Add((uint)i3);
|
|
}
|
|
}
|
|
|
|
ComputeNormal(vertices, indices);
|
|
ComputeTangents(vertices, indices);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Auto-compute smooth per-vertex normals.
|
|
/// </summary>
|
|
/// <param name="vertices">The vertex list.</param>
|
|
/// <param name="indices">The index list.</param>
|
|
public static void ComputeNormal(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
|
|
{
|
|
if (!vertices.IsCreated || vertices.Count < 3
|
|
|| !indices.IsCreated || indices.Count < 3)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (var i = 0; i < indices.Count; i += 3)
|
|
{
|
|
var i0 = indices[i];
|
|
var i1 = indices[i + 1];
|
|
var i2 = indices[i + 2];
|
|
|
|
var v0 = vertices[i0];
|
|
var v1 = vertices[i1];
|
|
var v2 = vertices[i2];
|
|
|
|
var edge1 = v1.position - v0.position;
|
|
var edge2 = v2.position - v0.position;
|
|
var faceNormal = math.cross(edge1.xyz, edge2.xyz);
|
|
|
|
vertices[i0].normal.xyz += faceNormal;
|
|
vertices[i1].normal.xyz += faceNormal;
|
|
vertices[i2].normal.xyz += faceNormal;
|
|
}
|
|
|
|
for (var i = 0; i < vertices.Count; i++)
|
|
{
|
|
vertices[i].normal = math.normalize(vertices[i].normal);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Auto-compute per-vertex tangents.
|
|
/// </summary>
|
|
/// <param name="vertices">The vertex list.</param>
|
|
/// <param name="indices">The index list.</param>
|
|
public static void ComputeTangents(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
|
|
{
|
|
using var scope = AllocationManager.CreateStackScope();
|
|
using var bitangents = new UnsafeArray<float4>(vertices.Count, Allocator.Stack);
|
|
|
|
for (var i = 0; i < indices.Count; i += 3)
|
|
{
|
|
var i0 = indices[i];
|
|
var i1 = indices[i + 1];
|
|
var i2 = indices[i + 2];
|
|
|
|
var v0 = vertices[i0];
|
|
var v1 = vertices[i1];
|
|
var v2 = vertices[i2];
|
|
|
|
var uv0 = vertices[i0].uv;
|
|
var uv1 = vertices[i1].uv;
|
|
var uv2 = vertices[i2].uv;
|
|
|
|
var deltaPos1 = v1.position - v0.position;
|
|
var deltaPos2 = v2.position - v0.position;
|
|
var deltaUV1 = uv1 - uv0;
|
|
var deltaUV2 = uv2 - uv0;
|
|
|
|
var r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
|
|
var tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
|
|
var bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r;
|
|
|
|
for (var j = 0; j < 3; j++)
|
|
{
|
|
var idx = indices[i + j];
|
|
var t = vertices[idx].tangent;
|
|
vertices[idx].tangent.xyz = t.xyz + tangent.xyz;
|
|
|
|
bitangents[idx] += bitangent;
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < vertices.Count; i++)
|
|
{
|
|
var n = vertices[i].normal;
|
|
var t = vertices[i].tangent;
|
|
|
|
var proj = n * math.dot(n, t);
|
|
t = math.normalize(t - proj);
|
|
|
|
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);
|
|
}
|
|
}
|
|
} |