Triangle doesn't render [duplicate] - c++

This question already has answers here:
How can I make OpenGL draw something using VBOs in XCODE?
(3 answers)
Closed 8 years ago.
I am having trouble rendering a simple triangle. The code below compiles and runs, except there isn't any triangle; only a black background.
GLuint VBO;
static void RenderSceneCB()
{
//glClear sets the bitplane area of the window to values previously selected by glClearColor, glClearDepth, and glClearStencil.
glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
//swaps the buffers of the current window if double buffered.
glutSwapBuffers();
}
static void InitializeGlutCallbacks()
{
glutDisplayFunc(RenderSceneCB);
}
static void CreateVertexBuffer()
{
Vector3f Vertices[3];
Vertices[0] = Vector3f(-1.0f, -1.0f, 0.0f);
Vertices[1] = Vector3f(1.0f, -1.0f, 0.0f);
Vertices[2] = Vector3f(0.0f, 1.0f, 0.0f);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA);
glutInitWindowSize(1024, 768);
glutInitWindowPosition(100, 100);
glutCreateWindow("Tutorial 02");
InitializeGlutCallbacks();
// Must be done after glut is initialized!
GLenum res = glewInit();
if (res != GLEW_OK) {
fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
return 1;
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
CreateVertexBuffer();
glutMainLoop();
return 0;
}

Since you do not have a shader, OpenGL does not know how to interpret your vertex attribute 0, as it only knows about position, color, etc. and not about generic attributes. Note that this may work on some GPUs as they will map the generic attributes to the same "slots", and zero would then be interpreted as position (typically NVidia is less strict with these issues).
You can use MiniShader, just put the following code after CreateVertexBuffer();:
minish::InitializeGLExts(); // initialize shading extensions
const char *vs =
"layout(location = 0) in vec3 pos;\n"
// the layout specifier binds this variable to vertex attribute 0
"void main()\n"
"{\n"
" gl_Position = gl_ModelViewProjectionMatrix * vec4(pos, 1.0);\n"
"}\n";
const char *fs = "void main() { gl_FragColor=vec4(.0, 1.0, .0, 1.0); }"; // green
minish::CompileShader(vs, fs);
Note that I wrote that from top of my head, in case there are some errors, please comment.

Related

My square I'm trying to render isn't showing up when using OpenGL [duplicate]

This question already has an answer here:
Why is the sprite not rendering in OpenGL?
(1 answer)
Closed 2 years ago.
I'm trying to render a square using two triangles, and then applying some transformations, but for whatever reason it isn't showing up. Here is the code:
#include <iostream>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
#define WINDOW_TITLE "Modern OpenGL 3D Cube"
#ifndef GLSL
#define GLSL(Version, Source) "#version " #Version "\n" #Source
#endif
GLint shaderProgram, windowWidth = 800, windowHeight = 600;
GLuint VBO, VAO, EBO, texture;
void UResizeWindow(int, int);
void URenderGraphics(void);
void UCreateShader(void);
void UCreateBuffers(void);
const GLchar* vertexShaderSource = GLSL(330,
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;
out vec3 mobileColor;
uniform mat4 shaderTransform;
void main() {
gl_Position = shaderTransform * vec4(position, 1.0f);
mobileColor = color;
});
const GLchar* fragmentShaderSource = GLSL(330,
in vec3 mobileColor;
out vec4 gpuColor;
void main() {
gpuColor = vec4(mobileColor, 1.0);
});
//main program
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(windowWidth, windowHeight);
glutCreateWindow(WINDOW_TITLE);
glutReshapeFunc(UResizeWindow);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
cout << "Failed to initialize GLEW" << endl;
return -1;
}
UCreateShader();
UCreateBuffers();
glUseProgram(shaderProgram);
glClearColor(0, 0, 0, 1);
glutDisplayFunc(URenderGraphics);
glutMainLoop();
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
return 0;
}
void UResizeWindow(int w, int h) {
windowWidth = w;
windowHeight = h;
glViewport(0, 0, windowWidth, windowHeight);
}
void URenderGraphics(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(VAO);
glm::mat4 currentTransform;
currentTransform = glm::translate(currentTransform, glm::vec3(0.0f, 0.5f, 0.0f));
currentTransform = glm::rotate(currentTransform, 45.0f, glm::vec3(0.0f, 0.0f, 1.0f));
currentTransform = glm::scale(currentTransform, glm::vec3(0.5f, 0.5f, 0.5f));
GLuint transformLocation = glGetUniformLocation(shaderProgram, "shaderTransform");
glUniformMatrix4fv(transformLocation, 1, GL_FALSE, glm::value_ptr(currentTransform));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glutSwapBuffers();
}
void UCreateShader() {
GLint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
GLint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
void UCreateBuffers() {
GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, 1, 0, 0, //top right vertex 0
0.5f, -0.5f, 0.0f, 0, 1, 0, //bottom right vertex 1
-0.5f, -0.5f, 0.0f, 0, 0, 1, //bottom left vertex 2
-0.5f, 0.5f, 0.0f, 1, 0, 1 //top left vertex 3
};
GLuint indices[] = {
0, 1, 3, //triangle 1
1, 2, 3 //triangle 2
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
}
It compiles and runs just fine, but it only opens a blank window. No graphics are shown on that window like it normally would. The output is supposed to look like a slightly rotated square rotated about its z-axis, but nothing appears at all. All help appreciated.
Some common things I check, when I get the infamous blank screen:
forgetting to call glUseProgram(shaderID) before you start passing uniforms (done)
pass the model matrix as an identity matrix.
double checking if the VBO/EBO are laid out in memory correctly (also, simplifying them during this step, ie. removing the color attribute, just pass position, and hard code the color in the fragment shader)
doing some error checking to see if there is a problem with the shader compilation using glGetShaderInfoLog and glGetProgramInfoLog.
The model matrix variable glm::mat4 currentTransform has to be initialized by the Identity matrix.
The OpenGL Mathematics (GLM) API documentation is based on OpenGL Shading Language (GLSL) and refers to The OpenGL Shading Language specification.
5.4.2 Vector and Matrix Constructors
[...] If there is a single scalar parameter to a matrix constructor, it is used to initialize all the components on the matrix's diagonal, with the remaining components initialized to 0.0.
An Identity matrix can be initialized by the single parameter 1.0:
glm::mat4 currentTransform;
glm::mat4 currentTransform(1.0f);

OpenGL rectangle inexplicably takes up entire window

So I am using GLEW & SDL2. At the moment I'm having trouble with drawing a simple rectangle.
I've done this before and got it to work no problem. (I have checked my old code, but could not find any signifigant differences)
Here's what the output should look like, aside from a different background color.
However, this is what the output looks like:
When I check the output with Renderdoc, all the values seem to be as they should be, but for some reason the output rectangle is signifigantly larger than the viewport. (Assuming the white border in the output window represents the viewport.)
I've googled around a bit, but could not find any solution to this issue. I'm figuring I'm just missing a single function call somewhere which is causing the program to output things in a weird way.
Here's the relevant code
game.cpp
#include "Game.h"
void Game::Game::main_loop()
{
//Placeholder setup;
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
};
unsigned int indices[] = {
0, 1, 2,
2, 3, 0
};
unsigned int vertex_array, vertex_buffer, element_buffer;
glGenVertexArrays(1, &vertex_array);
glBindVertexArray(vertex_array);
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &element_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
Asset::Loader l;
auto s = l.load_shader("res/GUI/Shaders/Textured_quad.vert", "res/GUI/Shaders/Textured_quad.frag");
keep_going = true;
while(keep_going)
{
handle_events();
renderer.clear();
s->use(); //Just calls 'glUseProgram' on the shader inside this object
glBindVertexArray(vertex_array);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
renderer.show();
}
}
void Game::Game::handle_events()
{
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_MOUSEBUTTONDOWN:
case SDL_QUIT:
keep_going = false;
}
}
}
Renderer.cpp
#include "Renderer.h"
Game::Graphics::Renderer::Renderer()
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
window = SDL_CreateWindow(
"GUI",
SDL_WINDOWPOS_CENTERED_DISPLAY(1),
SDL_WINDOWPOS_CENTERED_DISPLAY(1),
640,
480,
SDL_WINDOW_OPENGL
);
context = SDL_GL_CreateContext(
window
);
if(!window)
{
std::cerr << "Window Error: " << SDL_GetError() << std::endl;
return;
}
if(!context)
{
std::cerr << "GL Context Error: " << SDL_GetError() << std::endl;
return;
}
glewInit();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glViewport(0, 0, 640, 480);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glDisable(GL_BLEND);
}
Game::Graphics::Renderer::~Renderer()
{
SDL_HideWindow(window);
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
}
void Game::Graphics::Renderer::clear()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void Game::Graphics::Renderer::show()
{
SDL_GL_SwapWindow(window);
}
Shader
#version 330 core
layout (location = 0) in vec3 a_pos;
void main()
{
gl_Position = vec4(a_pos, 0.0f);
}
//fragment
#version 330 core
out vec4 o_color;
void main()
{
o_color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}
gl_Position = vec4(a_pos, 0.0f);
The X/Y/Z coordinates in gl_Position get divided by the W coordinate to get the screen coordinates. You are setting the W coordinate to 0, which means the X and Y coordinates become infinity and -infinity (1/0 and -1/0) and the Z coordinate becomes NaN.
Change it to:
vvvv
gl_Position = vec4(a_pos, 1.0f);

How to draw a VAO made out of 5 triangles in OpenGL?

I have recently written a program to draw a triangle with 3 different RGB values and I want to do the same with another separate VAO in the same program but I want this one composed of 5 triangles. Here is my main.cpp:
void framebuffer_size_callback(GFLWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
// Shaders
const char *vertexShaderSource =
"#version 410\n"
"in vec3 vp;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos, 1.0);\n"
"}\0";
const char *fragmentShader1Source =
"#version 410\n"
"out vec4 FragColor;\n"
"in vec3 myColor;\n"
"void main()\n"
"{\n"
"FragColor = vec4(myColor, 1.0f);\n"
"}\n\0";
int main ()
{
// start GL context and O/S window using the GLFW helper library
if (!glfwInit ())
{
fprintf (stderr, "ERROR: could not start GLFW3\n");
return 1;
}
// uncomment these lines if on Apple OS X
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(640, 480, "LearnOpenGL", NULL, NULL);
if (!window)
{
fprintf(stderr, "ERROR: could not open window with GLFW3\n");
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit();
// get version info
const GLubyte* renderer = glGetString(GL_RENDERER);
const GLubyte* version = glGetString(GL_VERSION);
printf("Renderer: %s\n", renderer);
printf("OpenGL version supported %s\n", version);
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS);
/* OTHER STUFF GOES HERE */
// Draw a single triangle VBO
float points[] = {
// positions // colors
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f 0.0f, 1.0f
};
GLuint VBO = 0;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
// Generate a VAO.
GLuint VAO = 0;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
// Compile a Vertex Shader
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// Compile a fragment shader.
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// Compile shaders into a executable shader program.
int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, fragmentShader);
glAttachShader(shaderProgram, vertexShader);
glLinkProgram(shaderProgram);
// Drawing the triangles aka render loop
while (!glfwWindowShouldClose(window))
{
processInput(window);
// wipe the drawing surface clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw Triangle
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
// Draw Triangle Fan; unfinished
// swap buffers and poll IO events
glfwPollEvents();
glfwSwapBuffers(window);
}
// close GL context and any other GLFW resources
glfwTerminate();
return 0;
}
Do I simply create another float "points" matrix like I did with my first VBO or something else? The tutorial Im following wasn't perfectly clear on this part.
Also, Im using Xcode on my Mac and I created separate .cpp files for my Fragment and Vertex shaders. Should I switch those to header files instead?
You have to specify an input attribute for the color (aColor) and to pass the color attribute from the vertex shader to the fragment shader (myColor). Use Layout Qualifiers to specify the attribute indices.
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
out vec3 myColor;
void main()
{
myColor = aColor;
gl_Position = vec4(aPos, 1.0);
}
#version 330 core
out vec4 FragColor;
in vec3 myColor;
void main()
{
FragColor = vec4(myColor, 1.0f);
}
Note your current vertex shader does not compile. Check if compiling of a shader succeeded checked by glGetShaderiv and the parameter GL_COMPILE_STATUS and if the linking of a program was successful can be checked by glGetProgramiv and the parameter GL_LINK_STATUS. See the answer to OpenGL ignores Quads and makes them Triangles for some code snippets.
Your vertices are tuples with 6 components (x, y, z, r, g, b):
float points[] = {
// positions // colors
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f 0.0f, 1.0f
};
Use glVertexAttribPointer to specify 2 vertex attributes. The stride and the offset have to be specified in bytes. The stride is 6 * sizeof(float). The offset of the vertex coordinates is 0 and the offset of the color attributes is 3 * sizeof(float). e.g:
GLuint VBO = 0;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
// Generate a VAO.
GLuint VAO = 0;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), NULL);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
If you want to draw more complex meshes, then you have to extend the vertes arrays. Just add another 3 vertices and colors to points array for the next triangle. Alternatively you can use a different primitive type like GL_TRIANGLE_STRIP or GL_TRIANGLE_FAN. See Triangle primitives
Example code:
#include <iostream>
#include <vector>
// Shaders
const char *vertexShaderSource = R"(#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
out vec3 myColor;
void main()
{
myColor = aColor;
gl_Position = vec4(aPos, 1.0);
}
)";
const char *fragmentShaderSource = R"(#version 330 core
out vec4 FragColor;
in vec3 myColor;
void main()
{
FragColor = vec4(myColor, 1.0f);
}
)";
bool CompileStatus( GLuint shader );
bool LinkStatus( GLuint program );
float radians( float deg ) { return deg * 3.141529 / 180.0; }
int main ()
{
// start GL context and O/S window using the GLFW helper library
if (!glfwInit())
{
fprintf (stderr, "ERROR: could not start GLFW3\n");
return 1;
}
// uncomment these lines if on Apple OS X
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(640, 480, "LearnOpenGL", NULL, NULL);
if (!window)
{
fprintf(stderr, "ERROR: could not open window with GLFW3\n");
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit();
// get version info
const GLubyte* renderer = glGetString(GL_RENDERER);
const GLubyte* version = glGetString(GL_VERSION);
printf("Renderer: %s\n", renderer);
printf("OpenGL version supported %s\n", version);
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS);
/* OTHER STUFF GOES HERE */
// Draw a single triangle VBO
float points[] = {
// positions // colors
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f * cos(radians(72)), 0.5f * sin(radians(72)), 0.0f, 0.0f, 0.0f, 1.0f,
0.5f * cos(radians(144)), 0.5f * sin(radians(144)), 0.0f, 1.0f, 1.0f, 0.0f,
0.5f * cos(radians(216)), 0.5f * sin(radians(216)), 0.0f, 0.0f, 1.0f, 1.0f,
0.5f * cos(radians(288)), 0.5f * sin(radians(288)), 0.0f, 1.0f, 0.0f, 1.0f,
0.5, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f
};
GLuint VBO = 0;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
// Generate a VAO.
GLuint VAO = 0;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), NULL);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
// Compile a Vertex Shader
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
CompileStatus( vertexShader );
// Compile a fragment shader.
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
CompileStatus( fragmentShader );
// Compile shaders into a executable shader program.
int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, fragmentShader);
glAttachShader(shaderProgram, vertexShader);
glLinkProgram(shaderProgram);
LinkStatus( shaderProgram );
// Drawing the triangles aka render loop
while (!glfwWindowShouldClose(window))
{
//processInput(window);
// wipe the drawing surface clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw Triangle
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLE_FAN, 0, 7);
// Draw Triangle Fan; unfinished
// swap buffers and poll IO events
glfwPollEvents();
glfwSwapBuffers(window);
}
// close GL context and any other GLFW resources
glfwTerminate();
return 0;
}
bool CompileStatus( GLuint shader )
{
GLint status = GL_TRUE;
glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
if (status == GL_FALSE)
{
GLint logLen;
glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &logLen );
std::vector< char >log( logLen );
GLsizei written;
glGetShaderInfoLog( shader, logLen, &written, log.data() );
std::cout << "compile error:" << std::endl << log.data() << std::endl;
}
return status != GL_FALSE;
}
bool LinkStatus( GLuint program )
{
GLint status = GL_TRUE;
glGetProgramiv( program, GL_LINK_STATUS, &status );
if (status == GL_FALSE)
{
GLint logLen;
glGetProgramiv( program, GL_INFO_LOG_LENGTH, &logLen );
std::vector< char >log( logLen );
GLsizei written;
glGetProgramInfoLog( program, logLen, &written, log.data() );
std::cout << "link error:" << std::endl << log.data() << std::endl;
}
return status != GL_FALSE;
}
You would do this by adding creating another float array containing your new points, and creating another VAO and VBO. Since you want a triangle fan (based on the comment in your code), and not 5 individual triangles you would make it like this:
float points_5_triangles[] = {
// positions // colors
// Original triangle
x1, y1, z1, r1, g1, b1, // point 1
x2, y2, z2, r2, g2, b2, // point 2
x3, y3, z3, r3, g3, b3, // point 3
// Another triangle made from point 1, 3 and 4
x4, y4, z4, r4, g4, b4,
// Another triangle made from point 1, 4 and 5
x5, y5, z5, r5, g5, b5,
// Another triangle made from point 1, 5 and 6
x6, y6, z6, r6, g6, b6,
// Another triangle made from point 1, 6 and 7
x7, y7, z7, r7, g7, b7,
};
GLuint VBO_5_triangles = 0;
glGenBuffers(1, &VBO_5_triangles);
glBindBuffer(GL_ARRAY_BUFFER, VBO_5_triangles);
glBufferData(GL_ARRAY_BUFFER, sizeof(points_5_triangles), points_5_triangles, GL_STATIC_DRAW);
// Generate another VAO.
GLuint VAO_5_triangles = 0;
glGenVertexArrays(1, &VAO_5_triangles);
glBindVertexArray(VAO_5_triangles);
glBindBuffer(GL_ARRAY_BUFFER, VBO_5_triangles);
glBufferData(GL_ARRAY_BUFFER, sizeof(points_5_triangles), points_5_triangles, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
Now when drawing your two objects you would first bind the target VAO, then render, then carry on to the next object:
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(VAO_5_triangles);
glDrawArrays(GL_TRIANGLE_FAN, 0, 7);
For more information on how a triangle fan is drawn see Triangle primitives

How to translate and rotate a Triangle in OpenGL over time?

I am trying to rotate and translate my single triangle over time. I have already written the main.cpp and I have written separate files for my Vertex and Fragment shader source code.
Here is the code in my main.cpp file:
void framebuffer_size_callback(GFLWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
// Shaders
const char *vertexShaderSource =
"#version 410\n"
"in vec3 vp;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos, 1.0);\n"
"}\0";
const char *fragmentShaderSource =
"#version 410\n"
"out vec4 FragColor;\n"
"in vec3 myColor;\n"
"void main()\n"
"{\n"
"FragColor = vec4(myColor, 1.0f);\n"
"}\n\0";
int main ()
{
// start GL context and O/S window using the GLFW helper library
if (!glfwInit ())
{
fprintf (stderr, "ERROR: could not start GLFW3\n");
return 1;
}
// uncomment these lines if on Apple OS X
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(640, 480, "LearnOpenGL", NULL, NULL);
if (!window)
{
fprintf(stderr, "ERROR: could not open window with GLFW3\n");
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit();
// get version info
const GLubyte* renderer = glGetString(GL_RENDERER);
const GLubyte* version = glGetString(GL_VERSION);
printf("Renderer: %s\n", renderer);
printf("OpenGL version supported %s\n", version);
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS);
// Draw a single triangle
float points[] = {
// positions // colors
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f 0.0f, 1.0f
};
GLuint VBO = 0;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
// Generate a VAO.
GLuint VAO = 0;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
// Compile a Vertex Shader
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// Compile a fragment shader.
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// Compile shaders into a executable shader program.
int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, fragmentShader);
glAttachShader(shaderProgram, vertexShader);
glLinkProgram(shaderProgram);
// Create another float array to make my triangle fan.
float points_5_triangles[] = {
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 1.0f, 2.0f, 0.5f,
// Another triangle made from point 1, 3, and 4
-0.5f,
}
// Generate another VBO for my Triangle Fan
GLuint VBO_5_triangles = 0;
glGenBuffers(1, &VBO_5_triangles);
glBindBuffer(GL_ARRAY_BUFFER, VBO_5_triangles);
glBufferData(GL_ARRAY_BUFFER, sizeof(points_5_triangles), points_5_triangles, GL_STATIC_DRAW);
// Generate another VAO for my Triangle Fan
GLuint VAO_5_triangles = 0;
glGenVertexArrays(1, &VAO_5_triangles);
glBindVertexArray(VAO_5_triangles);
glBindBuffer(GL_ARRAY_BUFFER, VBO_5_triangles);
glBufferData(GL_ARRAY_BUFFER, sizeof(points_5_triangles), points_5_triangles, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
// Drawing the triangles aka render loop
while (!glfwWindowShouldClose(window))
{
processInput(window);
// wipe the drawing surface clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw Triangle
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
// Draw Triangle Fan
glBindVertexArray(VAO_5_triangles);
glDrawArrays(GL_TRIANGLE_FAN, 0, 7);
// swap buffers and poll IO events
glfwPollEvents();
glfwSwapBuffers(window);
}
// close GL context and any other GLFW resources
glfwTerminate();
return 0;
}
The tutorial I am following does go over transformations but in the example it uses, the triangles have textures as well as shaders. For my purposes, I want to do this without textures added to my code.
Can someone walk me through how to add 2 transformations: translate and rotation to my "single triangle" as shown in this code?
Your triangle having a texture or not has nothing to do with transformation.
You rotate your triangle simply by calculating a transformation matrix, passing it to your vertex shader and multiply it with your coordinates.
Your Vertex Shader should look look something like this:
const char *vertexShaderSource =
"#version 410\n"
"layout (location = 0) in vec3 vp;\n"
"uniform mat4 transform;"
"void main()\n"
"{\n"
" gl_Position = transform * vec4(vp, 1.0);\n"
"}\0";
I recommend you to use the glm library for that. You calculate your matrix and pass it to your shader like this:
auto transformMatrix = glm::rotate( /* your rotation calculation */ );
auto transLoc = glGetUniformLocation(shaderProgram, "transform");
glUniformMatrix4fv(transLoc , 1, GL_FALSE, glm::value_ptr(transformMatrix));

Why can I have an OpenGL shader class, but not a VAO class?

I have been fiddling around with making a game/rendering engine, and I have found that I can have a class for a shader object, but if I wrap a VAO in a class, it won't render.
The shaders return no errors, and the VAO and shaders are valid OpenGL objects.
UPDATE
The problem is this line:
glBufferData(GL_ARRAY_BUFFER, sizeof(arrFVertex), arrFVertex, GL_STATIC_DRAW);
As #BDL suggested in the comments, I thought about it and I realized, it should be:
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * intNumVertex * 3, arrFVertex, GL_STATIC_DRAW);
UPDATE 2
In response to being put on hold, here is a Minimum Complete and Verifiable Example:
#include <OpenGL/gl3.h>
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
SDL_Window *window = NULL;
SDL_GLContext openGLRenderer;
bool bolRunning = true;
int intGLVersionMajor, intGLVersionMinor;
GLfloat arrFVertex[] = {
0.5f, 0.5f, 0.0f, // Top Right
0.5f, -0.5f, 0.0f, // Bottom Right
-0.5f, 0.5f, 0.0f, // Top Left
0.5f, -0.5f, 0.0f, // Bottom Right
-0.5f, -0.5f, 0.0f, // Bottom Left
-0.5f, 0.5f, 0.0f // Top Left
};
GLuint intVAO;
GLuint intVBO;
GLuint intShaderAttribPosition;
GLuint intShaderProgram;
GLuint intNumVertex = 6;
void loadShaders(const char *strVertexShaderSource, const char *strFragmentShaderSource) {
intShaderProgram = glCreateProgram();
GLuint intVertexShader;
intVertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(intVertexShader, 1, &strVertexShaderSource, NULL);
glCompileShader(intVertexShader);
GLuint intFragmentShader;
intFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(intFragmentShader, 1, &strFragmentShaderSource, NULL);
glCompileShader(intFragmentShader);
glAttachShader(intShaderProgram, intVertexShader);
glAttachShader(intShaderProgram, intFragmentShader);
glLinkProgram(intShaderProgram);
glDeleteShader(intVertexShader);
glDeleteShader(intFragmentShader);
}
void buildVAO(GLfloat *arrFVertex) {
intShaderAttribPosition = glGetAttribLocation(intShaderProgram, "f3Position");
glGenVertexArrays(1, &intVAO);
glBindVertexArray(intVAO);
glGenBuffers(1, &intVBO);
glBindBuffer(GL_ARRAY_BUFFER, intVBO);
glVertexAttribPointer(intShaderAttribPosition, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid *)0);
glEnableVertexAttribArray(intShaderAttribPosition);
glBufferData(GL_ARRAY_BUFFER, sizeof(arrFVertex), arrFVertex, GL_STATIC_DRAW);
glBindVertexArray(0);
}
int main(int argc, char **argv) {
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("GSEngine",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
640, 480,
SDL_WINDOW_OPENGL);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
if (window == NULL) {
printf("Could not create window: %s\n", SDL_GetError());
exit(1);
}
openGLRenderer = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, openGLRenderer);
glViewport(0, 0, 640, 480);
loadShaders("#version 330 core\n\
in vec3 f3Position;\n\
void main() {\n\
gl_Position = vec4(f3Position, 1.0);\n\
}", "#version 330 core\n\
out vec4 f4Color;\n\
void main() {\n\
f4Color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n\
}");
buildVAO(arrFVertex);
while (bolRunning) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
bolRunning = false;
}
}
SDL_GL_MakeCurrent(window, openGLRenderer);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(intShaderProgram);
glDrawArrays(GL_TRIANGLES, 0, intNumVertex);
SDL_GL_SwapWindow(window);
}
glDeleteBuffers(1, &intVBO);
glDeleteVertexArrays(1, &intVAO);
glDeleteShader(intShaderProgram);
SDL_GL_DeleteContext(openGLRenderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
The problem has nothing to do with the VAO, but with the VBO. Since you pass a pointer to the constructor:
void GSMesh::build(GLfloat *arrFVertex, GSShader *shader, int _intNumVertex)
{
glBufferData(GL_ARRAY_BUFFER, sizeof(arrFVertex), arrFVertex, GL_STATIC_DRAW);
}
sizeof(arrFVertex) = sizeof(GLfloat*) which is the size of the pointer, not the size of the array pointed to. The correct code will look like this:
glBufferData(GL_ARRAY_BUFFER,
sizeof(GLfloat) * _intNumVertex * 3, arrFVertex,
GL_STATIC_DRAW);
In general I have to add, that this is not the way how questions should be asked on SO. It would have been good if you would have included at least the relevant parts of the code in your question.
Despite what the spec says, with some drivers you must enable the shader before you can get the location of an attribute or uniform. This may be what is causing your problems.
In your code that would mean in your GSMesh::build method adding:
shader->use();
Before:
intShaderAttribPosition = glGetAttribLocation(shader->intShaderProgram, "f3Position");
Personally if the version of OpenGL that you are using has support for Vertex Attribute Indexes I'd use them instead.
In the vertex shader you could have something like:
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 tex_coords;
And then in your mesh class all you need is:
struct Vertex
{
glm::vec3 position;
glm::vec2 tex_coords;
};
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, position);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, tex_coords));