c++openglglm-mathvertices

How to make the base of a cylinder with shaders in OpenGL


I am trying make a cylinder with using vertices and indices in OpenGL. I am still trying to build the base of a cylinder using triangles and cosine and sine functions and render it. But for some reason, it came out as one big triangle made up of two triangles. Can someone help me figure the right coordinates for the base of a cylinder? Or even better, the coordinates a whole cylinder. Here is my code:

#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <iostream>

// GLM library 
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

using namespace std;

int width, height;
const double PI = 3.14159;
const float toRadians = PI / 180.0f;

// Draw Primitive(s)
void draw() {
    GLenum mode = GL_TRIANGLES;

    GLsizei indices = 6;

    glDrawElements(mode, indices, GL_UNSIGNED_BYTE, nullptr);
}

// Create and Compile Shaders
static GLuint CompileShader(const string& source, GLuint shaderType) {

    // Create Shader Object
    GLuint shaderID = glCreateShader(shaderType);
    const char* src = source.c_str();

    // Attach source code to Shader object
    glShaderSource(shaderID, 1, &src, nullptr);

    // Compile Shader
    glCompileShader(shaderID);

    // Return ID of Compiled shader
    return shaderID;
}

// Create Program Object
static GLuint CreateShaderProgram(const string& vertexShader, const string& fragmentShader) {

    // Compile vertex shader
    GLuint vertexShaderComp = CompileShader(vertexShader, GL_VERTEX_SHADER);

    // Compile fragment shader
    GLuint fragmentShaderComp = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    // Create program object
    GLuint shaderProgram = glCreateProgram();

    // Attch vertex and fragment shaders to program object
    glAttachShader(shaderProgram, vertexShaderComp);
    glAttachShader(shaderProgram, fragmentShaderComp);

    // Link shaders to create executable
    glLinkProgram(shaderProgram);

    // Delete compiled vertex and fragment shaders
    glDeleteShader(vertexShaderComp);
    glDeleteShader(fragmentShaderComp);

    // Return Shader Program
    return shaderProgram;
}

int main(void) {

    width = 640; height = 480;

    GLFWwindow* window;

    // Initialize the library
    if (!glfwInit())
        return -1;

    // Create a windowed mode window and its OpenGL context
    window = glfwCreateWindow(width, height, "Main Window", NULL, NULL);
    if (!window) {
        glfwTerminate();
        return -1;
    }

    // Make the window's context current
    glfwMakeContextCurrent(window);

    // Initialize GLEW
    if (glewInit() != GLEW_OK)
        cout << "Error!" << endl;

    GLfloat vertices[] = {

        // Triangle One
        0.0, 0.0, 0.0, // vert 0
        1.0, 0.0, 0.0,  // red

        cos(60), sin(60), 0.0, // vert 1
        0.0, 1.0, 0.0,  // green

        cos(60), -sin(60), 0.0,  // vert 2
        0.0, 0.0, 1.0,  // blue

        // Part of Triangle Two
        -cos(60), -sin(60), 0.0,  // vert 3
        1.0, 0.0, 1.0,  // purple

        // Part of Triangle Three
        -cos(60), -sin(60), 0.0, // vert 4
        0.0, 1.0, 0.0, // green

        // Part of Triangle Four
        -cos(60), sin(60), 0.0, // vert 5
        0.0, 0.0, 1.0, // blue

        // Part of Triangle Five
        -cos(60), sin(60), 0.0, // vert 6
        1.0, 0.0, 1.0, // purple

        // Part of Triangle Six
        -cos(60), sin(60), 0.0, // vert 7
        0.0, 1.0, 0.0  // green

    };

    // Define element indices 
    GLubyte indices[] = {
        0,1,2,
        0,2,3,
        0,3,4,
        0,4,5,
        0,5,6,
        0,6,7
        
    };

    // Enable Depth Buffer
    glEnable(GL_DEPTH_TEST);

    // Wireframe mode
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    GLuint VBO, EBO, VAO;

    glGenBuffers(1, &VBO); // Create VBO and returns ID
    glGenBuffers(1, &EBO); // Create EBO

    glGenVertexArrays(1, &VAO); // Create VAO
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO); // Select VBO and activate buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Select EBO

    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // Load vertex attributes
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // Load indices attributes

    // Specify attributes location and layout to GPU
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    // Color attribute location and layout
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glBindVertexArray(0);

    // Vertex shader source code
    string vertexShaderSource =
        "#version 330 core\n"
        "layout(location = 0) in vec4 vPosition;"
        "layout(location = 1) in vec4 aColor;"
        "out vec4 oColor;"
        "uniform mat4 model;"
        "uniform mat4 view;"
        "uniform mat4 projection;"
        "void main()\n"
        "{\n"
        "gl_Position = projection * view * model * vPosition;"
        "oColor = aColor;"
        "}\n";

    // Fragment shader source code
    string fragmentShaderSource =
        "#version 330 core\n"
        "in vec4 oColor;"
        "out vec4 fragColor;"
        "void main()\n"
        "{\n"
        "fragColor = oColor;"
        "}\n";

    // Creating Shader Program
    GLuint shaderProgram = CreateShaderProgram(vertexShaderSource, fragmentShaderSource);

    while (!glfwWindowShouldClose(window)) {

        // Resize window and graphics simultaneously
        glfwGetFramebufferSize(window, &width, &height);
        glViewport(0, 0, width, height);

        // Render here
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Use Shader Program exe and select VAO before drawing
        glUseProgram(shaderProgram); // Call Shader per-frame when updating attributes

        // Declare identity matrix 

        glm::mat4 viewMatrix(1.0f);
        glm::mat4 projectionMatrix(1.0f);

        // Initialize transforms

        //modelMatrix = glm::scale(modelMatrix, glm::vec3(1.0f, 1.0f, 1.0f));

        viewMatrix = glm::translate(viewMatrix, glm::vec3(0.0f, 0.0f, -3.0f));
        viewMatrix = glm::rotate(viewMatrix, 45.0f * toRadians, glm::vec3(1.0f, 0.0f, 0.0f));

        projectionMatrix = glm::perspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);

        // Select uniform shader and variable
        GLuint modelLoc = glGetUniformLocation(shaderProgram, "model");
        GLuint viewLoc = glGetUniformLocation(shaderProgram, "view");
        GLuint projectionLoc = glGetUniformLocation(shaderProgram, "projection");

        // Pass transform to Shader

        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix));
        glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix));

        glBindVertexArray(VAO); // User-defined VAO must be called before draw

        for (GLuint i = 0; i < 4; i++) {

            glm::mat4 modelMatrix(1.0f);

            glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix));

            // Draw primitive(s)
            draw();

        }

        // Unbind Shader exe and VOA after drawing per frame
        glBindVertexArray(0); // In case different VAO will be used after
        glUseProgram(0); // In case different shader will be used after

        glBindVertexArray(VAO);

        // Swap front and back buffers
        glfwSwapBuffers(window);

        // Poll for and process events
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

Solution

  • The unit of glm::perspectives filed of view argument is radian, but not degree. You can use glm::radians to convert from degree to radian:

    projectionMatrix = glm::perspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);

    projectionMatrix = glm::perspective(glm::radians(45.0f), (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
    

    The unit of cos and sin is radians, but not degrees. You must increment the angle for each vertex because you want to calculate the points around the circle:

    GLfloat vertices[] = {
        0.0,                  0.0,                  0.0, 1.0, 0.0, 0.0,
        cos(  0 * toRadians), sin(  0 * toRadians), 0.0, 0.0, 1.0, 0.0, 
        cos( 60 * toRadians), sin( 60 * toRadians), 0.0, 0.0, 0.0, 1.0, 
        cos(120 * toRadians), sin(120 * toRadians), 0.0, 1.0, 0.0, 1.0, 
        cos(180 * toRadians), sin(180 * toRadians), 0.0, 0.0, 1.0, 0.0, 
        cos(240 * toRadians), sin(240 * toRadians), 0.0, 0.0, 0.0, 1.0, 
        cos(300 * toRadians), sin(300 * toRadians), 0.0, 1.0, 0.0, 1.0,
        cos(360 * toRadians), sin(360 * toRadians), 0.0, 0.0, 1.0, 0.0
    };
    

    Of course you have to draw all the tringles. The number of indices therefore is 18, but not 6:

    void draw() {
        GLenum mode = GL_TRIANGLES;
        GLsizei indices = 18;
        glDrawElements(mode, indices, GL_UNSIGNED_BYTE, nullptr);
    }