I am trying to implement picking via following an opengl tutorial, I have a mesh with 6000 vertices and I wish to pick particular ones; I have chosen to do by redering uniquely coloured boxes at each vertex point, read the pixel on my mouse click at that point and that should return to me the ID of the closest vertex. The background is rendered as white so if I miss I get nothing.
However I have a problem, it only works most of the time; there are certain areas that if I click there I get white returned even though its clearly a vertex, and when rendering the colorized scene clearly has a redish box at the point I clicked.
Then there are white areas near the mesh, to the bottom left and at some random point away from it, returns me a hit.
I do not understand at all why this is happening, it should work.
void Display() {
Controls->setVector(indexed_vertices);
if (Controls->getPicking()) {
// Clear the screen in white
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for ( int i=0; i< indexed_vertices.size(); i++) {
// use shaders
glUseProgram(pickingProgramID);
// Get a handle for our "MVP" uniform
GLuint PickingMatrixID = glGetUniformLocation(pickingProgramID, "MVP");
glm::mat4 RotationMatrix = glm::toMat4(orientations);
glm::mat4 btTranslationMatrix = glm::translate(glm::mat4(1.0f), indexed_vertices[i]);
glm::mat4 myModelMatrix = ModelMatrix * Controls->getTranslationMatrix() * Controls->getRotationMatrix() * btTranslationMatrix;
MVP = ProjectionMatrix * ViewMatrix * myModelMatrix;
Controls->setCntrlsViewMatrix(ViewMatrix);
Controls->setCntrlsProjectionMatrix(ProjectionMatrix);
glUniformMatrix4fv(PickingMatrixID, 1, GL_FALSE, &MVP[0][0]);
// Convert "i", the integer mesh ID, into an RGB color
int r = (i & 0x000000FF) >> 0;
int g = (i & 0x0000FF00) >> 8;
int b = (i & 0x00FF0000) >> 16;
// OpenGL expects colors to be in [0,1], so divide by 255.
glUniform4f(pickingColorID, r/255.0f, g/255.0f, b/255.0f, 1.0f);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, gvertexbuffer);
glVertexAttribPointer(
0, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
// Draw the triangles !
glDrawElements(
GL_TRIANGLES, // mode
indices.size(), // count
GL_UNSIGNED_SHORT, // type
(void*)0 // element array buffer offset
);
// OpenGL expects colors to be in [0,1], so divide by 255.
}
glDisableVertexAttribArray(0);
glFlush();
glFinish();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Read the pixel at the center of the screen.
// You can also use glfwGetMousePos().
// Ultra-mega-over slow too, even for 1 pixel,
// because the framebuffer is on the GPU.
unsigned char data[4];
glReadPixels(Controls->get_mx_cur(), Controls->get_my_cur(),1,1, GL_RGBA, GL_UNSIGNED_BYTE, data);
std::cout << "MX: " << Controls->get_mx_cur() << " MY: " << Controls->get_my_cur() << std::endl;
// Convert the color back to an integer ID
int pickedID =
data[0] +
data[1] * 256 +
data[2] * 256*256;
//std::cout << std::hex << pickedID << std::dec<<std::endl;
if (pickedID == 0x00ffffff) { // Full white, must be the background !
printf("Miss\n");
}
else {
std::cout << "mesh " << pickedID << std::endl;
}
// Uncomment these lines to see the picking shader in effect
glutSwapBuffers();
skip = true;
Controls->setPicking(false);
}
if (!skip) {
// White background
glClearColor(0.2f, 0.25f, 0.5f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
glUseProgram(ShaderIDs[0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
glUniform1i(TextureID, 0);
glm::mat4 myModelMatrix = ModelMatrix * Controls->getTranslationMatrix() * Controls->getRotationMatrix();
MVP = ProjectionMatrix * ViewMatrix * myModelMatrix;
// The inverse transpose of the View Model Matrix will re-normalize the normals if there's
// been any scaling. Otherwise you don't need it.
glm::mat3 NormalMatrix = glm::mat3( glm::transpose(glm::inverse(ViewMatrix * myModelMatrix)));
Controls->setCntrlsViewMatrix(ViewMatrix);
Controls->setCntrlsProjectionMatrix(ProjectionMatrix);
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &myModelMatrix[0][0]);
// Notice we're passing a 3 by 3 matrix here.
glUniformMatrix3fv(NormalMatrixID, 1, GL_FALSE, &NormalMatrix[0][0]);
glUniform3f(CameraID, cameraLoc.x, cameraLoc.y, cameraLoc.z);
glUniform3f(LightPosID, lightPosition.x, lightPosition.y, lightPosition.z);
// VBO buffer: vertices
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
1, // attribute
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2rd attribute buffer : normals
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
2, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
if ( Controls->getRenderingMode() == 0 ) {
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//glDisable(GL_POLYGON_OFFSET_FILL);
}
else if (Controls->getRenderingMode() == 1 ) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_CULL_FACE);
//glDisable(GL_POLYGON_OFFSET_FILL);
glUseProgram(ShaderIDs[1]);
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &myModelMatrix[0][0]);
// Notice we're passing a 3 by 3 matrix here.
glUniformMatrix3fv(NormalMatrixID, 1, GL_FALSE, &NormalMatrix[0][0]);
glUniform3f(CameraID, cameraLoc.x, cameraLoc.y, cameraLoc.z);
glUniform3f(LightPosID, lightPosition.x, lightPosition.y, lightPosition.z);
}
else if (Controls->getRenderingMode() == 2 ) {
glUseProgram(ShaderIDs[1]);
//
glm::mat4 MyOffsetMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(1.025,1.025,1.025));
MyOffsetMatrix = glm::mat4(1.0f);
glm::mat4 myModelMatrix2 = ModelMatrix * Controls->getTranslationMatrix() *
Controls->getRotationMatrix()*MyOffsetMatrix;
glm::mat3 NormalMatrix2 = glm::mat3( glm::transpose(glm::inverse(ViewMatrix *
myModelMatrix2)));
glm::mat4 MVP2 = ProjectionMatrix * ViewMatrix * myModelMatrix2;
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP2[0][0]);
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &myModelMatrix2[0][0]);
// Notice we're passing a 3 by 3 matrix here.
glUniformMatrix3fv(NormalMatrixID, 1, GL_FALSE, &NormalMatrix2[0][0]);
glUniform3f(CameraID, cameraLoc.x, cameraLoc.y, cameraLoc.z);
glUniform3f(LightPosID, lightPosition.x, lightPosition.y, lightPosition.z);
// The rest is exactly the same as the first object
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
// 3rd attribute buffer : normals
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_CULL_FACE);
glEnable(GL_POLYGON_OFFSET_FILL);
// Draw the triangles !
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, (void*)0);
glEnable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glPolygonOffset(2.0f, 2.0f);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//glDisable(GL_POLYGON_OFFSET_FILL);
glUseProgram(ShaderIDs[0]);
}
//glUseProgram(ShaderIDs[1]);
// Draw the triangles !
glDrawElements(
GL_TRIANGLES, // mode
indices.size(), // count
GL_UNSIGNED_SHORT, // type
(void*)0 // element array buffer offset
);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glutSwapBuffers();
}
}
The problem was two-fold: Crazy numbers returned is a result of improper multisampling enabled when I wanted specific colour values (how to have my cake and eat it might need a bit of work but right now I don't care), and secondly because glReadPixels() inverts the Y axis and needed to do Height - Current_Mouse_Position for the Y value.
Perhaps glPoints would be faster means of doing what I'm doing, I'll need to look into it.
Related
I am trying to use two groups of shaders. ImageShader draws a bigger square, GridShader draws a smaller square. Inside init function I declare the programs (inside new OpenGL::OpenGLShader), after that I insert buffer with position for
I get the following result:
(the bright square is the ImageShader, declared second)
Render result
Here is the code for init() function:
gridShader = new OpenGL::OpenGLShader(Common::GetShaderResource(IDR_SHADERS_GRID_SQUARE_VERTEX), Common::GetShaderResource(IDR_SHADERS_GRID_SQUARE_FRAGMENT));
gridShader->bind();
//3x positions
float verticesSquare[6][3] = {
-0.5f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
imageShader->unbind();
And here are the render functions:
void OpenglRenderer::RenderScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
visualize_image();
visualize_grid();
renderToImage();
SwapBuffers(hdc);
}
void OpenglRenderer::visualize_image()
{
imageShader->bind();
GLint position = glGetAttribLocation(imageShader->shader_id, "position");
GLint uvPos = glGetAttribLocation(imageShader->shader_id, "uvPos");
glEnableVertexAttribArray(position);
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0);
glEnableVertexAttribArray(uvPos);
glVertexAttribPointer(uvPos, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(position);
glDisableVertexAttribArray(uvPos);
imageShader->unbind();
}
void OpenglRenderer::visualize_grid()
{
gridShader->bind();
GLint position = glGetAttribLocation(gridShader->shader_id, "position");
glEnableVertexAttribArray(position);
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(position);
gridShader->unbind();
}
Since you want to draw from two different buffers, you have to make sure that the correct one is bound in the rendering method (or better to say, when setting up the vertex attribute pointer). At the moment, all data is taken from vboIndexImage because this is the buffer bound when you call glVertexAttribPointer. From your setup code, I guess you shouldn't even setup the vertex attribute pointers in the render methods and only bind the correct VAO instead:
Setup:
glGenVertexArrays(1, &vaoIndexImage);
glGenBuffers(1, &vboIndexImage);
glBindVertexArray(vaoIndexImage);
glBindBuffer(GL_ARRAY_BUFFER, vboIndexImage);
glBufferData(GL_ARRAY_BUFFER, sizeof(verticesImage), &verticesImage[0][0], GL_STATIC_DRAW);
GLint position = glGetAttribLocation(imageShader->shader_id, "position");
GLint uvPos = glGetAttribLocation(imageShader->shader_id, "uvPos");
glEnableVertexAttribArray(position);
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0);
glEnableVertexAttribArray(uvPos);
glVertexAttribPointer(uvPos, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
Rendering:
glBindVertexArray(vaoIndexImage);
glDrawArrays(GL_TRIANGLES, 0, 6);
Similar code should be used for the grid.
The class copied below serve to create an OpenGL context in a QT widget.
However it doesn't display any point while it works well when I use GLFW...
#include "glwidget.h"
#include "shader.hpp"
GLWidget::GLWidget(QWidget *parent) : QGLWidget(parent) {
}
GLWidget::~GLWidget() {
// Cleanup VBO
glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &colorbuffer);
glDeleteBuffers(1, &elementbuffer);
glDeleteProgram(programID);
glDeleteVertexArrays(1, &VertexArrayID);
}
void GLWidget::initializeGL()
{
glewInit();
// Dark blue background
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
// Create and compile our GLSL program from the shaders
programID = LoadShaders("SimpleVertexShader.vertexshader", "ColorFragmentShader.fragmentshader");
// Get a handle for our "MVP" uniform
MatrixID = glGetUniformLocation(programID, "MVP");
ModelMatrixID = glGetUniformLocation(programID, "M");
// Get a handle for our buffers
vertexPosition_modelspaceID = glGetAttribLocation(programID, "vertexPosition_modelspace");
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Temporary code for vertices and their color generation
vertices.push_back(glm::vec3(0,0,0)); // A point situated at 0,0,0 for test
color.push_back(glm::vec3(1.0, 0.0, 0.0));
index.push_back(0);
int size = 1000;
for (int i = 1; i < size; ++i) {
vertices.push_back(glm::vec3((rand() % 100) / 10, (rand() % 100) / 10, (rand() % 100) / 10));
color.push_back(glm::vec3(1.0, 0.0, 0.0));
index.push_back(i);
}
/*Computing the points centroid */
for (int i = 0; i < vertices.size(); i++)
{
mx += vertices[i][0];
my += vertices[i][1];
mz += vertices[i][2];
}
mx = mx / vertices.size(); my = my / vertices.size(); mz = mz / vertices.size();
for (int i = 0; i < vertices.size(); i++)
{
vertices[i][0] = vertices[i][0] - mx;
vertices[i][1] = vertices[i][1] - my;
vertices[i][2] = vertices[i][2] - mz;
}
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glBufferData(GL_ARRAY_BUFFER, color.size() * sizeof(glm::vec3), &color[0], GL_STATIC_DRAW);
glGenBuffers(1, &elementbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index.size() * sizeof(unsigned int), &index[0], GL_STATIC_DRAW);
/* Line indexing, not in use actually....
unsigned int indexL[] = { 1550, vertices.size() - 1300 };
GLuint elementbufferLine;
glGenBuffers(1, &elementbufferLine);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbufferLine);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * sizeof(unsigned int), &indexL[0], GL_STATIC_DRAW); */
}
void GLWidget::resizeGL(int w, int h)
{
//glViewport(0, 0, w, h);
ViewMatrix = glm::lookAt(
glm::vec3(-5, -5, -5), // Camera is here
glm::vec3(mx, my, mz), // and looks here
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
ModelMatrix = glm::mat4(1.0f);
ProjectionMatrix = glm::perspective(glm::radians(80.0f), float(w) /float(h), 0.1f, 100.0f);
MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
}
void GLWidget::paintGL()
{
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Using shaders */
glUseProgram(programID);
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
1, // attribute. No particular reason for 1, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
// Draw the point cloud !
glPointSize(5);
glDrawElements(
GL_POINTS, // mode
index.size(), // count
GL_UNSIGNED_INT, // type
(void*)0 // element array buffer offset
);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
I believe with your math, all vertices are created in a (0,0,0)-(9.9, 9.9, 9.9) range. Then you compute the centroid and subtract. lets say your mx, my, mz is (5.0, 5.0, 5.0). Now if you subtract the centroid, all your points are now in the range (-5.0, -5.0, -5.0) and (4.9, 4.9, 4.9).
In other words all you have done is center all your points to the origin. I believe you should be looking at the origin (0, 0, 0) not (5, 5, 5).
I'm using shaders and modern OpenGL. I tried glGetError() checks but no error is returned, I also tried debugging with apitrace, but I couldn't find anything. I'm not even sure if the problem is initialization or drawing code.
Sprite init:
void Sprite::init(float _x, float _y, float _width, float _height, const char* texture_path) {
x = _x;
y = _y;
width = _width;
height = _height;
texture.init(texture_path);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
// This array will hold our vertex data
// We need 4 vertices, and each vertex has 2 floats for X and Y
Vertex vertexData[4];
// Top right
vertexData[0].set_position(x + width, y + height);
vertexData[0].set_uv(1.0f, 1.0f);
// Bottom right
vertexData[1].set_position(x + width, y);
vertexData[1].set_uv(1.0f, 0.0f);
// Bottom left
vertexData[2].set_position(x, y);
vertexData[2].set_uv(0.0f, 0.0f);
// Top left
vertexData[3].set_position(x, y + height);
vertexData[3].set_uv(0.0f, 1.0f);
for (int i = 0; i < 4; i++) {
vertexData[i].set_color(255, 255, 255, 255);
}
GLuint indices[] = { // Note that we start from 0!
0, 1, 3, // First Triangle
1, 2, 3 // Second Triangle
};
// Bind the vertex buffer object (active buffer)
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Upload the buffer data to GPU
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Unbind the buffer
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
Sprite draw:
void Sprite::draw() {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.id);
// Bind the buffer object
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
// Tell OpenGL that we want to use the first attribute array
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
// This is the position attribute pointer
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
// This is the color attribute pointer
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color));
// This is the UV attribute pointer
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, uv));
// Draw the 4 vertices to the screen
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// Disable the vertex attrib array
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
// Unbind the VBO and EBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
Rendering code:
Sprite sprite;
sprite.init(0, 0, 500, 500, "assets/textures/awesomeface.png");
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Enable shader
shader_program.enable();
sprite.draw();
// Disable shader
shader_program.disable();
// Swap buffers
window.swap_window();
You need to call glEnable(GL_TEXTURE_2D); to enable use of textures. It would also be preferable to disable it as soon as you are done using that utility, simply by putting glDisable(GL_TEXTURE2D); as soon as you have finished drawing, or whenever you are done working with textures. Hope this helps! I had this problem as well, and it took me a good 3 days of staring at a blinking cursor to figure out.
I am working on a Project to create Geometry by using a Geometry Shader and Transform Feedback.
I am currently trying to have the Geometry Shader return its input (1 triangle) without changing/adding anything, but its not working.
I would appreciate any help/advice I can get. Here are parts of my code:
The creation of the Program for Transform Feedback:
//==========================================
// Create the Transform Program
//==========================================
int check = LoadShader("Shaders//transformVS.glsl", GL_VERTEX_SHADER, transformVS);
//TODO: check for fail
check = LoadShader("Shaders//transformGS.glsl", GL_GEOMETRY_SHADER, transformGS);
//TODO: check for fail
transformProgram = glCreateProgram();
glAttachShader(transformProgram, transformVS);
glAttachShader(transformProgram, transformGS);
glBindAttribLocation(transformProgram, 0, "position_in");
glBindAttribLocation(transformProgram, 1, "normal_in");
glBindAttribLocation(transformProgram, 2, "length_in");
static const char* varyings[] = { "position_out", "normal_out", "length_out" };
glTransformFeedbackVaryings(transformProgram, 3, varyings, GL_INTERLEAVED_ATTRIBS);
glLinkProgram(transformProgram);
if (CheckProgram(transformProgram) == -1){
glDetachShader(transformProgram, transformVS);
glDetachShader(transformProgram, transformGS);
glDeleteShader(transformVS);
transformVS = 0;
glDeleteShader(transformGS);
transformGS = 0;
glDeleteProgram(transformProgram);
transformProgram = 0;
return -1;
}
error = glGetError();
The Creation of the VBOs, VAOs and TFOs:
//=====================================
// Create VBOs
//=====================================
glGenBuffers(2, VBOID);
glBindBuffer(GL_ARRAY_BUFFER, VBOID[0]);
glBufferData(GL_ARRAY_BUFFER, 3 * sizeof(TVertex_VNL), vertices, GL_DYNAMIC_COPY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
error = glGetError();
glBindBuffer(GL_ARRAY_BUFFER, VBOID[1]);
glBufferData(GL_ARRAY_BUFFER, 3 * sizeof(TVertex_VNL), NULL, GL_DYNAMIC_COPY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
error = glGetError();
//=====================================
// Create VAOs
//=====================================
glGenVertexArrays(2, VAOID);
glBindVertexArray(VAOID[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBOID[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(TVertex_VNL), BUFFER_OFFSET(0)); //position
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(TVertex_VNL), BUFFER_OFFSET(sizeof(float) * 3)); //normal
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(TVertex_VNL), BUFFER_OFFSET(sizeof(float) * 6)); //length
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindVertexArray(0);
error = glGetError();
glBindVertexArray(VAOID[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBOID[1]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(TVertex_VNL), BUFFER_OFFSET(0)); //position
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(TVertex_VNL), BUFFER_OFFSET(sizeof(float) * 3)); //normal
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(TVertex_VNL), BUFFER_OFFSET(sizeof(float) * 6)); //length
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindVertexArray(0);
error = glGetError();
//=====================================
// Create TFOs
//=====================================
glGenTransformFeedbacks(2, TFOID);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, TFOID[0]);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, VBOID[0]);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
error = glGetError();
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, TFOID[1]);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, VBOID[1]);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
error = glGetError();
The render Method:
//=========================================
// Clear Screen
//=========================================
//Clear all the buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//========================================
// Transform Feedback
//========================================
glEnable(GL_RASTERIZER_DISCARD);
glUseProgram(transformProgram);
glBindVertexArray(VAOID[0]);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, TFOID[1]);
glBeginTransformFeedback(GL_TRIANGLES);
glDrawArrays(GL_TRIANGLES, 0, 3);
glEndTransformFeedback();
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
glDisable(GL_RASTERIZER_DISCARD);
//========================================
// Draw Triangle
//========================================
//Bind the shader that we want to use
glUseProgram(renderProgram);
//Setup all uniforms for your shader
glUniformMatrix4fv(renderMVP, 1, FALSE, &MVP[0][0]);
//Bind the VAO
glBindVertexArray(VAOID[1]);
glDrawArrays(GL_TRIANGLES, 0, 3);
//glDrawTransformFeedback(GL_TRIANGLES, TFOID[1]);
//========================================
// Swap Buffers
//========================================
glutSwapBuffers();
The Vertex Shader:
#version 330
in vec3 position_in;
in vec3 normal_in;
in float length_in;
out vec3 vs_position;
out vec3 vs_normal;
out float vs_length;
void main()
{
vs_position = position_in;
vs_normal = normal_in;
vs_length = length_in;
}
The Geometry Shader:
#version 330
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in vec3 vs_position[];
in vec3 vs_normal[];
in float vs_length[];
out vec3 position_out;
out vec3 normal_out;
out float length_out;
void main()
{
for(int i = 0; i < 3; i++){
position_out = vs_position[i];
normal_out = vs_normal[i];
length_out = vs_length[i];
EmitVertex();
}
EndPrimitive();
}
Your geometry shader is not emitting any vertices because the for loop body is never entered:
for(int i = 0; i >= 3; i++){
|Actually, I am trying to display two or more models on the screen at the same time. I am generating three different vertex buffers for vertices, colors, normals separately, here is the main code:
//==================From here is my implementation ==========================//
// Create and compile our GLSL program from the shaders. Todo: load shader
GLuint programID = LoadShaders("simple_shading.vertexshader", "simple_shading.fragmentshader");
// Get a handle for uniform variables such as matrices, lights, ....
GLuint ModelMatrixID = glGetUniformLocation(programID, "ModelMatrix");
GLuint ViewMatrixID = glGetUniformLocation(programID, "ViewMatrix");
GLuint NormalMatrixID = glGetUniformLocation(programID, "NormalMatrix");
GLuint lightPosition_worldspaceID = glGetUniformLocation(programID, "lightPosition_worldspace");
GLuint lightColorID = glGetUniformLocation(programID, "lightColor");
// Get a handle for vertex attribute arrays such as vertex positions, colors, normals, ....
GLuint vertexPosition_modelspaceID = glGetAttribLocation(programID, "vertexPosition_modelspace");
GLuint vertexColorID = glGetAttribLocation(programID, "vertexColor");
GLuint vertexNormal_modelspaceID = glGetAttribLocation(programID, "vertexNormal_modelspace");
// Load your scene
TRIModel model;
TRIModel model2;
model.loadFromFile("models/ball.tri");
model2.loadFromFile("models/ball.tri");
//vector<TRIModel> models;
/*** Here shows an exmple which generates three different vertex buffers for vertices, colors, normals.***/
//However, you can always incorporate them together in a single buffer.(Hint: use glBufferSubData)
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, model.vertices.size() * sizeof(vec3), &model.vertices[0], GL_STATIC_DRAW);
GLuint colorbuffer;
glGenBuffers(1, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glBufferData(GL_ARRAY_BUFFER, model.vertices.size() * sizeof(vec3), &model.foreColors[0], GL_STATIC_DRAW);
GLuint normalbuffer;
glGenBuffers(1, &normalbuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glBufferData(GL_ARRAY_BUFFER, model.vertices.size() * sizeof(vec3), &model.normals[0], GL_STATIC_DRAW);
///*** **/
GLfloat rotZ;
while (!glfwWindowShouldClose(window))
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// //Tell OpenGL to use the shader program
glUseProgram(programID);
// //send matrix to shader: You can use the keyboard and mouse to close the window and control the transformation
// // (See computeMatricesFromKey(window) )
mat4 ModelMatrix;
mat4 ViewMatrix = lookAt( vec3(0.5, 0.5, 1), vec3(2, 3, 2), vec3(0, 1.0, 0.0) );
//move object to the world origin
ModelMatrix = translate(mat4(1.0), -vec3(model.center[0], model.center[1], model.center[2]));
ModelMatrix = scale( ModelMatrix, vec3(0.002, 0.002, 0.002) );
ModelMatrix = rotate( ModelMatrix, rotZ, vec3(0.0, 0.0, 1.0) );
mat4 NormalMatrix = transpose( inverse(ViewMatrix * ModelMatrix) );
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
glUniformMatrix4fv(NormalMatrixID, 1, GL_FALSE, &NormalMatrix[0][0]);
// //send lights to shader
vec3 lightPosition = vec3(4, 4, 4);
vec3 lightColor = vec3(1.0, 1.0, 1.0);
glUniform3f(lightPosition_worldspaceID, lightPosition.x, lightPosition.y, lightPosition.z);
glUniform3f(lightColorID, lightColor.r, lightColor.g, lightColor.b);
//define an vertex attribute array on the vertex buffer
glEnableVertexAttribArray(vertexPosition_modelspaceID);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
vertexPosition_modelspaceID, // The attribute we want to configure
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*) 0 // array buffer offset
);
// //define an vertex attribute array on the color buffer
glEnableVertexAttribArray(vertexColorID);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
vertexColorID, // The attribute we want to configure
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*) 0 // array buffer offset
);
// //define an vertex attribute array on the normal buffer
glEnableVertexAttribArray(vertexNormal_modelspaceID);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
vertexNormal_modelspaceID, // The attribute we want to configure
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*) 0 // array buffer offset
);
//draw the scene by vertex attribute arrays
glDrawArrays(GL_TRIANGLES, 0, model.vertices.size());
glDisableVertexAttribArray(vertexPosition_modelspaceID);
glDisableVertexAttribArray(vertexColorID);
glDisableVertexAttribArray(vertexNormal_modelspaceID);
glfwSwapBuffers(window);
glfwPollEvents();
//
// //update rotate angle
rotZ += 0.1;
}
//// Cleanup VBO and shade //glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &colorbuffer);
glDeleteBuffers(1, &normalbuffer);
glDeleteProgram(programID);
//=================== implementation Ends here ================================//
I read in some resources that I can incorporate them together in a single buffer using glBufferSubData, but I dont know how to use it. eventually, I have successfully displayed one model as shown in the picture. Now, if I need to display another model, lets say I want to display another ball on the right side, what should I do? I tried to generate a nother set of buffers , but it is still not working. what I can see is just model one. Any ideas?