So by default, libgdx renders both sides of a face. When you make a cube using a mesh (supplying vertices and indices), it renders the faces inside the cube (wasting render time).
I want to stop this because it wastes render time when I have x amount of voxels on the screen.
I have tried face culling but it's completely broken. It removes the sides and everything.
Here's my code:
public void setup() {
String vertexShader = "attribute vec4 a_position; \n" + "attribute vec4 a_color;\n" + "attribute vec2 a_texCoord0;\n" + "uniform mat4 u_projTrans;\n" + "varying vec4 v_color;" + "varying vec2 v_texCoords;" + "void main() \n" + "{ \n" + " v_color = vec4(1, 1, 1, 1); \n" + " v_texCoords = a_texCoord0; \n" + " gl_Position = u_projTrans * a_position; \n" + "} \n";
String fragmentShader = "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n" + "varying vec4 v_color;\n" + "varying vec2 v_texCoords;\n" + "uniform sampler2D u_texture;\n" + "void main() \n" + "{ \n" + " gl_FragColor = v_color * texture2D(u_texture, v_texCoords);\n" + "}";
shader = new ShaderProgram(vertexShader, fragmentShader);
float[] vertices = { -0.5f, 0.5f, -0.5f, 0, 0, -0.5f, -0.5f, -0.5f, 0, 1, 0.5f, -0.5f, -0.5f, 1, 1, 0.5f, 0.5f, -0.5f, 1, 0, -0.5f, 0.5f, 0.5f, 0, 0, -0.5f, -0.5f, 0.5f, 0, 1, 0.5f, -0.5f, 0.5f, 1, 1, 0.5f, 0.5f, 0.5f, 1, 0, 0.5f, 0.5f, -0.5f, 0, 0, 0.5f, -0.5f, -0.5f, 0, 1, 0.5f, -0.5f, 0.5f, 1, 1, 0.5f, 0.5f, 0.5f, 1, 0, -0.5f, 0.5f, -0.5f, 0, 0, -0.5f, -0.5f, -0.5f, 0, 1, -0.5f, -0.5f, 0.5f, 1, 1, -0.5f, 0.5f, 0.5f, 1, 0, -0.5f, 0.5f, 0.5f, 0, 0, -0.5f, 0.5f, -0.5f, 0, 1, 0.5f, 0.5f, -0.5f, 1, 1, 0.5f, 0.5f, 0.5f, 1, 0, -0.5f, -0.5f, 0.5f, 0, 0, -0.5f, -0.5f, -0.5f, 0, 1, 0.5f, -0.5f, -0.5f, 1, 1, 0.5f, -0.5f, 0.5f, 1, 0
};
short[] indices = { 0, 1, 3, 3, 1, 2, 4, 5, 7, 7, 5, 6, 8, 9, 11, 11, 9, 10, 12, 13, 15, 15, 13, 14, 16, 17, 19, 19, 17, 18, 20, 21, 23, 23, 21, 22
};
texture = new Texture("texture.png");
Gdx.input.setCursorCatched(false);
mesh = new Mesh(true, vertices.length / 3, indices.length, VertexAttribute.Position(), VertexAttribute.TexCoords(0));
mesh.setVertices(vertices);
mesh.setIndices(indices);
GL40.glEnable(GL40.GL_DEPTH_TEST);
//GL40.glEnable(GL40.GL_CULL_FACE);
//GL40.glCullFace(GL40.GL_BACK);
}
public void render() {
Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
cameraController.update();
texture.bind();
shader.begin();
shader.setUniformMatrix("u_projTrans", camera.combined);
shader.setUniformi("u_texture", 0);
mesh.render(shader, GL46.GL_TRIANGLES);
shader.end();
}
When Face Culling is enabled then then primitives are discarded, dependent on the winding order of the vertex coordinates, as seen from the point of view.
For this a winding order for the front faces is defined, by glFrontFace. By default this is counter clockwise.
If back faces sculling is enabled:
GL40.glEnable(GL40.GL_CULL_FACE);
GL40.glCullFace(GL40.GL_BACK);
then the polygons which have the opposite winding order (clockwise) are discarded.
According to your vertex coordinates
float[] vertices = {
-0.5f, 0.5f, -0.5f, 0, 0,
-0.5f, -0.5f, -0.5f, 0, 1,
0.5f, -0.5f, -0.5f, 1, 1,
0.5f, 0.5f, -0.5f, 1, 0,
-0.5f, 0.5f, 0.5f, 0, 0,
-0.5f, -0.5f, 0.5f, 0, 1,
0.5f, -0.5f, 0.5f, 1, 1,
0.5f, 0.5f, 0.5f, 1, 0,
0.5f, 0.5f, -0.5f, 0, 0,
0.5f, -0.5f, -0.5f, 0, 1,
0.5f, -0.5f, 0.5f, 1, 1,
0.5f, 0.5f, 0.5f, 1, 0,
-0.5f, 0.5f, -0.5f, 0, 0,
-0.5f, -0.5f, -0.5f, 0, 1,
-0.5f, -0.5f, 0.5f, 1, 1,
-0.5f, 0.5f, 0.5f, 1, 0,
-0.5f, 0.5f, 0.5f, 0, 0,
-0.5f, 0.5f, -0.5f, 0, 1,
0.5f, 0.5f, -0.5f, 1, 1,
0.5f, 0.5f, 0.5f, 1, 0,
-0.5f, -0.5f, 0.5f, 0, 0,
-0.5f, -0.5f, -0.5f, 0, 1,
0.5f, -0.5f, -0.5f, 1, 1,
0.5f, -0.5f, 0.5f, 1, 0
};
and indices
short[] indices = {
0, 1, 3, 3, 1, 2,
4, 5, 7, 7, 5, 6,
8, 9, 11, 11, 9, 10,
12, 13, 15, 15, 13, 14,
16, 17, 19, 19, 17, 18,
20, 21, 23, 23, 21, 22
};
This means that the 1st, 3rd and 5th row of indices have the wrong winding order. It has to be:
short[] indices = {
0, 3, 1, 3, 2, 1,
4, 5, 7, 7, 5, 6,
8, 11, 9, 11, 10, 9,
12, 13, 15, 15, 13, 14,
16, 19, 17, 19, 18, 17,
20, 21, 23, 23, 21, 22
};
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 have rendered 3d objects numerous times before in DirectX but this time encountered a strange problem, on which I wasted a day figuring out and still have nothing. I have a DX11 Context in which I load 3d models from obj files. I had to make a skybox and figured out that a good starting point would be to try to render a cube and then proceed further. My graphics pipeline draws many things, so unless I purposefully unbind the index shader, it will remain bound. If I try to render the cube with my cube’s index buffer bound, it doesn’t work. But if I don’t bind the index buffer it uses the previously bound buffer (as far as I can make out) and renders the vertices weirdly as expected. I must be missing something major here. I have spent hours and hours and still couldn’t solve the problem. I would be grateful if someone could help…
PS: I am using these weird indices just for testing, as I had assumed that they were causing the problem.
I am quite baffled by this behavior, I must be missing something here.
void SkyBox::CreateShader(Vertex * verts, size_t size_of_verts, WORD* indices, size_t size_of_indices)
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Shader Compilation ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ID3D10Blob* VS = nullptr;
ID3D10Blob* PS = nullptr;
ID3D10Blob* ErrMSG = nullptr;
D3DX11CompileFromFile("SkyShader.shader", 0, 0, "SKYMAP_VS", "vs_4_0", 0, 0, 0, &VS, &ErrMSG, 0);
D3DX11CompileFromFile("SkyShader.shader", 0, 0, "SKYMAP_PS", "ps_4_0", 0, 0, 0, &PS, &ErrMSG, 0);
char* p = new char[100];
// encapsulate both shaders into shader objects
if (!ErrMSG && VS && PS)
{
pRenderer->GetDevice()->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), nullptr, &pVertexShader);
pRenderer->GetDevice()->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), nullptr, &pPixelShader);
}
else
{
ELOG("The Shader file cannot be compiled. Please run this executable from the directory that contains the Shader file.");
exit(1);
}
D3D11_INPUT_ELEMENT_DESC IED[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = ARRAYSIZE(IED);
pRenderer->GetDevice()->CreateInputLayout(IED, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Vertex Buffer ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = size_of_verts;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = verts;
pRenderer->GetDevice()->CreateBuffer(&bd, &InitData, OUT &pVBuffer); // creating the buffer
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Index Buffer /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = size_of_indices;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = indices;
pRenderer->GetDevice()->CreateBuffer(&bd, &InitData, OUT &pIBuffer);
}
SkyBox::SkyBox()
{
}
SkyBox::SkyBox(CRenderer * pRenderer)
:
pRenderer(pRenderer)
{
}
void SkyBox::CreateTri()
{
Vertex verts[]
{
{-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{ 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f},
{-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 0.0f}
};
WORD indices[] {
0, 1, 2,
3, 4, 5,
6, 7, 8,
9, 10, 11,
12, 13, 14,
15, 16, 17,
18, 19, 20,
21, 22, 23,
24, 25, 26,
27, 28, 29,
30, 31, 32,
33, 34, 35,
};
CubeMesh Cube;
Cube.CreateMesh();
CreateShader(verts, sizeof(Vertex) * 36, indices, sizeof(WORD) * 36);
}
void SkyBox::Render()
{
const UINT vStride = sizeof(Vertex);
const UINT vOffset = 0;
pRenderer->GetDeviceContext()->VSSetShader(pVertexShader, 0, 0);
pRenderer->GetDeviceContext()->PSSetShader(pPixelShader, 0, 0);
pRenderer->GetDeviceContext()->IASetInputLayout(pLayout);
pRenderer->GetDeviceContext()->IASetVertexBuffers(0, 1, &pVBuffer, &vStride, &vOffset);
pRenderer->GetDeviceContext()->IASetIndexBuffer(pIBuffer, DXGI_FORMAT_R16_UINT, 0);
pRenderer->GetDeviceContext()->DrawIndexed(36, 0, 0);
}
And here's the shader
float4 SKYMAP_VS( float4 Pos : POSITION, float4 Norm : NORMAL ) : SV_POSITION
{
return Pos;
}
float4 SKYMAP_PS( float4 Pos : SV_POSITION ) : SV_Target
{
return float4( 1.0f, 1.0f, 0.0f, 1.0f );
}
// I don't know how it could be simpler...
```c++
In SkyBox::Render(), if i don't set the index buffer it uses the previously bound buffer (as mentioned before) but if i bind the buffer it literally draws nothing. And yes, the the index buffer is created successfully.
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
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.