Search code examples
c++openglglslglfwgl-triangle-strip

Rendering a single triangle using TriangleStrip renders a rectangle


I am trying to render a triangle with a triangle strip, but the word thing is that I am getting a rectangle.

Here is my client application code. I hardcoded points and the indices, create a VBO and an index buffer, and just call glDrawElements.

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

#include <GL/glew.h>
#include <GLFW/glfw3.h>

using namespace std;

#define PI 3.14159265359

static string ParseShader(string filepath) {
    ifstream stream(filepath);
    string line;
    stringstream stringStream;

    while (getline(stream, line))
    {
        stringStream << line << '\n';
    }

    return stringStream.str();
}

static unsigned int CompileShader(unsigned int type, const string& source) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str(); // this returns a pointer to data inside the string, the first character
    glShaderSource(id, 1, &src, nullptr); // shader id, count of source codes, a pointer to the array that holds the strings
    glCompileShader(id);

    int result;
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);
    if (result == GL_FALSE) {
        int length;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        char* message = (char*)alloca(length * sizeof(char));
        glGetShaderInfoLog(id, length, &length, message);
        cout << type << endl;
        cout << message << endl;
        glDeleteShader(id);
        return 0;
    }
    return id;
}

// takes the shader codes as a string parameters 
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader)
{
    GLuint program = glCreateProgram();
    unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
    unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);


    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program); // validate if the program is valid and can be run in the current state of opengl

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

int main(void)
{
    GLFWwindow* window;

    float Angle = 40;

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

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

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

    // call glewInit after creating the context...
    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        /* Problem: glewInit failed, something is seriously wrong. */
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
    }

    const int vertexCoordinateCount = 2;
    const int coordinateCount = 6;
    const int indexCount = 3;

    GLfloat coordinates[coordinateCount] = {
        500.0f,  0.0f,
        -250.0f, 250.f,
        -250.f,  -250.f, 
    };

    GLuint indices[indexCount] = { 0, 1, 2 };

    GLuint position_buffer;
    glGenBuffers(1, &position_buffer);
    glBindBuffer(GL_ARRAY_BUFFER, position_buffer);
    glBufferData(GL_ARRAY_BUFFER, coordinateCount * sizeof(float), coordinates, GL_STATIC_DRAW);

    glVertexAttribPointer(0, vertexCoordinateCount, GL_FLOAT, GL_FALSE, sizeof(float) * vertexCoordinateCount, 0);
    glEnableVertexAttribArray(0);

    GLuint index_buffer;
    glGenBuffers(1, &index_buffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(GLuint), indices, GL_STATIC_DRAW);

    string vertexSource = ParseShader("vertex.shader");
    string fragmentSource = ParseShader("fragment.shader");

    unsigned int program = CreateShader(vertexSource, fragmentSource);
    glUseProgram(program);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        // Render here 
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, nullptr);

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

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

    glDeleteProgram(program);

    glfwTerminate();
    return 0;
}

My vertex shader :

#version 330 core
layout(location = 0) in vec3 aPos;

void main()
{
    gl_Position = vec4(aPos, 1.0);
}

And my fragment shader:

#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}

Edit: Adding a screenshot of the render result. Result


Solution

  • You do not transform the vertex coordinates. Therefore the vertices must be spepcified in Normalized Device Space, in range [-1.0, 1.0]. e.g.:

    GLfloat coordinates[coordinateCount] = {
        1.0f,  1.0f,
       -1.0f,  1.0f,
        1.0f, -1.0f, 
    };
    

    You're actually drawing a triangle, but you only see an inner part of it. The rest is clipped.