mirror of
https://github.com/UOH-CS-Level5/551455-graphics-programming-2526-the-repo-Zyb3rWolfi.git
synced 2025-11-29 00:43:08 +00:00
362 lines
15 KiB
C#
362 lines
15 KiB
C#
using OpenTK.Mathematics;
|
|
|
|
namespace TheLabs;
|
|
|
|
public static class ShapeFactory
|
|
{
|
|
public static Mesh CreateTexturedCube()
|
|
{
|
|
List<Vertex> vertices = new List<Vertex>();
|
|
List<uint> indices = new List<uint>();
|
|
|
|
// --- FRONT FACE (Normal 0, 0, 1) ---
|
|
// Sequence: Bottom-Left -> Bottom-Right -> Top-Right -> Top-Left
|
|
Helpers.AddFace(vertices, indices,
|
|
new Vertex(new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(0, 0, 1), new Vector2(0, 0), Vector3.Zero, Vector3.Zero), // BL
|
|
new Vertex(new Vector3( 0.5f, -0.5f, 0.5f), new Vector3(0, 0, 1), new Vector2(1, 0), Vector3.Zero, Vector3.Zero), // BR
|
|
new Vertex(new Vector3( 0.5f, 0.5f, 0.5f), new Vector3(0, 0, 1), new Vector2(1, 1), Vector3.Zero, Vector3.Zero), // TR
|
|
new Vertex(new Vector3(-0.5f, 0.5f, 0.5f), new Vector3(0, 0, 1), new Vector2(0, 1), Vector3.Zero, Vector3.Zero) // TL
|
|
);
|
|
|
|
// --- BACK FACE (Normal 0, 0, -1) ---
|
|
// Sequence: Bottom-Right -> Bottom-Left -> Top-Left -> Top-Right (Relative to Front view)
|
|
Helpers.AddFace(vertices, indices,
|
|
new Vertex(new Vector3( 0.5f, -0.5f, -0.5f), new Vector3(0, 0, -1), new Vector2(0, 0), Vector3.Zero, Vector3.Zero), // BR
|
|
new Vertex(new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(0, 0, -1), new Vector2(1, 0), Vector3.Zero, Vector3.Zero), // BL
|
|
new Vertex(new Vector3(-0.5f, 0.5f, -0.5f), new Vector3(0, 0, -1), new Vector2(1, 1), Vector3.Zero, Vector3.Zero), // TL
|
|
new Vertex(new Vector3( 0.5f, 0.5f, -0.5f), new Vector3(0, 0, -1), new Vector2(0, 1), Vector3.Zero, Vector3.Zero) // TR
|
|
);
|
|
|
|
// --- LEFT FACE (Normal -1, 0, 0) ---
|
|
// Sequence: Back-Left -> Front-Left -> Front-Top -> Back-Top
|
|
Helpers.AddFace(vertices, indices,
|
|
new Vertex(new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(-1, 0, 0), new Vector2(0, 0), Vector3.Zero, Vector3.Zero), // BL
|
|
new Vertex(new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(-1, 0, 0), new Vector2(1, 0), Vector3.Zero, Vector3.Zero), // FL
|
|
new Vertex(new Vector3(-0.5f, 0.5f, 0.5f), new Vector3(-1, 0, 0), new Vector2(1, 1), Vector3.Zero, Vector3.Zero), // FT
|
|
new Vertex(new Vector3(-0.5f, 0.5f, -0.5f), new Vector3(-1, 0, 0), new Vector2(0, 1), Vector3.Zero, Vector3.Zero) // BT
|
|
);
|
|
|
|
// --- RIGHT FACE (Normal 1, 0, 0) ---
|
|
// Sequence: Front-Right -> Back-Right -> Back-Top -> Front-Top
|
|
Helpers.AddFace(vertices, indices,
|
|
new Vertex(new Vector3( 0.5f, -0.5f, 0.5f), new Vector3(1, 0, 0), new Vector2(0, 0), Vector3.Zero, Vector3.Zero), // FR
|
|
new Vertex(new Vector3( 0.5f, -0.5f, -0.5f), new Vector3(1, 0, 0), new Vector2(1, 0), Vector3.Zero, Vector3.Zero), // BR
|
|
new Vertex(new Vector3( 0.5f, 0.5f, -0.5f), new Vector3(1, 0, 0), new Vector2(1, 1), Vector3.Zero, Vector3.Zero), // BT
|
|
new Vertex(new Vector3( 0.5f, 0.5f, 0.5f), new Vector3(1, 0, 0), new Vector2(0, 1), Vector3.Zero, Vector3.Zero) // FT
|
|
);
|
|
|
|
// --- TOP FACE (Normal 0, 1, 0) ---
|
|
// Sequence: Front-Left -> Front-Right -> Back-Right -> Back-Left
|
|
Helpers.AddFace(vertices, indices,
|
|
new Vertex(new Vector3(-0.5f, 0.5f, 0.5f), new Vector3(0, 1, 0), new Vector2(0, 0), Vector3.Zero, Vector3.Zero), // FL
|
|
new Vertex(new Vector3( 0.5f, 0.5f, 0.5f), new Vector3(0, 1, 0), new Vector2(1, 0), Vector3.Zero, Vector3.Zero), // FR
|
|
new Vertex(new Vector3( 0.5f, 0.5f, -0.5f), new Vector3(0, 1, 0), new Vector2(1, 1), Vector3.Zero, Vector3.Zero), // BR
|
|
new Vertex(new Vector3(-0.5f, 0.5f, -0.5f), new Vector3(0, 1, 0), new Vector2(0, 1), Vector3.Zero, Vector3.Zero) // BL
|
|
);
|
|
|
|
// --- BOTTOM FACE (Normal 0, -1, 0) ---
|
|
// Sequence: Front-Left -> Back-Left -> Back-Right -> Front-Right
|
|
Helpers.AddFace(vertices, indices,
|
|
new Vertex(new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(0, -1, 0), new Vector2(0, 1), Vector3.Zero, Vector3.Zero), // FL
|
|
new Vertex(new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(0, -1, 0), new Vector2(0, 0), Vector3.Zero, Vector3.Zero), // BL
|
|
new Vertex(new Vector3( 0.5f, -0.5f, -0.5f), new Vector3(0, -1, 0), new Vector2(1, 0), Vector3.Zero, Vector3.Zero), // BR
|
|
new Vertex(new Vector3( 0.5f, -0.5f, 0.5f), new Vector3(0, -1, 0), new Vector2(1, 1), Vector3.Zero, Vector3.Zero) // FR
|
|
);
|
|
|
|
|
|
List<float> finalFloats = new List<float>();
|
|
|
|
foreach (var v in vertices)
|
|
{
|
|
finalFloats.Add(v.Position.X); finalFloats.Add(v.Position.Y); finalFloats.Add(v.Position.Z);
|
|
finalFloats.Add(v.Normal.X); finalFloats.Add(v.Normal.Y); finalFloats.Add(v.Normal.Z);
|
|
finalFloats.Add(v.TexCoords.X); finalFloats.Add(v.TexCoords.Y);
|
|
|
|
// --- NEW: Add Tangent and Bitangent ---
|
|
finalFloats.Add(v.Tangent.X); finalFloats.Add(v.Tangent.Y); finalFloats.Add(v.Tangent.Z);
|
|
finalFloats.Add(v.Bitangent.X); finalFloats.Add(v.Bitangent.Y); finalFloats.Add(v.Bitangent.Z);
|
|
}
|
|
|
|
return new Mesh(finalFloats.ToArray(), indices.ToArray(), Mesh.VertexLayout.PosTexNormalTangent);
|
|
}
|
|
|
|
public static Mesh CreateColouredCircle()
|
|
{
|
|
float[] vertices = {
|
|
|
|
|
|
};
|
|
|
|
int segments = 100;
|
|
for (int i = 0; i <= segments; i++)
|
|
{
|
|
|
|
float angle = i * 2.0f * MathF.PI / segments;
|
|
float x = 0.5f * MathF.Cos(angle);
|
|
float y = 0.5f * MathF.Sin(angle);
|
|
|
|
Array.Resize(ref vertices, vertices.Length + 7);
|
|
vertices[^7] = x;
|
|
vertices[^6] = y;
|
|
vertices[^5] = 0f;
|
|
|
|
}
|
|
|
|
return new Mesh(vertices, Mesh.VertexLayout.PosColor);
|
|
}
|
|
|
|
public static Mesh CreateTexturedCircle()
|
|
{
|
|
var vertices = new List<float>();
|
|
|
|
int segments = 100;
|
|
|
|
vertices.Add(0f); // Center X
|
|
vertices.Add(0f); // Center Y
|
|
vertices.Add(0f); // Center Z
|
|
vertices.Add(0.5f); // Center U
|
|
vertices.Add(0.5f); // Center V
|
|
for (int i = 0; i <= segments; i++)
|
|
{
|
|
|
|
float angle = i * 2.0f * MathF.PI / segments;
|
|
float x = 0.5f * MathF.Cos(angle);
|
|
float y = 0.5f * MathF.Sin(angle);
|
|
|
|
vertices.Add(x); // X
|
|
vertices.Add(y); // Y
|
|
vertices.Add(0f); // Z
|
|
vertices.Add((x + 0.5f)); // U
|
|
vertices.Add((y + 0.5f)); // V
|
|
|
|
}
|
|
|
|
return new Mesh(vertices.ToArray(), Mesh.VertexLayout.PosTex);
|
|
}
|
|
|
|
public static Mesh CreateColorCube()
|
|
{
|
|
float[] vertices = {
|
|
-0.5f, -0.5f, 0.5f, 1f, 0f, 0f, 1f, 0f, 0f, 1f, // Bottom-left
|
|
0.5f, -0.5f, 0.5f, 0f, 1f, 0f, 1f, 0f, 0f, 1f, // Bottom-right
|
|
0.5f, 0.5f, 0.5f, 0f, 0f, 1f, 1f, 0f, 0f, 1f, // Top-right
|
|
-0.5f, 0.5f, 0.5f, 1f, 1f, 0f, 1f, 0f, 0f, 1f, // Top-left
|
|
|
|
// Back face (z = -0.5)
|
|
-0.5f, -0.5f, -0.5f, 1f, 0f, 1f, 1f, 0f, 0f, -1f, // Bottom-left
|
|
0.5f, -0.5f, -0.5f, 0f, 1f, 1f, 1f, 0f, 0f, -1f, // Bottom-right
|
|
0.5f, 0.5f, -0.5f, 1f, 1f, 1f, 1f, 0f, 0f, -1f, // Top-right
|
|
-0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 1f, 0f, 0f, -1f, // Top-left
|
|
};
|
|
|
|
uint[] indices = {
|
|
// Front face
|
|
0, 1, 2,
|
|
2, 3, 0,
|
|
|
|
// Back face
|
|
4, 5, 6,
|
|
6, 7, 4,
|
|
|
|
// Left face
|
|
4, 0, 3,
|
|
3, 7, 4,
|
|
|
|
// Right face
|
|
1, 5, 6,
|
|
6, 2, 1,
|
|
|
|
// Top face
|
|
3, 2, 6,
|
|
6, 7, 3,
|
|
|
|
// Bottom face
|
|
4, 5, 1,
|
|
1, 0, 4
|
|
};
|
|
|
|
return new Mesh(vertices, indices, Mesh.VertexLayout.PosColor);
|
|
}
|
|
|
|
public static Mesh CreateTexturedCylinder(int segments = 32, float height = 1.0f, float radius = 0.5f)
|
|
{
|
|
var vertices = new List<float>();
|
|
var indices = new List<uint>();
|
|
uint vertexIndex = 0;
|
|
|
|
float halfHeight = height / 2.0f;
|
|
uint topCenterIndex = vertexIndex;
|
|
vertices.AddRange(new[]
|
|
{
|
|
0.0f, halfHeight, 0.0f, // Position
|
|
0.5f, 0.5f
|
|
}); // Top center vertex
|
|
|
|
vertexIndex++;
|
|
|
|
uint topStartIndex = vertexIndex;
|
|
|
|
for (int i = 0; i <= segments; i++)
|
|
{
|
|
float angle = i * 2.0f * MathF.PI / segments;
|
|
float x = radius * MathF.Cos(angle);
|
|
float z = radius * MathF.Sin(angle);
|
|
|
|
// UV coordinates are mapped from model space (-0.5 to +0.5)
|
|
// to texture space (0.0 to 1.0)
|
|
float u = x / (radius * 2) + 0.5f;
|
|
float v = z / (radius * 2) + 0.5f;
|
|
|
|
vertices.AddRange(new[] { x, halfHeight, z, u, v });
|
|
vertexIndex++;
|
|
}
|
|
|
|
// Add Top Cap Indices (Triangle Fan)
|
|
for (int i = 0; i < segments; i++)
|
|
{
|
|
indices.Add(topCenterIndex);
|
|
indices.Add(topStartIndex + (uint)i);
|
|
indices.Add(topStartIndex + (uint)((i + 1) % segments)); // Wrap around
|
|
}
|
|
|
|
uint sideStartIndex = vertexIndex;
|
|
|
|
// Loop from 0 to segments (inclusive) to get (segments + 1)
|
|
// vertices for wrapping the texture seamlessly.
|
|
for (int i = 0; i <= segments; i++)
|
|
{
|
|
float angle = i * 2.0f * MathF.PI / segments;
|
|
float x = radius * MathF.Cos(angle);
|
|
float z = radius * MathF.Sin(angle);
|
|
|
|
// The U coordinate goes from 0.0 to 1.0 around the cylinder
|
|
float u = (float)i / segments;
|
|
|
|
// Add Top Side Vertex
|
|
vertices.AddRange(new[] { x, halfHeight, z, u, 1.0f }); // V = 1.0 (top)
|
|
vertexIndex++;
|
|
|
|
// Add Bottom Side Vertex
|
|
vertices.AddRange(new[] { x, -halfHeight, z, u, 0.0f }); // V = 0.0 (bottom)
|
|
vertexIndex++;
|
|
}
|
|
// Add Side Wall Indices (Quad Strip)
|
|
for (int i = 0; i < segments; i++)
|
|
{
|
|
// Each segment has 2 vertices (top, bottom)
|
|
// We reference the vertices we just created.
|
|
uint topCurrent = sideStartIndex + (uint)(i * 2);
|
|
uint bottomCurrent = topCurrent + 1;
|
|
uint topNext = sideStartIndex + (uint)((i + 1) * 2);
|
|
uint bottomNext = topNext + 1;
|
|
|
|
// Triangle 1 (CCW)
|
|
indices.Add(topCurrent);
|
|
indices.Add(bottomCurrent);
|
|
indices.Add(topNext);
|
|
|
|
// Triangle 2 (CCW)
|
|
indices.Add(bottomCurrent);
|
|
indices.Add(bottomNext);
|
|
indices.Add(topNext);
|
|
}
|
|
|
|
// --- 4. Create the Mesh ---
|
|
return new Mesh(vertices.ToArray(), indices.ToArray(), Mesh.VertexLayout.PosTex);
|
|
}
|
|
public static Mesh CreateTexturedSphere(float radius = 0.5f, int stacks = 20, int slices = 20)
|
|
{
|
|
var vertices = new List<float>();
|
|
var indices = new List<uint>();
|
|
|
|
// 1. Generate Vertices
|
|
for (int i = 0; i <= stacks; i++)
|
|
{
|
|
// V ranges from 0.0 to 1.0 (bottom to top)
|
|
float v = (float)i / stacks;
|
|
|
|
// Phi ranges from -PI/2 (bottom) to +PI/2 (top)
|
|
float phi = v * MathF.PI - MathF.PI / 2;
|
|
|
|
for (int j = 0; j <= slices; j++)
|
|
{
|
|
// U ranges from 0.0 to 1.0 (around the sphere)
|
|
float u = (float)j / slices;
|
|
|
|
// Theta ranges from 0 to 2*PI
|
|
float theta = u * 2 * MathF.PI;
|
|
|
|
// Calculate Position (Spherical Coordinates)
|
|
float x = radius * MathF.Cos(phi) * MathF.Cos(theta);
|
|
float y = radius * MathF.Sin(phi);
|
|
float z = radius * MathF.Cos(phi) * MathF.Sin(theta);
|
|
|
|
// Calculate Normal (Normalized position)
|
|
// Since center is (0,0,0), normal is just (x,y,z) normalized.
|
|
// Or simpler: (x/r, y/r, z/r)
|
|
float nx = x / radius;
|
|
float ny = y / radius;
|
|
float nz = z / radius;
|
|
|
|
// Add Vertex Data: Pos (3) + Normal (3) + Tex (2)
|
|
vertices.Add(x); vertices.Add(y); vertices.Add(z); // Position
|
|
vertices.Add(nx); vertices.Add(ny); vertices.Add(nz); // Normal
|
|
vertices.Add(u); vertices.Add(v); // Texture
|
|
}
|
|
}
|
|
|
|
// 2. Generate Indices
|
|
for (int i = 0; i < stacks; i++)
|
|
{
|
|
for (int j = 0; j < slices; j++)
|
|
{
|
|
// We are building a quad from 4 vertices:
|
|
// TopLeft (TL), TopRight (TR), BottomLeft (BL), BottomRight (BR)
|
|
|
|
uint bl = (uint)(i * (slices + 1) + j);
|
|
uint br = (uint)(i * (slices + 1) + (j + 1));
|
|
uint tl = (uint)((i + 1) * (slices + 1) + j);
|
|
uint tr = (uint)((i + 1) * (slices + 1) + (j + 1));
|
|
|
|
// Triangle 1
|
|
indices.Add(bl);
|
|
indices.Add(br);
|
|
indices.Add(tl);
|
|
|
|
// Triangle 2
|
|
indices.Add(br);
|
|
indices.Add(tr);
|
|
indices.Add(tl);
|
|
}
|
|
}
|
|
|
|
return new Mesh(vertices.ToArray(), indices.ToArray(), Mesh.VertexLayout.PosTexNormal);
|
|
}
|
|
public static Mesh CreateTexturedQuad()
|
|
{
|
|
List<Vertex> vertices = new List<Vertex>();
|
|
List<uint> indices = new List<uint>();
|
|
|
|
// Create a flat quad facing UP (Normal 0, 1, 0)
|
|
Helpers.AddFace(vertices, indices,
|
|
new Vertex(new Vector3(-0.5f, 0.0f, 0.5f), new Vector3(0, 1, 0), new Vector2(0, 0), Vector3.Zero, Vector3.Zero), // BL
|
|
new Vertex(new Vector3( 0.5f, 0.0f, 0.5f), new Vector3(0, 1, 0), new Vector2(1, 0), Vector3.Zero, Vector3.Zero), // BR
|
|
new Vertex(new Vector3( 0.5f, 0.0f, -0.5f), new Vector3(0, 1, 0), new Vector2(1, 1), Vector3.Zero, Vector3.Zero), // TR
|
|
new Vertex(new Vector3(-0.5f, 0.0f, -0.5f), new Vector3(0, 1, 0), new Vector2(0, 1), Vector3.Zero, Vector3.Zero) // TL
|
|
);
|
|
|
|
// Convert to arrays and return
|
|
List<float> finalFloats = new List<float>();
|
|
foreach (var v in vertices)
|
|
{
|
|
finalFloats.Add(v.Position.X); finalFloats.Add(v.Position.Y); finalFloats.Add(v.Position.Z);
|
|
finalFloats.Add(v.Normal.X); finalFloats.Add(v.Normal.Y); finalFloats.Add(v.Normal.Z);
|
|
finalFloats.Add(v.TexCoords.X); finalFloats.Add(v.TexCoords.Y);
|
|
finalFloats.Add(v.Tangent.X); finalFloats.Add(v.Tangent.Y); finalFloats.Add(v.Tangent.Z);
|
|
finalFloats.Add(v.Bitangent.X); finalFloats.Add(v.Bitangent.Y); finalFloats.Add(v.Bitangent.Z);
|
|
}
|
|
|
|
return new Mesh(finalFloats.ToArray(), indices.ToArray(), Mesh.VertexLayout.PosTexNormalTangent);
|
|
}
|
|
|
|
} |