Search code examples
openglglm-math

How do I get rid of the red line in my OpenGL circle


Here is the output of my program.

Here is my code

 #include <cstdio>      // for C++ i/o
#include <iostream>
using namespace std;    // to avoid having to use std::

#define GLEW_STATIC     // include GLEW as a static library
#include <GLEW/glew.h>  // include GLEW
#include <GLFW/glfw3.h> // include GLFW (which includes the OpenGL header)
#include <glm/glm.hpp>  // include GLM (ideally should only use the GLM headers that are actually used)
using namespace glm;    // to avoid having to use glm::

#include "shader.h"

#define PI 3.14159265
#define MAX_SLICES 32
#define MIN_SLICES 8
#define MAX_VERTICES (MAX_SLICES+2)*3   // a triangle fan should have a minimum of 3 vertices
#define CIRCLE_RADIUS 0.5
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600

// global variables
GLfloat g_vertices[MAX_VERTICES] = {
    0.0f, 0.0f, 0.0f,
    0.0f, 0.0f, 0.0f
};

GLuint g_slices = MAX_SLICES;   // number of circle slices

GLuint g_VBO = 0;               // identifiers
GLuint g_VAO = 0;           
GLuint g_shaderProgramID = 0;       

void generate_circle()
{
    float angle = PI*2 / static_cast<float>(g_slices);  // used to generate x and y coordinates
    float scale_factor = static_cast<float>(WINDOW_HEIGHT) / WINDOW_WIDTH;  // scale to make it a circle instead of an elipse
    int index = 0;  // vertex index

    g_vertices[3] = CIRCLE_RADIUS * scale_factor;   // set x coordinate of vertex 1

    // generate vertex coordinates for triangle fan
    for (int i = 2; i < g_slices+2; i++)
    {
        // multiply by 3 because a vertex has x, y, z coordinates
        index = i * 3;

        g_vertices[index] = CIRCLE_RADIUS * cos(angle) * scale_factor;
        g_vertices[index + 1] = CIRCLE_RADIUS * sin(angle);
        g_vertices[index + 2] = 0.0f;

        // update to next angle
        angle += PI*2 / static_cast<float>(g_slices);
    }
}

static void init()
{
    glClearColor(0.0, 0.0, 0.0, 1.0);   // set clear background colour

    // create and compile our GLSL program from the shader files
    g_shaderProgramID = loadShaders("SimpleVS.vert", "SimpleFS.frag");

    // generate vertices of triangle fan
    generate_circle();

    // create VBO and buffer the data
    glGenBuffers(1, &g_VBO);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*(g_slices + 2), g_vertices, GL_STATIC_DRAW);

    // create VAO and specify VBO data
    glGenVertexArrays(1, &g_VAO);
    glBindVertexArray(g_VAO);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);  // specify the form of the data

    glEnableVertexAttribArray(0);   // enable vertex attributes
}

// function used to render the scene
static void render_scene()
{
    glClear(GL_COLOR_BUFFER_BIT);   // clear colour buffer

    glUseProgram(g_shaderProgramID);    // use the shaders associated with the shader program

    glBindVertexArray(g_VAO);           // make VAO active
    glDrawArrays(GL_LINE_LOOP, 0, g_slices+2);  // display the vertices based on the primitive type

    glFlush();  // flush the pipeline
}

int main(void)
{
    GLFWwindow* window = NULL;  // pointer to a GLFW window handle

    glfwSetErrorCallback(error_callback);   // set error callback function

    // initialise GLFW
    if(!glfwInit()) 
    {
        // if failed to initialise GLFW
        exit(EXIT_FAILURE);
    }

    // minimum OpenGL version 3.3
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

    // create a window and its OpenGL context
    window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "DemoCode", NULL, NULL);

    // if failed to create window
    if(window == NULL)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwMakeContextCurrent(window); // set window context as the current context
    glfwSwapInterval(1);            // swap buffer interval

    // initialise GLEW
    if(glewInit() != GLEW_OK) 
    {
        // if failed to initialise GLEW
        cerr << "GLEW initialisation failed" << endl;
        exit(EXIT_FAILURE);
    }

    // set key callback function
    glfwSetKeyCallback(window, key_callback);

    // initialise rendering states
    init();

    // the rendering loop
    while(!glfwWindowShouldClose(window))
    {
        render_scene();             // render the scene

        glfwSwapBuffers(window);    // swap buffers
        glfwPollEvents();           // poll for events
    }

    // clean up
    glDeleteProgram(g_shaderProgramID);
    glDeleteBuffers(1, &g_VBO);
    glDeleteVertexArrays(1, &g_VAO);

    // close the window and terminate GLFW
    glfwDestroyWindow(window);
    glfwTerminate();

    exit(EXIT_SUCCESS);
}

I want to get rid of the red line coming out from the axis. I just want a hollow circle. I'm using GL_LINE_LOOP to draw my arrays. Am I using the wrong primitive? I have tried adjusting the coordinates in g_vertices and it does make the line smaller, but when I increase the radius of the circle, the line appears again.


Solution

  • You are drawing a GL_LINE_LOOP:

    see Khronos group OGL Primitive documentation:

    GL_LINE_LOOP: As line strips, except that the first and last vertices are also used as a line. Thus, you get n lines for n input vertices. If the user only specifies 1 vertex, the drawing command is ignored. The line between the first and last vertices happens after all of the previous lines in the sequence.

    You initilize the first and the second vertex position with (0, 0, 0):

    GLfloat g_vertices[MAX_VERTICES] = {
        0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f
    };
    

    And then you add the vertices for the circle, because your loop starts as the index starts at index 2:

    for (int i = 2; i < g_slices+2; i++)
    {
      ......
    }
    

    What you are drawing is a line from the center to the first point on the circle. Then you draw the circle. Finally the last vertex position (on the circle) is connected to the first, which is the center point of the circle.

    You have to skip the 2 vertices at the begin of the list. You do not have to initialize the first two vertices and you can start the loop at 0. See the code above:

    Definitions and global variables:

    #define MAX_SLICES 32
    #define MAX_VERTICES MAX_SLICES*3 
    
    GLfloat g_vertices_circle[MAX_VERTICES];
    GLuint g_slices = MAX_SLICES; 
    

    Create the vertex position and color attribute array

    for (int i = 0; i < g_slices; i++)
    {
        float angle = (float)PI * 2.0f * (float)i / float(g_slices); 
        int   index = i * 3;
    
        g_vertices_circle[index] = CIRCLE_RADIUS * cos(angle) * scale_factor;
        g_vertices_circle[index + 1] = CIRCLE_RADIUS * sin(angle);
        g_vertices_circle[index + 2] = 0.0f;
    }
    

    Set up vertex buffer object:

    glGenBuffers(1, &g_VBO);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * g_slices, g_vertices, GL_STATIC_DRAW);
    

    And finally the drawing:

    glDrawArrays( GL_LINE_LOOP, 0, g_slices );