So i have a couple classes. A renderer and box2drenderer. Now both use their own vertex buffer and their own vertex array object. The Renderer is instantiated first with the following code:
glGenBuffers(1, &ebo);
glGenBuffers(1, &vbo);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLfloat vertices[] = {
// Position(2) Color(3) Texcoords(2)
0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // Top-left
1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, // Top-right
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // Bottom-right
0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f // Bottom-left
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), 0);
GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(5 * sizeof(GLfloat)));
glBindVertexArray(0);
glUseProgram(shaderProgram);
projection = glm::ortho(0.0f, width, height, 0.0f);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUseProgram(0);
Then I call the setup function for the box2d:
void Box2DRenderer::setRenderer(Renderer * r) {
this->renderer = r;
const GLchar * fragSource =
"#version 150 core\n\
precision mediump float;\n\
uniform vec4 u_color;\n\
out vec4 Color;\n\
\n\
void main()\n\
{\n\
Color = u_color;\n\
}";
const GLchar * vertSource =
"#version 150 core\n\
uniform mediump mat4 u_projection;\n\
uniform mediump float u_pointSize;\n\
in vec2 a_position;\n\
\n\
void main()\n\
{\n\
gl_PointSize = u_pointSize;\n\
gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\n\
}";
this->renderer->compileProgram(vertSource, fragSource, vertShader, fragShader, shaderProgram);
glUseProgram(shaderProgram);
glGenBuffers(1, &vbo);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "u_projection"), 1, GL_FALSE, glm::value_ptr(this->renderer->getProjectionMatrix()));
GLuint positionLocation = glGetAttribLocation(shaderProgram, "a_position");
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
glBindVertexArray(0);
colorLocation = glGetUniformLocation(shaderProgram, "u_color");
pointSizeLocation = glGetUniformLocation(shaderProgram, "u_pointSize");
glUseProgram(0);
}
The Renderer for now just draws textures. So i draw the player via the method:
void Renderer::renderTexture(sf::FloatRect &bounds, Texture &texture, Region *region) {
glm::mat4 model;
model = glm::translate(model, glm::vec3(bounds.left, bounds.top, 0.0f));
model = glm::scale(model, glm::vec3(bounds.width, bounds.height, 0.0f));
GLint modelMat = glGetUniformLocation(shaderProgram, "mMatrix");
glUniformMatrix4fv(modelMat, 1, GL_FALSE, glm::value_ptr(model));
float x = region->pos.x / texture.getWidth();
float y = region->pos.y / texture.getHeight();
float rx = (region->width + region->pos.x) / texture.getWidth();
float ry = (region->height + region->pos.y) / texture.getHeight();
GLfloat vertices[] = {
// Position(2) Color(3) Texcoords(2)
0.0f, 0.0f, 1.0f, 1.0f, 1.0f, x, y, // Top-left
1.0f, 0.0f, 1.0f, 1.0f, 1.0f, rx, y, // Top-right
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, rx, ry, // Bottom-right
0.0f, 1.0f, 1.0f, 1.0f, 1.0f, x, ry // Bottom-left
};
glBindTexture(GL_TEXTURE_2D, texture.getTextureId());
glBindVertexArray(vao);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
Now, if i don't initialize the box2d renderer, it works fine. If i have the box2d renderer, the texture coords are getting messed up. The whole texture seems to get drawn across the screen instead of regions at their correct place.
Given i'm turning on and off the BindVertexArray, I feel like I shouldn't have an issue, but for the life of me I can't figure it out. I can post screenshots of the difference if you'd like.
You probably fell victim to a fairly common misconception: Contrary to what you might have expected, the GL_ARRAY_BUFFER binding is not part of the VAO state.
At the tail end of the posted code you have this sequence:
glBindVertexArray(vao);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
The glBufferSubData() call will modify data in the currently bound GL_ARRAY_BUFFER, which is the buffer that you last made a glBindBuffer(GL_ARRAY_BUFFER, ...) call for. This is unrelated to the buffer you had bound when you previously used the VAO.
For additional illustration, here is a typical call sequence:
glBindVertexArray(vaoA);
glBindBuffer(GL_ARRAY_BUFFER, vboA);
glBindVertexArray(vaoB);
glBindBuffer(GL_ARRAY_BUFFER, vboB);
glBindVertexArray(vaoA);
The current GL_ARRAY_BUFFER binding at the end of this sequence is vboB. Since the binding is not part of the VAO state, it is simply based on the most recent glBindBuffer() call.
All you need to do to fix this is to add the glBindBuffer() call before glBufferSubData().
Note that the GL_ELEMENT_ARRAY_BUFFER binding is part of the VAO state. This may seem inconsistent, but it's not. The VAO bundles all the vertex setup state that is used by draw commands. The GL_ELEMENT_ARRAY_BUFFER binding controls which index buffer is used by draw commands, so it is part of this state. On the other hand, the current GL_ARRAY_BUFFER binding has no effect on the draw command, and is therefore not part of the VAO state.
Related
I'm creating a game in SDL where everything has to be drawn in OpenGL. I've drawn two shapes with different textures and added keyboard controls. My problem is only my Player textured shape should be controllable but instead both of my shapes are stuck together and the vector I thought controlled the enemy position doesn't. Is my problem when I draw? How do I make it so I my player controls only move the player shape.
//Declare transform and model matrix.
glm::mat4 Model; glm::mat4 Rotation; glm::mat4 View;
glm::mat4 Projection;
glm::vec3 Player = glm::vec3(2.0f, 0.5f, -1.0f);
GLfloat playermovespeed = 0.1f;
Projection = glm::ortho(0.0f, 4.0f, 0.0f, 3.0f, -1.0f, 100.0f);
Model = glm::translate(Model, Player);
GLint ProjectionLocation = glGetUniformLocation(shaderProgram, "ProjectionMat");
glUniformMatrix4fv(ProjectionLocation, 1, GL_FALSE, glm::value_ptr(Projection));
SDL_GetWindowSize(window, &w, &h); glViewport(0, 0, w, h);
while (WindowOpen)
{
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture[0]);
Model = glm::mat4();
Model = glm::translate(Model, glm::vec3(0.0f, 15.0f, 5.0f)); //Position of enemy shape
GLint ModelLocation = glGetUniformLocation(shaderProgram, "ModelMat");
GLint ViewLocation = glGetUniformLocation(shaderProgram, "ViewMat");
//glUniformMatrix4fv(ModelLocation, 1, GL_FALSE, glm::value_ptr(Model*Rotation));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
//Player texture
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, textureA);
Model = glm::mat4(); //y
Model = glm::translate(Model, Player); //Position control of ship.
ModelLocation = glGetUniformLocation(shaderProgram, "ModelMat");
glUniformMatrix4fv(ModelLocation, 1, GL_FALSE, glm::value_ptr(Model));
glUniformMatrix4fv(ViewLocation, 1, GL_FALSE, glm::value_ptr(View));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
SDL_GL_SwapWindow(window);
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
WindowOpen = false;
if (event.type == SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_RIGHT:
Player.x += playermovespeed;
break;
case SDLK_LEFT:
Player.x -= playermovespeed;
break;
default:
break;
}
}
}
}
}
But just in case here is also how I set up everything.
GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // Top Right
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // Bottom Right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // Bottom Left
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
};
GLuint indices[] = { start from 0!
0, 1, 3,
1, 2, 3,
};
//Load image Enemy; //Load image Player; //Load shaders;
GLuint VBO;
glGenBuffers(1, &VBO);
GLuint EBO;
glGenBuffers(1, &EBO);
GLuint texture[2];
glGenTextures(2, texture);
glBindTexture(GL_TEXTURE_2D, texture[0]);
//set texture parameters. First texture.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
SDL_FreeSurface(image);
//Second texture same way as first; //Set texture parameters
GLuint VAO;
glGenVertexArrays(1, &VAO);
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, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
I have a problem with my code. I am rendering two objects at the moment. They are floor and figure. Floor is in VAO[0] and figure in VAO1. My problem is that I can not see the object floor. I know I have to change the view of the object floor to make it visible. I want to do this with an rotation. I only want to change floor. Here is my hole code. Could someone please help me. I only want to use modern opengl in this content opengl 3.3. I want to have my view like this: My scene The red area is floor and the green is figure.
How can I achieve my objective. For your information. This is a test scene. My distant objective is hole scene like in a 3d game. So this means more polygones for the floor and rest of the scence like walls, ceillings, objects in the room and nps. All made with sprites, as I think this would be the best way if will not use a 3d programm to create 3d models. So if you have tips for my objects, appreciate it.
Thank you for your help.
#define GLFW_NO_GLU
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>
int main()
{
if(glfwInit()==GL_FALSE)
{
std::cerr<<"GLFW FAIL";
return 1;
}
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);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(1024, 748, "My Game", NULL, NULL);
if (window==GL_FALSE)
{
std::cerr<<"Open Window FAIL";
return 1;
}
glfwMakeContextCurrent(window);
glewExperimental = true;
if(glewInit()!=GLEW_OK)
{
std::cerr<<"GLEW FAIL";
return 1;
}
glViewport(0, 0, 1024, 748);
const GLchar* vertexshadersrc="#version 330 core\n"
"layout (location = 0) in vec4 position;\n"
"uniform mat4 matrix;\n"
"void main()\n"
"{\n"
"gl_Position = gl_Position=matrix * position;\n"
"}\0";
const GLchar* fragmentshadersrc="#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color=vec4(1.0f,0.0f,0.0f,1.0f);\n"
"}\0";
GLuint vertexshader=glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexshader,1,&vertexshadersrc,NULL);
glCompileShader(vertexshader);
GLint compile_ok;
GLint errlength;
GLchar* errmsg;
glGetShaderiv(vertexshader,GL_COMPILE_STATUS, &compile_ok);
if(compile_ok==GL_FALSE)
{
glGetShaderiv(vertexshader, GL_INFO_LOG_LENGTH,&errlength);
errmsg=new GLchar[errlength];
glGetShaderInfoLog(vertexshader,errlength,&errlength,errmsg);
std::cerr<<"Vertexshader";
std::cerr<<errmsg;
return 1;
}
GLuint fragmentshader=glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentshader,1,&fragmentshadersrc,NULL);
glCompileShader(fragmentshader);
glGetShaderiv(fragmentshader,GL_COMPILE_STATUS, &compile_ok);
if(compile_ok==GL_FALSE)
{
glGetShaderiv(fragmentshader, GL_INFO_LOG_LENGTH,&errlength);
errmsg=new GLchar[errlength];
glGetShaderInfoLog(fragmentshader,errlength,&errlength,errmsg);
std::cerr<<"Fragmentshader";
std::cerr<<errmsg;
return 1;
}
GLuint programm=glCreateProgram();
glAttachShader(programm,vertexshader);
glAttachShader(programm,fragmentshader);
glLinkProgram(programm);
glDeleteShader(vertexshader);
glDeleteShader(fragmentshader);
GLfloat floor[]=
{
-1.0f, 0.0f, 1.0f,
-1.0f, 0.0f, -1.0f,
1.0f, 0.0f, 1.0f,
1.0f, 0.0f, -1.0f,
};
GLfloat floorc[]=
{
1.0f,0.0f,0.0f,1.0f
};
GLfloat figure[] = {
-0.2f, 0.4f, -0.1f,
-0.2f, 0.0f, -0.1f,
0.2f, 0.4f, -0.1f,
0.2f, 0.0f, -0.1f
};
GLfloat figurec[]=
{
0.0f,1.0f,0.0f,1.0f
};
GLfloat tree[] = {
-0.7f, 0.4f, -0.1f,
-0.7f, 0.0f, -0.1f,
-0.3f, 0.4f, -0.1f,
-0.3f, 0.0f, -0.1f
};
GLuint VAO[3], VBO[6];
glGenVertexArrays(3, VAO);
glGenBuffers(6, VBO);
glBindVertexArray(VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER,sizeof(floor),floor,GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER,sizeof(floorc),floorc,GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glBindVertexArray(VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(figure), figure, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, VBO[3]);
glBufferData(GL_ARRAY_BUFFER, sizeof(figurec), figurec, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glBindVertexArray(VAO[2]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[4]);
glBufferData(GL_ARRAY_BUFFER, sizeof(tree), tree, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glm::mat4 projection;
projection=glm::perspective(45.0f,4.0f/3.0f,0.1f,100.0f);
glm::mat4 modelview;
modelview=glm::translate(glm::mat4(1.0f),glm::vec3(0.0f, 0.0f, -1.0f));
glm::mat4 mpmatrix=projection*modelview;
//GLuint position=glGetAttribLocation(programm,"position");
GLuint matrixuni=glGetUniformLocation(programm,"matrix");
//glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(GLvoid*)0);
glUseProgram(programm);
glUniformMatrix4fv(matrixuni,1,GL_FALSE,&mpmatrix[0][0]);
while (!glfwWindowShouldClose(window))
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(VAO[0]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(VAO[1]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
/*glBindVertexArray(VAO[2]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);*/
glfwPollEvents();
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
Image on the screen generated from 3 matrices: projection matrix, view matrix and model matrix. Seems that you forget about view matrix. I replaced your matrix part by this code:
glm::mat4 projection;
projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
glm::mat4 view;
view = glm::lookAt(glm::vec3(0, 0.25, 0.75), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
glm::mat4 modelview;
modelview = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -1.0f));
glm::mat4 mpmatrix = projection*view*modelview;
And I got this picture:
It's look like your picture but both objects have red color because they use same shaders where color sets as red.
UPD:
Maybe for you will be enough decrease a little floor height:
GLfloat floor[] = {
-1.0f, -0.05f, 1.0f,
-1.0f, -0.05f, -1.0f,
1.0f, -0.05f, 1.0f,
1.0f, -0.05f, -1.0f,
};
So I finally set up opengl window properly and got triangles to show up using vaos, vbos and glDrawElements() etc.
Here is the what i have
But now I have new problem - can't get shaders to work. I don't quite understand them yet. I want fragment shader to show vertex colors which I put into a separate buffer object.
Example code:
const char* vertexShaderSource =
"#program 330\n"
"layout(location = 0) in vec2 position;\n"
"layout(location = 1) in vec3 color;\n"
"out vec4 fragColor;\n"
"void main(void){\n"
"gl_Position = vec4(position, 0.0, 1.0);\n"
"fragColor = vec4(color, 1.0);\n"
"}";
const char* fragShaderSource =
"#program 330\n"
"in vec4 fragColor;\n"
"out vec4 outColor;\n"
"void main(void){\n"
"outColor = fragColor;\n"
"}";
GLuint programID = glCreateProgram();
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShaderID, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShaderID);
GLuint fragShaderID = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragShaderID, 1, &fragShaderSource, NULL);
glCompileShader(fragShaderID);
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragShaderID);
glLinkProgram(programID);
glValidateProgram(programID);
GLfloat vertexPositions[8] =
{
-0.5f, 0.5f,
0.5f, 0.5f,
-0.5f, -0.5f,
0.5f, -0.5f,
};
GLfloat colors[18] =
{
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
};
GLushort indices[6] =
{
0, 1, 2,
1, 3, 2
};
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo; //Vertices
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertexPositions, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
GLuint cbo; //Colors
glGenBuffers(1, &cbo);
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 18, colors, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLuint ibo; //Indexes
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * 6, indices, GL_STATIC_DRAW);
And render:
while(..)
{
..clear
glBindVertexArray(vao);
glUseProgram(programID);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)(0));
..update
}
Everything seems to work fine except for shaders. Any help is appreciated :)
Thanks.
In each of the shaders, change "#program 330\n" to "#version 330\n". That is how you specify which GLSL version to use.
I programmed an OpenGL application with an SDL window. Core Profile running OpenGL 4.1 on a Mac OSX 10.9. The command glClearColor works great and I get the right color on screen. But inside my renderer I got the GL_INVALID_OPERATION error everytime I execute the commands glEnableVertexAttribArray and glDrawArrays.
That is the code:
Vertex Shader:
#version 410
in vec4 position;
void main(void)
{
gl_Position = position;
}
Fragment Shader:
#version 410
out vec4 out_Color;
void main(void)
{
out_Color = vec4(0.0, 1.0, 0.0, 1.0);
}
All shader compile and linked to an program. No linking error!
Creating buffer with data:
static const float VertexBufferData[] = {
0.75f, 0.75f, 0.0f, 1.0f,
0.75f, -0.75f, 0.0f, 1.0f,
-0.75f, -0.75f, 0.0f, 1.0f,
};
glGenBuffers(1, &m_VertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexBufferData), VertexBufferData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Render:
glUseProgram(m_ShaderProgram);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
// glDrawElements( GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
Output:
AS BDL already said: The solution is to create a VAO. As a short description: A VAO (Vertex Array Object) is a collection of VBOs, which describes the vertex layout and the vertices for the shader.
More informations here:
OpenGL VAO best practices
http://www.swiftless.com/tutorials/opengl4/4-opengl-4-vao.html
So I have changed the following code blocks:
Buffer:
static const float VertexBufferData[] = {
0.75f, 0.75f, 0.0f, 1.0f,
0.75f, -0.75f, 0.0f, 1.0f,
-0.75f, -0.75f, 0.0f, 1.0f,
};
glGenVertexArrays(1, &m_VertexBufferArray);
glBindVertexArray(m_VertexBufferArray);
glGenBuffers(1, &m_VertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_VertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexBufferData), VertexBufferData, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
Render:
glUseProgram(m_ShaderProgram);
glBindVertexArray(m_VertexBufferArray);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glUseProgram(0);
Result:
I'm trying to write a basic OpenGL 3.3 program with shaders, buffers, etc. drawing a cube. The problem is that the cube is not drawn. Sorry for such an amout of code, but i feel like the error might be anywhere, because to me it all seems right: display function is looping, shaders are compiled, matrices are passed to shaders. I suspecting that something might be wrong with culling. Please take a look. Here is the code (I'm using freeglut, first init() is called, then display runs in a loop):
initialization code:
struct ProgramData
{
GLuint theProgram;
GLuint iModel;
GLuint iView;
GLuint iProjection;
};
ProgramData shaderProgram;
ProgramData LoadProgram(const std::string &strVertexShader,
const std::string &strFragmentShader)
{
std::vector<GLuint> shaderList;
shaderList.push_back(LoadShader(GL_VERTEX_SHADER, strVertexShader));
shaderList.push_back(LoadShader(GL_FRAGMENT_SHADER, strFragmentShader));
ProgramData data;
data.theProgram = CreateProgram(shaderList);
data.iModel = glGetUniformLocation(data.theProgram, "mModel");
data.iView = glGetUniformLocation(data.theProgram, "mView");
data.iProjection = glGetUniformLocation(data.theProgram, "mProjection");
return data;
}
float cube_vertices[] = {
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
GREEN_COLOR,
BLUE_COLOR,
RED_COLOR,
BROWN_COLOR,
GREEN_COLOR,
BLUE_COLOR,
RED_COLOR,
BROWN_COLOR,
};
GLubyte cube_elements[] = {
0,1,2, 2,3,0,
0,3,4, 4,5,0,
0,5,6, 6,1,0,
1,6,7, 7,2,1,
7,4,3, 3,2,7,
4,7,6, 6,5,4
};
void InitializeProgram()
{
//initialize vertex buffer
glGenBuffers(1, &vertex_buffer_obj);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_obj);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_vertices),
cube_vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//initialize index buffer
glGenBuffers(1, &index_buffer_obj);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_obj);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cube_elements),
cube_elements, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
shaderProgram = LoadProgram("shader.vert", "shader.frag");
}
void init()
{
InitializeProgram();
int numberOfVertices = 8;
size_t color_data_offset = sizeof(float) * 3 * numberOfVertices;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_obj);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0,
(void*)color_data_offset);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_obj);
glBindVertexArray(0);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CW);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glDepthRange(0.0f, 1.0f);
}
vertex shader:
#version 330
layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec3 color;
uniform mat4 mProjection;
uniform mat4 mView;
uniform mat4 mModel;
smooth out vec3 theColor;
void main()
{
gl_Position = mProjection * mView * mModel * vec4(inPosition, 1);
theColor = color;
}
fragment shader:
#version 330
smooth in vec3 theColor;
out vec4 outputColor;
void main()
{
outputColor = vec4(theColor, 1);
}
draw code:
glm::vec3 cam_pos(3, 2, 3);
void display()
{
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram.theProgram);
glm::mat4 model_matrix = glm::translate(glm::vec3(0, 0, 0));
glm::mat4 view_matrix = glm::lookAt(cam_pos,
glm::vec3(0, 0, 0), glm::vec3(0, 0, 1));
glm::mat4 proj_matrix = glm::perspective(45.0f, 1.0f, 1.0f, 100.0f);
glUniformMatrix4fv(shaderProgram.iProjection, 1,
GL_FALSE, glm::value_ptr(proj_matrix));
glUniformMatrix4fv(shaderProgram.iView, 1,
GL_FALSE, glm::value_ptr(view_matrix));
glUniformMatrix4fv(shaderProgram.iModel, 1,
GL_FALSE, glm::value_ptr(model_matrix));
glBindVertexArray(vao);
int size; glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER,
GL_BUFFER_SIZE, &size);
glDrawElements(GL_TRIANGLES, size / sizeof(GLubyte), GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
glUseProgram(0);
glutSwapBuffers();
glutPostRedisplay();
}
UPD: in init method when an offset for colors is calculated should be
sizeof(float) * 3 * numberOfVertices instead of
sizeof(GLubyte) * 3 * numberOfVertices, colors are stored as floats. Rendering problem not solved.
SOLVED: thank you for help. See my answer below.
On thing I did spot when glancing over your code is the following line from your vertex shader:
gl_Position = mProjection * mView * mModel * vec4(inPosition, 0);
That 0 should really be a 1.0.
In display() function
glDrawElements(GL_TRIANGLES, size / sizeof(GLubyte), GL_UNSIGNED_SHORT, 0);
should be changed to
glDrawElements(GL_TRIANGLES, size / sizeof(GLubyte), GL_UNSIGNED_BYTE, 0);
and in init()
glFrontFace(GL_CW);
to
glFrontFace(GL_CCW);
So the problem was that I passed to OpenGL incorrect data. Index array is of GLUbyte (1byte size each array element) but I for some reason decided it was GLushort (2bytes).
edit: doesn't matter a lot, but up vector (when generating camera matrix) should be not glm::vec3(0, 0, 1) but glm::vec3(0, 1, 0)