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);
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I am supposed to draw 6 different 2D shapes (dot, line, triangle, square, star, circle) and assign them each a different color. I managed to draw all of them and color them, except for my circle. The color i gave (g_colors_circle) the circle however is drawn from the center of the circle but does not reach the edges. Here is the current output:
Can someone tell me how to fix it?
Here is my code:
SimpleTriangle.cpp:
#include <cstdio> // for C++ i/o
#include <iostream>
using namespace std; // to avoid having to use std::
#define GLEW_STATIC // include GLEW as a static library
#include <GLEW/glew.h> // include GLEW
#include <GLFW/glfw3.h> // include GLFW (which includes the OpenGL header)
#include <glm/glm.hpp> // include GLM (ideally should only use the GLM headers that are actually used)
using namespace glm; // to avoid having to use glm::
#include "shader.h"
/*-------------------- Circle Code --------------------*/
//Constants for Circle
#define PI 3.14159265
#define MAX_SLICES 32
#define MIN_SLICES 8
#define MAX_VERTICES (MAX_SLICES+2)*3 // a triangle fan should have a minimum of 3 vertices
#define CIRCLE_RADIUS 0.5
GLuint g_VBO_circle[2]; // identifiers
GLuint g_VAO_circle = 0;
//Vertices for the circle
GLfloat g_vertices_circle[MAX_VERTICES] = {
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
};
GLfloat g_colors_circle[] = {
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f
};
GLuint g_slices = MIN_SLICES; // number of circle slices
//raz: i think this generates the vertice values for array of the circle
void generate_circle()
{
float angle = PI * 2 / static_cast<float>(g_slices); // used to generate x and y coordinates
float scale_factor = static_cast<float>(768) / 1024; // scale to make it a circle instead of an elipse
int index = 0; // vertex index
g_vertices_circle[3] = CIRCLE_RADIUS * scale_factor; // set x coordinate of vertex 1
// generate vertex coordinates for triangle fan
for (int i = 2; i < g_slices + 2; i++)
{
// multiply by 3 because a vertex has x, y, z coordinates
index = i * 3;
g_vertices_circle[index] = CIRCLE_RADIUS * cos(angle) * scale_factor;
g_vertices_circle[index + 1] = CIRCLE_RADIUS * sin(angle);
g_vertices_circle[index + 2] = 0.0f;
// update to next angle
angle += PI * 2 / static_cast<float>(g_slices);
}
}
static void init_circle()
{
// generate vertices of triangle fan
generate_circle();
// create VBO (vertice positions) and buffer the data
glGenBuffers(2, g_VBO_circle);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_vertices_circle, GL_DYNAMIC_DRAW);
// create VBO (vertice color) and buffer the data
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_colors_circle, GL_STATIC_DRAW);
// create VAO and specify VBO data
glGenVertexArrays(1, &g_VAO_circle);
glBindVertexArray(g_VAO_circle);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[1]);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glEnableVertexAttribArray(0); // enable vertex attributes
glEnableVertexAttribArray(1);
}
/*---------------------------------------------------------*/
// global variables
GLuint g_VBO[2]; // vertex buffer object identifier
GLuint g_VAO = 0; // vertex array object identifier
GLuint g_shaderProgramID = 0; // shader program identifier
static void init()
{
glClearColor(0.0, 0.0, 0.0, 1.0); // set clear background colour
// create and compile our GLSL program from the shader files
g_shaderProgramID = loadShaders("SimpleVS.vert", "SimpleFS.frag");
// enable point size
glEnable(GL_PROGRAM_POINT_SIZE);
// set line width
glLineWidth(5.0);
GLfloat verticesPosition[] = {
//Dot
-0.7f, 0.7f, 0.0f,
//Line
-0.5f, 0.7f, 0.0f,
-0.2f, 0.7f, 0.0f,
//Triangle
0.2f, 0.75f, 0.0f,
0.0f, 0.4f, 0.0f,
0.4f, 0.4f, 0.0f,
//Star
0.0f, 0.2f, 0.0f,
0.1f, 0.1f, 0.0f,
0.2f, 0.05f, 0.0f,
0.1f, 0.0f, 0.0f,
0.2f, -0.1f, 0.0f,
0.0f, 0.0f, 0.0f,
-0.2f, -0.1f, 0.0f,
-0.1f, 0.0f, 0.0f,
-0.2f, 0.05f, 0.0f,
-0.1f, 0.1f, 0.0f,
//Rectangle
-0.8f, 0.4f, 0.0f,
-0.8f, 0.0f, 0.0f,
-0.3f, 0.4f, 0.0f,
-0.3f, 0.0f, 0.0f
};
GLfloat verticesColor[] = {
//Dot
1.0f, 1.0f, 1.0f,
//Line
0.5f, 0.0f, 0.0f,
0.5f, 0.0f, 0.0f,
//Triangle
0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f,
//Star
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
//Rectangle
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
// create VBO and buffer the data
glGenBuffers(2, g_VBO);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]); // bind the VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(verticesPosition), verticesPosition, GL_STATIC_DRAW); // copy data to buffer
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]); // bind the VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(verticesColor), verticesColor, GL_STATIC_DRAW); // copy data to buffer
// create VAO and specify VBO data
glGenVertexArrays(1, &g_VAO);
glBindVertexArray(g_VAO);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]); // bind the VBO
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[1]); // bind the VBO
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); // specify the form of the data
glEnableVertexAttribArray(0); // enable vertex attributes
glEnableVertexAttribArray(1);
}
// function used to render the scene
static void render_scene()
{
glClear(GL_COLOR_BUFFER_BIT); // clear colour buffer
glUseProgram(g_shaderProgramID); // use the shaders associated with the shader program
glBindVertexArray(g_VAO); // make VAO active
glDrawArrays(GL_POINTS, 0, 1); //Draw dot
glDrawArrays(GL_LINES, 1, 2); //Draw line
glDrawArrays(GL_TRIANGLES, 3, 3); //Draw triangle
glDrawArrays(GL_LINE_LOOP, 6, 10); //Draw star
glDrawArrays(GL_TRIANGLE_STRIP, 16, 4); //Draw rectangle
glFlush(); // flush the pipeline
//To draw circle
glBindVertexArray(g_VAO_circle); // make VAO for circle active
glDrawArrays(GL_TRIANGLE_FAN, 0, g_slices + 2); // display the vertices based on the primitive type
glFlush(); // flush the pipeline
}
// key press or release callback function
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
// quit if the ESCAPE key was press
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
{
// set flag to close the window
glfwSetWindowShouldClose(window, GL_TRUE);
return;
}
else if (key == GLFW_KEY_W && action == GLFW_PRESS)
{
// renderer using wireframe
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
return;
}
else if (key == GLFW_KEY_S && action == GLFW_PRESS)
{
// renderer using wireframe
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
return;
}
else if (key == GLFW_KEY_UP && action == GLFW_PRESS)
{
if (g_slices < MAX_SLICES)
{
g_slices++; // increment number of slices
// generate vertices of triangle fan
generate_circle();
// bind and copy data to GPU
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_vertices_circle, GL_DYNAMIC_DRAW);
}
return;
}
else if (key == GLFW_KEY_DOWN && action == GLFW_PRESS)
{
if (g_slices > MIN_SLICES)
{
g_slices--; // decrement number of slices
// generate vertices of triangle fan
generate_circle();
// bind and copy data to GPU
glBindBuffer(GL_ARRAY_BUFFER, g_VBO_circle[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * (g_slices + 2), g_vertices_circle, GL_DYNAMIC_DRAW);
return;
}
}
}
// error callback function
static void error_callback(int error, const char* description)
{
cerr << description << endl; // output error description
}
int main(void)
{
GLFWwindow* window = NULL; // pointer to a GLFW window handle
glfwSetErrorCallback(error_callback); // set error callback function
// initialise GLFW
if(!glfwInit())
{
// if failed to initialise GLFW
exit(EXIT_FAILURE);
}
// minimum OpenGL version 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// create a window and its OpenGL context
window = glfwCreateWindow(1024, 768, "Assignment 1", NULL, NULL);
// if failed to create window
if(window == NULL)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window); // set window context as the current context
glfwSwapInterval(1); // swap buffer interval
// initialise GLEW
if(glewInit() != GLEW_OK)
{
// if failed to initialise GLEW
cerr << "GLEW initialisation failed" << endl;
exit(EXIT_FAILURE);
}
// set key callback function
glfwSetKeyCallback(window, key_callback);
// initialise rendering states
init();
init_circle();
// the rendering loop
while(!glfwWindowShouldClose(window))
{
render_scene(); // render the scene
glfwSwapBuffers(window); // swap buffers
glfwPollEvents(); // poll for events
}
// clean up
glDeleteProgram(g_shaderProgramID);
glDeleteBuffers(1, g_VBO);
glDeleteVertexArrays(1, &g_VAO);
glDeleteBuffers(1, g_VBO_circle);
glDeleteVertexArrays(1, &g_VAO_circle);
// close the window and terminate GLFW
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
SimpleVS.vert:
#version 330 core
// input data (different for all executions of this shader)
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec3 aColor;
// output data (will be interpolated for each fragment)
out vec3 vColor; //raz: this output is passed as input to the fragment shader
void main()
{
// set point size
gl_PointSize = 10.0;
// set vertex position
gl_Position = vec4(aPosition, 1.0);
// the color of each vertex will be interpolated
// to produce the color of each fragment
vColor = aColor;
}
SimpleFS.frag:
#version 330 core
// interpolated values from the vertex shaders
in vec3 vColor;
// output data
out vec3 fColor;
void main()
{
// set output color
fColor = vColor;
}
For each vertex in your circle geometry, you must set a color attribute. The 2 array buffers g_vertices_circle and g_colors_circle, which you are using for your attribute buffers, must have the same number of elements.
If the circle has to be unicolor, you must always use the same color for each element in the color attribute buffer.
In between the primitives the attributes are interpolate according to its barycentric coordinates. You did set the color for the center of the circle and the first outer point, but not the colors for the other outer points and left them undefined (probably black), this causes the effect you can see in your example.
Create a buffer for the color attributes in the same length as your vertex buffer and fill it up when you generate your vertices.
Your revised code should look something like this:
GLfloat g_colors_circle[MAX_VERTICES] = {
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f
};
for (int i = 2; i < g_slices + 2; i++)
{
// multiply by 3 because a vertex has x, y, z coordinates
index = i * 3;
g_vertices_circle[index] = CIRCLE_RADIUS * cos(angle) * scale_factor;
g_vertices_circle[index + 1] = CIRCLE_RADIUS * sin(angle);
g_vertices_circle[index + 2] = 0.0f;
g_colors_circle[index] = 1.0f;
g_colors_circle[index + 1] = 1.0f;
g_colors_circle[index + 2] = 0.0f;
// update to next angle
angle += PI * 2 / static_cast<float>(g_slices);
}
Note, if you only want to have single-color geometry, you can omit the color attributes and set the color through a single uniform variable.
I have problems to draw something using glDrawArrays() and no other question here could help me solve it. The code should draw a sphere, but for debuging I fill "m_vertices" with the vertices for a simple cube.
My Code is following:
First the init function.
init()
{
m_shader.compileShaders("Shaders/colorShading.vert", "Shaders/colorShading.frag");
m_shader.addAttribute("position");
m_shader.addAttribute("normal");
m_shader.linkShaders();
//setup VAO and VBO
glGenVertexArrays(1, &m_vao);
glGenBuffers(1, &m_vbo);
//init VAO
glBindVertexArray(m_vao);
//bind Buffer used by VAO
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
//enable needed AttributeArrays
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//position attribute pointer
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexBuffer), (void*)offsetof(VertexBuffer, vertex));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, sizeof(VertexBuffer), (void*)offsetof(VertexBuffer, normal));
//release VAO
glBindVertexArray(0);
//release VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
//Set-Up a static scene
// Projection matrix : 45° Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
glm::mat4 projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
// Camera matrix
glm::mat4 view = glm::lookAt(
glm::vec3(4, 3, 3), // Camera is at (4,3,3), in World Space
glm::vec3(0, 0, 0), // and looks at the origin
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
// Model Matrix
glm::mat4 model = glm::mat4(1.0f);
//set ModelViewProjection-Matrix of this object
m_mvp = projection * view * model;
}
This function is used to set up everything needed to draw my Object.
Then there is an update function:
update()
{
//update Sphere and get current vertices
//currently setting vertices for a cube
m_sphere->updateSphere(m_vertices);
//m_vertices is passed in per reference
//it stores 6 quads based on 2 triangles (36 vertices)
//the vertices are stored counter clockwise
//update VBO
//bind buffer
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
//orphan the buffer
glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(VertexBuffer), nullptr, GL_STATIC_DRAW);
//upload data
glBufferSubData(GL_ARRAY_BUFFER, 0, m_vertices.size() * sizeof(VertexBuffer), &m_vertices[0]);
//release buffer
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
The update function updates the VBO. This is needed cause the final Sphere should implement LevelOfDetail.
And finally the draw function:
draw()
{
glEnable(GL_DEPTH_TEST);
//activate shader
m_shader.use();
//set-up the mvp-uniform
GLuint matrixID = m_shader.getUniformLocation("MVP");
glUniformMatrix4fv(matrixID, 1, GL_FALSE, &m_mvp[0][0]);
//draw Planet
glBindVertexArray(m_vao);
glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
glBindVertexArray(0);
//deactivate shader
m_shader.unuse();
glDisable(GL_DEPTH_TEST);
}
This function should just binds/sets up the shader and draw the object.
The problem is that it doesn't draw the object and I have no idea why.
If someone could spot my mistake and explain what I did wrong here, I would be very grateful.
EDIT:
So as requested I add my code, which fills in the cube data:
static const std::vector<GLfloat> g_vertex_buffer_data = {
-1.0f,-1.0f,-1.0f,
-1.0f,-1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f,-1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f,-1.0f,
1.0f,-1.0f, 1.0f,
-1.0f,-1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f,-1.0f,
1.0f,-1.0f, 1.0f,
-1.0f,-1.0f, 1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f,-1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f,-1.0f,
-1.0f, 1.0f,-1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f
};
updateSphere(std::vector<VertexBuffer> &vertices)
{
if(!vertices.empty())
vertices.clear();
for (int i = 0; i < g_vertex_buffer_data.size();)
{
VertexBuffer buffer;
glm::vec3 vertex(g_vertex_buffer_data[i], g_vertex_buffer_data[i+1], g_vertex_buffer_data[i+2]);
buffer.setVertex(vertex);
buffer.setNormal(glm::normalize(vertex));
vertices.emplace_back(buffer);
i += 3;
}
}
Also the VertexBuffer struct:
struct Vector3 {
float x;
float y;
float z;
};
struct VertexBuffer {
Vector3 vertex;
Vector3 normal;
void setVertex(glm::vec3 vec)
{
vertex.x = vec.x;
vertex.y = vec.y;
vertex.z = vec.z;
}
void setNormal(glm::vec3 vec)
{
normal.x = vec.x;
normal.y = vec.y;
normal.z = vec.z;
}
};
My shader class is already tested in serveral other projects and works perfectly fine. I assume that I missmanage the VAO and VBO or the cube data. But I could be completly wrong here.
And I corrected the VAO generation, that was my bad and I wonder why I didn't see this. But that didn't fix the problem here.
The color and depth buffer get cleared in the mainloop of my project. Should I clear them on every draw call of an Object?
I don't understood how do OpenGL's buffers work. I learn OpenGL, by means of OpenGL Redbook 8th edition.
For example, I have an array of position, an array of color and an array of indices:
static const GLfloat strip_position[] =
{
-4.0f, 0.0f, -1.0f, 1.0f, //0
-3.5f, -1.0f, -1.0f, 1.0f, //1
-3.0f, 0.0f, -1.0f, 1.0f, //2
-2.5f, -1.0f, -1.0f, 1.0f, //3
-2.0f, 0.0f, -1.0f, 1.0f, //4
-1.5f, -1.0f, -1.0f, 1.0f, //5
-1.0f, 0.0f, -1.0f, 1.0f, //6
-0.5f, -1.0f, -1.0f, 1.0f, //7
0.0f, 0.0f, -1.0f, 1.0f //8
};
static const GLfloat strip_colors[] =
{
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
};
static const GLushort strip_indices[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8
};
Good.Then I create Vertex Array Object is follows:
GLuint vao[1]; // vertex array object
glGenVertexArrays(1, vao);
glBindVertexArray(vao[0]);
In my understanding, first parameter (GLsizei n) is number of an arrays of position(or coordinate of vertices of ONE my object).
Then I create Element Array Buffer is follows:
GLuint ebo[1]; // element buffer object
glGenBuffers(1, ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof(strip_indices),
strip_indices,
GL_STATIC_DRAW
);
Then I create Vertex Buffer Object is follows:
GLuint vbo[1]; // vertex buffer object
glGenBuffers(1, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(
GL_ARRAY_BUFFER,
sizeof(strip_position) + sizeof(strip_colors),
NULL,
GL_STATIC_DRAW
);
glBufferSubData(
GL_ARRAY_BUFFER,
0, //offset
sizeof(strip_position), //size date
strip_position //data
);
glBufferSubData(
GL_ARRAY_BUFFER,
sizeof(strip_position), //offset
sizeof(strip_colors), //size data
strip_colors //data
);
Next I call glVertexAttribPointer() is follows:
glVertexAttribPointer(
0, //index
4, //size
GL_FLOAT, //type
GL_FALSE, //normalized
0, //stride
NULL //pointer
);
glVertexAttribPointer(
1,
4,
GL_FLOAT,
GL_FALSE,
0,
(const GLvoid*)sizeof(strip_position)
);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
What does that function?(glVertexAttribPointer() and glEnableVertexAttribArray())
Okay. I finished initialize a my data. Now I can draw it's follows:
glBindVertexArray(vao[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
glDrawElements(GL_TRIANGLE_STRIP, 8, GL_UNSIGNED_SHORT, NULL);
How OpenGL understood, which buffer need to use and where it is? Word "bind" is mean a relation? i.e. something bind with something? And If I want to display a two object, what do I do?
For example, I have a two arrays of position, a two arrays of position and a two arrays of indices?
static const GLfloat TWOstrip_colors[] =
{
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f
};
static const GLfloat TWOstrip_colors[] =
{
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
};
static const GLushort TWOstrip_indices[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8
};
How do this?
OpenGL has the notion of so called objects. Those are not models or geometrical objects, but encapsulations of internal state. If you're familiar with object oriented programming, and the C++ STL OpenGL objects can be thought of kind of class instances.
The call glGenBuffers(count, out_names) could be roughtly interpreted into something like
std::map<GLuint, openglobject*> bufferobjects;
glGenBuffers(GLuint count, std::vector<GLuint> *out_names)
{
out_names->resize(count);
for(int i=0; i < count; i++) {
GLuint name = get_next_free_handle_ID();
bufferobjects[name] = NULL;
out_names.set(i, name);
}
}
So what it does is, it reserves a handle ID (OpenGL calls them names) and allocates a slot for it in the internal mapping between handles and bufferobject instance pointers.
The call glBindBuffer actually creates the buffer object, something like that
glBindBuffer(GLenum target, GLuint name)
{
openglobject *objinstance = NULL;
if( name != 0 ) {
if( !bufferobjects.has_key(name) ) {
push_openglerror( INVALID_NAME );
return;
}
objinstance = bufferobjects[name];
if( NULL == bufferobjects[name] ) {
switch(target) {
case GL_ARRAY_BUFFER:
objinstance = new OpenGLArrayBuffer; break;
case GL_ELEMENT_ARRAY_BUFFER:
objinstance = new OpenGLElementArrayBuffer; break;
/* ... and so on */
default:
push_openglerror( INVALID_TARGET ); return;
}
bufferobjects[name] = objinstance;
}
}
}
if( objinstance != NULL && target_of(objinstance) != target ) {
opengl_pusherror( INVALID_TARGET );
}
switch( target ) {
case GL_ARRAY_BUFFER:
/* this would be a static function of the subclass setting
* global singleton instance pointer
*/
OpenGLArrayBuffer::make_current(objinstance);
break;
/* ... and so on */
}
}
I think you can see there this is going: The buffer target specifies the type of subclass the instance is you're working with and its static members.
glBufferData then actually allocates memory of the particular object, and can initialize it with the contents of a buffer you pass to it. glBufferSubData just copies data to the internal storage.
So much for the Buffer Objects (of which there are several kinds).
The other part are the Vertex Array Objects. Those are special OpenGL objects that create an association between vertex attributes, which are per-vertex data passed to the shaders based on their attribute index and the array buffer objects from which this data is takes.
When you call glGenVertexArray something like this happens:
std::map<GLuint, openglobject*> vertexarrayobjects;
glGenVertexArrays(GLuint count, std::vector<GLuint> *out_names)
{
out_names->resize(count);
for(int i=0; i < count; i++) {
GLuint name = get_next_free_handle_ID();
vertexarrayrobjects[name] = NULL;
out_names.set(i, name);
}
}
Looks familiar, doesn't it? The only difference is, that a different mapping structure is used. glBindVertexArray does the allocation of an instance and so on.
Now the calls glEnableVertexAttribute and glVertexAttribPointer can be thought as the following:
glEnableVertexAttribute(GLuint idx)
{
((OpenGLVertexArrayObject*)currentvertexarray)->add_attribute(idx);
}
glVertexAttribPointer(GLuint idx, ..., void *ptr)
{
((OpenGLVertexArrayObject*)currentvertexarray)->bind_attribute(
idx,
OpenGLArrayBuffer::get_current(),
(off_t)ptr );
}
Okay, that last bit requires some explanation. That you pass a pointer to glVertexAttribPointer is a legacy from OpenGL-1.1 where there were no OpenGL buffer objects and instead you pointed directly to memory of your program. Then buffer objects got introduced and those don't require a pointer but a byte sized offset when binding. So the OpenGL devs went the dirty route and just lied to the compilers about it. I did explain the details in my answer to the question "What is the result of NULL + int?"
Note that OpenGL-4 introduced a new, much more powerfull and flexible API to create VAO attribute ←→ VBO bindings.
there is always a "current Buffer" of each target set by glBindBuffer(target, id) on which most the buffer operations know to operate.
openGL uses glEnableVertexAttribArray to know which attributes it should look for, if not called then openGL will not use the data.
glVertexAttribPointer tells openGL where in the currently bound GL_ARRAY_BUFFER the attributes must be found for the current vertexArrays. in your example: (assuming vbo[0] is still bound to GL_ARRAY_BUFFER)
attribute for index 0 is found in vbo[0] with 4 floats per vertex tightly packed and starting from 0
attribute for index 1 is found in vbo[0] with 4 floats per vertex tightly packed and starting from sizeof(strip_position)
these bindings persist over glBindBuffer calls so if you want to rebind then you'll need to bind the other buffer call glVertexAttribPointer and then you can unbind again
I suggest you always call glBindBuffer with a 0 buffer so openGL knows you don't want to work with the current buffer anymore and avoid strange behaviors
to create the second object you can refill the various buffers each time you switch objects
or you can either create 2 sets of buffers:
GLuint vao[2]; // vertex array object
glGenVertexArrays(2, vao);
glBindVertexArray(vao[0]);
GLuint ebo[2]; // element buffer object
glGenBuffers(2, ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof(strip_indices),
strip_indices,
GL_STATIC_DRAW
);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[1]);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof(strip_indices),
TWO_strip_indices,
GL_STATIC_DRAW
);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
GLuint vbo[2]; // vertex buffer object
glGenBuffers(2, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(
GL_ARRAY_BUFFER,
sizeof(strip_position) + sizeof(strip_colors),
NULL,
GL_STATIC_DRAW
);
glBufferSubData(
GL_ARRAY_BUFFER,
0, //offset
sizeof(strip_position), //size date
strip_position //data
);
glBufferSubData(
GL_ARRAY_BUFFER,
sizeof(strip_position), //offset
sizeof(strip_colors), //size data
strip_colors //data
);
//fill other buffer (assuming the first TWOstrip_colors was actually TWOstrip_position
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(
GL_ARRAY_BUFFER,
sizeof(TWOstrip_position) + sizeof(TWOstrip_colors),
NULL,
GL_STATIC_DRAW
);
glBufferSubData(
GL_ARRAY_BUFFER,
0, //offset
sizeof(TWOstrip_position), //size date
strip_position //data
);
glBufferSubData(
GL_ARRAY_BUFFER,
sizeof(TWOstrip_position), //offset
sizeof(TWOstrip_colors), //size data
strip_colors //data
);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(vao[0]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0])
glVertexAttribPointer(
0, //index
4, //size
GL_FLOAT, //type
GL_FALSE, //normalized
0, //stride
NULL //pointer
);
glVertexAttribPointer(
1,
4,
GL_FLOAT,
GL_FALSE,
0,
(const GLvoid*)sizeof(strip_position)
);
glBindVertexArray(vao[1]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glVertexAttribPointer(
0, //index
4, //size
GL_FLOAT, //type
GL_FALSE, //normalized
0, //stride
NULL //pointer
);
glVertexAttribPointer(
1,
4,
GL_FLOAT,
GL_FALSE,
0,
(const GLvoid*)sizeof(TWOstrip_position)
);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
then to draw:
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindVertexArray(vao[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
glDrawElements(GL_TRIANGLE_STRIP, 8, GL_UNSIGNED_SHORT, NULL);
glBindVertexArray(vao[1]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[1]);
glDrawElements(GL_TRIANGLE_STRIP, 8, GL_UNSIGNED_SHORT, NULL);
I am learning OpenGL 4.0 and I want to draw a simple triangle using OpenGL 4.0 and GLSL. I'm using VAO with interleaved arrays to do it, but the result it display is not what I want:
Now I post part of my code:
void SceneBasic::setupVAOInterleavedArrays()
{
//三角形的顶点和颜色信息数组:混合数组
float positionAndColorData[] = {
-0.8f, -0.8f, 0.0f,1.0f, 0.0f, 0.0f,
0.8f, -0.8f, 0.0f,0.0f, 1.0f, 0.0f,
0.0f, 0.8f, 0.0f,0.0f, 0.0f, 1.0f };
//glInterleavedArrays(GL_C3F_V3F,0,positionAndColorData)
GLuint vboHandle;//VBO
glGenBuffers(1,&vboHandle);
glBindBuffer(GL_ARRAY_BUFFER,vboHandle);
glBufferData(GL_ARRAY_BUFFER,18 * sizeof(float),
positionAndColorData,GL_STATIC_DRAW);
//VAO
glGenVertexArrays(1,&vaoHandle);
glBindVertexArray(vaoHandle);
//enable the generic vertex attribute indexes
//indicates that the values for the attributes will be accessed
//and used for rendering
glEnableVertexAttribArray(0);//position
glEnableVertexAttribArray(1);//color
//make the connection between the buffer objects and the generic
//vertex attributes indexes
glBindBuffer(GL_ARRAY_BUFFER,vboHandle);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3 * sizeof(float),BUFFER_OFFSET(0));
glBindBuffer(GL_ARRAY_BUFFER,vboHandle);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,3 * sizeof(float),BUFFER_OFFSET(3 * sizeof(float)));
}
void SceneBasic::initScene()
{
compileAndLinkShader();
//setupVAO();
setupVAOInterleavedArrays();
}
void SceneBasic::render()
{
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vaoHandle);
glDrawArrays(GL_TRIANGLES,0,3);
glBindVertexArray(0);
}
But if I don't use interleaved array, the result is right:
This is the part of my code when I don't use interleaved arrays:
void SceneBasic::setupVAO()
{
//三角形的顶点和颜色信息数组
float positionData[] = {
-0.8f, -0.8f, 0.0f,
0.8f, -0.8f, 0.0f,
0.0f, 0.8f, 0.0f };
float colorData[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f };
glGenBuffers(2,vboHandles);
GLuint positionBufferHandle = vboHandles[0];
GLuint colorBufferHandle = vboHandles[1];
glBindBuffer(GL_ARRAY_BUFFER,positionBufferHandle);
glBufferData(GL_ARRAY_BUFFER,9 * sizeof(float),
positionData,GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,colorBufferHandle);
glBufferData(GL_ARRAY_BUFFER,9 * sizeof(float),
colorData,GL_STATIC_DRAW);
//VAO
glGenVertexArrays(1,&vaoHandle);
glBindVertexArray(vaoHandle);
//enable the generic vertex attribute indexes
//indicates that the values for the attributes will be acessed
//and used for rendering
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//make the connection between the buffer objects abd the generic
//vertex attributes indexes
glBindBuffer(GL_ARRAY_BUFFER,positionBufferHandle);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,BUFFER_OFFSET(0));
glBindBuffer(GL_ARRAY_BUFFER,colorBufferHandle);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,BUFFER_OFFSET(0));
}
I am so curious, why is my code not producing the expected result when I use interleaved arrays?
The stride is wrong, since you have 6 elements per vertex, you need to pass 6 * sizeof (float) as the stride.