Compare commits

...

2 Commits

Author SHA1 Message Date
da9990908a Added normal textures 2025-11-27 17:58:57 +00:00
d2b3027a11 refracted lighting again 2025-11-25 15:15:38 +00:00
9 changed files with 325 additions and 108 deletions

View File

@ -0,0 +1,67 @@
using OpenTK.Mathematics;
namespace TheLabs;
public static class Helpers
{
public static void CalculateTangent(ref Vertex v1, ref Vertex v2, ref Vertex v3)
{
// 1. Calculate Edge Vectors (Geometry)
Vector3 edge1 = v2.Position - v1.Position;
Vector3 edge2 = v3.Position - v1.Position;
// 2. Calculate Edge Vectors (Texture Space)
Vector2 deltaUV1 = v2.TexCoords - v1.TexCoords;
Vector2 deltaUV2 = v3.TexCoords - v1.TexCoords;
// 3. The Math (Solving linear equations)
float f = 1.0f / (deltaUV1.X * deltaUV2.Y - deltaUV2.X * deltaUV1.Y);
Vector3 tangent;
tangent.X = f * (deltaUV2.Y * edge1.X - deltaUV1.Y * edge2.X);
tangent.Y = f * (deltaUV2.Y * edge1.Y - deltaUV1.Y * edge2.Y);
tangent.Z = f * (deltaUV2.Y * edge1.Z - deltaUV1.Y * edge2.Z);
// Normalize it
tangent = Vector3.Normalize(tangent);
Vector3 bitangent = Vector3.Normalize(Vector3.Cross(edge1, edge2));
// 4. Assign the same tangent to all 3 vertices of the triangle
// (For smooth objects, you would average them, but for a cube, this is fine)
v1.Tangent = tangent; v1.Bitangent = bitangent;
v2.Tangent = tangent; v2.Bitangent = bitangent;
v3.Tangent = tangent; v3.Bitangent = bitangent;
}
public static void AddFace(List<Vertex> vertices, List<uint> indices,
Vertex v0, Vertex v1, Vertex v2, Vertex v3)
{
// 1. Calculate Tangents
// We calculate it twice to ensure the tangent is consistent across the whole face
// Triangle 1 (Bottom-Left, Bottom-Right, Top-Right)
CalculateTangent(ref v0, ref v1, ref v2);
// Triangle 2 (Bottom-Left, Top-Right, Top-Left)
CalculateTangent(ref v0, ref v2, ref v3);
// 2. Track where these new vertices start in the main list
// (If the list has 4 items, the new ones start at index 4)
uint offset = (uint)vertices.Count;
// 3. Add Vertices to the list
vertices.Add(v0); // Index: offset + 0
vertices.Add(v1); // Index: offset + 1
vertices.Add(v2); // Index: offset + 2
vertices.Add(v3); // Index: offset + 3
// 4. Add Indices for the two triangles (Standard Quad)
// Triangle 1
indices.Add(offset + 0);
indices.Add(offset + 1);
indices.Add(offset + 2);
// Triangle 2
indices.Add(offset + 0);
indices.Add(offset + 2);
indices.Add(offset + 3);
}
}

View File

@ -11,12 +11,21 @@ public struct Lighting
public Vector3 diffuseColour;
public Vector3 specularColour;
public float constant;
public float linear;
public float quadratic;
public Lighting(Vector3 pos, Vector3 ambient, Vector3 diffuse, Vector3 specular)
{
position = pos;
ambientColour = ambient;
diffuseColour = diffuse;
specularColour = specular;
constant = 1.0f;
linear = 0.09f;
quadratic = 0.032f;
}
public void Apply(Shader shader)
@ -25,5 +34,10 @@ public struct Lighting
GL.Uniform3(GL.GetUniformLocation(shader.Handle, "uPointLight.ambientColour"), ref ambientColour);
GL.Uniform3(GL.GetUniformLocation(shader.Handle, "uPointLight.diffuseColour"), ref diffuseColour);
GL.Uniform3(GL.GetUniformLocation(shader.Handle, "uPointLight.specularColour"), ref specularColour);
GL.Uniform1(GL.GetUniformLocation(shader.Handle, "uPointLight.constant"), constant);
GL.Uniform1(GL.GetUniformLocation(shader.Handle, "uPointLight.linear"), linear);
GL.Uniform1(GL.GetUniformLocation(shader.Handle, "uPointLight.quadratic"), quadratic);
}
}

View File

@ -12,7 +12,7 @@ public class Mesh : IDisposable
private readonly int _vertexCount;
private readonly bool _useIndices;
public enum VertexLayout { PosColor, PosTex, PosTexNormal }
public enum VertexLayout { PosColor, PosTex, PosTexNormal, PosTexNormalTangent }
public Mesh(float[] vertices, uint[] indices, VertexLayout layout)
{
@ -65,7 +65,7 @@ public class Mesh : IDisposable
if (layout == VertexLayout.PosColor)
{
// Stride = 7 floats (3 Pos + 4 Color)
var stride = 7 * sizeof(float);
var stride = 14 * sizeof(float);
// Location 0: Position
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
@ -77,6 +77,13 @@ public class Mesh : IDisposable
GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
GL.EnableVertexAttribArray(2);
GL.VertexAttribPointer(3, 3, VertexAttribPointerType.Float, false, stride, 8 * sizeof(float));
GL.EnableVertexAttribArray(3);
// Loc 4: Bitangent (Offset 11) <-- NEW
GL.VertexAttribPointer(4, 3, VertexAttribPointerType.Float, false, stride, 11 * sizeof(float));
GL.EnableVertexAttribArray(4);
}
else if (layout == VertexLayout.PosTex)
{
@ -96,7 +103,7 @@ public class Mesh : IDisposable
else if (layout == VertexLayout.PosTexNormal)
{
// Stride = 8 floats (3 Pos + 3 Normal + 2 Tex)
var stride = 8 * sizeof(float);
var stride = 14 * sizeof(float);
// Location 0: Position
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
@ -109,6 +116,32 @@ public class Mesh : IDisposable
// Location 2: TexCoord (Offset 6 floats: 3 pos + 3 normal)
GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, stride, 6 * sizeof(float));
GL.EnableVertexAttribArray(2);
}
else if (layout == VertexLayout.PosTexNormalTangent)
{
// --- NEW LOGIC FOR CUBES (Stride 14) ---
var stride = 14 * sizeof(float);
// Loc 0: Position
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
GL.EnableVertexAttribArray(0);
// Loc 1: Normal
GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
GL.EnableVertexAttribArray(1);
// Loc 2: TexCoord
GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, stride, 6 * sizeof(float));
GL.EnableVertexAttribArray(2);
// Loc 3: Tangent
GL.VertexAttribPointer(3, 3, VertexAttribPointerType.Float, false, stride, 8 * sizeof(float));
GL.EnableVertexAttribArray(3);
// Loc 4: Bitangent
GL.VertexAttribPointer(4, 3, VertexAttribPointerType.Float, false, stride, 11 * sizeof(float));
GL.EnableVertexAttribArray(4);
}
}

View File

@ -58,8 +58,9 @@ namespace TheLabs
base.OnLoad();
// --- Set up Lighting and Material ---
_mainLight = new Lighting(new Vector3(1.2f, 1.0f, 2.0f),
new Vector3(0.3f),
_mainLight = new Lighting(new Vector3(
1.2f, 1.0f, 2.0f),
new Vector3(0.5f),
new Vector3(1.5f),
new Vector3(1.0f));
@ -78,14 +79,17 @@ namespace TheLabs
// -- Load Shaders, Textures, and Create Scene Objects ---
_shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag");
_texture = new Texture("Textures/placeholder.png");
_texture = new Texture("Textures/cobble.jpg");
Texture _normalMap = new Texture("Textures/cobbleNormal.jpg");
// --- Create Scene Graph ---
_rootNode = new SceneNode();
// Create Example Object
_buildingObject = ShapeFactory.CreateTexturedSphere();
_buildingObject = ShapeFactory.CreateTexturedCube();
_buildingRender = new RenderObject(_buildingObject, _shader, _texture, _defaultMaterial, _mainLight);
_buildingRender.NormalMap = _normalMap;
_buildingNode = new SceneNode(_buildingRender);
_buildingNode.Position = new Vector3(2.0f, -1.0f, 0.0f);
_buildingNode.Scale = new Vector3(0.1f, 0.1f, 0.1f);

View File

@ -9,6 +9,7 @@ public class RenderObject
public Mesh Mesh;
public Shader Shader;
public Texture Texture;
public Texture NormalMap;
public Material Material;
public Lighting Lighting;
@ -16,6 +17,7 @@ public class RenderObject
public Matrix4 Transform = Matrix4.Identity;
public Quaternion Rotation = Quaternion.Identity;
public Vector3 Scale = Vector3.One;
public bool UseTexture = true;
public RenderObject(Mesh mesh, Shader shader, Texture texture, Material material, Lighting lighting)
{
@ -38,8 +40,27 @@ public class RenderObject
Material mat = new Material(pink * 0.1f, pink * 0.6f, Vector3.One, 32.0f);
Shader.Use();
Texture.Use();
Shader.SetInt("uTexture", 0);
if (Texture != null && UseTexture)
{
Texture.Use(TextureUnit.Texture0);
Shader.SetInt("uTexture", 0);
GL.Uniform1(GL.GetUniformLocation(Shader.Handle, "uUseTexture"), 1);
}
else
{
GL.Uniform1(GL.GetUniformLocation(Shader.Handle, "uUseTexture"), 0);
}
if (NormalMap != null)
{
NormalMap.Use(TextureUnit.Texture1);
Shader.SetInt("uNormalMap", 1);
GL.Uniform1(GL.GetUniformLocation(Shader.Handle, "uUseNormalMap"), 1);
}
else
{
GL.Uniform1(GL.GetUniformLocation(Shader.Handle, "uUseNormalMap"), 0);
}
Material.Apply(Shader);
light.Apply(Shader);

View File

@ -9,6 +9,7 @@ out vec4 outputColor; // The final output color of the fragment
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoord;
in mat3 vTBN; // Tangent, Bitangent, Normal matrix
struct MaterialProperty {
vec3 ambientColour;
@ -22,60 +23,75 @@ struct LightProperty {
vec3 ambientColour;
vec3 diffuseColour;
vec3 specularColour;
float constant;
float linear;
float quadratic;
};
// --- UNIFORMS ---
uniform sampler2D uTexture; // Image Texture
uniform sampler2D uNormalMap; // Normal Map Texture
uniform vec3 uViewPos; // Camera Position
uniform MaterialProperty uMaterial; // Material Properties
uniform LightProperty uPointLight; // Light Properties
uniform int uUseTexture; // Flag to indicate if texture should be used
uniform int uUseNormalMap; // Flag to indicate if normal map should be used
vec3 CalcPointLight(LightProperty light, vec3 normal, vec3 fragPos, vec3 viewDir) {
vec3 lightDir = normalize(light.position - fragPos);
// 1. Diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// 2. Specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), uMaterial.shininess);
// 3. Attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance +
light.quadratic * (distance * distance));
// 4. Combine results
vec3 ambient = light.ambientColour * uMaterial.ambientColour;
vec3 diffuse = light.diffuseColour * diff * uMaterial.diffuseColour;
vec3 specular = light.specularColour * spec * uMaterial.specularColour;
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return (ambient + diffuse + specular);
}
void main()
{
// --- LIGHTING CALCULATIONS ---
// Lighting Setup (hardcoded for simplicity)
vec3 lightPos = vec3(1.2f, 1.0f, 2.0f);
vec3 lightColor = vec3(1.0f, 1.0f, 1.0f);
vec3 norm;
// 1. Get Texture Color
// Sample the texture at the given texture coordinates
vec4 objColor = texture(uTexture, TexCoord);
if (uUseNormalMap == 1) {
vec3 normalFromTexture = texture(uNormalMap, TexCoord).rgb;
vec3 colourShift = normalFromTexture * 2.0 - 1.0; // Transform from [0,1] to [-1,1]
// 1. Setup Vectors
norm = normalize(vTBN * colourShift);
// 2. Ambient strength
// A constant, dim light that ensure s object are not completely dark
// It simply multiplies the light color by a small factor
float ambientStrength = 0.1f;
vec3 ambient = uMaterial.ambientColour * uPointLight.ambientColour;
} else {
norm = normalize(Normal);
}
// 3. Diffuse
// Creates the "matte" effect by calculating the angle between the light direction and the surface normal
vec3 viewDir = normalize(uViewPos - FragPos);
// Normalize the normal vector and calculate the light direction
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(uPointLight.position - FragPos);
// 2. Calculate Lighting using the Function
vec3 result = CalcPointLight(uPointLight, norm, FragPos, viewDir);
// The dot product gives us the cosine of the angle between the two vectors
// The max function ensures we don't get negative values (light coming from behind the surface)
float diff = max(dot(norm, lightDir), 0.0f);
vec3 diffuse = (uPointLight.diffuseColour * diff) * uMaterial.diffuseColour;
// 3. Apply Texture Switch
if (uUseTexture == 1) {
// 4. Specular
// Creates the shiny highlights on the surface
float shininess = 32.0f;
// Calculate the view direction and the reflection direction
vec3 viewDirection = normalize(uViewPos - FragPos);
// If the light is coming from the light direction, we need to negate it for reflection
vec3 reflectDirection = reflect(-lightDir, normalize(Normal));
outputColor = vec4(result, 1.0) * texture(uTexture, TexCoord);
} else {
outputColor = vec4(result, 1.0);
}
// Calculate the specular component using the dot product and shininess factor
float spec = pow(max(dot(viewDirection, reflectDirection), 0.0f), shininess);
vec3 specular = uMaterial.specularColour * spec * uPointLight.specularColour;
// 5. Combine
// We multiply (Ambient + Diffuse) by the Texture Color.
// We ADD Specular afterwards so the highlights look bright white (like plastic/metal).
vec3 result = (ambient + diffuse) * objColor.rgb + specular;
outputColor = vec4(result, objColor.a);
}

View File

@ -7,12 +7,15 @@
layout(location = 0) in vec3 aPosition; // Raw 3D position
layout(location = 1) in vec3 aNormal; // The direction perpendicular to the surface
layout(location = 2) in vec2 aTexCoord; // The U,V texture coordinates
layout(location = 3) in vec3 aTangent; // Tangent vector for normal mapping
layout(location = 4) in vec3 aBitangent; // Bitangent vector for normal mapping
// --- OUTPUTS ---
// We can pass data to the fragment shader through these
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoord;
out mat3 vTBN;
// --- UNIFORMS ---
// These are matrices that help transform our vertices
@ -22,6 +25,12 @@ uniform mat4 projection;
void main(void)
{
vec3 T = normalize(vec3(model * vec4(aTangent, 0.0)));
vec3 B = normalize(vec3(model * vec4(aBitangent, 0.0)));
vec3 N = normalize(vec3(model * vec4(aNormal, 0.0)));
vTBN = mat3(T, B, N);
// 1. Calculate World Position
FragPos = vec3(model * vec4(aPosition, 1.0));

View File

@ -1,72 +1,83 @@
namespace TheLabs;
using OpenTK.Mathematics;
namespace TheLabs;
public static class ShapeFactory
{
public static Mesh CreateTexturedCube()
{
float[] vertices = {
// Format: X, Y, Z, NX, NY, NZ, U, V
List<Vertex> vertices = new List<Vertex>();
List<uint> indices = new List<uint>();
// --- Front Face (Normal points +Z: 0, 0, 1) ---
-0.5f, -0.5f, 0.5f, 0f, 0f, 1f, 0f, 0f, // Bottom-left
0.5f, -0.5f, 0.5f, 0f, 0f, 1f, 1f, 0f, // Bottom-right
0.5f, 0.5f, 0.5f, 0f, 0f, 1f, 1f, 1f, // Top-right
-0.5f, 0.5f, 0.5f, 0f, 0f, 1f, 0f, 1f, // Top-left
// --- 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 points -Z: 0, 0, -1) ---
-0.5f, -0.5f, -0.5f, 0f, 0f, -1f, 1f, 0f,
0.5f, -0.5f, -0.5f, 0f, 0f, -1f, 0f, 0f,
0.5f, 0.5f, -0.5f, 0f, 0f, -1f, 0f, 1f,
-0.5f, 0.5f, -0.5f, 0f, 0f, -1f, 1f, 1f,
// --- 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 points -X: -1, 0, 0) ---
-0.5f, -0.5f, -0.5f, -1f, 0f, 0f, 0f, 0f,
-0.5f, -0.5f, 0.5f, -1f, 0f, 0f, 1f, 0f,
-0.5f, 0.5f, 0.5f, -1f, 0f, 0f, 1f, 1f,
-0.5f, 0.5f, -0.5f, -1f, 0f, 0f, 0f, 1f,
// --- 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 points +X: 1, 0, 0) ---
0.5f, -0.5f, -0.5f, 1f, 0f, 0f, 1f, 0f,
0.5f, -0.5f, 0.5f, 1f, 0f, 0f, 0f, 0f,
0.5f, 0.5f, 0.5f, 1f, 0f, 0f, 0f, 1f,
0.5f, 0.5f, -0.5f, 1f, 0f, 0f, 1f, 1f,
// --- 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 points +Y: 0, 1, 0) ---
-0.5f, 0.5f, -0.5f, 0f, 1f, 0f, 0f, 1f,
0.5f, 0.5f, -0.5f, 0f, 1f, 0f, 1f, 1f,
0.5f, 0.5f, 0.5f, 0f, 1f, 0f, 1f, 0f,
-0.5f, 0.5f, 0.5f, 0f, 1f, 0f, 0f, 0f,
// --- 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 points -Y: 0, -1, 0) ---
-0.5f, -0.5f, -0.5f, 0f, -1f, 0f, 1f, 1f,
0.5f, -0.5f, -0.5f, 0f, -1f, 0f, 0f, 1f,
0.5f, -0.5f, 0.5f, 0f, -1f, 0f, 0f, 0f,
-0.5f, -0.5f, 0.5f, 0f, -1f, 0f, 1f, 0f
// --- 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
);
};
uint[] indices = {
// Front face
0, 2, 1,
0, 2, 3,
// Back face
4, 5, 6,
4, 6, 7,
// Left face
8, 9, 10,
8, 10, 11,
// Right face
12, 14, 13,
12, 14, 15,
// Top face
16, 17, 18,
16, 18, 19,
// Bottom face
20, 22, 21,
20, 22, 23
};
List<float> finalFloats = new List<float>();
return new Mesh(vertices, indices, Mesh.VertexLayout.PosTexNormal);
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()
@ -321,6 +332,26 @@ public static class ShapeFactory
return new Mesh(vertices.ToArray(), indices.ToArray(), Mesh.VertexLayout.PosTexNormal);
}
public static Mesh createTexturedSquare()
{
float[] vertices = {
// Format: X, Y, Z, U, V
// --- Front Face ---
-0.5f, -0.5f, 0.0f, 0f, 0f, // Bottom-left
0.5f, -0.5f, 0.0f, 1f, 0f, // Bottom-right
0.5f, 0.5f, 0.0f, 1f, 1f, // Top-right
-0.5f, 0.5f, 0.0f, 0f, 1f, // Top-left
};
uint[] indices = {
// Front face
0, 2, 1,
0, 2, 3,
};
return new Mesh(vertices, indices, Mesh.VertexLayout.PosTex);
}
}

22
TheRepo/TheLabs/Vertex.cs Normal file
View File

@ -0,0 +1,22 @@
using OpenTK.Mathematics;
namespace TheLabs;
public struct Vertex
{
public Vector3 Position;
public Vector3 Normal;
public Vector2 TexCoords;
public Vector3 Tangent;
public Vector3 Bitangent;
// A constructor to make creating them easy
public Vertex(Vector3 position, Vector3 normal, Vector2 texCoords, Vector3 tangent, Vector3 bitangent)
{
Position = position;
Normal = normal;
TexCoords = texCoords;
Tangent = tangent;
Bitangent = bitangent;
}
}