I made a VBO cube a while ago, It work's great but it has a lack of performance.
How can I remove invisible faces in a VBO?
I also have a problem with the textures, they are seemed to be messed up :/
If anyone knows something to fix that, it would be great!
My code:
#include <windows.h>
#include <iostream>
#include <glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#define OFFSET_BUFFER(bytes) ((GLfloat *)NULL + bytes)
PFNGLGENBUFFERSARBPROC glGenBuffers = NULL;
PFNGLBINDBUFFERPROC glBindBuffer = NULL;
PFNGLBUFFERDATAPROC glBufferData = NULL;
GLfloat vertex[];
GLuint m_vertexBuffer;
GLuint m_textureBuffer;
void VBOinit()
{
#ifdef _WIN32
glGenBuffers = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffers");
glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
#else
glGenBuffers = (PFNGLGENBUFFERSARBPROC)glXGetProcAddress((const GLubyte*)"glGenBuffers");
glBindBuffer = (PFNGLBINDBUFFERPROC)glXGetProcAddress((const GLubyte*)"glBindBuffer");
glBufferData = (PFNGLBUFFERDATAPROC)glXGetProcAddress((const GLubyte*)"glBufferData");
#endif
if (!glGenBuffers || !glBindBuffer || !glBufferData)
{
std::cerr << "VBOs are not supported by your graphics card" << std::endl;
return;
}
// TEXTURE VBO
GLfloat texture[] =
{
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1
};
glGenBuffers(1, &m_textureBuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(texture), &texture, GL_STATIC_DRAW);
// GEOMETRIC VBO
GLfloat vertex[] =
{
0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, // v0-v0.5f-v2 (front)
-0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, // v2-v3-v0
0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, // v0-v3-v4 (right)
0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, // v4-v5-v0
0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, // v0-v5-v6 (top)
-0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, // v6-v0.5f-v0
-0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, // v0.5f-v6-v7 (left)
-0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, // v7-v2-v0.5f
-0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, // v7-v4-v3 (bottom)
0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, // v3-v2-v7
0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, // v4-v7-v6 (back)
-0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f // v6-v5-v4
};
glGenBuffers(1, &m_vertexBuffer); //Generate a buffer for the vertices
glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); //Bind the vertex buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), &vertex[0], GL_STATIC_DRAW); //Send the data to OpenGL
}
void VBOrender(int x, int y, int z)
{
glBindTexture(GL_TEXTURE_2D, Texture::textures[0]);
glTranslatef(x, y, z);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer);
glTexCoordPointer(2, GL_FLOAT, 0, OFFSET_BUFFER(0));
//glPolygonMode(GL_FRONT, GL_LINE);
glDrawArrays(GL_TRIANGLES, 0, 36);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glTranslatef(-x, -y, -z);
}
Thank you for reading :)
Adding detail on what we started in the comments above, plus a couple more things.
As was previously suggested, add glEnable(GL_CULL_FACE). I doubt that it addresses your bottleneck, but it can't hurt.
One other thing you should generally do is store your positions and texture coordinates interleaved in a single buffer, instead of storing them in separate buffers. Again, I think you're limited elsewhere right now, just a general recommendation.
To illustrate what I suggested in the comment about avoiding to set redundant state inside your loop. Right now your structure in pseudo code looks like this:
loop over x, y, z
VBOrender(x, y, z)
end loop
Instead, I would structure it like this:
VBObind()
loop over x, y, z
VBOrender(x, y, z)
end loop
VBOunbind()
And split up the code in your current VBOrender function like this:
void VBObind()
{
glBindTexture(GL_TEXTURE_2D, Texture::textures[0]);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer);
glTexCoordPointer(2, GL_FLOAT, 0, OFFSET_BUFFER(0));
}
void VBOunbind()
{
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
void VBOrender(int x, int y, int z)
{
glTranslatef(x, y, z);
glDrawArrays(GL_TRIANGLES, 0, 36);
glTranslatef(-x, -y, -z);
}
I expect that this will give you a significant performance improvement. To get massively better performance, you would need something more dramatic, like packing all the cubes in a single draw call. This looks slightly tricky, though, because from what I can see in your code on pastebin, the rendering of each cube is conditional.
If you're willing to write your own shaders, you can make the translation an attribute, which would be much faster to update than the fixed function transformation matrix.
You can turn on back-face culling by calling:
glFrontFace(GL_CCW); // <- says faces are defined in counter-clockwise order. Change if yours are in clockwise order
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
As for your textures, it looks like you've defined texture coordinates for 11 cube faces, but you you have 36 triangles you're drawing. 36 triangles would be 18 quads, so I think you need more texture coordinates.
Related
If you look at my history you can see some more context for what I'm trying to achieve.
I'm trying to draw multiple cubes with an element buffer without using instancing but for the sake of simplicity i'll use quads drawn with triangles.
If I have a VBO my array would look like below:
float cubeVertices[] = {
//FRONT
-0.5f, 0.5f, 0.5f, //front top left
-0.5f, -0.5f, 0.5f, //front bottom left
0.5f, 0.5f, 0.5f, //front top right
0.5f, 0.5f, 0.5f, //front top right
-0.5f, -0.5f, 0.5f, //front bottom left
0.5f, -0.5f, 0.5f //front bottom right
};
And converted to an element buffer it looks like:
float cubeVertices[] = {
-0.5f, 0.5f, 0.5f, //front top left
0.5f, 0.5f, 0.5f, //front top right
-0.5f, -0.5f, 0.5f, //front bottom left
0.5f, -0.5f, 0.5f //front bottom right
};
unsigned int cubeIndices[] = {
0, 2, 1, //FRONT
1, 2, 3
};
But what do I do if I want to draw multiple? (WITHOUT INSTANCING)
For a VBO it seems simple enough
float cubeVertices[] = {
//FRONT translate(x, y, z)
-0.5f, 0.5f, 0.5f, 0, 0, 0,//front top left
-0.5f, -0.5f, 0.5f, 0, 0, 0,//front bottom left
0.5f, 0.5f, 0.5f, 0, 0, 0,//front top right
0.5f, 0.5f, 0.5f, 0, 0, 0,//front top right
-0.5f, -0.5f, 0.5f, 0, 0, 0,//front bottom left
0.5f, -0.5f, 0.5f, 0, 0, 0,//front bottom right
//FRONT translate(x, y, z)
-0.5f, 0.5f, 0.5f, 1, 1, 1,//front top left
-0.5f, -0.5f, 0.5f, 1, 1, 1,//front bottom left
0.5f, 0.5f, 0.5f, 1, 1, 1,//front top right
0.5f, 0.5f, 0.5f, 1, 1, 1,//front top right
-0.5f, -0.5f, 0.5f, 1, 1, 1,//front bottom left
0.5f, -0.5f, 0.5f, 1, 1, 1,//front bottom right
};
Where each face is moved by the translate of (x y z) like model = glm::translate(model, glm::vec3(x, y, z))
But this has a lot of duplicate data like repeating the translation 6 times per quad and writing the vertex drawn locations twice per quad and an extra 2 duplicate vertices per quad.
Now imagine that for more advanced models and it seems like the waste of memory would get quite large.
So how do I convert the above to an element buffer? Ideally without duplicating data obviously.
I'll write some code/pseudo code to help explain what I'm after.
float cubeVertices[] = {
-0.5f, 0.5f, 0.5f, //front top left
0.5f, 0.5f, 0.5f, //front top right
-0.5f, -0.5f, 0.5f, //front bottom left
0.5f, -0.5f, 0.5f //front bottom right
};
unsigned int cubeIndices[] = {
0, 2, 1, //FRONT
1, 2, 3
};
unsigned int cubeLocations[] = {
0, 0, 0,
1, 1, 1
};
for (int loc = 0; loc < 2; ++loc)
{
for (int i = 0; i < 6; ++i)
{
//VERTEX COORDS //MODEL LOCATION
Draw(cubeVertices[cubeIndices[i]], cubeLocations[loc]);
}
}
**But done in one draw call, e.g. a simple mesh (Not instancing)**
The above would generates a memory efficient version of the VBO as an element array
Not sure how well I've articulated what I'm after is but I've tried my best to provide an explanation of my goal.
Think of a basic minecraft clone where all the unneeded drawn faces really starts to add up and instancing no longer works so meshing is now required.
I am getting half polygon rendered while using Indices in OpenGL. Any idea what's going wrong?
float vertices[] = {
-0.5f, 0.5f, 0,
-0.5f, -0.5f, 0,
0.5f, -0.5f, 0,
0.5f, -0.5f, 0,
0.5f, 0.5f, 0,
-0.5f, 0.5f, 0
};
uint32_t Indices[] = {
0,1,3,
3,1,2
};
When you draw with indices you just need 4 vertices not 6. The index is the "address" of the vertex:
float vertices[] = {
-0.5f, -0.5f, 0, // vertex 0
0.5f, -0.5f, 0, // vertex 1
0.5f, 0.5f, 0, // vertex 2
-0.5f, 0.5f, 0 // vertex 3
};
uint32_t Indices[] = {
0, 1, 3, // 1. triangle, vertices 0, 1, 2
0, 2, 3 // 2. triangle, vertices 0, 2, 3
};
Are you drawing with indices ? If that's the case you just need 4 vertices
If you're drawing with indices then the data is incorrect index 2 and 3 have the same value supplying the same two positions won't do anything, You're supplying two vertices to draw a triangle which requires 3 vertices
I am creating a 3D cube from an array made out of vertices and colours. I would like to separate these colours and vertices into their separate arrays and render the cube with the right colors. But I do not know how to properly create the VBO so the program doesn't crash.
So this is my Cube class that holds vertices,
private float[] vertices = {
//Position //Colours
// VO
-0.5f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, //Bottom right
// V1
-0.5f, -0.5f, 0.5f, 0.0f, 0.5f, 0.0f, 1.0f, //Top Left
// V2
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 1.0f, //Top Right
// V3
0.5f, 0.5f, 0.5f, 0.0f, 0.5f, 0.5f, 1.0f, //Bottom left
// V4
-0.5f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
// V5
0.5f, 0.5f, -0.5f, 0.0f, 0.5f, 0.0f, 1.0f,
// V6
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 1.0f,
// V7
0.5f, -0.5f, -0.5f, 0.0f, 0.5f, 0.5f, 1.0f,
};
private int[] triangles = {
// Front face
0, 1, 3, 3, 1, 2,
// Top Face
4, 0, 3, 5, 4, 3,
// Right face
3, 2, 7, 5, 3, 7,
// Left face
6, 1, 0, 6, 0, 4,
// Bottom face
2, 1, 6, 2, 6, 7,
// Back face
7, 6, 4, 7, 4, 5,
};
And this is how I want my arrays to be seperated (Same class as above)
private float[] vertices = {
//Position
// VO
-0.5f, 0.5f, 0.5f,
// V1
-0.5f, -0.5f, 0.5f,
// V2
0.5f, -0.5f, 0.5f,
// V3
0.5f, 0.5f, 0.5f,
// V4
-0.5f, 0.5f, -0.5f,
// V5
0.5f, 0.5f, -0.5f,
// V6
-0.5f, -0.5f, -0.5f,
// V7
0.5f, -0.5f, -0.5f,
};
private float[] colours = {
//Colours
// VO
0.5f, 0.0f, 0.0f, 1.0f,
// V1
0.0f, 0.5f, 0.0f, 1.0f,
// V2
0.0f, 0.0f, 0.5f, 1.0f,
// V3
0.0f, 0.5f, 0.5f, 1.0f,
// V4
0.5f, 0.0f, 0.0f, 1.0f,
// V5
0.0f, 0.5f, 0.0f, 1.0f,
// V6
0.0f, 0.0f, 0.5f, 1.0f,
// V7
0.0f, 0.5f, 0.5f, 1.0f,
};
private int[] triangles = {
// Front face
0, 1, 3, 3, 1, 2,
// Top Face
4, 0, 3, 5, 4, 3,
// Right face
3, 2, 7, 5, 3, 7,
// Left face
6, 1, 0, 6, 0, 4,
// Bottom face
2, 1, 6, 2, 6, 7,
// Back face
7, 6, 4, 7, 4, 5,
};
So this is my Mesh class where all the rendering stuff gets procesed. My question is how can I apply the colours array into this class ? I can only render he cube with the right colors only if the vertices class contains the vertices position and colors, not if they are seperate.
public void Init(){
/*
float aspectRation = (float) width / height;
projectionMatrix = new Matrix4f().perspective(FOV, aspectRation, nearPlane, farPlane);
*/
//COMPILE AND LINK SHADERS
//************
// Vertex Shader
//************
vertexID = glCreateShader(GL_VERTEX_SHADER); //Load shader type
glShaderSource(vertexID, vertexShaderSrc); // Pass shader source to GPU
glCompileShader(vertexID); // Compile shader
//Error check in compilation process
int success = glGetShaderi(vertexID,GL_COMPILE_STATUS);
if(success == GL_FALSE){
int lenght = glGetShaderi(vertexID, GL_INFO_LOG_LENGTH);
System.out.println("ERROR: 'defaultShader.glsl: \n\t Vertex shader compilation failed !");
System.out.println(glGetShaderInfoLog(vertexID,lenght));
}
//************
// Fragment Shader
//************
fragmentID = glCreateShader(GL_FRAGMENT_SHADER); //Load shader type
glShaderSource(fragmentID, fragmentShaderSrc); // Pass shader source to GPU
glCompileShader(fragmentID); // Compile shader
//Error check in compilation process
success = glGetShaderi(fragmentID,GL_COMPILE_STATUS);
if(success == GL_FALSE){
int lenght = glGetShaderi(fragmentID, GL_INFO_LOG_LENGTH);
System.out.println("ERROR: 'defaultShader.glsl: \n\t Vertex shader compilation failed !");
System.out.println(glGetShaderInfoLog(fragmentID,lenght));
}
//************
// Link shaders and Check for errors
//************
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexID);
glAttachShader(shaderProgram, fragmentID);
glLinkProgram(shaderProgram);
//Check for linking errors
success = glGetProgrami(shaderProgram, GL_LINK_STATUS);
if(success == GL_FALSE){
int lenght = glGetProgrami(shaderProgram, GL_INFO_LOG_LENGTH);
System.out.println("ERROR: 'defaultShader.glsl:' \n\t Linking of shaders failed !");
System.out.println(glGetProgramInfoLog(fragmentID,lenght));
assert false : "";
}
int uniformLocation = glGetUniformLocation(shaderProgram,"projectionMatrix");
uniforms.put("projectionMatrix",uniformLocation);
int uniformPosLocation = glGetUniformLocation(shaderProgram,"worldMatrix");
uniformsPosition.put("worldMatrix",uniformPosLocation);
//************
// Generate VAO, VBO and EBO and send them to GPU
//************
// GENERATE VAO
VAO_ID = glGenVertexArrays();
glBindVertexArray(VAO_ID);
//Create float buffer of vertices
FloatBuffer vertexBuffer = MemoryUtil.memAllocFloat(vertices.length);
vertexBuffer.put(vertices).flip();
// GENERATE VBO and upload VertexBuffer
VBO_ID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, VBO_ID);
glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW);
memFree(vertexBuffer);
//Create Indices and upload them
IntBuffer elementBuffer = MemoryUtil.memAllocInt(triangles.length);
elementBuffer.put(triangles).flip();
//Create EBO
EBO_ID = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO_ID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementBuffer, GL_STATIC_DRAW);
//Create vertex attribute pointers
int positionSize = 3;
int colorSize = 4;
int floatSizeInBytes = 4;
int vertexSizeInBytes = (positionSize + colorSize) * floatSizeInBytes;
glVertexAttribPointer(0, positionSize, GL_FLOAT, false, vertexSizeInBytes, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, colorSize, GL_FLOAT, false, vertexSizeInBytes, positionSize * floatSizeInBytes);
glEnableVertexAttribArray(1);
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
public void Render(){
//Bind shader program
glUseProgram(shaderProgram);
SetUniform("projectionMatrix", projectionMatrix);
SetUniform2("worldMatrix", worldMatrix);
//Bind VAO currently in use
glBindVertexArray(VAO_ID);
//Enable vertex atribute pointers
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//Draw triangles
glDrawElements(GL_TRIANGLES,triangles.length, GL_UNSIGNED_INT,0);
//Unbind everything
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
glUseProgram(0);
}
From what I understand about OpenGL, it looks like as if you are closing the current buffers being send to the GPU before it can receive colour data. (I might be completely wrong about this)
I tried this aproach on my project, so you may have to fidle little bit to make it work for your project, but the aproach should be the same.
With this you should be able to use the seperated arrays for color, triangles and vertices
//************
// Generate VAO, VBO and EBO and send them to GPU
//************
// GENERATE VAO
VAO_ID = glGenVertexArrays();
glBindVertexArray(VAO_ID);
//POSITION VBO
// GENERATE VBO and upload VertexBuffer
VBO_ID = glGenBuffers();
//Create float buffer of vertices
FloatBuffer vertexBuffer = MemoryUtil.memAllocFloat(vertices.length);
vertexBuffer.put(vertices).flip();
glBindBuffer(GL_ARRAY_BUFFER, VBO_ID);
glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
//COLOR VBO
//GENERATE VBO and upload colourBuffer
colourVBO_ID = glGenBuffers();
FloatBuffer colourBuffer = MemoryUtil.memAllocFloat(colours.length);
colourBuffer.put(colours).flip();
glBindBuffer(GL_ARRAY_BUFFER, colourVBO_ID);
glBufferData(GL_ARRAY_BUFFER, colourBuffer, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 0);
//TRIANGLE VBO
//Create Indices and upload them
EBO_ID = glGenBuffers();
IntBuffer elementBuffer = MemoryUtil.memAllocInt(triangles.length);
elementBuffer.put(triangles).flip();
//Create EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO_ID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
memFree(vertexBuffer);
memFree(colourBuffer);
memFree(elementBuffer);
I recently needed to implement a function in the QT+OPENGL environment, that is, I drew a cube (presumably in the center of the view) in my own defined framebuffer (I defined it as fbo) and colored it in red. And nothing is drawn in the default buffer, so I can't see my cube in the view (but it is drawn in the framebuffer fbo)
I hope that when I click in the middle of the view (the position of the cube), I can display the color of the cube----red instead of the color of the background of the view.
Here are the problems I have encountered:
I can only get the color of the background of the view with the mouse, and the cube drawn in the frame buffer is not picked up (the cube is red).
In the initializeGL() function, I initialized and configured the framebuffer fbo and some of the configuration required to draw the cube.
In the paintGL() function, I bind my defined framebuffer to GL_FRAMEBUFFER and then do the drawing.
In the mousePressEvent(QMouseEvent *e) function, I did the picking work. This is the response function of the QT mouse click. I put the information read by glReadPixels into the array pix and print it out.
void OpenglWidget::initializeGL()
{
core1 = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_0_Core>();
core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
core->glGenFramebuffers(1, &fbo);
core->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Create the texture object for the primitive information buffer
core->glGenTextures(1, &m_pickingTexture);
glBindTexture(GL_TEXTURE_2D, m_pickingTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32UI, SCR_WIDTH, SCR_HEIGHT,
0, GL_RGB_INTEGER, GL_UNSIGNED_INT, NULL);
core1->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D,
m_pickingTexture, 0);
// Create the texture object for the depth buffer
core->glGenTextures(1, &m_depthTexture);
core->glBindTexture(GL_TEXTURE_2D, m_depthTexture);
core->glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SCR_WIDTH, SCR_HEIGHT,
0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
core1->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
m_depthTexture, 0);
// Disable reading to avoid problems with older GPUs
core->glReadBuffer(GL_NONE);
// Verify that the FBO is correct
GLenum Status = core->glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (Status == GL_FRAMEBUFFER_COMPLETE) {
qDebug() << "ok";
}
// Restore the default framebuffer
core->glBindTexture(GL_TEXTURE_2D, 0);
core->glBindFramebuffer(GL_FRAMEBUFFER, 0);
GLfloat verticPosition[] = {
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
};
GLint beamIndices[] = {
0,1,2,3,4,5,6,7
};
core->glGenVertexArrays(1, &VAOBeam);
core->glGenBuffers(1, &VBOBeam);
core->glGenBuffers(1, &EBOBeam);
core->glBindVertexArray(VAOBeam);
core->glBindBuffer(GL_ARRAY_BUFFER, VBOBeam);
core->glBufferData(GL_ARRAY_BUFFER,sizeof(float) * 3 * 36, verticPosition, GL_STATIC_DRAW);
core->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOBeam);
core->glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 8, beamIndices, GL_STATIC_DRAW);
core->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
core->glEnableVertexAttribArray(0);
core->glBindBuffer(GL_ARRAY_BUFFER, 0);
core->glBindVertexArray(0);
}
void OpenglWidget::paintGL()
{
core->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClearColor(0,0,1,1);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
float frametime =GetFrameTime();
mCamera.Update(frametime);
Shader GLprogram = Shader("E:\\QT\\OpenglTest\\vs.vert","E:\\QT\\OpenglTest\\fs.frag");
GLprogram.use();
core->glBindVertexArray(VAOBeam);
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, mCamera.TempTranslateVrc);
glm::mat4 view = glm::mat4(1.0f);
//view = glm::lookAt(glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.5f,0.5f,0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
view = glm::lookAt(mCamera.mPos,mCamera.mViewCenter,mCamera.mUp);
glm::mat4 projection = glm::mat4(1.0f);
projection = glm::perspective(glm::radians(45.0f), (float)1.0, 0.1f, 100.0f);
GLprogram.setMatrix4f("model",model);
GLprogram.setMatrix4f("view",view);
GLprogram.setMatrix4f("projection",projection);
core->glDrawArrays(GL_TRIANGLES,0,36);
core->glUseProgram(0);
update();
}
void OpenglWidget::mousePressEvent(QMouseEvent *e)
{
core1 = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_0_Core>();
float pix[4] = {0.0};
mCamera.getInitPos(e->x(),e->y());//This is the camera's setup function, no need to worry about it.
core1->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
core1->glReadBuffer(GL_COLOR_ATTACHMENT1);
core1->glReadPixels(e->x() , 500 - e->y() + 65, 1, 1, GL_RGBA, GL_FLOAT, pix);
qDebug() << e->x()<< 500 - e->y() <<pix[0] << pix[1] << pix[2] << pix[3];
}
I can only get the color of the background of the view with the mouse, and the cube drawn in the frame buffer is not picked up (the cube is red).
The issue is caused, because in the color buffer attached to GLCOLOR ATTACHMENT1, never is rendered to.
The name of the enumerator constant for the 1st color buffer, which can be attached by glFramebufferTexture2D to a framebuffer is GL_COLOR_ATTACHMENT0, rather than not GL_COLOR_ATTACHMENT1:
void OpenglWidget::initializeGL()
{
// [...]
core1->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0, // <---- GL_COLOR_ATTACHMENT0 instead of GL_COLOR_ATTACHMENT1
GL_TEXTURE_2D,
m_pickingTexture, 0);
// [...]
}
void OpenglWidget::mousePressEvent(QMouseEvent *e)
{
// [...]
core1->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
core1->glReadBuffer(GL_COLOR_ATTACHMENT0); // <---- GL_COLOR_ATTACHMENT0
// [ ...]
}
Note, by default it is rendered to the first color buffer (GL_COLOR_ATTACHMENT0) of a framebuffer. If you want to render to an other color buffer, than the 1st one, then you would have to specify a color buffer (list) explicitly by glDrawBuffers.
See OpenGL 4.6 API Core Profile Specification; 17.4.1 Selecting Buffers for Writing; page 513:
17.4.1 Selecting Buffers for Writing
[...] The set of buffers of a framebuffer object to which all fragment colors are written is controlled with the commands
void DrawBuffers( sizei n, const enum *bufs );
void NamedFramebufferDrawBuffers( uint framebuffer, sizei n, const enum *bufs );
[...] For framebuffer objects, in the initial state the draw buffer for
fragment color zero is COLOR_ATTACHMENT0. For both the default framebuffer
and framebuffer objects, the initial state of draw buffers for fragment colors other then zero is NONE.
I am trying to reduce the number of faces that are rendered in my voxel engine by implementing a greedy meshing algorithm similar to Mikola's (http://0fps.net/2012/06/30/meshing-in-a-minecraft-game/)
Since I am using a VBO to draw each triangle for every cube I am wondering how I will be able to merge the triangles of adjacent cubes?
For reference here is what my cube vertex array looks like (note that it is interleaved to allow for texture coordinates to be included):
GLfloat cubeInterleaved[] =
{
// Front face u v
-0.5f, -0.5f, 0.5f, 0, 0,
0.5f, -0.5f, 0.5f, 1, 0,
0.5f, 0.5f, 0.5f, 1, 1,
-0.5f, 0.5f, 0.5f, 0, 1,
// Right face
0.5f, -0.5f, 0.5f, 0, 0,
0.5f, -0.5f, -0.5f, 1, 0,
0.5f, 0.5f, -0.5f, 1, 1,
0.5f, 0.5f, 0.5f, 0, 1,
// Back face
0.5f, -0.5f, -0.5f, 0, 0,
-0.5f, -0.5f, -0.5f, 1, 0,
-0.5f, 0.5f, -0.5f, 1, 1,
0.5f, 0.5f, -0.5f, 0, 1,
// Left face
-0.5f, -0.5f, -0.5f, 0, 0,
-0.5f, -0.5f, 0.5f, 1, 0,
-0.5f, 0.5f, 0.5f, 1, 1,
-0.5f, 0.5f, -0.5f, 0, 1,
// Top Face
-0.5f, 0.5f, 0.5f, 0, 0,
0.5f, 0.5f, 0.5f, 1, 0,
0.5f, 0.5f, -0.5f, 1, 1,
-0.5f, 0.5f, -0.5f, 0, 1,
// Bottom Face
0.5f, -0.5f, 0.5f, 0, 0,
-0.5f, -0.5f, 0.5f, 1, 0,
-0.5f, -0.5f, -0.5f, 1, 1,
0.5f, -0.5f, -0.5f, 0, 1
};
Since I am using a VBO to draw each triangle for every cube I am confused as to how I will be able to merge the triangles of adjacent cubes.
By using only a subset of the vertices, which is done by properly populating the index buffer for drawing.
Take this set of 4 triangles for example
5
/ \
3 --- 4
/ \ / \
0 --- 1 --- 2
You can either draw
GL_TRIANGLES: 0 1 3 1 2 4 1 4 3 3 4 5
or if all the vertices are coplanar you can just use the outer edges
GL_TRIANGLES: 0 2 5
And you can do the same with the vertices of blocks forming your world by appropriately populating the index buffer passed to glDrawElements