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
Added circle and cube
This commit is contained in:
parent
83d2311ff5
commit
825bdb0b59
@ -3,6 +3,8 @@ using OpenTK.Windowing.Common;
|
||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
using LearnOpenTK.Common;
|
||||
using OpenTK.Mathematics;
|
||||
using TheLabs.Shapes;
|
||||
|
||||
namespace TheLabs
|
||||
{
|
||||
@ -19,20 +21,23 @@ namespace TheLabs
|
||||
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // Bottom-right vertex
|
||||
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, // Top vertex
|
||||
};
|
||||
|
||||
private readonly float[] _quadvertices =
|
||||
{
|
||||
// x, y, z
|
||||
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Bottom-left vertex
|
||||
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Bottom-right vertex
|
||||
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top vertex
|
||||
|
||||
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Bottom-left vertex
|
||||
0.0f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Bottom-right vertex
|
||||
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top vertex
|
||||
};
|
||||
|
||||
// These are the handles to OpenGL objects. A handle is an integer representing where the object lives on the
|
||||
// graphics card. Consider them sort of like a pointer; we can't do anything with them directly, but we can
|
||||
// send them to OpenGL functions that need them.
|
||||
|
||||
// What these objects are will be explained in OnLoad.
|
||||
private int _vertexBufferObject;
|
||||
|
||||
private int _vertexArrayObject;
|
||||
|
||||
// This class is a wrapper around a shader, which helps us manage it.
|
||||
// The shader class's code is in the Common project.
|
||||
// What shaders are and what they're used for will be explained later in this tutorial.
|
||||
private Cube _cube;
|
||||
private Circle _circle;
|
||||
private Shader _shader;
|
||||
private float _rotation;
|
||||
|
||||
public MyExampleWindow(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings)
|
||||
: base(gameWindowSettings, nativeWindowSettings)
|
||||
@ -41,127 +46,57 @@ namespace TheLabs
|
||||
|
||||
// Now, we start initializing OpenGL.
|
||||
protected override void OnLoad()
|
||||
{
|
||||
{
|
||||
// This is called when the window is created and is where we can set up OpenGL resources.
|
||||
base.OnLoad();
|
||||
|
||||
// This will be the color of the background after we clear it, in normalized colors.
|
||||
// Normalized colors are mapped on a range of 0.0 to 1.0, with 0.0 representing black, and 1.0 representing
|
||||
// the largest possible value for that channel.
|
||||
// This is a deep green.
|
||||
GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
||||
|
||||
// We need to send our vertices over to the graphics card so OpenGL can use them.
|
||||
// To do this, we need to create what's called a Vertex Buffer Object (VBO).
|
||||
// These allow you to upload a bunch of data to a buffer, and send the buffer to the graphics card.
|
||||
// This effectively sends all the vertices at the same time.
|
||||
|
||||
// First, we need to create a buffer. This function returns a handle to it, but as of right now, it's empty.
|
||||
_vertexBufferObject = GL.GenBuffer();
|
||||
|
||||
// Now, bind the buffer. OpenGL uses one global state, so after calling this,
|
||||
// all future calls that modify the VBO will be applied to this buffer until another buffer is bound instead.
|
||||
// The first argument is an enum, specifying what type of buffer we're binding. A VBO is an ArrayBuffer.
|
||||
// There are multiple types of buffers, but for now, only the VBO is necessary.
|
||||
// The second argument is the handle to our buffer.
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferObject);
|
||||
|
||||
// Finally, upload the vertices to the buffer.
|
||||
// Arguments:
|
||||
// Which buffer the data should be sent to.
|
||||
// How much data is being sent, in bytes. You can generally set this to the length of your array, multiplied by sizeof(array type).
|
||||
// The vertices themselves.
|
||||
// How the buffer will be used, so that OpenGL can write the data to the proper memory space on the GPU.
|
||||
// There are three different BufferUsageHints for drawing:
|
||||
// StaticDraw: This buffer will rarely, if ever, update after being initially uploaded.
|
||||
// DynamicDraw: This buffer will change frequently after being initially uploaded.
|
||||
// StreamDraw: This buffer will change on every frame.
|
||||
// Writing to the proper memory space is important! Generally, you'll only want StaticDraw,
|
||||
// but be sure to use the right one for your use case.
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, _vertices.Length * sizeof(float), _vertices, BufferUsageHint.StaticDraw);
|
||||
|
||||
// One notable thing about the buffer we just loaded data into is that it doesn't have any structure to it. It's just a bunch of floats (which are actaully just bytes).
|
||||
// The opengl driver doesn't know how this data should be interpreted or how it should be divided up into vertices. To do this opengl introduces the idea of a
|
||||
// Vertex Array Obejct (VAO) which has the job of keeping track of what parts or what buffers correspond to what data. In this example we want to set our VAO up so that
|
||||
// it tells opengl that we want to interpret 12 bytes as 3 floats and divide the buffer into vertices using that.
|
||||
// To do this we generate and bind a VAO (which looks deceptivly similar to creating and binding a VBO, but they are different!).
|
||||
_vertexArrayObject = GL.GenVertexArray();
|
||||
GL.BindVertexArray(_vertexArrayObject);
|
||||
|
||||
// Now, we need to setup how the vertex shader will interpret the VBO data; you can send almost any C datatype (and a few non-C ones too) to it.
|
||||
// While this makes them incredibly flexible, it means we have to specify how that data will be mapped to the shader's input variables.
|
||||
|
||||
// To do this, we use the GL.VertexAttribPointer function
|
||||
// This function has two jobs, to tell opengl about the format of the data, but also to associate the current array buffer with the VAO.
|
||||
// This means that after this call, we have setup this attribute to source data from the current array buffer and interpret it in the way we specified.
|
||||
// Arguments:
|
||||
// Location of the input variable in the shader. the layout(location = 0) line in the vertex shader explicitly sets it to 0.
|
||||
// How many elements will be sent to the variable. In this case, 3 floats for every vertex.
|
||||
// The data type of the elements set, in this case float.
|
||||
// Whether or not the data should be converted to normalized device coordinates. In this case, false, because that's already done.
|
||||
// The stride; this is how many bytes are between the last element of one vertex and the first element of the next. 3 * sizeof(float) in this case.
|
||||
// The offset; this is how many bytes it should skip to find the first element of the first vertex. 0 as of right now.
|
||||
// Stride and Offset are just sort of glossed over for now, but when we get into texture coordinates they'll be shown in better detail.
|
||||
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 7 * sizeof(float), 0);
|
||||
GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, 7 * sizeof(float), 3 * sizeof(float));
|
||||
|
||||
// Enable variable 0 in the shader.
|
||||
GL.EnableVertexAttribArray(0);
|
||||
GL.EnableVertexAttribArray(1);
|
||||
|
||||
// We've got the vertices done, but how exactly should this be converted to pixels for the final image?
|
||||
// Modern OpenGL makes this pipeline very free, giving us a lot of freedom on how vertices are turned to pixels.
|
||||
// The drawback is that we actually need two more programs for this! These are called "shaders".
|
||||
// Shaders are tiny programs that live on the GPU. OpenGL uses them to handle the vertex-to-pixel pipeline.
|
||||
// Check out the Shader class in Common to see how we create our shaders, as well as a more in-depth explanation of how shaders work.
|
||||
// shader.vert and shader.frag contain the actual shader code.
|
||||
// Set The background color to a nice blue.
|
||||
GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
||||
// Enable depth buffering.
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
// Create and compile our shader program from the shader source files
|
||||
_shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag");
|
||||
|
||||
// Now, enable the shader.
|
||||
// Just like the VBO, this is global, so every function that uses a shader will modify this one until a new one is bound instead.
|
||||
// Create a cube
|
||||
_cube = new Cube();
|
||||
_circle = new Circle();
|
||||
// Use the shader program. This is similar to "activating" the shader program.
|
||||
_shader.Use();
|
||||
|
||||
// Setup is now complete! Now we move to the OnRenderFrame function to finally draw the triangle.
|
||||
|
||||
}
|
||||
|
||||
// Now that initialization is done, let's create our render loop.
|
||||
protected override void OnRenderFrame(FrameEventArgs e)
|
||||
{
|
||||
// This is called once per frame and is where all the rendering code goes.
|
||||
base.OnRenderFrame(e);
|
||||
|
||||
// This clears the image, using what you set as GL.ClearColor earlier.
|
||||
// OpenGL provides several different types of data that can be rendered.
|
||||
// You can clear multiple buffers by using multiple bit flags.
|
||||
// However, we only modify the color, so ColorBufferBit is all we need to clear.
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
|
||||
// To draw an object in OpenGL, it's typically as simple as binding your shader,
|
||||
// setting shader uniforms (not done here, will be shown in a future tutorial)
|
||||
// binding the VAO,
|
||||
// and then calling an OpenGL function to render.
|
||||
|
||||
// Bind the shader
|
||||
_shader.Use();
|
||||
|
||||
// Bind the VAO
|
||||
GL.BindVertexArray(_vertexArrayObject);
|
||||
|
||||
// And then call our drawing function.
|
||||
// For this tutorial, we'll use GL.DrawArrays, which is a very simple rendering function.
|
||||
// Arguments:
|
||||
// Primitive type; What sort of geometric primitive the vertices represent.
|
||||
// OpenGL used to support many different primitive types, but almost all of the ones still supported
|
||||
// is some variant of a triangle. Since we just want a single triangle, we use Triangles.
|
||||
// Starting index; this is just the start of the data you want to draw. 0 here.
|
||||
// How many vertices you want to draw. 3 for a triangle.
|
||||
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
|
||||
|
||||
// OpenTK windows are what's known as "double-buffered". In essence, the window manages two buffers.
|
||||
// One is rendered to while the other is currently displayed by the window.
|
||||
// This avoids screen tearing, a visual artifact that can happen if the buffer is modified while being displayed.
|
||||
// After drawing, call this function to swap the buffers. If you don't, it won't display what you've rendered.
|
||||
// Clear the color buffer and the depth buffer
|
||||
GL.Clear(ClearBufferMask.DepthBufferBit | ClearBufferMask.ColorBufferBit);
|
||||
|
||||
// Update the rotation
|
||||
|
||||
// Create the model, view, and projection matrices
|
||||
Matrix4 model = Matrix4.CreateRotationY(_rotation) * Matrix4.CreateRotationX(_rotation * 0.5f);
|
||||
Matrix4 view = Matrix4.CreateTranslation(0.0f, 0.0f, -3.0f);
|
||||
Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView(
|
||||
MathHelper.DegreesToRadians(45f),
|
||||
Size.X / (float)Size.Y,
|
||||
0.1f,
|
||||
100.0f
|
||||
);
|
||||
// Set the matrices in the shader
|
||||
int modelLoc = GL.GetUniformLocation(_shader.Handle, "model");
|
||||
int viewLoc = GL.GetUniformLocation(_shader.Handle, "view");
|
||||
int projLoc = GL.GetUniformLocation(_shader.Handle, "projection");
|
||||
|
||||
// Send the matrices to the shader
|
||||
GL.UniformMatrix4(modelLoc, false, ref model);
|
||||
GL.UniformMatrix4(viewLoc, false, ref view);
|
||||
GL.UniformMatrix4(projLoc, false, ref projection);
|
||||
|
||||
// Draw the cube
|
||||
_cube.Draw(_shader, model);
|
||||
_circle.Draw(_shader, model);
|
||||
SwapBuffers();
|
||||
|
||||
// And that's all you have to do for rendering! You should now see a yellow triangle on a black screen.
|
||||
GL.GetError();
|
||||
}
|
||||
|
||||
protected override void OnUpdateFrame(FrameEventArgs e)
|
||||
@ -174,6 +109,13 @@ namespace TheLabs
|
||||
{
|
||||
Close();
|
||||
}
|
||||
if (input.IsKeyDown(Keys.R))
|
||||
{
|
||||
_rotation += 0.8f * (float)e.Time; // Update rotation only when the condition is met
|
||||
} else if (input.IsKeyDown(Keys.T))
|
||||
{
|
||||
_rotation -= 0.8f * (float)e.Time; // Update rotation only when the condition is met
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnResize(ResizeEventArgs e)
|
||||
@ -205,10 +147,6 @@ namespace TheLabs
|
||||
GL.BindVertexArray(0);
|
||||
GL.UseProgram(0);
|
||||
|
||||
// Delete all the resources.
|
||||
GL.DeleteBuffer(_vertexBufferObject);
|
||||
GL.DeleteVertexArray(_vertexArrayObject);
|
||||
|
||||
GL.DeleteProgram(_shader.Handle);
|
||||
|
||||
base.OnUnload();
|
||||
|
||||
@ -28,7 +28,9 @@
|
||||
layout(location = 0) in vec3 aPosition;
|
||||
layout(location = 1) in vec4 aColour;
|
||||
out vec4 outColour;
|
||||
|
||||
uniform mat4 model;
|
||||
uniform mat4 view;
|
||||
uniform mat4 projection;
|
||||
|
||||
// Like C, we have an entrypoint function. In this case, it takes void and returns void, and must be named main.
|
||||
// You can do all sorts of calculations here to modify your vertices, but right now, we don't need to do any of that.
|
||||
@ -40,5 +42,5 @@ out vec4 outColour;
|
||||
void main(void)
|
||||
{
|
||||
outColour = aColour;
|
||||
gl_Position = vec4(aPosition, 1.0);
|
||||
gl_Position = projection * view * model * vec4(aPosition, 1.0);
|
||||
}
|
||||
83
TheRepo/TheLabs/Shapes/Circle.cs
Normal file
83
TheRepo/TheLabs/Shapes/Circle.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using LearnOpenTK.Common;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Mathematics;
|
||||
|
||||
namespace TheLabs.Shapes;
|
||||
|
||||
public class Circle
|
||||
{
|
||||
// Vertex Array Object, Vertex Buffer Object, Element Buffer Object
|
||||
private int _vao;
|
||||
private int _vbo;
|
||||
private int _ebo;
|
||||
private int _vertexCount;
|
||||
|
||||
private readonly float[] _vertices =
|
||||
{
|
||||
|
||||
|
||||
};
|
||||
private int _maxVert = 100;
|
||||
public Circle()
|
||||
{
|
||||
for (int i = 0; i <= _maxVert; i++)
|
||||
{
|
||||
|
||||
float angle = i * 2.0f * MathF.PI / _maxVert;
|
||||
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] = 0.0f;
|
||||
_vertices[^4] = 1f;
|
||||
_vertices[^3] = 0f;
|
||||
_vertices[^2] = 0f;
|
||||
_vertices[^1] = 1f;
|
||||
|
||||
}
|
||||
// The Vertex Array Object
|
||||
// This stores the confifuration of vertex atributes
|
||||
_vao = GL.GenVertexArray();
|
||||
// The Vertex Buffer Object
|
||||
// This stores the actual vertex data e.g. positions, colors, normals, texture coordinates
|
||||
_vbo = GL.GenBuffer();
|
||||
|
||||
// We bind the VAO
|
||||
GL.BindVertexArray(_vao);
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); // Specifying the type of buffer
|
||||
// Uploading the vertex data to the GPU
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, _vertices.Length * sizeof(float), _vertices, BufferUsageHint.StaticDraw);
|
||||
|
||||
// We tell opengl how to interpret the vertex data.
|
||||
// The Location 0 corresponds to the layout(location = 0) in the vertex shader
|
||||
// How many components (x, y, z) -> 3
|
||||
// Data type -> float
|
||||
// Not normalized
|
||||
// The Stride -> The total size of a vertex (in bytes)
|
||||
// The offset -> The position data starts at the beginning of the vertex data so 0
|
||||
var stride = 7 * sizeof(float);
|
||||
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
|
||||
GL.EnableVertexAttribArray(0);
|
||||
GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
|
||||
GL.EnableVertexAttribArray(1);
|
||||
|
||||
GL.BindVertexArray(0);
|
||||
}
|
||||
|
||||
public void Draw(Shader shader, Matrix4 matrix4)
|
||||
{
|
||||
shader.SetMatrix4("model", matrix4);
|
||||
GL.BindVertexArray(_vao);
|
||||
GL.DrawArrays(PrimitiveType.TriangleFan, 0, _vertices.Length / 7);
|
||||
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GL.DeleteBuffer(_vbo);
|
||||
GL.DeleteBuffer(_ebo);
|
||||
GL.DeleteVertexArray(_vao);
|
||||
}
|
||||
}
|
||||
113
TheRepo/TheLabs/Shapes/Cube.cs
Normal file
113
TheRepo/TheLabs/Shapes/Cube.cs
Normal file
@ -0,0 +1,113 @@
|
||||
using LearnOpenTK.Common;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Mathematics;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
|
||||
namespace TheLabs.Shapes;
|
||||
|
||||
public class Cube
|
||||
{
|
||||
// Vertex Array Object, Vertex Buffer Object, Element Buffer Object
|
||||
private int _vao;
|
||||
private int _vbo;
|
||||
private int _ebo;
|
||||
private int _vertexCount;
|
||||
|
||||
private readonly float[] _cubevertices =
|
||||
{
|
||||
// Position // Color (RGBA)
|
||||
// Front face (z = +0.5)
|
||||
-0.5f, -0.5f, 0.5f, 1f, 0f, 0f, 1f, // Bottom-left
|
||||
0.5f, -0.5f, 0.5f, 1f, 0f, 0f, 1f, // Bottom-right
|
||||
0.5f, 0.5f, 0.5f, 0f, 0f, 0f, 1f, // Top-right
|
||||
-0.5f, 0.5f, 0.5f, 1f, 0f, 0f, 1f, // Top-left
|
||||
|
||||
// Back face (z = -0.5)
|
||||
-0.5f, -0.5f, -0.5f, 1f, 0f, 1f, 1f, // Bottom-left
|
||||
0.5f, -0.5f, -0.5f, 0f, 1f, 1f, 1f, // Bottom-right
|
||||
0.5f, 0.5f, -0.5f, 1f, 1f, 1f, 1f, // Top-right
|
||||
-0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 1f // Top-left
|
||||
};
|
||||
private readonly uint[] _cubeIndices =
|
||||
{
|
||||
// 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
|
||||
};
|
||||
|
||||
public Cube()
|
||||
{
|
||||
// The number of vertices to draw
|
||||
_vertexCount = _cubeIndices.Length;
|
||||
// The Vertex Array Object
|
||||
// This stores the confifuration of vertex atributes
|
||||
_vao = GL.GenVertexArray();
|
||||
// The Vertex Buffer Object
|
||||
// This stores the actual vertex data e.g. positions, colors, normals, texture coordinates
|
||||
_vbo = GL.GenBuffer();
|
||||
// The Element Buffer Object, stores the indices for indexed drawing
|
||||
_ebo = GL.GenBuffer();
|
||||
|
||||
// We bind the VAO
|
||||
GL.BindVertexArray(_vao);
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); // Specifying the type of buffer
|
||||
// Uploading the vertex data to the GPU
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, _cubevertices.Length * sizeof(float), _cubevertices, BufferUsageHint.StaticDraw);
|
||||
|
||||
// Now we set up the EBO
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _ebo);
|
||||
// Uploading the index data to the GPU
|
||||
GL.BufferData(BufferTarget.ElementArrayBuffer, _cubeIndices.Length * sizeof(uint), _cubeIndices, BufferUsageHint.StaticDraw);
|
||||
|
||||
// We tell opengl how to interpret the vertex data.
|
||||
// The Location 0 corresponds to the layout(location = 0) in the vertex shader
|
||||
// How many components (x, y, z) -> 3
|
||||
// Data type -> float
|
||||
// Not normalized
|
||||
// The Stride -> The total size of a vertex (in bytes)
|
||||
// The offset -> The position data starts at the beginning of the vertex data so 0
|
||||
var stride = 7 * sizeof(float);
|
||||
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0);
|
||||
GL.EnableVertexAttribArray(0);
|
||||
GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float));
|
||||
GL.EnableVertexAttribArray(1);
|
||||
|
||||
GL.BindVertexArray(0);
|
||||
}
|
||||
|
||||
public void Draw(Shader shader, Matrix4 matrix4)
|
||||
{
|
||||
shader.SetMatrix4("model", matrix4);
|
||||
|
||||
GL.BindVertexArray(_vao);
|
||||
GL.DrawElements(PrimitiveType.Triangles, _cubeIndices.Length, DrawElementsType.UnsignedInt, 0);
|
||||
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GL.DeleteBuffer(_vbo);
|
||||
GL.DeleteBuffer(_ebo);
|
||||
GL.DeleteVertexArray(_vao);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user