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
Introduced scene maps and a model loader for external models
This commit is contained in:
parent
cf8eb3f5fd
commit
1fd8aada02
@ -8,6 +8,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AssimpNet" Version="5.0.0-beta1" />
|
||||||
<PackageReference Include="OpenTK" Version="4.8.2" />
|
<PackageReference Include="OpenTK" Version="4.8.2" />
|
||||||
<PackageReference Include="StbImageSharp" Version="2.30.15" />
|
<PackageReference Include="StbImageSharp" Version="2.30.15" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
77
TheRepo/TheLabs/ModelLoader.cs
Normal file
77
TheRepo/TheLabs/ModelLoader.cs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
namespace TheLabs;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Assimp; // The library we just installed
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
public static class ModelLoader
|
||||||
|
{
|
||||||
|
public static Mesh LoadMesh(string path)
|
||||||
|
{
|
||||||
|
var importer = new AssimpContext();
|
||||||
|
|
||||||
|
var scene = importer.ImportFile(path, PostProcessSteps.Triangulate | PostProcessSteps.JoinIdenticalVertices);
|
||||||
|
|
||||||
|
if (scene == null || scene.SceneFlags.HasFlag(SceneFlags.Incomplete) || scene.RootNode == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Error loading model: " + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- NEW LOGIC: Combine all meshes into one ---
|
||||||
|
List<float> allVertices = new List<float>();
|
||||||
|
List<uint> allIndices = new List<uint>();
|
||||||
|
|
||||||
|
// We need to track how many vertices we've added so far
|
||||||
|
// so the indices point to the correct new location
|
||||||
|
uint indexOffset = 0;
|
||||||
|
|
||||||
|
// Loop through EVERY mesh found in the file (Legs, Torso, Head, etc.)
|
||||||
|
foreach (var mesh in scene.Meshes)
|
||||||
|
{
|
||||||
|
// 1. Process Vertices for this specific part
|
||||||
|
for (int i = 0; i < mesh.VertexCount; i++)
|
||||||
|
{
|
||||||
|
// Position (x, y, z)
|
||||||
|
var pos = mesh.Vertices[i];
|
||||||
|
allVertices.Add(pos.X);
|
||||||
|
allVertices.Add(pos.Y);
|
||||||
|
allVertices.Add(pos.Z);
|
||||||
|
|
||||||
|
// Texture Coordinates (u, v)
|
||||||
|
if (mesh.HasTextureCoords(0))
|
||||||
|
{
|
||||||
|
var uv = mesh.TextureCoordinateChannels[0][i];
|
||||||
|
allVertices.Add(uv.X);
|
||||||
|
allVertices.Add(uv.Y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allVertices.Add(0.0f);
|
||||||
|
allVertices.Add(0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Process Indices for this specific part
|
||||||
|
for (int i = 0; i < mesh.FaceCount; i++)
|
||||||
|
{
|
||||||
|
var face = mesh.Faces[i];
|
||||||
|
for (int j = 0; j < face.IndexCount; j++)
|
||||||
|
{
|
||||||
|
// CRITICAL: We add the offset to the index!
|
||||||
|
// If the leg had 100 vertices, the first vertex of the torso
|
||||||
|
// needs to be index 100, not 0.
|
||||||
|
allIndices.Add((uint)(face.Indices[j] + indexOffset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increase the offset by the number of vertices we just added
|
||||||
|
indexOffset += (uint)mesh.VertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return one giant Mesh containing the whole character
|
||||||
|
return new Mesh(allVertices.ToArray(), allIndices.ToArray(), Mesh.VertexLayout.PosTex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using OpenTK.Graphics.OpenGL4;
|
using Assimp;
|
||||||
|
using OpenTK.Graphics.OpenGL4;
|
||||||
using OpenTK.Windowing.Common;
|
using OpenTK.Windowing.Common;
|
||||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||||
using OpenTK.Windowing.Desktop;
|
using OpenTK.Windowing.Desktop;
|
||||||
@ -16,22 +17,20 @@ namespace TheLabs
|
|||||||
// Negative Y coordinates move to the bottom, positive Y move to the top.
|
// Negative Y coordinates move to the bottom, positive Y move to the top.
|
||||||
// OpenGL only supports rendering in 3D, so to create a flat triangle, the Z coordinate will be kept as 0.
|
// OpenGL only supports rendering in 3D, so to create a flat triangle, the Z coordinate will be kept as 0.
|
||||||
|
|
||||||
|
private SceneNode _rootNode;
|
||||||
|
private SceneNode _characterNode;
|
||||||
|
private SceneNode _buildingNode;
|
||||||
private Shader _shader;
|
private Shader _shader;
|
||||||
private Camera _camera;
|
private Camera _camera;
|
||||||
// - Resources that only need to be created once
|
// - Resources that only need to be created once
|
||||||
private Mesh _cubeMesh;
|
private Mesh _exampleObject;
|
||||||
private Mesh _circleMesh;
|
private Mesh _buildingObject;
|
||||||
private Mesh _cylinderMesh;
|
private Texture _texture;
|
||||||
private Texture _cubeTexture;
|
private RenderObject _render;
|
||||||
private Texture _cubeTexture2;
|
private RenderObject _buildingRender;
|
||||||
private float _rotation;
|
float _rotation = 0.0f;
|
||||||
|
|
||||||
// -- Scene Objects
|
// -- Scene Objects
|
||||||
private RenderObject _cubeObject;
|
|
||||||
private RenderObject _cubeObject2;
|
|
||||||
private RenderObject _circleObject;
|
|
||||||
private RenderObject _cylinderObject;
|
|
||||||
private Bus _bus;
|
|
||||||
|
|
||||||
private Vector3 _cameraPosition = new Vector3(0.0f, 0.0f, -3.0f);
|
private Vector3 _cameraPosition = new Vector3(0.0f, 0.0f, -3.0f);
|
||||||
private Vector3 _cameraFront = new Vector3(0.0f, 0.0f, -1.0f);
|
private Vector3 _cameraFront = new Vector3(0.0f, 0.0f, -1.0f);
|
||||||
@ -62,20 +61,31 @@ namespace TheLabs
|
|||||||
//GL.Disable(EnableCap.CullFace);
|
//GL.Disable(EnableCap.CullFace);
|
||||||
|
|
||||||
//GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
|
//GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
|
||||||
// Set The background color to a nice blue.
|
|
||||||
GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
||||||
GL.Enable(EnableCap.DepthTest);
|
GL.Enable(EnableCap.DepthTest);
|
||||||
_camera = new Camera(_cameraPosition, _cameraFront, _cameraUp);
|
_camera = new Camera(_cameraPosition, _cameraFront, _cameraUp);
|
||||||
|
_shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag");
|
||||||
|
_texture = new Texture("Textures/texture-a.png");
|
||||||
|
|
||||||
|
_rootNode = new SceneNode();
|
||||||
|
_exampleObject = ModelLoader.LoadMesh("Objects/cat.obj");
|
||||||
|
_buildingObject = ModelLoader.LoadMesh("Objects/building1.obj");
|
||||||
|
_render = new RenderObject(_exampleObject, _shader, _texture);
|
||||||
|
_buildingRender = new RenderObject(_buildingObject, _shader, _texture);
|
||||||
|
|
||||||
|
_characterNode = new SceneNode(_render);
|
||||||
|
_characterNode.Position = new Vector3(0.0f, -1.0f, 0.0f);
|
||||||
|
_rootNode.AddChild(_characterNode);
|
||||||
|
|
||||||
|
_buildingNode = new SceneNode(_buildingRender);
|
||||||
|
_buildingNode.Position = new Vector3(2.0f, -1.0f, 0.0f);
|
||||||
|
_rootNode.AddChild(_buildingNode);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CursorState = CursorState.Grabbed;
|
CursorState = CursorState.Grabbed;
|
||||||
|
|
||||||
_shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag");
|
|
||||||
_cubeTexture = new Texture("Textures/placeholder.png");
|
|
||||||
_cubeTexture2 = new Texture("Textures/placeholder.png");
|
|
||||||
|
|
||||||
_bus = new Bus(_cubeTexture, _shader);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -105,9 +115,8 @@ namespace TheLabs
|
|||||||
0.1f,
|
0.1f,
|
||||||
100.0f
|
100.0f
|
||||||
);
|
);
|
||||||
|
|
||||||
// --- Draw Scene Objects ---
|
// --- Draw Scene Objects ---
|
||||||
_bus.DrawBus(view, projection);
|
_rootNode.Draw(view, projection, Matrix4.Identity);
|
||||||
|
|
||||||
SwapBuffers();
|
SwapBuffers();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ public class RenderObject
|
|||||||
Shader.Use();
|
Shader.Use();
|
||||||
Shader.SetInt("uTexture", 0);
|
Shader.SetInt("uTexture", 0);
|
||||||
// 2. Bind Texture
|
// 2. Bind Texture
|
||||||
Texture.Use(); // Assumes you have a Texture class
|
Texture.Use();
|
||||||
// 3. Calculate Model Matrix
|
// 3. Calculate Model Matrix
|
||||||
Matrix4 model = Matrix4.CreateScale(Scale) * Matrix4.CreateFromQuaternion(Rotation) * Matrix4.CreateTranslation(Position);
|
Matrix4 model = Matrix4.CreateScale(Scale) * Matrix4.CreateFromQuaternion(Rotation) * Matrix4.CreateTranslation(Position);
|
||||||
int modelLoc = GL.GetUniformLocation(Shader.Handle, "model");
|
int modelLoc = GL.GetUniformLocation(Shader.Handle, "model");
|
||||||
|
|||||||
45
TheRepo/TheLabs/SceneNode.cs
Normal file
45
TheRepo/TheLabs/SceneNode.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using OpenTK.Mathematics;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace TheLabs;
|
||||||
|
|
||||||
|
public class SceneNode
|
||||||
|
{
|
||||||
|
public RenderObject? RenderObject;
|
||||||
|
|
||||||
|
public List<SceneNode> Children = new List<SceneNode>();
|
||||||
|
|
||||||
|
public Vector3 Position = Vector3.Zero;
|
||||||
|
public Quaternion Rotation = Quaternion.Identity;
|
||||||
|
public Vector3 Scale = Vector3.One;
|
||||||
|
|
||||||
|
public SceneNode(RenderObject? renderObject = null)
|
||||||
|
{
|
||||||
|
RenderObject = renderObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddChild(SceneNode child)
|
||||||
|
{
|
||||||
|
Children.Add(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(Matrix4 view, Matrix4 projection, Matrix4 parentTransform)
|
||||||
|
{
|
||||||
|
Matrix4 localTransform = Matrix4.CreateScale(Scale) * Matrix4.CreateFromQuaternion(Rotation) * Matrix4.CreateTranslation(Position);
|
||||||
|
Matrix4 globalTransform = localTransform * parentTransform;
|
||||||
|
|
||||||
|
if (RenderObject != null)
|
||||||
|
{
|
||||||
|
RenderObject.Position = Vector3.Zero;
|
||||||
|
RenderObject.Rotation = Quaternion.Identity;
|
||||||
|
RenderObject.Scale = Vector3.One;
|
||||||
|
|
||||||
|
RenderObject.Draw(view, projection);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in Children)
|
||||||
|
{
|
||||||
|
child.Draw(view, projection, globalTransform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,85 +5,70 @@ namespace TheLabs.Shapes;
|
|||||||
|
|
||||||
public class Bus
|
public class Bus
|
||||||
{
|
{
|
||||||
|
public SceneNode MainNode;
|
||||||
|
|
||||||
private Mesh _wheelMesh;
|
private Mesh _wheelMesh;
|
||||||
private RenderObject _wheelObject;
|
private Mesh _bodyMesh;
|
||||||
|
private Mesh _roofMesh;
|
||||||
|
|
||||||
private Texture _wheelTexture;
|
|
||||||
private Shader _wheelShader;
|
|
||||||
private Texture _bodyTexture;
|
|
||||||
|
|
||||||
public Bus(Texture texture, Shader shader)
|
public Bus(Texture wheelTexture,Texture bodyTexture, Shader shader)
|
||||||
{
|
{
|
||||||
_wheelTexture = new Texture("Textures/rubber.jpg");
|
|
||||||
_wheelShader = shader;
|
|
||||||
|
|
||||||
_bodyTexture = new Texture("Textures/rust.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DrawWheel(Matrix4 view, Matrix4 projection, Vector3 position)
|
|
||||||
{
|
|
||||||
Matrix4 localTransform = Matrix4.Identity;
|
|
||||||
//Matrix4 comboTransform = localTransform * _wheelObject.Transform;
|
|
||||||
|
|
||||||
_wheelMesh = ShapeFactory.CreateTexturedCylinder();
|
_wheelMesh = ShapeFactory.CreateTexturedCylinder();
|
||||||
_wheelObject = new RenderObject(_wheelMesh, _wheelShader, _wheelTexture);
|
_bodyMesh = ShapeFactory.CreateTexturedCube();
|
||||||
|
_roofMesh = ShapeFactory.CreateTexturedCylinder();
|
||||||
|
|
||||||
// Front Left Wheel
|
MainNode = new SceneNode();
|
||||||
_wheelObject.Position = new Vector3(position);
|
|
||||||
_wheelObject.Scale = new Vector3(0.3f, 0.1f, 0.2f);
|
|
||||||
_wheelObject.Rotation = Quaternion.FromAxisAngle(Vector3.UnitX, MathHelper.DegreesToRadians(90.0f));
|
|
||||||
|
|
||||||
_wheelObject.Draw(view, projection);
|
// Building the body
|
||||||
|
var bodyObj = new RenderObject(_bodyMesh, shader, bodyTexture);
|
||||||
|
var bodyNode = new SceneNode(bodyObj);
|
||||||
|
bodyNode.Scale = new Vector3(1.5f, 0.5f, 0.5f);
|
||||||
|
bodyNode.Scale = new Vector3(0.0f, 0.0f, 0.0f);
|
||||||
|
MainNode.AddChild(bodyNode);
|
||||||
|
|
||||||
}
|
// Building the body
|
||||||
|
var roofObj = new RenderObject(_roofMesh, shader, bodyTexture);
|
||||||
|
var roofNode = new SceneNode(roofObj);
|
||||||
|
roofNode.Position = new Vector3(0.0f, 0.25f, 0.0f);
|
||||||
|
roofNode.Scale = new Vector3(0.5f, 1.5f, .25f);
|
||||||
|
roofNode.Rotation = Quaternion.FromAxisAngle(Vector3.UnitY, MathHelper.DegreesToRadians(90.0f));
|
||||||
|
roofNode.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitX, MathHelper.DegreesToRadians(90.0f));
|
||||||
|
MainNode.AddChild(roofNode);
|
||||||
|
|
||||||
public void drawBody(Matrix4 view, Matrix4 projection)
|
// Building the wheels
|
||||||
{
|
|
||||||
Mesh bodyMesh = ShapeFactory.CreateTexturedCube();
|
|
||||||
RenderObject bodyObject = new RenderObject(bodyMesh, _wheelShader, _bodyTexture);
|
|
||||||
|
|
||||||
bodyObject.Position = new Vector3(0.0f, 0.0f, 0.0f);
|
|
||||||
bodyObject.Scale = new Vector3(1.5f, 0.5f, 0.5f);
|
|
||||||
|
|
||||||
bodyObject.Draw(view, projection);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawRoof(Matrix4 view, Matrix4 projection)
|
|
||||||
{
|
|
||||||
Mesh roofMesh = ShapeFactory.CreateTexturedCylinder();
|
|
||||||
RenderObject roofObject = new RenderObject(roofMesh, _wheelShader, _bodyTexture);
|
|
||||||
|
|
||||||
roofObject.Position = new Vector3(0.0f, 0.25f, 0.0f);
|
|
||||||
roofObject.Scale = new Vector3(0.5f, 1.5f, .25f);
|
|
||||||
|
|
||||||
roofObject.Rotation = Quaternion.FromAxisAngle(Vector3.UnitY, MathHelper.DegreesToRadians(90.0f));
|
|
||||||
roofObject.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitX, MathHelper.DegreesToRadians(90.0f));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
roofObject.Draw(view, projection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DrawBus(Matrix4 view, Matrix4 projection)
|
|
||||||
{
|
|
||||||
// Drawing 4 wheels
|
|
||||||
float xOffset = 0.4f; // Reduced to bring wheels closer to the body
|
float xOffset = 0.4f; // Reduced to bring wheels closer to the body
|
||||||
float zOffset = 0.28f; // Reduced to bring front and back wheels closer
|
float zOffset = 0.28f; // Reduced to bring front and back wheels closer
|
||||||
float yOffset = -0.3f; // Adjusted to ensure wheels touch the body
|
float yOffset = -0.3f; // Adjusted to ensure wheels touch the body
|
||||||
|
|
||||||
// Drawing 4 wheels
|
Vector3[] wheelPositions =
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
{
|
||||||
float xPosition = (i % 2 == 0) ? -xOffset : xOffset; // Left or Right
|
new Vector3(-xOffset, yOffset, zOffset), // Front Left
|
||||||
float zPosition = (i < 2) ? zOffset : -zOffset; // Front or Back
|
new Vector3(xOffset, yOffset, zOffset), // Front Right
|
||||||
|
new Vector3(-xOffset, yOffset, -zOffset), // Back Left
|
||||||
|
new Vector3(xOffset, yOffset, -zOffset) // Back Right
|
||||||
|
};
|
||||||
|
|
||||||
DrawWheel(view, projection, new Vector3(xPosition, yOffset, zPosition));
|
foreach (var pos in wheelPositions)
|
||||||
|
{
|
||||||
|
var wheelObj = new RenderObject(_wheelMesh, shader, wheelTexture);
|
||||||
|
var wheelNode = new SceneNode(wheelObj);
|
||||||
|
|
||||||
|
wheelNode.Position = pos; // Relative to the MainNode!
|
||||||
|
wheelNode.Scale = new Vector3(0.3f, 0.1f, 0.2f);
|
||||||
|
// Rotate cylinder to act like a wheel
|
||||||
|
wheelNode.Rotation = Quaternion.FromAxisAngle(Vector3.UnitX, MathHelper.DegreesToRadians(90.0f));
|
||||||
|
|
||||||
|
MainNode.AddChild(wheelNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drawing the body
|
}
|
||||||
drawBody(view, projection);
|
|
||||||
// Drawing the roof
|
|
||||||
drawRoof(view, projection);
|
public void Draw(Matrix4 view, Matrix4 projection)
|
||||||
|
{
|
||||||
|
MainNode.Draw(view, projection, Matrix4.Identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,6 @@ public class Texture : IDisposable
|
|||||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||||
|
|
||||||
// --- Set texture parameters ---
|
// --- Set texture parameters ---
|
||||||
// Repeat the texture if UVs go outside [0, 1]
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AssimpNet" Version="5.0.0-beta1" />
|
||||||
<PackageReference Include="OpenTK" Version="4.8.2" />
|
<PackageReference Include="OpenTK" Version="4.8.2" />
|
||||||
<PackageReference Include="StbImageSharp" Version="2.30.15" />
|
<PackageReference Include="StbImageSharp" Version="2.30.15" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AssimpNet" Version="5.0.0-beta1" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user