Creating Cube Object

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:

Drawing Cube OpenGL

We have to find the necessary indices for each faces:

Faces of the cube
Front face:       7-6-2 , 7-2-3
Back 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:
Cube
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:
Cube Depth Test


No comments:

Post a Comment