How Can I Render Round Vertices Using OpenGL 4.0?

102 Views Asked by At

I have an MFC based Windows desktop SDI application built with the Doc-View framework and which displays modern OpenGL based 3D graphics in the MainFrame. It used for rendering relatively simple objects/shapes that are constructed from collections of specified points (vertices), lines and curves.

All the common frequently encountered/used OpenGL operations are managed by small library of dedicated classes (e.g Camera, PipelineManager, ShaderManager, Quaternion, etc).

The OpenGL version used is 3.0, which is defined via a 'GLDisplay' class:

bool Initialize(HWND wnd,
                int bitsPerPixel = 32,
                int major = 3, 
                int minor = 0, 
                bool compatibleContext = false, 
                bool fullscreen = false);

The implementation of the Initialize() is below (note the use of 'GL_POINT_SMOOTH'):

bool GLDisplay::Initialize(HWND wnd,
                           int bitsPerPixel,
                           int major, 
                           int minor, 
                           bool compatibleContext, 
                           bool fullscreen )
{
    //first get the device context using the existing window handle  
    m_deviceContext = GetDC(wnd);

    //if this is the first time we are creating a screen
    //then setup the window properties and get the extension function
    if (s_isFirstInit)
    {
        //set the properties of the RGBA color modes and buffers (only done ONCE)
        s_pixelFormatClass.nSize = sizeof(PIXELFORMATDESCRIPTOR);
        s_pixelFormatClass.nVersion = 1;
        s_pixelFormatClass.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | 
                                       PFD_DOUBLEBUFFER;
        s_pixelFormatClass.iPixelType = PFD_TYPE_RGBA;

        //size of the depth testing buffer. 
        s_pixelFormatClass.cDepthBits = 32;   
        s_pixelFormatClass.cStencilBits = 32;

        //set pixel format so that the device and render context can work together
        s_pixelFormat = ChoosePixelFormat(m_deviceContext, &s_pixelFormatClass);
        SetPixelFormat(m_deviceContext, s_pixelFormat, &s_pixelFormatClass);

        //variables to store properties of the window
        HGLRC tempRenderContext;
        
        //create a temporary OpenGL rendering context using device context
        //this context is only used to acquire the extension 
        //function to enable creating a MODERN OpenGL context
        tempRenderContext = wglCreateContext(m_deviceContext);

        //enable the temporary rendering context  
        wglMakeCurrent(m_deviceContext, tempRenderContext);

        //acquire extension function for modern OpenGL (only done ONCE)
        s_wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)                               
                                         wglGetProcAddress("wglCreateContextAttribsARB");

        //destroy the temporary context 
        wglDeleteContext(tempRenderContext);
    }

    //set the pixel format so that the device and render context 
    SetPixelFormat(m_deviceContext, s_pixelFormat, &s_pixelFormatClass);

    //set OpenGL into core or compatibility mode
    int profile;
    
    if (compatibleContext)
    {
        profile = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
    }

    else
    {
        profile = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
    }

    //set the attributes for creating a modern OpenGL context 
    //the final 0 value in the array indicates the end of the array
    int attribs[]  = {  WGL_CONTEXT_MAJOR_VERSION_ARB, major,
                        WGL_CONTEXT_MINOR_VERSION_ARB, minor,
                        WGL_CONTEXT_PROFILE_MASK_ARB, profile, 0 };

    //create the modern OpenGL context using the extension function
    m_renderContext = s_wglCreateContextAttribsARB(m_deviceContext, NULL, attribs);

    //enable the final rendering context  
    wglMakeCurrent(m_deviceContext, m_renderContext);

    //only initialize GLEW ONCE when the FIRST window is created
    if (s_isFirstInit)
    {
        //set GLEW library flag to combat potential errors for core mode
        glewExperimental = GL_TRUE;

        //enable blending for transparency (for text rendering)
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        s_isFirstInit = false;
    }

    //allow for vertices to be rounded
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_POINT_SMOOTH);

    return true;
}

The application also uses two relatively simple shaders 'Main.vert':

#version 150

in vec3 vertexIn;  
in vec4 colorIn;
in vec2 textureIn;

out vec3 vertexOut;
out vec4 colorOut;
out vec2 textureOut;

//send a combined model-view-projection matrix into the shader (mvp)
//instead of multiplying projection * view * model for each vertex, 
//therefore allowing for less calculations
uniform mat4 mvp;

void main(void)
{
  colorOut = colorIn;
  textureOut = textureIn;
  gl_Position = mvp * vec4(vertexIn, 1.0f);
}

and 'Main.frag':

#version 150

in vec3 vertexOut;
in vec4 colorOut;
in vec2 textureOut;

out vec4 pixelColor;

uniform bool isTextured;
uniform sampler2D textureImage;

void main(void)
{
  if(isTextured)
  {
    vec2 uv;
    uv.x = textureOut.x;
    uv.y = 1 - textureOut.y;
    pixelColor = colorOut * texture(textureImage, uv);
  }
    
  else
  {
      pixelColor = colorOut;
  }
}

Using all this I can pleasingly render vertices as round points (of a size I choose), as shown below.

enter image description here

BUT IF I change the hardcoded OpenGL version specified from 3.0 to 4.0 then I get the vertices undesirably rendered as squares. See example below.

enter image description here

What changes or new code do I need to be able to continue rendering the vertices as round points?

1

There are 1 best solutions below

0
DavidH On

I thank those who replied to this question. I have managed to fix the problem by adding to my project new dedicated 'Point.vert' and 'Point.frag' shaders.

Using these additional shaders the application now once again renders points as round solid filled circles, as shown in the screencapture.

This is the code:

// Point.frag
#version 400

in vec3 vertexOut;
in vec4 colorOut;

out vec4 pixelColor;

void main(void)
{
    // Radius of the point in normalized device coordinates
    float radius = 0.5;  

    // Calculate the distance from the center of the point
    float dist = distance(gl_PointCoord, vec2(0.5, 0.5));

    // Discard fragments outside the circle
    if (dist > radius)
        discard;  

    pixelColor = colorOut;
}
//Point.vert
#version 400

in vec3 vertexIn;  
in vec4 colorIn;

out vec3 vertexOut;
out vec4 colorOut;

//Instead of multiplying projection * view * model for each vertex, 
//we send in a pre-calculated mvp matrix, therefore requiring less calculations
uniform mat4 mvp;

void main(void)
{
    colorOut = colorIn;
    gl_Position = mvp * vec4(vertexIn, 1.0f);
}