Finally, we will be able to make a three-dimensional drawing with this post. I'm going to draw cube.
Firstly, we have to think the coordinates of the cube vertices in the three-dimensional space. The origin of the cube must be (x:0,y:0,z:0). According to this information, we have to calculate the position of the 8 vertices:
We have to find the necessary indices for each faces:
Front face: 7-6-2 , 7-2-3Back face: 4-5-1 , 4-1-0
Top face: 4-5-6 , 4-6-7
Bottom face: 0-1-2 , 0-2-3
Right face: 6-5-1 , 6-1-2
Left face: 7-4-0 , 7-0-3
I'm going to add a new method called GenerateCube for Cube in Mesh class:
public Mesh(ObjectType objType)
{
if(objType is ObjectType.Quad2D) GenerateQuad();
if(objType is ObjectType.Cube) GenerateCube();
}
...
private void GenerateCube()
{
float len = 1.0f;
// colors
var (c0r, c0b, c0g, c0a) = (0.1f, 0.5f, 0.1f, 1.0f);
var (c1r, c1b, c1g, c1a) = (0.1f, 0.5f, 0.6f, 1.0f);
var (c2r, c2b, c2g, c2a) = (0.3f, 0.8f, 0.2f, 1.0f);
var (c3r, c3b, c3g, c3a) = (0.1f, 0.3f, 0.1f, 1.0f);
var (c4r, c4b, c4g, c4a) = (0.4f, 0.5f, 0.1f, 1.0f);
var (c5r, c5b, c5g, c5a) = (0.5f, 0.2f, 0.3f, 1.0f);
var (c6r, c6b, c6g, c6a) = (0.1f, 0.2f, 0.4f, 1.0f);
var (c7r, c7b, c7g, c7a) = (0.7f, 0.5f, 0.5f, 1.0f);
float[] vertices =
{
-len, -len, -len, c0r, c0b, c0g, c0a, // 0
len, -len, -len, c1r, c1b, c1g, c1a, // 1
len, -len, len, c2r, c2b, c2g, c2a, // 2
-len, -len, len, c3r, c3b, c3g, c3a, // 3
-len, len, -len, c4r, c4b, c4g, c4a, // 4
len, len, -len, c5r, c5b, c5g, c5a, // 5
len, len, len, c6r, c6b, c6g, c6a, // 6
-len, len, len, c7r, c7b, c7g, c7a // 7
};
int[] indices =
{
7, 6, 2, 7, 2, 3, // front face
4, 5, 1, 4, 1, 0, // back face
4, 5, 6, 4, 6, 7, // top face
0, 1, 2, 0, 2, 3, // bottom face
6, 5, 1, 6, 1, 2, // right face
7, 4, 0, 7, 0, 3 // left face
};
indexCount = 36;
GenerateVAOforCube(len, vertices, indices);
}
...
private void GenerateVAOforCube(float len, float[] vertices, int[] indices)
{
GL.GenVertexArrays(1, out vao);
GL.BindVertexArray(vao);
// create vbo to store the data in opengl and copy data to vbo
GL.GenBuffers(1, out vbo);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, sizeof(float) * vertices.Length, vertices, BufferUsageHint.StaticDraw);
// create ebo
GL.GenBuffers(1, out ebo);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ebo);
GL.BufferData(BufferTarget.ElementArrayBuffer, sizeof(int) * indices.Length, indices, BufferUsageHint.StaticDraw);
// tell opengl how to use the data via attributes
// position attribute
// int attrPosition_Position = GL.GetAttribLocation(shader.ShaderProgram, "aPos");
int attrPosition_Position = 0;
GL.EnableVertexAttribArray(attrPosition_Position);
GL.VertexAttribPointer(attrPosition_Position, 3, VertexAttribPointerType.Float, false, sizeof(float) * 7, 0);
int attrPosition_Color = 1;
GL.EnableVertexAttribArray(attrPosition_Color);
GL.VertexAttribPointer(attrPosition_Color, 4, VertexAttribPointerType.Float, false, sizeof(float) * 7, sizeof(float) * 3);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindVertexArray(0);
}
}
I created new folder named cube in shaders. The vertex shader:
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec4 aColor;
uniform mat4 uTransform;
uniform mat4 projection;
uniform mat4 view;
out vec4 passColor;
void main()
{
gl_Position = vec4(aPos, 1.0) * uTransform * view * projection;
passColor = aColor;
}
The fragment shader:
#version 330 core
in vec4 passColor;
out vec4 FragColor;
// uniform sampler2D textureSampler;
void main()
{
FragColor = passColor;
}
I updated CreateShader method in the ShaderManager class:
...
public void CreateShader(ObjectType objectType)
{
if(!Shaders.ContainsKey(objectType))
{
if(objectType == ObjectType.Quad2D)
{
Shader shader = new Shader("shaders/triangle/vertexShader.glsl","shaders/triangle/fragmentShader.glsl");
shaders[objectType] = shader;
}
if(objectType == ObjectType.Cube)
{
Shader shader = new Shader("shaders/cube/vertexShader.glsl","shaders/cube/fragmentShader.glsl");
shaders[objectType] = shader;
}
}
}
}
Finally, we can add a new cube to program:
...
private void InitScene()
{
...
objectManager.AddObject(ObjectType.Cube);
camera = new Camera(shaderManager, 45f, 1024, 768, 0.1f, 100f);
// camera.Position = new Vector3(15f,0f,1f);
}
Let's look at the result:
That's works but there is a problem. At this moment, we need to activate depth buffer, and also we have clear it in every frame. I updated RenderManager class as follows:
...
public RenderManager(ObjectManager objectManager)
{
this.objectManager = objectManager;
GL.Enable(EnableCap.DepthTest);
}
private void Clear()
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
}
...
}
}
Probably, it will not work because we are using SFML for window. Therefore we need to set some settings of SFML Window:
public Window(VideoMode mode, string title, ContextSettings settings) : base(mode, title, SFML.Window.Styles.Default, settings)
{
InitWindowSettings();
}
Configure the window in App class like below:
public App()
{
SFML.Window.ContextSettings settings = new ContextSettings();
settings.DepthBits = 24;
window = new Window(new VideoMode(1024, 768), "OpenTK Test", settings);
...
That should be fine:
No comments:
Post a Comment