Related
I'm trying to render multiple objects in OpenGL using multiple VAO's and VBO's. To render multiple objects using the same vertices I've done it, but what I want to do is to use different vertices for each object, for example to draw a square and a circle. For a square I only need 6 vertices but for circle I need 360.
I have error with reading or creating the shaders.
Here is the Vertex Shader:
#version 330 core
layout (location = 0) in vec4 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * position;
}
Fragment Shader:
#version 330 core
layout(location = 0) out vec4 color;
uniform vec4 u_Color;
void main()
{
color = u_Color;
}
The VAO and VBO generating and binding
// Circle
std::vector<VertexFormat> vertices;
for (int i = 0; i < 360; i++)
{
GLfloat angle = i * ((2.0f * 3.14159f) / 360);
vertices.push_back(VertexFormat(glm::vec3(cos(angle) * 100.0f, sin(angle) * 100.0f, 0.0f)));
}
// Pipette object
std::vector<VertexFormat> pipetteVertices;
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 500.0f, injPipette.y + 500.0f, 0.0f))); // 0
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 700.0f, injPipette.y + 500.0f, 0.0f))); // 1
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 700.0f, injPipette.y + 700.0f, 0.0f))); // 2
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 500.0f, injPipette.y + 700.0f, 0.0f))); // 3
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 500.0f, injPipette.y + 500.0f, 0.0f)));
pipetteVertices.push_back(VertexFormat(glm::vec3(injPipette.x + 700.0f, injPipette.y + 700.0f, 0.0f)));
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexFormat) * 6, &pipetteVertices[0], GL_STATIC_DRAW);
//Position attribute
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (GLvoid *)0);
GLuint vao2;
glGenVertexArrays(1, &vao2);
glBindVertexArray(vao2);
GLuint vbo2;
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexFormat) * 360, &vertices[0], GL_STATIC_DRAW);
//Position attribute
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (GLvoid *) 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
And the draw call in the rendering loop:
//Get the uniform locations of model, view and projection matrices
modelID = glGetUniformLocation(program, "model");
viewID = glGetUniformLocation(program, "view");
projectionID = glGetUniformLocation(program, "projection");
//View transform
glm::mat4 view = glm::lookAt(glm::vec3(0, 0, 2), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
//Projection transform
//glm::mat4 projection = glm::perspective(45.0f, (GLfloat)screenWidth / (GLfloat)screenHeight, 0.1f, 1000.0f);
glm::mat4 projection = glm::ortho(0.0f, (GLfloat)screenWidth, 0.0f, (GLfloat)screenHeight, 0.1f, 10.0f);
{
glUniformMatrix4fv(viewID, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projectionID, 1, GL_FALSE, glm::value_ptr(projection));
glm::mat4 translate = glm::translate(glm::mat4(1.0), glm::vec3(100.0f + move_x, 100.0f + move_y, 0.0f));
glm::mat4 rotate = glm::rotate(glm::mat4(1.0), 0.0f, glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3(1.0f, 1.0f, 2.0f));
glm::mat4 model = translate * rotate * scale;
glUniformMatrix4fv(modelID, 1, GL_FALSE, glm::value_ptr(model));
glUniform4f(color, 0.0f, 0.0f, 1.0f, 1.0f);
//Render
glDrawArrays(GL_TRIANGLE_FAN, 0, 360);
}
{
glUniformMatrix4fv(viewID, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projectionID, 1, GL_FALSE, glm::value_ptr(projection));
glm::mat4 translate = glm::translate(glm::mat4(1.0), glm::vec3(300.0f + injPipette.x, 300.0f + injPipette.y, 0.0f));
glm::mat4 rotate = glm::rotate(glm::mat4(1.0), 0.0f, glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3(1.0f, 1.0f, 2.0f));
glm::mat4 model = translate * rotate * scale;
glUniformMatrix4fv(modelID, 1, GL_FALSE, glm::value_ptr(model));
glUniform4f(color, 1.0f, 0.0f, 0.0f, 0.5f);
//Render
glDrawArrays(GL_TRIANGLES, 0, 6);
}
I repeat, to draw multiple objects using the same vertices I've done it. I need to know how to draw multiple objects using the same vertex and fragment shader but different number of vertices. The project is small, just rendering maximum 10 objects in 2D.
Drawing commands such as glDrawArrays process and draw the arrays of generic vertex attribute data specified in the currently bound Vertex Array Object.
This means that you need to bind the correct vertex array object before executing the Draw call:
// [...]
glBindVertexArray(vao2);
glDrawArrays(GL_TRIANGLE_FAN, 0, 360);
// [...]
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
I found a project with the code:
#pragma once
#include "glm\glm.hpp"
struct VertexFormat
{
glm::vec3 position;
VertexFormat(const glm::vec3 &iPos)
{
position = iPos;
}
VertexFormat()
{
}
};
This question already has an answer here:
Can't set uniform value in OpenGL shader
(1 answer)
Closed 6 years ago.
I have a simple vertex array that draws a quad to the screen.
glViewport(0, 0, screenWidth, screenHeight);
// Load shaders
...
GLfloat vertices[] = {
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
GLuint vao, vbo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
...
glUseProgram(program);
glUniform3f(glGetUniformLocation(program, "spriteColour"), colour.x, colour.y, colour.z);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
Using the below simple vertex and fragment shaders.
#version 330 core
layout (location = 0) in vec2 vertex;
void main()
{
gl_Position = vec4(vertex.xy, 0.0, 1.0);
}
#version 330 core
out vec4 color;
uniform vec3 spriteColour;
void main()
{
color = vec4(spriteColour, 1.0);
}
This works exactly how I expect. It renders a rectangle to the upper right corner of the window.
Now I want to add a simple model and projection matrix. I am using an orthographic projection matrix and my model matrix just scales the quad to 100 x 100.
glm::mat4 projection = glm::ortho(0.0f, (GLfloat)screenWidth, (GLfloat)screenHeight, 0.0f, -1.0f, 1.0f);
glUniformMatrix4fv(glGetUniformLocation(shader, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
...
glm::mat4 model;
model = glm::scale(model, glm::vec3(100.0f, 100.0f, 1.0f));
glUniformMatrix4fv(glGetUniformLocation(program, "model"), 1, GL_FALSE, glm::value_ptr(model));
...
// Update vertex shader
#version 330 core
layout (location = 0) in vec2 vertex;
uniform mat4 model;
uniform mat4 projection;
void main()
{
gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);
}
I would expect this to render a 100 x 100 quad at the top left of the screen however I don't see anything.
I can only assume that somehow my transformations are causing the quad to be drawn off screen and clipped? I am pretty new at Open GL so I am not entirely sure what is wrong here. I've been over it numerous times and based on the tutorials I am using (http://learnopengl.com/) it seems correct.
Does anyone have any ideas as to what I've done wrong?
Turns out you need to activate the program before setting uniforms.
Can't set uniform value in OpenGL shader
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.
The issue is that I can't figure out how to properly draw two objects, because my another object isn't being drawn.
Here's the main code:
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
GLuint VertexArrayID2;
glGenVertexArrays(1, &VertexArrayID2);
glBindVertexArray(VertexArrayID2);
GLuint programID = LoadShaders( "SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader" );
GLuint MatrixID = glGetUniformLocation(programID, "MVP");
GLuint MatrixID2 = glGetUniformLocation(programID, "MVP2");
glm::mat4 Projection = glm::perspective(45.0f, 5.0f / 4.0f, 0.1f, 100.0f);
glm::mat4 View = glm::lookAt(
glm::vec3(4*2,3*2,8*2),
glm::vec3(0,0,0),
glm::vec3(0,1,0)
);
glm::mat4 Model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glm::mat4 Model2 = glm::translate(glm::mat4(1.0f), glm::vec3(-5.0f, 0.0f, 0.0f));
glm::mat4 MVP2 = Projection * View * Model2;
glUniformMatrix4fv(MatrixID2, 1, GL_FALSE, &MVP2[0][0]);
static const GLfloat g_vertex_buffer_data[] = {
-1.0f,-1.0f,-1.0f,
-1.0f,-1.0f, 1.0f,
(plenty of floats)
1.0f,-1.0f, 1.0f
};
static const GLfloat g_vertex_buffer_data2[] = {
-1.0f, -1.0f, 3.0f,
(plenty of floats)
0.0f, 1.0f, 2.0f,
};
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
GLuint vertexbuffer2;
glGenBuffers(1, &vertexbuffer2);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data2), g_vertex_buffer_data2, GL_STATIC_DRAW);
do{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programID);
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(MatrixID2, 1, GL_FALSE, &MVP2[0][0]);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);
glDrawArrays(GL_TRIANGLES, 0, 12*3);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2);
glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,0,(void*)0);
glDrawArrays(GL_TRIANGLES, 0, 4*3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glfwSwapBuffers(window);
glfwPollEvents();
}
And shader:
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 2) in vec3 vertexPosition_modelspace2;
uniform mat4 MVP;
uniform mat4 MVP2;
void main(){
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
gl_Position = MVP2 * vec4(vertexPosition_modelspace2,1);
}
I have noticed that only last object is being drawn, so the issue is that 'gl_Position' overwrites it's values, but how should I figure it out?
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
gl_Position = MVP2 * vec4(vertexPosition_modelspace2,1);
That is not how the graphics pipeline work. You can not draw two objects at the same time. Just the last write to gl_Position will be effective, and your first object will be completely ignored. In the most basic variant, you want to draw two completely independent objects, and you will need two draw calls for that - as you do in your code.
However, when doing so, you do not need two different vertex attributes. Your shader just processes vertices, which in your case only have the verexPosition_modelspace attribute. So you can use that attribute for all the objects you want to draw. There is no point in using different attributes for different objects if the attribute means the same thing.
Let's have a look at your drawing code:
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);
Here, you set up vertex attribute 0 to point to the vertex data of the first buffer, and you enable the attribute array. So the data will not be used as source for vertexPosition_modelspace.
glDrawArrays(GL_TRIANGLES, 0, 12*3);
Now you draw the object. But as we already have seen, your shader does only really use vertexPosition_modelspace2, for which you did not have set an pointer, or enabled the array. Since the array is disabled, the GL will use the current value of attribute 2 - for all vertices. So in the case of triangles, you create triangles with all points being the same - getting triangles with a surface area of 0 and are invisible anyways, no matter what actual value attribute 2 currently has.
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);
Now you do a strange thing: you enable attribute 2 array, but do not set a pointer for it! You should re-specify the pointer for attribute 0 to point to your second model.
glDrawArrays(GL_TRIANGLES, 0, 4*3);
Now you draw with both attribute 0 and 2 enabled. Attribute 0 will contain the data you want, but is ignored by the shader. Attribute 2 is just point somewhere, and you get undefined behavior - it might just crash, but It might also display strange stuff, or nothing at all.
To make this work, just remove vertexPosition_modelspace2 completely from the shader. Use just one MVP matrix also.
When drawing any object, you have to:
Set the MVP uniform matrix for the object
Set the attribute pointer for attribute 0
Enable the attribute array for attribute 0 (or make sure it is already enabled)
Issue the draw call
You can do this with as many objects as you want.
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)