Related
I have taken code for two projects. One being the code for creating a cube and another is the code for creating a pyramid. I am now trying to render both of the objects in OpenGL which I have done the problem is the objects are attached to one another. I have added some code heading towards rendering them separately, however I am now stuck where my cube is only showing 3 of the triangles used to create it and the whole pyramid shows. Yet the objects are still attached to one another. Any help or guidance?
#include <iostream> // cout, cerr
#include <cstdlib> // EXIT_FAILURE
#include <GL/glew.h> // GLEW library
#include <GLFW/glfw3.h> // GLFW library
// GLM Math Header inclusions
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std; // Standard namespace
using glm::vec3;
using glm::mat4;
/*Shader program Macro*/
#ifndef GLSL
#define GLSL(Version, Source) "#version " #Version " core \n" #Source
#endif
// Unnamed namespace
namespace
{
const char* const WINDOW_TITLE = "3D Scene Troubleshooting"; // Macro for window title
// Variables for window width and height
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
// Stores the GL data relative to a given mesh
struct GLMesh
{
GLuint vao; // Handle for the vertex array object 1
GLuint vao2; // Handle for the vertex array object 2
GLuint vbos[2]; // Handles for the vertex buffer objects 1
GLuint vbos2[2]; // Handles for the vertex buffer objects 2
GLuint cubeIndices; // Number of cube indices of the mesh
GLuint pyramidIndices; // Number of pyramid indices of the mesh
};
// Main GLFW window
GLFWwindow* gWindow = nullptr;
// Triangle mesh data
GLMesh gMesh;
// Shader program
GLuint gProgramId;
}
/* User-defined Function prototypes to:
* initialize the program, set the window size,
* redraw graphics on the window when resized,
* and render graphics on the screen
*/
bool UInitialize(int, char* [], GLFWwindow** window);
void UResizeWindow(GLFWwindow* window, int width, int height);
void UProcessInput(GLFWwindow* window);
void UCreateMesh(GLMesh& mesh);
void UDestroyMesh(GLMesh& mesh);
void URender();
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint& programId);
void UDestroyShaderProgram(GLuint programId);
/* Vertex Shader Source Code*/
const GLchar* vertexShaderSource = GLSL(440,
layout(location = 0) in vec3 position; // Vertex data from Vertex Attrib Pointer 0
layout(location = 1) in vec4 color; // Color data from Vertex Attrib Pointer 1
out vec4 vertexColor; // variable to transfer color data to the fragment shader
//Global variables for the transform matrices
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f); // transforms vertices to clip coordinates
vertexColor = color; // references incoming color data
}
);
/* Fragment Shader Source Code*/
const GLchar* fragmentShaderSource = GLSL(440,
in vec4 vertexColor; // Variable to hold incoming color data from vertex shader
out vec4 fragmentColor;
void main()
{
fragmentColor = vec4(vertexColor);
}
);
int main(int argc, char* argv[])
{
if (!UInitialize(argc, argv, &gWindow))
return EXIT_FAILURE;
// Create the mesh
UCreateMesh(gMesh); // Calls the function to create the Vertex Buffer Object
// Create the shader program
if (!UCreateShaderProgram(vertexShaderSource, fragmentShaderSource, gProgramId))
return EXIT_FAILURE;
// Sets the background color of the window to black (it will be implicitely used by glClear)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// render loop
// -----------
while (!glfwWindowShouldClose(gWindow))
{
// input
// -----
UProcessInput(gWindow);
// Render this frame
URender();
glfwPollEvents();
}
// Release mesh data
UDestroyMesh(gMesh);
// Release shader program
UDestroyShaderProgram(gProgramId);
exit(EXIT_SUCCESS); // Terminates the program successfully
}
// Initialize GLFW, GLEW, and create a window
bool UInitialize(int argc, char* argv[], GLFWwindow** window)
{
// GLFW: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// GLFW: window creation
// ---------------------
* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "3D Scene TroubleShooting", NULL, NULL);
if (*window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return false;
}
glfwMakeContextCurrent(*window);
glfwSetFramebufferSizeCallback(*window, UResizeWindow);
// GLEW: initialize
// ----------------
// Note: if using GLEW version 1.13 or earlier
glewExperimental = GL_TRUE;
GLenum GlewInitResult = glewInit();
if (GLEW_OK != GlewInitResult)
{
std::cerr << glewGetErrorString(GlewInitResult) << std::endl;
return false;
}
// Displays GPU OpenGL version
cout << "INFO: OpenGL Version: " << glGetString(GL_VERSION) << endl;
return true;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
void UProcessInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function
executes
void UResizeWindow(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
// Functioned called to render a frame
void URender()
{
// Enable z-depth
glEnable(GL_DEPTH_TEST);
// Clear the frame and z buffers
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 1. Scales the object by 2
glm::mat4 scale = glm::scale(glm::vec3(2.0f, 2.0f, 2.0f));
// 2. Rotates shape by 15 degrees in the x axis
glm::mat4 rotation = glm::rotate(45.0f, glm::vec3(1.0, 1.0f, 1.0f));
// 3. Place object at the origin
glm::mat4 translation = glm::translate(glm::vec3(0.5f, -0.3f, -0.1f));
// Model matrix: transformations are applied right-to-left order
glm::mat4 model = translation * rotation * scale;
// Transforms the camera: move the camera back (z axis)
glm::mat4 view = glm::translate(glm::vec3(-2.6f, 2.9f, -5.0f));
// Creates a orthographic projection
glm::mat4 projection = glm::ortho(-5.0f, 5.0f, -5.0f, 5.0f, 0.1f, 100.0f);
// Set the shader to be used
glUseProgram(gProgramId);
// Retrieves and passes transform matrices to the Shader program
GLint modelLoc = glGetUniformLocation(gProgramId, "model");
GLint viewLoc = glGetUniformLocation(gProgramId, "view");
GLint projLoc = glGetUniformLocation(gProgramId, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
// Activate the VBOs contained within the mesh's VAO
glBindVertexArray(gMesh.vao);
glBindVertexArray(gMesh.vao2);
// Draws the CUBE
glDrawElements(GL_TRIANGLES, gMesh.cubeIndices, GL_UNSIGNED_SHORT, NULL); // Draws the triangle
glDrawArrays(GL_TRIANGLES, 0, 24);
// Draws the PYRAMID
glDrawElements(GL_TRIANGLES, gMesh.pyramidIndices, GL_UNSIGNED_SHORT, NULL); // Draws the triangle
glDrawArrays(GL_TRIANGLES, 0, 54);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
glfwSwapBuffers(gWindow); // Flips the the back buffer with the front buffer every frame.
}
void UCylinder(GLUquadric* qobj, GLdouble baseRadius, GLdouble topRadius, GLdouble height, GLint slices, GLint stacks)
{
GLUquadricObj* quadratic;
quadratic = gluNewQuadric();
gluCylinder(quadratic, 0.3f, 0.3f, 3.0f, 32, 32);
glDrawElements(GL_TRIANGLES, gMesh.cubeIndices, GL_UNSIGNED_SHORT, NULL);
}
// Implements the UCreateMesh function
void UCreateMesh(GLMesh& mesh)
{
// Position and Color data
GLfloat verts[] = {
// Vertex Positions // Colors (r,g,b,a)
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top Right Vertex 0 (effects top right and bottom right top sides of cube)
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Bottom Right corner Vertex 1
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Bottom center of cube Vertex 2 (effects bottom left and bottomr right sides of cube)
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Center of cube Vertex 3 (effects top, bottom left and bottom right sides of cube)
0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // Bottomside left of cube Vertex 4 (doesn't effect cube color at all with current orientation)
0.5f, 0.5f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top center of cube Vertex 5
-0.5f, 0.5f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top left corner cube Vertex 6 (effects both top and bottom left sides of cube)
-0.5f, -0.5f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Bottom left of cube Vertex 7
// Vertex Positions // Colors (r,g,b,a)
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, // Vertex 8
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, // Vertex 9
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, // Vertex 10
-0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, // Vertex 11
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f, // Vertex 12
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // Vertex 13
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, // Vertex 14
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, // Vertex 15
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Vertex 16
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 1.0f, // Vertex 17
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f, // Vertex 18
0.0f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // Vertex 19
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, // Vertex 20
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, // Vertex 21
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, // Vertex 22
-0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, // Vertex 23
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, // Vertex 24
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // Vertex 25
};
// Index data to share position data
GLushort cubeIndices[] = {
0, 1, 3, // Triangle 1
1, 2, 3, // Triangle 2
0, 1, 4, // Triangle 3
0, 4, 5, // Triangle 4
0, 5, 6, // Triangle 5
0, 3, 6, // Triangle 6
4, 5, 6, // Triangle 7
4, 6, 7, // Triangle 8
2, 3, 6, // Triangle 9
2, 6, 7, // Triangle 10
1, 4, 7, // Triangle 11
1, 2, 7, // Triangle 12
};
GLushort pyramidIndices[] = {
8, 9, 10, // Triangle 1
11, 12, 13, // Triangle 2
14, 15, 16, // Triangle 3
17, 18, 19, // Triangle 4
20, 21, 22, // Triangle 5
23, 24, 25 // Triangle 6
};
const GLuint floatsPerVertex = 3;
const GLuint floatsPerColor = 4;
// For CUBE
glGenVertexArrays(1, &mesh.vao); // we can also generate multiple VAOs or buffers at the same time
glBindVertexArray(mesh.vao);
// For PYRAMID
glGenVertexArrays(1, &mesh.vao2);
glBindVertexArray(mesh.vao2);
// Create 2 buffers: first one for the vertex data; second one for the indices for the CUBE
glGenBuffers(2, mesh.vbos);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos[0]); // Activates the buffer for CUBE
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU for CUBE
// Create 2 buffers: first one for the vertex data; second one for the indices for the PYRAMID
glGenBuffers(2, mesh.vbos2);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos2[0]); // Activates the buffer for PYRAMID
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU for PYRAMID
// For CUBE
mesh.cubeIndices = sizeof(cubeIndices) / sizeof(cubeIndices[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), cubeIndices, GL_STATIC_DRAW);
// For PYRAMID
mesh.pyramidIndices = sizeof(pyramidIndices) / sizeof(pyramidIndices[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos2[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(pyramidIndices), pyramidIndices, GL_STATIC_DRAW);
// Strides between vertex coordinates is 6 (x, y, z, r, g, b, a). A tightly packed stride is 0.
GLint stride = sizeof(float) * (floatsPerVertex + floatsPerColor);// The number of floats before each
// Create Vertex Attribute Pointers
glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, floatsPerColor, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerVertex));
glEnableVertexAttribArray(1);
}
void UDestroyMesh(GLMesh& mesh)
{
// For CUBE
glDeleteVertexArrays(1, &mesh.vao);
glDeleteBuffers(2, mesh.vbos);
// For PYRAMID
glDeleteVertexArrays(1, &mesh.vao2);
glDeleteBuffers(2, mesh.vbos2);
}
// Implements the UCreateShaders function
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint& programId)
{
// Compilation and linkage error reporting
int success = 0;
char infoLog[512];
// Create a Shader program object.
programId = glCreateProgram();
// Create the vertex and fragment shader objects
GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
// Retrive the shader source
glShaderSource(vertexShaderId, 1, &vtxShaderSource, NULL);
glShaderSource(fragmentShaderId, 1, &fragShaderSource, NULL);
// Compile the vertex shader, and print compilation errors (if any)
glCompileShader(vertexShaderId); // compile the vertex shader
// check for shader compile errors
glGetShaderiv(vertexShaderId, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShaderId, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
return false;
}
glCompileShader(fragmentShaderId); // compile the fragment shader
// check for shader compile errors
glGetShaderiv(fragmentShaderId, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShaderId, sizeof(infoLog), NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
return false;
}
// Attached compiled shaders to the shader program
glAttachShader(programId, vertexShaderId);
glAttachShader(programId, fragmentShaderId);
glLinkProgram(programId); // links the shader program
// check for linking errors
glGetProgramiv(programId, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(programId, sizeof(infoLog), NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
return false;
}
glUseProgram(programId); // Uses the shader program
return true;
}
void UDestroyShaderProgram(GLuint programId)
{
glDeleteProgram(programId);
}
See Vertex Specification. You cannot specify 2 vertex array objects at the same time. You have to do this in a row.
The Vertex Array Binding is a global state. Only one VAO can be bound at a time.
When calling OpenGL instructions like glVertexAttribPointer, glEnableVertexAttribArray and glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,...)`, the state of the currently bound Vertex Array Object is changed. Note that different VAOs can use the same data buffers.
void UCreateMesh(GLMesh& mesh)
{
// [...]
glGenBuffers(1, mesh.vbos);
glGenBuffers(2, mesh.vbos2);
// 1 Vertex Buffer for both objects
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
// Strides between vertex coordinates is 6 (x, y, z, r, g, b, a). A tightly packed stride is 0.
GLint stride = sizeof(float) * (floatsPerVertex + floatsPerColor);// The number of floats before each
// CUBE
glGenVertexArrays(1, &mesh.vao); // we can also generate multiple VAOs or buffers at the same time
glBindVertexArray(mesh.vao);
// Create Vertex Attribute Pointers
glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, floatsPerColor, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerVertex));
glEnableVertexAttribArray(1);
mesh.cubeIndices = sizeof(cubeIndices) / sizeof(cubeIndices[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), cubeIndices, GL_STATIC_DRAW);
// PYRAMID
glGenVertexArrays(1, &mesh.vao2);
glBindVertexArray(mesh.vao2);
// Create Vertex Attribute Pointers
glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, floatsPerColor, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerVertex));
glEnableVertexAttribArray(1);
mesh.pyramidIndices = sizeof(pyramidIndices) / sizeof(pyramidIndices[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos2[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(pyramidIndices), pyramidIndices, GL_STATIC_DRAW);
}
Finally you can draw the meshes one after the other. The draw call uses the data from the currently bound Vertex Array Object. As already mentioned, only one VAO can be bound at a time:
glBindVertexArray(gMesh.vao);
glDrawElements(GL_TRIANGLES, gMesh.cubeIndices, GL_UNSIGNED_SHORT, NULL);
glBindVertexArray(gMesh.vao2);
glDrawElements(GL_TRIANGLES, gMesh.pyramidIndices, GL_UNSIGNED_SHORT, NULL);
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'm rendering this cube and it should show the front of the cube but instead it shows the back (green color). How do i solve this? I've been sitting for a couple of hours trying to fix this but nothing helped. I was trying various things like changing the order in which the triangles are rendered and it didn't help either. Thanks for any help. Here's my code.
float vertices[] =
{
//front
-0.5f, -0.5f, 0.0f, 1.f, 0.0f, 0.5f,
0.5f, -0.5f, 0.0f, 1.f, 0.0f, 0.5f,
0.5f, 0.5f, 0.0f, 1.f, 0.0f, 0.5f,
-0.5f, 0.5f, 0.0f, 1.f, 0.0f, 0.5f,
//back
-0.5f/2, -0.5f/2, -0.5f, 0.0f, 1.f, 0.0f,
0.5f/2, -0.5f/2, -0.5f, 0.0f, 1.f, 0.0f,
0.5f/2, 0.5f/2, -0.5f, 0.0f, 1.f, 0.0f,
-0.5f/2, 0.5f/2, -0.5f, 0.0f, 1.f, 0.0f,
};
unsigned int indices[] =
{
//front
0, 2, 3,
0, 1, 2,
//back
4, 6, 7,
4, 5, 6,
//top
3, 6, 2,
3, 7, 6,
//bottom
0, 1, 5,
0, 5, 4,
//left
3, 0, 4,
3, 4, 7,
//right
1, 2, 5,
2, 6, 5
};
int main()
{
if (!glfwInit())
{
std::cout << "ERROR" << std::endl;
return -1;
}
int width = 640;
int height = 480;
window = glfwCreateWindow(width, height, "OPENGL", NULL, NULL);
if (!window)
{
std::cout << "ERROR: WINDOW" << std::endl;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
if (glewInit() != GLEW_OK)
{
std::cout << "ERROR: GLEW" << std::endl;
}
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
std::cout << "OpenGL " << glGetString(GL_VERSION) << std::endl;
VertexArray va1;
VertexBuffer vb1(vertices, sizeof(vertices), GL_STATIC_DRAW);
IndexBuffer ib1(indices, sizeof(indices), GL_STATIC_DRAW);
va1.linkAttrib(vb1, 0, 3, GL_FLOAT, 6 * sizeof(float), 0);
va1.linkAttrib(vb1, 1, 3, GL_FLOAT, 6 * sizeof(float), 3 * sizeof(float));
ShaderSources sources = parseShader("basic.shader");
unsigned int program = createShaderProgram(sources.vertexSource, sources.fragmentSource);
glUseProgram(program);
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(unsigned int), GL_UNSIGNED_INT, nullptr);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
And here what the cube looks like:
You currently are using glEnable(GL_DEPTH_TEST) withglDepthFunc(GL_LESS), which means only fragments having a smaller z (or depth) component are rendered when rendering overlapped triangles. Since your vertex positions are defined with the back-face having a smaller z coordinate than the front-face, all front-face fragments are ignored (since their z coordinate is larger).
Solutions are:
Using glDepthFunc(GL_GREATER) instead of glDepthFunc(GL_LESS) (which may not work in your case, considering your vertices have z <= 0.0 and the depth buffer is cleared to 0.0)
Modify your vertex positions to give front-face triangles a smaller z component than back-face triangles.
I believe that when using matrix transforms, a smaller z component normally indicates the fragment is closer to the camera, which is why glDepthFunc(GL_LESS) is often used.
As the title says, I'm trying to render a cube using the code below (plus a custom Shader class and the actual shaders omitted for brevity) to render a tilted cube turning on the Y axis.
The problem is with the texture: if I just download some .png from Google Images it renders just fine, but if I create some random texture using MS Paint and only change the file path to said MS Paint texture I get an Exception thrown at 0x00007FFA3BEADB68 (nvoglv64.dll) in Untitled_OpenGL_Project.exe: 0xC0000005: Access violation reading location 0x000001F6A94A2000. exception.
What is the problem? Is it something to do with the value for transparent pixels or something? (grasping at straws here)
main.cpp:
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "Shader.h"
#include "utils.h"
#include "stb_image.h"
int main()
{
// Setup
if (!Utility::glfwSetup())
return -1;
GLFWwindow* window = Utility::glfwOpenWindow(Utility::SCREEN_WIDTH, Utility::SCREEN_HEIGHT, "GLFW Window");
glfwMakeContextCurrent(window);
if (!Utility::gladSetup())
return -1;
glfwSetKeyCallback(window, Utility::key_callback);
glEnable(GL_DEPTH_TEST);
// Program
glViewport(0, 0, 800, 600);
float vertices[] = {
// Position // Texel
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 1.0f
};
unsigned int indices[] = {
0, 1, 3,
0, 2, 3,
4, 5, 7,
4, 6, 7,
8, 9, 11,
8, 10, 11,
12, 13, 15,
12, 14, 15,
16, 17, 19,
16, 18, 19,
20, 21, 23,
20, 22, 23
};
// Buffer setup
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
float tiltAngle = 70.0f;
// MVP
glm::mat4 model = glm::mat4(1.0f);
glm::vec3 zAxis = glm::vec3(0.0f, 0.0f, 1.0f);
model = glm::rotate(model, (float) glm::radians(tiltAngle), zAxis);
glm::mat4 view = glm::mat4(1.0f);
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float) Utility::SCREEN_WIDTH / Utility::SCREEN_HEIGHT, 0.1f, 100.0f);
// Texture
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
Utility::texSetup(GL_REPEAT, GL_REPEAT, GL_NEAREST, GL_LINEAR);
int width, height, numChannels;
unsigned char* data = stbi_load("res/textures/BlackFrame.png", &width, &height, &numChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
// Shader setup
Shader shader("res/shaders/VertexShader.shader", "res/shaders/FragShader.shader");
glUseProgram(shader.ID);
shader.setUniformMat4f(model, "model");
shader.setUniformMat4f(view, "view");
shader.setUniformMat4f(proj, "proj");
shader.setUniform1i(0, "texture1");
// Time
float prevTime = (float)glfwGetTime();
while (!glfwWindowShouldClose(window))
{
// Setup
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Input
Utility::processInput(window);
// Rendering
float curTime = (float)glfwGetTime();
float deltaTime = curTime - prevTime;
prevTime = curTime;
// Rotate around Y axis
glm::vec3 yAxis = glm::vec3(0.0f, 1.0f, 0.0f);
model = glm::rotate(model, (float)glm::radians(-tiltAngle), zAxis);
model = glm::rotate(model, deltaTime, yAxis);
model = glm::rotate(model, (float)glm::radians(tiltAngle), zAxis);
shader.setUniformMat4f(model, "model");
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
// Clean-up
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
utils.cpp:
int Utility::glfwSetup()
{
if (!glfwInit())
{
std::cerr << "Failed to initialize GLFW" << std::endl;
return 0;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, VERSION_MAJOR);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, VERSION_MINOR);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
std::cout << "GLFW " << VERSION_MAJOR << "." << VERSION_MINOR << " initialized successfully." << std::endl;
return 1;
}
int Utility::gladSetup()
{
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
glfwTerminate();
return 0;
}
return 1;
}
void Utility::texSetup(int wrapParamS, int wrapParamT, int minParam, int magParam)
{
stbi_set_flip_vertically_on_load(true);
float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapParamS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapParamT);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minParam);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magParam);
}
GLFWwindow* Utility::glfwOpenWindow(int width, int height, const char* title)
{
GLFWwindow* window = glfwCreateWindow(width, height, title, NULL, NULL);
if (window == NULL)
{
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return NULL;
}
return window;
}
void Utility::processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
It is not guaranteed that a PNG file has 4 channels or that stbi_load will return an image with 4 channels.
stbi_load can be forced to generate an image with 4 color channels, by explicitly pass 4 to the last parameter:
unsigned char* data = stbi_load("BlackFrame.png", &width, &height, &numChannels, 0);
unsigned char* data = stbi_load("BlackFrame.png", &width, &height, &numChannels, 4);
See stb_image.h:
Basic usage (see HDR discussion below for HDR usage):
int x,y,n;
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
// ... process data if not NULL ...
// ... x = width, y = height, n = # 8-bit components per pixel ...
// ... replace '0' with '1'..'4' to force that many components per pixel
// ... but 'n' will always be the number that it would have been if you said 0
stbi_image_free(data);
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.