Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 10 of 14

Thread: I'm trying to render a triangle

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Junior Member Newbie
    Join Date
    Sep 2017
    Posts
    27

    I'm trying to render a triangle

    Hello all,

    I'm very new on OpenGL and at this beginning I've found it very complex. I would think C++ is the most complex language but it's better.

    Anyway, the code below is for rendering my first triangle. Please take a look:

    Code :
    #include <glad/glad.h> 
    #include <GLFW/glfw3.h>
    #include <C:\Users\Abbasi\Desktop\std_lib_facilities_4.h>
    using namespace std;
     
     
    //*********************************
     
    int main()
    {
    	glfwInit();
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
     
    	GLFWwindow* window = glfwCreateWindow(800, 600, "The First Triangle", NULL, NULL);
     
    	if (window == NULL)
    	{
    		cout << "Failed to create GLFW window" << endl;
    		glfwTerminate();
    		return -1;
    	}
     
    	glfwMakeContextCurrent(window);
     
     
    	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) 
    	{
    		cout << "Failed to initialize GLAD" << endl;
    		return -1;
    	}
     
    	glViewport(0, 0, 700, 500);
     
    	float vertices[] = {
    	   -0.5f, -0.5f, 0.5f,
    		0.5f, -0.5f, 0.5f,
    		0.0f,  0.5f, 0.0f
    	};
     
      unsigned int VBO;  // Creating a vertex buffer object
      glGenBuffers(1, &VBO);
      glBindBuffer(GL_ARRAY_BUFFER, VBO);
      glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
     
        // Creating the Vertex Shader
      const char* vertexShaderSource = "#version 330 core\nlayout (location = 0)"
    		"in vec3 aPos;\n\nvoid main()\n{\ngl_Position ="
    		"vec4(aPos.x, aPos.y, aPos.z, 1.0);\n}\n\0";
     
      unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
      glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
      glCompileShader(vertexShader);
     
       //check the vertex shader compilation error(s)
      int success;
      char infoLog[512];
      glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
      if (!success)
      {
    	  glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
    	  cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl;
      }
     
       // Creating the Fragment Shader
      const char* fragmentShaderSource = "#version 330 core\n"
    	  "out vec4 FragColor;\n\nvoid main()\n{\n"
    	  "FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n}\n\0";
     
      unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
      glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
      glCompileShader(fragmentShader);
     
      //check the fragment shader compilation error(s)
      glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
      if (!success)
      {
    	  glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
    	  cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl;
      }
     
        // Linking both shaders into a shader program for rendering
      unsigned int shaderProgram = glCreateProgram();
      glAttachShader(shaderProgram, vertexShader);
      glAttachShader(shaderProgram, fragmentShader);
      glLinkProgram(shaderProgram);
     
      //check the shader program linking error(s)
      glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
      if (!success)
      {
    	  glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
    	  cout << "ERROR::PROGRAM::SHADER::LINKING_FAILED\n" << infoLog << endl;
      }
     
      glUseProgram(shaderProgram);
     
        // We no longer need the prior shaders after the linking
      glDeleteShader(vertexShader);
      glDeleteShader(fragmentShader);
     
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
      glEnableVertexAttribArray(0);
     
      unsigned int VAO;
      glGenVertexArrays(1, &VAO);
      glBindVertexArray(VAO);
      glDrawArrays(GL_TRIANGLES, 0, 3);
     
      system("pause");
    	return 0;
    }

    The output is:

    Click image for larger version. 

Name:	1.jpg 
Views:	22 
Size:	11.9 KB 
ID:	2543

    What is the problem of this code that doesn't show the triangle, please?

  2. #2
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,716
    The most immediately and obviously wrong thing is this block of code:
    Code :
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    What's wrong with this is that you actually don't have a VAO active when you make your glEnableVertexAttribArray and glVertexAttribPointer calls; this is illegal per core GL Specification; see https://www.khronos.org/registry/Ope...ribArray.xhtml
    GL_INVALID_OPERATION is generated by glEnableVertexAttribArray and glDisableVertexAttribArray if no vertex array object is bound.
    GL_INVALID_OPERATION is generated by glEnableVertexArrayAttrib and glDisableVertexArrayAttrib if vaobj is not the name of an existing vertex array object.

  3. #3
    Junior Member Newbie
    Join Date
    Sep 2017
    Posts
    27
    Thanks for the answer.
    By running the program I get no errors.
    What's the simplest way to make the issue solved please?

  4. #4
    Intern Newbie
    Join Date
    Mar 2017
    Posts
    47
    As mhagain mentioned, you need to have a currently bound vertex array object before you call commands like glEnableVertexAttribArray and glVertexAttribPointer. So you just need to generate a VAO and bind it before calling those commands.

    You actually have a run-time error flagged by OpenGL (won't show in compilation). In your current code, after 'glEnableVertexAttribArray(0);', call glGetError() and check it's value. You'll get 1282 (that's what I see in my VS 2015 debugger in cases like these). In hex, this is 0x0502, and your glad.h labels this as GL_INVALID_OPERATION. As mhagain quoted, this GL_INVALID_OPERATION came from not binding a VAO before calling the two VertexAttrib commands.

    Anyways, as for actually displaying the triangle, in this particular snippet, you'd also want to call glSwapBuffers() before your system("pause") call. Looking at your GLFW setup code, you didn't specify anything about whether you wanted a double-buffer or not, so GLFW gave a double-buffered OpenGL rendering context to you. The glDrawArrays command would then default to drawing to the back buffer, and you'd have to swap it out with the front to actually get it displayed.

    So code-wise, after your last glDeleteShaders call, use this (I added comments where I thought would be helpful):

    Code :
    ...
    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO); //must have a VAO bound before callling VertexAttribPointer and EnableVertexAttribArray
     
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
     
    glBindVertexArray(0); //I prefer to unbind OpenGL objects when I'm not using them, for consistency
    glBindBuffer(GL_ARRAY_BUFFER, 0);
     
    glBindVertexArray(VAO); //rebind VAO before calling glDrawArrays
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glBindVertexArray(0);
     
    glfwSwapBuffers(window); //
    system("pause");
     
    glfwTerminate(); //use to close window 
     
    //
    //good practice to delete your OpenGL objects when you're sure you don't need them anymore
    glDeleteBuffers(1, &VBO);
    glDeleteVertexArrays(1, &VAO);
    ...

    Hope that helps. That's an interesting approach to trying to display a triangle. I assume you're using the LearnOpenGL "Hello Triangle" tutorial. Would've thought you'd use a window while loop like the tutorial did, but guess you wanted to avoid the loop for now.
    Last edited by DragonautX; 11-12-2017 at 02:29 PM. Reason: comment add

  5. #5
    Junior Member Newbie
    Join Date
    Sep 2017
    Posts
    27
    Hi, thanks for your answer.
    The thing the is odd to me is binding something and unbinding it and then binding it again and unbinding. That seems rather repetitive.

    I used this code: (although I don't think a professional programmer of OpenGL would also code a triangle that way)



    Code :
    #include <glad/glad.h> 
    #include <GLFW/glfw3.h>
    #include <C:\Users\Abbasi\Desktop\std_lib_facilities_4.h>
    using namespace std;
     
    // Creating the Vertex Shader
    const char* vertexShaderSource = "#version 330 core\nlayout (location = 0)"
    "in vec3 aPos;\n\nvoid main()\n{\ngl_Position ="
    "vec4(aPos.x, aPos.y, aPos.z, 1.0);\n}\n\0";
     
    // Creating the Fragment Shader
    const char* fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n\nvoid main()\n{\n"
    "FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n}\n\0";
     
    //*********************************
     
    int main()
    {
    	glfwInit();
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
     
    	GLFWwindow* window = glfwCreateWindow(800, 600, "The First Triangle", nullptr, nullptr);
    	glfwMakeContextCurrent(window);
    	gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
     
    	float vertices[] = {
    		-0.5f, -0.5f, 0.5f,
    		0.5f, -0.5f, 0.5f,
    		0.0f,  0.5f, 0.0f
    	};
     
    	unsigned int VBO;  
    	glGenBuffers(1, &VBO);
    	glBindBuffer(GL_ARRAY_BUFFER, VBO);
    	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
     
    	unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    	glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
    	glCompileShader(vertexShader);
     
    	unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    	glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
    	glCompileShader(fragmentShader);
     
    	// Linking both shaders into a shader program for rendering
    	unsigned int shaderProgram = glCreateProgram();
    	glAttachShader(shaderProgram, vertexShader);
    	glAttachShader(shaderProgram, fragmentShader);
    	glLinkProgram(shaderProgram);
     
    	glUseProgram(shaderProgram);
     
    	unsigned int VAO;
    	glGenVertexArrays(1, &VAO);
    	glBindVertexArray(VAO); //must have a VAO bound before callling VertexAttribPointer 
    	                        //and EnableVertexAttribArray
     
    	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    	glEnableVertexAttribArray(0);
    	glDrawArrays(GL_TRIANGLES, 0, 3);
     
    	glfwSwapBuffers(window);
    	system("pause");
    	glfwTerminate();
    	return 0;
    }

  6. #6
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,716
    Unbinding is something that you only see in relatively recent tutorials, and is not actually necessary at all. I would personally be happier if tutorial writers didn't unbind, but instead taught how the API actually works, which calls interact with currently bound objects, and what the correct states and bindings you need for a given API call are. IMO, unbinding is bad practice that can hide programmer errors; you should be wanting to expose those errors instead so that you can correct them and learn from them.

  7. #7
    Intern Newbie
    Join Date
    Mar 2017
    Posts
    47
    (to Tomyfr) Rebinding like that isn't required. It's more of my own design style. You can remove the extra bindings as you need.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •