I am trying to create a cylinder and plane to put underneath cylinder. Before I created a new vertex buffer object for the plane, the cylinder was rendering just fine. But for some reason, neither the cylinder or the plane are rendering when I run the program. I have created an EBO for the cylinder, but I am still getting a black window. I don't know if I need to create an EBO for each shape and a VAO for each shape or if there is something wrong with my draw function. Can someone point out what may be the problem? Here is my code:
#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <iostream>
// GLM library
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
int width, height;
const double PI = 3.14159;
const float toRadians = PI / 180.0f;
// Draw Primitive(s)
void draw() {
GLenum mode = GL_TRIANGLES;
GLsizei indices = 60;
glDrawElements(mode, indices, GL_UNSIGNED_BYTE, nullptr);
}
// Create and Compile Shaders
static GLuint CompileShader(const string& source, GLuint shaderType) {
// Create Shader Object
GLuint shaderID = glCreateShader(shaderType);
const char* src = source.c_str();
// Attach source code to Shader object
glShaderSource(shaderID, 1, &src, nullptr);
// Compile Shader
glCompileShader(shaderID);
// Return ID of Compiled shader
return shaderID;
}
// Create Program Object
static GLuint CreateShaderProgram(const string& vertexShader, const string& fragmentShader) {
// Compile vertex shader
GLuint vertexShaderComp = CompileShader(vertexShader, GL_VERTEX_SHADER);
// Compile fragment shader
GLuint fragmentShaderComp = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
// Create program object
GLuint shaderProgram = glCreateProgram();
// Attch vertex and fragment shaders to program object
glAttachShader(shaderProgram, vertexShaderComp);
glAttachShader(shaderProgram, fragmentShaderComp);
// Link shaders to create executable
glLinkProgram(shaderProgram);
// Delete compiled vertex and fragment shaders
glDeleteShader(vertexShaderComp);
glDeleteShader(fragmentShaderComp);
// Return Shader Program
return shaderProgram;
}
int main(void) {
width = 640; height = 480;
GLFWwindow* window;
// Initialize the library
if (!glfwInit())
return -1;
// Create a windowed mode window and its OpenGL context
window = glfwCreateWindow(width, height, "Main Window", NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
// Make the window's context current
glfwMakeContextCurrent(window);
// Initialize GLEW
if (glewInit() != GLEW_OK)
cout << "Error!" << endl;
GLfloat cylinderVertices[] = {
// Base of the cylinder
// Triangle One // Color
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, // Vertex 0 red
cos(0 * toRadians), sin(0 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 1 green
cos(60 * toRadians), sin(60 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 2 blue
// Part of Triangle Two
cos(120 * toRadians), sin(120 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 3 purple
// Part of Triangle Three
cos(180 * toRadians), sin(180 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 4 greem
// Part of Triangle Four
cos(240 * toRadians), sin(240 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 5 blue
// Part of Triangle Five
cos(300 * toRadians), sin(300 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 6 purple
// Part of Triangle Six
cos(360 * toRadians), sin(360 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 7 green
// Sides of the cylinder
// Part of Triangle Seven
cos(0 * toRadians), sin(0 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 8 red
// Part of Triangle Eight
cos(60 * toRadians), sin(60 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 9 green
// Part of Triangle Nine
cos(120 * toRadians), sin(120 * toRadians), 2.0, 0.0, 0.0, 1.0, // Vertex 10 blue
// Part of Triangle Ten
cos(180 * toRadians), sin(180 * toRadians), 2.0, 1.0, 0.0, 1.0, // Vertex 11 purple
// Part of Triangle Eleven
cos(240 * toRadians), sin(240 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 12 red
// Part of Triangle Twelve
cos(300 * toRadians), sin(300 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 13 green
};
// Define element indices
GLubyte cylinderIndices[] = {
// Bottom base
0,1,2,
0,2,3,
0,3,4,
0,4,5,
0,5,6,
0,6,7,
// Sides
1,2,8,
2,9,8,
2,3,9,
3,10,9,
3,4,10,
4,11,10,
5,11,4,
5,12,11,
5,6,12,
6,13,12,
6,1,13,
1,8,13
};
GLfloat planeVertices[] = {
// positon attributes (x,y,z)
0.0f, 0.0f, 0.0f, // vert 14
0.0f, 1.0f, 0.0f, // red
0.0f, 0.866f, 0.0f, // vert 15
0.0f, 1.0f, 0.0f, // green
1.0f, 0.0f, 0.0f, // vert 16
0.0f, 1.0f, 0.0f, // blue
1.0f, 0.866f, 0.0f, // vert 17
1.0f, 0.0f, 1.0f // purple
};
// Define element indices
GLubyte planeIndices[] = {
14,16,15,
16,17,15
};
// Enable Depth Buffer
glEnable(GL_DEPTH_TEST);
// Wireframe mode
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
GLuint cylinderVBO, planeVBO, EBO, VAO;
glGenBuffers(1, &cylinderVBO); // Create VBO and returns ID
glGenBuffers(1, &planeVBO);
glGenBuffers(1, &EBO); // Create EBO
glGenVertexArrays(1, &VAO); // Create VAO
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO); // Select VBO and activate buffer
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Select EBO
glBufferData(GL_ARRAY_BUFFER, sizeof(cylinderVertices), cylinderVertices, GL_STATIC_DRAW); // Load vertex attributes
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cylinderIndices), cylinderIndices, GL_STATIC_DRAW); // Load indices attributes
glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW); // Load vertex attributes
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW); // Load indices attributes
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute location and layout
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
// Vertex shader source code
string vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec4 vPosition;"
"layout(location = 1) in vec4 aColor;"
"out vec4 oColor;"
"uniform mat4 model;"
"uniform mat4 view;"
"uniform mat4 projection;"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vPosition;"
"oColor = aColor;"
"}\n";
// Fragment shader source code
string fragmentShaderSource =
"#version 330 core\n"
"in vec4 oColor;"
"out vec4 fragColor;"
"void main()\n"
"{\n"
"fragColor = oColor;"
"}\n";
// Creating Shader Program
GLuint shaderProgram = CreateShaderProgram(vertexShaderSource, fragmentShaderSource);
while (!glfwWindowShouldClose(window)) {
// Resize window and graphics simultaneously
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// Render here
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use Shader Program exe and select VAO before drawing
glUseProgram(shaderProgram); // Call Shader per-frame when updating attributes
// Declare identity matrix
glm::mat4 modelMatrix(1.0f);
glm::mat4 viewMatrix(1.0f);
glm::mat4 projectionMatrix(1.0f);
// Initialize transforms
modelMatrix = glm::scale(modelMatrix, glm::vec3(0.5f, 0.5f, 0.5f));
// I increased the third argument from -3.0f to -6.0f to make the object smaller
// Moved the cup to the right by increasing the x coordinate
viewMatrix = glm::translate(viewMatrix, glm::vec3(0.5f, 0.0f, -6.0f));
// I changed up somme of the arguments, so the object would tilt right instead of toward me
viewMatrix = glm::rotate(viewMatrix, 45.0f * toRadians, glm::vec3(-0.5f, 1.0f, 1.5f));
projectionMatrix = glm::perspective(45.0f * toRadians, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
// Select uniform shader and variable
GLuint modelLoc = glGetUniformLocation(shaderProgram, "model");
GLuint viewLoc = glGetUniformLocation(shaderProgram, "view");
GLuint projectionLoc = glGetUniformLocation(shaderProgram, "projection");
// Pass transform to Shader
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glBindVertexArray(VAO); // User-defined VAO must be called before draw
for (GLuint i = 0; i < 4; i++) {
glm::mat4 modelMatrix(1.0f);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix));
// Draw primitive(s)
draw();
}
// Unbind Shader exe and VOA after drawing per frame
glBindVertexArray(0); // In case different VAO will be used after
glUseProgram(0); // In case different shader will be used after
glBindVertexArray(VAO);
// Swap front and back buffers
glfwSwapBuffers(window);
// Poll for and process events
glfwPollEvents();
}
glfwTerminate();
return 0;
}
Ok, so there is a bit of a structural problem with your plane & cylinder buffer layouts (ind indexing).
Vertex Buffers
First, let's start with the vertex data and associated buffers (we'll worry about indexing later).
You have 2 choices for how to send the data to the GPU.
Seperate vertex buffers for each shape. i.e. specify a cylinderVBO (with all cylinder vertices) and a planeVBO (with all plane vertices).
Combine both sets of vertices into a single vertex buffer.
If you are specifying the buffers separately, then setup EACH buffer in turn.
// do the cylinder buffer first!
glGenBuffers(1, &cylinderVBO);
glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cylinderVertices), cylinderVertices, GL_STATIC_DRAW); // Load vertex attributes
// NOW do the plane buffer!
glGenBuffers(1, &planeVBO);
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW); // Load vertex attributes
If you want to combine the buffers into one big blob, then generate one big array:
GLfloat allVertices[] = {
// ------------- cylinderVertices[]
// Base of the cylinder
// Triangle One // Color
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, // Vertex 0 red
cos(0 * toRadians), sin(0 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 1 green
cos(60 * toRadians), sin(60 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 2 blue
// Part of Triangle Two
cos(120 * toRadians), sin(120 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 3 purple
// Part of Triangle Three
cos(180 * toRadians), sin(180 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 4 greem
// Part of Triangle Four
cos(240 * toRadians), sin(240 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 5 blue
// Part of Triangle Five
cos(300 * toRadians), sin(300 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 6 purple
// Part of Triangle Six
cos(360 * toRadians), sin(360 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 7 green
// Sides of the cylinder
// Part of Triangle Seven
cos(0 * toRadians), sin(0 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 8 red
// Part of Triangle Eight
cos(60 * toRadians), sin(60 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 9 green
// Part of Triangle Nine
cos(120 * toRadians), sin(120 * toRadians), 2.0, 0.0, 0.0, 1.0, // Vertex 10 blue
// Part of Triangle Ten
cos(180 * toRadians), sin(180 * toRadians), 2.0, 1.0, 0.0, 1.0, // Vertex 11 purple
// Part of Triangle Eleven
cos(240 * toRadians), sin(240 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 12 red
// Part of Triangle Twelve
cos(300 * toRadians), sin(300 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 13 green
// ------------- planeVertices[]
// positon attributes (x,y,z)
0.0f, 0.0f, 0.0f, // vert 14
0.0f, 1.0f, 0.0f, // red
0.0f, 0.866f, 0.0f, // vert 15
0.0f, 1.0f, 0.0f, // green
1.0f, 0.0f, 0.0f, // vert 16
0.0f, 1.0f, 0.0f, // blue
1.0f, 0.866f, 0.0f, // vert 17
1.0f, 0.0f, 1.0f // purple
};
// Now generate a vertex buffer with all vertex data in one buffer
GLuint allVerticesVBO;
glGenBuffers(1, & allVerticesVBO);
glBindBuffer(GL_ARRAY_BUFFER, allVerticesVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(allVertices), allVertices, GL_STATIC_DRAW); // Load vertex attributes
Index Buffers
Now, depending on how you set the vertex buffers up previously, you will have to do one (but not both!) of the following.
If you have separated your vertex buffers (one for cylinder, one for the plane), then you will need separate index buffers as well.
// we need two index buffers, one for the plane, one for the cylinder
GLuint cylinderIBO, planeIBO;
//--------------------
// cylinder
//--------------------
// Define element indices
GLubyte cylinderIndices[] = {
// Bottom base
0,1,2,
0,2,3,
0,3,4,
0,4,5,
0,5,6,
0,6,7,
// Sides
1,2,8,
2,9,8,
2,3,9,
3,10,9,
3,4,10,
4,11,10,
5,11,4,
5,12,11,
5,6,12,
6,13,12,
6,1,13,
1,8,13
};
glGenBuffers(1, &cylinderIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cylinderIndices), cylinderIndices, GL_STATIC_DRAW); // Load indices attributes
//--------------------
// plane
//--------------------
GLubyte planeIndices[] = {
0,2,1, //< NOTE: These must start at ZERO in this case!
2,3,1
};
glGenBuffers(1, &planeIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW); // Load indices attributes
If however you wish to combine both shapes into a single buffer, then instead do this:
// we need one index buffer!
GLuint allIndicesIBO;
// Define element indices
GLubyte allIndices[] = {
//--------------------
// cylinder
//--------------------
// Bottom base
0,1,2,
0,2,3,
0,3,4,
0,4,5,
0,5,6,
0,6,7,
// Sides
1,2,8,
2,9,8,
2,3,9,
3,10,9,
3,4,10,
4,11,10,
5,11,4,
5,12,11,
5,6,12,
6,13,12,
6,1,13,
1,8,13,
//--------------------
// plane
//--------------------
14,16,15, //< NOTE: these now start at 14!
16,17,15
};
glGenBuffers(1, &allIndicesIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, allIndicesIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(allIndices), allIndices, GL_STATIC_DRAW); // Load indices attributes
Vertex Buffer Objects
If you have set up separate buffers for each shape, then you have two choices in how you set up the VAOs.
1.1 Create two VAO's, one for each shape.
GLuint cylinderVAO, planeVAO;
// generate a bind new VAO for the cylinder
glGenVertexArrays(1, & cylinderVAO);
glBindVertexArray(cylinderVAO);
// specify which buffers the current VAO should use
glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO);
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute location and layout
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
// generate a bind new VAO for the plane
glGenVertexArrays(1, &planeVAO);
glBindVertexArray(planeVAO);
// specify which buffers the current VAO should use
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO);
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute location and layout
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
To render the data like this, you'll need 2 draw calls, one for each shape.
glBindVertexArray(cylinderVAO);
glDrawElements(mode, 54, GL_UNSIGNED_BYTE, nullptr);
glBindVertexArray(planeVAO);
glDrawElements(mode, 6, GL_UNSIGNED_BYTE, nullptr);
1.2 Setup 1 VAO, but rebind the vertex & index buffers on the fly.
GLuint sharedVAO;
// generate a bind new VAO for the cylinder
glGenVertexArrays(1, & sharedVAO);
glBindVertexArray(sharedVAO);
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute location and layout
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
To render the data like this, you'll need 2 draw calls, one for each shape.
// specify the shared vertex format
glBindVertexArray(sharedVAO);
// specify data sources for cylinder, and render
glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO);
glDrawElements(mode, 54, GL_UNSIGNED_BYTE, nullptr);
// specify data sources for plane, and render
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO);
glDrawElements(mode, 6, GL_UNSIGNED_BYTE, nullptr);
If however you have specified all of the data in a single vertex buffer, and a single index buffer, then instead you can do:
GLuint sharedVAO;
// generate a bind new VAO for the cylinder
glGenVertexArrays(1, & sharedVAO);
glBindVertexArray(sharedVAO);
// specify data sources for the VAO
glBindBuffer(GL_ARRAY_BUFFER, allVerticesVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, allIndicesIBO);
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute location and layout
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
To render the data like this, you'll need 1 draw call.
// render both shapes in one draw call
glBindVertexArray(sharedVAO);
glDrawElements(mode, 60, GL_UNSIGNED_BYTE, nullptr);
And that's it.
Related
I am trying to create six sides for a cylinder using OpenGL and two triangles for each side. I am currently using wireframe mode, so I can see the triangles that are being used. I finished by code for the cylinderVertices array and the cylinderIndices array, but whenever I run the program, the base comes out perfectly, but the sides are messed up. Is there something wrong with the angles that I am using for the sine and cosine coordinates in my cylinderVertices array or do my indices need fixing in my cylinderIndices array? Maybe someone can help me give the right coordinates. Here is my code:
#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <iostream>
// GLM library
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
int width, height;
const double PI = 3.14159;
const float toRadians = PI / 180.0f;
// Draw Primitive(s)
void draw() {
GLenum mode = GL_TRIANGLES;
GLsizei indices = 63;
glDrawElements(mode, indices, GL_UNSIGNED_BYTE, nullptr);
}
// Create and Compile Shaders
static GLuint CompileShader(const string& source, GLuint shaderType) {
// Create Shader Object
GLuint shaderID = glCreateShader(shaderType);
const char* src = source.c_str();
// Attach source code to Shader object
glShaderSource(shaderID, 1, &src, nullptr);
// Compile Shader
glCompileShader(shaderID);
// Return ID of Compiled shader
return shaderID;
}
// Create Program Object
static GLuint CreateShaderProgram(const string& vertexShader, const string& fragmentShader) {
// Compile vertex shader
GLuint vertexShaderComp = CompileShader(vertexShader, GL_VERTEX_SHADER);
// Compile fragment shader
GLuint fragmentShaderComp = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
// Create program object
GLuint shaderProgram = glCreateProgram();
// Attch vertex and fragment shaders to program object
glAttachShader(shaderProgram, vertexShaderComp);
glAttachShader(shaderProgram, fragmentShaderComp);
// Link shaders to create executable
glLinkProgram(shaderProgram);
// Delete compiled vertex and fragment shaders
glDeleteShader(vertexShaderComp);
glDeleteShader(fragmentShaderComp);
// Return Shader Program
return shaderProgram;
}
int main(void) {
width = 640; height = 480;
GLFWwindow* window;
// Initialize the library
if (!glfwInit())
return -1;
// Create a windowed mode window and its OpenGL context
window = glfwCreateWindow(width, height, "Main Window", NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
// Make the window's context current
glfwMakeContextCurrent(window);
// Initialize GLEW
if (glewInit() != GLEW_OK)
cout << "Error!" << endl;
GLfloat cylinderVertices[] = {
// Base of the cylinder
// Triangle One // Color
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, // Vertex 0 red
cos( 0 * toRadians), sin( 0 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 1 green
cos( 60 * toRadians), sin( 60 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 2 blue
// Part of Triangle Two
cos(120 * toRadians), sin(120 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 3 purple
// Part of Triangle Three
cos(180 * toRadians), sin(180 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 4 greem
// Part of Triangle Four
cos(240 * toRadians), sin(240 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 5 blue
// Part of Triangle Five
cos(300 * toRadians), sin(300 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 6 purple
// Part of Triangle Six
cos(360 * toRadians), sin(360 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 7 green
// Sides of the cylinder
// Part of Triangle Seven
cos( 0 * toRadians), sin( 0 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 8 red
// Part of Triangle Eight
cos( 45 * toRadians), sin( 45 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 9 green
// Part of Triangle Nine
cos( 60 * toRadians), sin( 60 * toRadians), 2.0, 0.0, 0.0, 1.0, // Vertex 10 blue
// Part of Triangle Ten
cos( 105 * toRadians), sin( 105 * toRadians), 2.0, 1.0, 0.0, 1.0, // Vertex 11 purple
// Part of Triangle Eleven
cos( 120 * toRadians), sin( 120 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 12 red
// Part of Triangle Twelve
cos( 165 * toRadians), sin( 165 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 13 green
// Part of Triangle Thirteen
cos( 180 * toRadians), sin( 180 * toRadians), 2.0, 0.0, 0.0, 1.0, // Vertex 14 blue
// Part of Triangle Fourteen
cos( 225 * toRadians), sin( 225 * toRadians), 2.0, 1,0, 0.0, 1.0, // Vertex 15 purple
// Part of Triangle Fifteen
cos( 240 * toRadians), sin( 240 * toRadians), 2.0, 1.0, 0.0, 0.0 // Vertex 16 red
};
// Define element indices
GLubyte cylinderIndices[] = {
0,1,2,
0,2,3,
0,3,4,
0,4,5,
0,5,6,
0,6,7,
1,2,8,
2,8,9,
3,2,10,
2,9,10,
3,10,11,
3,4,11,
4,11,12,
4,5,12,
5,12,13,
5,6,13,
6,13,14,
5,6,14,
5,6,15,
6,1,15,
1,6,8
};
// Enable Depth Buffer
glEnable(GL_DEPTH_TEST);
// Wireframe mode
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
GLuint VBO, EBO, VAO;
glGenBuffers(1, &VBO); // Create VBO and returns ID
glGenBuffers(1, &EBO); // Create EBO
glGenVertexArrays(1, &VAO); // Create VAO
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO); // Select VBO and activate buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Select EBO
glBufferData(GL_ARRAY_BUFFER, sizeof(cylinderVertices), cylinderVertices, GL_STATIC_DRAW); // Load vertex attributes
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cylinderIndices), cylinderIndices, GL_STATIC_DRAW); // Load indices attributes
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute location and layout
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
// Vertex shader source code
string vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec4 vPosition;"
"layout(location = 1) in vec4 aColor;"
"out vec4 oColor;"
"uniform mat4 model;"
"uniform mat4 view;"
"uniform mat4 projection;"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vPosition;"
"oColor = aColor;"
"}\n";
// Fragment shader source code
string fragmentShaderSource =
"#version 330 core\n"
"in vec4 oColor;"
"out vec4 fragColor;"
"void main()\n"
"{\n"
"fragColor = oColor;"
"}\n";
// Creating Shader Program
GLuint shaderProgram = CreateShaderProgram(vertexShaderSource, fragmentShaderSource);
while (!glfwWindowShouldClose(window)) {
// Resize window and graphics simultaneously
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// Render here
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use Shader Program exe and select VAO before drawing
glUseProgram(shaderProgram); // Call Shader per-frame when updating attributes
// Declare identity matrix
glm::mat4 modelMatrix(1.0f);
glm::mat4 viewMatrix(1.0f);
glm::mat4 projectionMatrix(1.0f);
// Initialize transforms
modelMatrix = glm::scale(modelMatrix, glm::vec3(0.5f, 0.5f, 0.5f));
// I increased the third argument from -3.0f to -6.0f to make the object smaller
viewMatrix = glm::translate(viewMatrix, glm::vec3(0.0f, 0.0f, -6.0f));
// I changed up somme of the arguments, so the object would tilt left instead of toward me
viewMatrix = glm::rotate(viewMatrix, 45.0f * toRadians, glm::vec3(-0.5f, 1.0f, 1.5f));
projectionMatrix = glm::perspective(45.0f * toRadians, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
// Select uniform shader and variable
GLuint modelLoc = glGetUniformLocation(shaderProgram, "model");
GLuint viewLoc = glGetUniformLocation(shaderProgram, "view");
GLuint projectionLoc = glGetUniformLocation(shaderProgram, "projection");
// Pass transform to Shader
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glBindVertexArray(VAO); // User-defined VAO must be called before draw
for (GLuint i = 0; i < 4; i++) {
glm::mat4 modelMatrix(1.0f);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix));
// Draw primitive(s)
draw();
}
// Unbind Shader exe and VOA after drawing per frame
glBindVertexArray(0); // In case different VAO will be used after
glUseProgram(0); // In case different shader will be used after
glBindVertexArray(VAO);
// Swap front and back buffers
glfwSwapBuffers(window);
// Poll for and process events
glfwPollEvents();
}
glfwTerminate();
return 0;
}
This fixed the problem:
GLfloat cylinderVertices[] = {
// Base of the cylinder
// Triangle One // Color
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, // Vertex 0 red
cos( 0 * toRadians), sin( 0 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 1 green
cos( 60 * toRadians), sin( 60 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 2 blue
// Part of Triangle Two
cos(120 * toRadians), sin(120 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 3 purple
// Part of Triangle Three
cos(180 * toRadians), sin(180 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 4 greem
// Part of Triangle Four
cos(240 * toRadians), sin(240 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 5 blue
// Part of Triangle Five
cos(300 * toRadians), sin(300 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 6 purple
// Part of Triangle Six
cos(360 * toRadians), sin(360 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 7 green
// Sides of the cylinder
// Part of Triangle Seven
cos( 0 * toRadians), sin( 0 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 8 red
// Part of Triangle Eight
cos( 60 * toRadians), sin( 60 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 9 green
// Part of Triangle Nine
cos( 120 * toRadians), sin( 120 * toRadians), 2.0, 0.0, 0.0, 1.0, // Vertex 10 blue
// Part of Triangle Ten
cos( 180 * toRadians), sin( 180 * toRadians), 2.0, 1.0, 0.0, 1.0, // Vertex 11 purple
// Part of Triangle Eleven
cos( 240 * toRadians), sin( 240 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 12 red
// Part of Triangle Twelve
cos( 300 * toRadians), sin( 300 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 13 green
};
// Define element indices
GLubyte cylinderIndices[] = {
// Bottom base
0,1,2,
0,2,3,
0,3,4,
0,4,5,
0,5,6,
0,6,7,
// Sides
1,2,8,
2,9,8,
2,3,9,
3,10,9,
3,4,10,
4,11,10,
5,11,4,
5,12,11,
5,6,12,
6,13,12,
6,1,13,
1,8,13
};
I am trying to create a lamp or light source in OpenGL in the form of a cube. My current code renders a cylinder sitting on a plane with textures whenever I run the program. I have defined planePositions and planeRotations and I have used those variables in a for loop to form a cube that will be my shining lamp. But for some reason, a lamp is not rendering at all. Is there a way to incorporate my current plane into the for loop or is there a better way to create a lamp? Here is my code:
#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <iostream>
// GLM library
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <SOIL2.h>
using namespace std;
int width, height;
const double PI = 3.14159;
const float toRadians = PI / 180.0f;
// Input Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
// Initialize FOV
GLfloat fov = 45.f;
double cameraSpeedPerSecond = 2.5;
// Define Camera Attributes
glm::vec3 cameraPosition;
glm::vec3 target;
glm::vec3 cameraDirection;
glm::vec3 worldUp;
glm::vec3 cameraRight;
glm::vec3 cameraUp;
// Declare target prototype
glm::vec3 getTarget();
// Camera transformation prototype
void TransformCamera();
// Boolean for keys and mouse buttons
bool keys[1024], mouseButtons[3];
// Boolean to check camera transformations
bool isPanning = false, isOrbiting = false;
bool projectionIsPerspective = true;
// Radius, Pitch, and Yaw
GLfloat radius = 3.f, rawYaw = 0.f, rawPitch = 0.f, degYaw, degPitch;
GLfloat deltaTime = 0.f, lastFrame = 0.f;
GLfloat lastX = 400, lastY = 300, xChange, yChange;
bool firstMouseMove = true; // Detect inititial mouse movement
// Light source position
glm::vec3 lightPosition(1.0f, 1.0f, 1.0f);
void initCamera();
void UProcessInput(GLFWwindow* window);
// Draw Primitive(s)
void draw() {
GLenum mode = GL_TRIANGLES;
GLsizei indices = 62;
glDrawElements(mode, indices, GL_UNSIGNED_BYTE, nullptr);
}
// Create and Compile Shaders
static GLuint CompileShader(const string& source, GLuint shaderType) {
// Create Shader Object
GLuint shaderID = glCreateShader(shaderType);
const char* src = source.c_str();
// Attach source code to Shader object
glShaderSource(shaderID, 1, &src, nullptr);
// Compile Shader
glCompileShader(shaderID);
// Return ID of Compiled shader
return shaderID;
}
// Create Program Object
static GLuint CreateShaderProgram(const string& vertexShader, const string& fragmentShader) {
// Compile vertex shader
GLuint vertexShaderComp = CompileShader(vertexShader, GL_VERTEX_SHADER);
// Compile fragment shader
GLuint fragmentShaderComp = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
// Create program object
GLuint shaderProgram = glCreateProgram();
// Attch vertex and fragment shaders to program object
glAttachShader(shaderProgram, vertexShaderComp);
glAttachShader(shaderProgram, fragmentShaderComp);
// Link shaders to create executable
glLinkProgram(shaderProgram);
// Delete compiled vertex and fragment shaders
glDeleteShader(vertexShaderComp);
glDeleteShader(fragmentShaderComp);
// Return Shader Program
return shaderProgram;
}
int main(void) {
width = 640; height = 480;
GLFWwindow* window;
// Initialize the library
if (!glfwInit())
return -1;
// Create a windowed mode window and its OpenGL context
window = glfwCreateWindow(width, height, "Main Window", NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
glfwSetScrollCallback(window, scroll_callback);
glfwSetCursorPosCallback(window, cursor_position_callback);
glfwSetKeyCallback(window, key_callback);
// Make the window's context current
glfwMakeContextCurrent(window);
// Initialize GLEW
if (glewInit() != GLEW_OK)
cout << "Error!" << endl;
initCamera();
GLfloat cylinderVertices[] = {
// Base of the cylinder
// Triangle One // Color
// Vertex 0 // Red // UV
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.0,
// Vertex 1 // Green // UV
cos(0 * toRadians), sin(0 * toRadians), 0.0, 0.0, 1.0, 0.0, 1.0, 0.0,
// Vertex 2 // Blue // UV
cos(60 * toRadians), sin(60 * toRadians), 0.0, 0.0, 0.0, 1.0, 1.0, 0.0,
// Part of Triangle Two
// Vertex 3 // Purple // UV
cos(120 * toRadians), sin(120 * toRadians), 0.0, 1.0, 0.0, 1.0, 1.0, 0.0,
// Part of Triangle Three
// Vertex 4 // Green // UV
cos(180 * toRadians), sin(180 * toRadians), 0.0, 0.0, 1.0, 0.0, 1.0, 0.0,
// Part of Triangle Four
// Vertex 5 // Blue // UV
cos(240 * toRadians), sin(240 * toRadians), 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
// Part of Triangle Five
// Vertex 6 // Purple // UV
cos(300 * toRadians), sin(300 * toRadians), 0.0, 1.0, 0.0, 1.0, 0.0, 0.0,
// Part of Triangle Six
// Vertex 7 // Green // UV
cos(360 * toRadians), sin(360 * toRadians), 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
// Sides of the cylinder
// Part of Triangle Seven
// Vertex 8 // Red // UV
cos(0 * toRadians), sin(0 * toRadians), 2.0, 1.0, 0.0, 0.0, 1.0, 1.0,
// Part of Triangle Eight
// Vertex 9 // Green // UV
cos(60 * toRadians), sin(60 * toRadians), 2.0, 0.0, 1.0, 0.0, 1.0, 1.0,
// Part of Triangle Nine
// Vertex 10 // Blue // UV
cos(120 * toRadians), sin(120 * toRadians), 2.0, 0.0, 0.0, 1.0, 1.0, 1.0,
// Part of Triangle Ten
// Vertex 11 // Purple // UV
cos(180 * toRadians), sin(180 * toRadians), 2.0, 1.0, 0.0, 1.0, 0.0, 1.0,
// Part of Triangle Eleven
// Vertex 12 // Red // UV
cos(240 * toRadians), sin(240 * toRadians), 2.0, 1.0, 0.0, 0.0, 0.0, 1.0,
// Part of Triangle Twelve
// Vertex 13 // Green // UV
cos(300 * toRadians), sin(300 * toRadians), 2.0, 0.0, 1.0, 0.0, 0.0, 1.0
};
// we need two index buffers, one for the plane, one for the cylinder
GLuint cylinderIBO, planeIBO, lampIBO;
// Define element indices
GLubyte cylinderIndices[] = {
// Bottom base
0,1,2,
0,2,3,
0,3,4,
0,4,5,
0,5,6,
0,6,7,
// Sides
1,2,8,
2,9,8,
2,3,9,
3,10,9,
3,4,10,
4,11,10,
5,11,4,
5,12,11,
5,6,12,
6,13,12,
6,1,13,
1,8,13
};
glGenBuffers(1, &cylinderIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cylinderIndices), cylinderIndices, GL_STATIC_DRAW); // Load indices attributes
GLfloat planeVertices[] = {
// positon attributes (x,y,z)
-2.0f, 2.0f, 0.0f, // plane vertex 0
0.0f, 1.0f, 1.0f, // cyan
0.0f, 0.0, // UV
2.0f, 1.0f, -0.2f, // plane vertex 1
1.0f, 1.0f, 0.0f, // yellow
0.0f, 1.0f, // UV
-3.0f, 0.0f, 0.0f, // plane vertex 2
1.0f, 1.0f, 0.0f, // yellow
1.0f, 0.0, // UV
1.0f, -1.0f, -0.2f, // plane vertex 3
0.0f, 1.0f, 1.0f, // cyan
1.0f, 1.0f // UV
};
// Define element indicesd
GLubyte planeIndices[] = {
0,2,1,
2,3,1
};
// Plane Transforms
glm::vec3 planePositions[] = {
glm::vec3(0.0f, 0.0f, 0.5f),
glm::vec3(0.5f, 0.0f, 0.0f),
glm::vec3(0.0f, 0.0f, -0.5f),
glm::vec3(-0.5f, 0.0f, 0.0f),
glm::vec3(0.0f, 0.5f, 0.0f),
glm::vec3(0.0f, -0.5f, 0.0f)
};
glm::float32 planeRotations[] = {
0.0f, 90.0f, 0.0f, 50.0f, 90.0f, 90.0f
};
glGenBuffers(1, &planeIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW); // Load indices attributes
GLfloat lampVertices[] = {
-0.5, -0.5, 0.0, // index 0
-0.5, 0.5, 0.0, // index 1
0.5, -0.5, 0.0, // index 2
0.5, 0.5, 0.0 // index 3
};
GLubyte lampIndices[] = {
0, 1, 2,
1, 2, 3
};
glGenBuffers(1, &lampIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lampIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(lampIndices), lampIndices, GL_STATIC_DRAW); // Load indices attributes
// Enable Depth Buffer
glEnable(GL_DEPTH_TEST);
// Wireframe mode
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
GLuint cylinderVBO, planeVBO, EBO, lampVBO, lampEBO;
glGenBuffers(1, &cylinderVBO); // Create VBO and returns ID
glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO); // Select VBO and activate buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(cylinderVertices), cylinderVertices, GL_STATIC_DRAW); // Load vertex attributes
glGenBuffers(1, &planeVBO); // Create VBO and returns ID
glBindBuffer(GL_ARRAY_BUFFER, planeVBO); // Select VBO and activate buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW); // Load vertex attributes
glGenBuffers(1, &EBO); // Create EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Select EBO
glGenBuffers(1, &lampVBO); // Creat VBO and returns ID
glBindBuffer(GL_ARRAY_BUFFER, lampVBO); // Select VBO and activate buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(lampVertices), lampVertices, GL_STATIC_DRAW); // Load vertex attributes
glGenBuffers(1, &lampEBO); // Create EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lampEBO); // Select EBO
GLuint cylinderVAO, planeVAO, lampVAO;
// generate a bind new VAO for the cylinder
glGenVertexArrays(1, &cylinderVAO);
glBindVertexArray(cylinderVAO);
// specify which buffers the current VAO should use
glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO);
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute location and layout
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
// generate a bind new VAO for the plane
glGenVertexArrays(1, &planeVAO);
glBindVertexArray(planeVAO);
// specify which buffers the current VAO should use
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO);
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Color attribute location and layout
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
// generate a bind new VAO for the lamp
glGenVertexArrays(1, &lampVAO);
glBindVertexArray(lampVAO);
// specify which buffers the current VAO should use
glBindBuffer(GL_ARRAY_BUFFER, lampVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lampIBO);
// Specify attributes location and layout to GPU
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
glBindVertexArray(cylinderVAO);
glDrawElements(GL_TRIANGLES, 54, GL_UNSIGNED_BYTE, nullptr);
glBindVertexArray(planeVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
glBindVertexArray(lampVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
// Load textures
int crateTexWidth, crateTexHeight, gridTexWidth, gridTexHeight;
unsigned char* crateImage = SOIL_load_image("crate.png", &crateTexWidth, &crateTexHeight, 0, SOIL_LOAD_RGB);
unsigned char* gridImage = SOIL_load_image("grid.png", &gridTexWidth, &gridTexHeight, 0, SOIL_LOAD_RGB);
// Generate Textures
GLuint crateTexture;
glGenTextures(1, &crateTexture);
glBindTexture(GL_TEXTURE_2D, crateTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, crateTexWidth, crateTexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, crateImage);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(crateImage);
glBindTexture(GL_TEXTURE_2D, 0);
GLuint gridTexture;
glGenTextures(1, &gridTexture);
glBindTexture(GL_TEXTURE_2D, gridTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, gridTexWidth, gridTexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, gridImage);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(gridImage);
glBindTexture(GL_TEXTURE_2D, 0);
// Vertex shader source code
string vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec3 vPosition;"
"layout(location = 1) in vec3 aColor;"
"layout(location = 2) in vec2 texCoord;"
"out vec3 oColor;"
"out vec2 oTexCoord;"
"uniform mat4 model;"
"uniform mat4 view;"
"uniform mat4 projection;"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vec4(vPosition.x, vPosition.y, vPosition.z, 1.0);"
"oColor = aColor;"
"oTexCoord = texCoord;"
"}\n";
// Fragment shader source code
string fragmentShaderSource =
"#version 330 core\n"
"in vec3 oColor;"
"in vec2 oTexCoord;"
"out vec4 fragColor;"
"uniform sampler2D myTexture;"
"uniform vec3 objectColor;"
"uniform vec3 lightColor;"
"uniform vec3 lightPos;"
"void main()\n"
"{\n"
"fragColor = texture(myTexture, oTexCoord) * vec4(objectColor * lightColor, 1.0f);"
"}\n";
// Lamp Vertex shader source code
string lampVertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec3 vPosition;"
"uniform mat4 model;"
"uniform mat4 view;"
"uniform mat4 projection;"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vec4(vPosition.x, vPosition.y, vPosition.z, 1.0);"
"}\n";
// Lamp Fragment shader source code
string lampFragmentShaderSource =
"#version 330 core\n"
"out vec4 fragColor;"
"void main()\n"
"{\n"
"fragColor = vec4(1.0f);"
"}\n";
// Creating Shader Program
GLuint shaderProgram = CreateShaderProgram(vertexShaderSource, fragmentShaderSource);
GLuint lampShaderProgram = CreateShaderProgram(lampVertexShaderSource, lampFragmentShaderSource);
double currentTime = glfwGetTime();
// loop until th euser closes window
while (!glfwWindowShouldClose(window)) {
double newTime = glfwGetTime();
deltaTime = newTime - currentTime;
currentTime = newTime;
// Resize window and graphics simultaneously
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// Render here
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
UProcessInput(window);
// Use Shader Program exe and select VAO before drawing
glUseProgram(shaderProgram); // Call Shader per-frame when updating attributes
// Declare identity matrix
glm::mat4 modelMatrix(1.0f);
glm::mat4 viewMatrix(1.0f);
glm::mat4 projectionMatrix(1.0f);
// Initialize transforms
modelMatrix = glm::scale(modelMatrix, glm::vec3(0.5f, 0.5f, 0.5f));
// I increased the third argument from -3.0f to -6.0f to make the object smaller
// Moved the cup to the right by increasing the x coordinate
//viewMatrix = glm::translate(viewMatrix, glm::vec3(0.5f, 0.0f, -6.0f));
// I changed up somme of the arguments, so the object would tilt right instead of toward me
//viewMatrix = glm::rotate(viewMatrix, 45.0f * toRadians, glm::vec3(-0.5f, 1.0f, 1.5f));
//
// Transforms the camera: move the camera back (z axis)
viewMatrix = glm::lookAt(cameraPosition, cameraPosition + cameraDirection, worldUp);
if (projectionIsPerspective) {
projectionMatrix = glm::perspective(45.0f * toRadians, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
}
else
projectionMatrix = glm::ortho(-10.f, 10.f, -10.f * ((GLfloat)height / width), 10.f * ((GLfloat)height / width), 0.1f, 100.0f);
// Get matrix's uniform location and set matrix
// Select uniform shader and variable
GLuint modelLoc = glGetUniformLocation(shaderProgram, "model");
GLuint viewLoc = glGetUniformLocation(shaderProgram, "view");
GLuint projectionLoc = glGetUniformLocation(shaderProgram, "projection");
// Get light and object color, and light position location
GLint objectColorLoc = glGetUniformLocation(shaderProgram, "objectColor");
GLint lightColorLoc = glGetUniformLocation(shaderProgram, "lightColor");
GLint lightPosLoc = glGetUniformLocation(shaderProgram, "lightPos");
// Assign Light and Object Colors
glUniform3f(objectColorLoc, 0.46f, 0.36f, 0.25f);
glUniform3f(lightColorLoc, 1.0f, 1.0f, 1.0f);
// Set light position
glUniform3f(lightColorLoc, lightPosition.x, lightPosition.y, lightPosition.z);
// Pass transform to Shader
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glBindTexture(GL_TEXTURE_2D, crateTexture);
glBindVertexArray(cylinderVAO);
glDrawElements(GL_TRIANGLES, 54, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, gridTexture);
glBindVertexArray(planeVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr); // User-defined VAO must be called before draw
for (GLuint i = 0; i < 4; i++) {
glm::mat4 modelMatrix(1.0f);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix));
// Draw primitive(s)
draw();
}
// Unbind Shader exe and VOA after drawing per frame
glBindVertexArray(0); // In case different VAO will be used after
glUseProgram(0); // In case different shader will be used after
glUseProgram(lampShaderProgram);
// Get matrix's uniform location and set matrix
// Select uniform shader and variable
GLuint lampModelLoc = glGetUniformLocation(lampShaderProgram, "model");
GLuint lampViewLoc = glGetUniformLocation(lampShaderProgram, "view");
GLuint lampProjectionLoc = glGetUniformLocation(lampShaderProgram, "projection");
glUniformMatrix4fv(lampViewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(lampProjectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glBindVertexArray(lampVAO); // Calls lamp VAO
// Transform planes to form cube
for (GLuint i = 0; i < 6; i++) {
glm::mat4 modelMatrix;
modelMatrix = glm::translate(modelMatrix, planePositions[i] / glm::vec3(8.,8.,8.) + lightPosition);
modelMatrix = glm::rotate(modelMatrix, planeRotations[i] * toRadians, glm::vec3(0.0f, 1.0f, 0.0f));
modelMatrix = glm::scale(modelMatrix, glm::vec3(.125f, .125f, .125f));
if (i >= 4)
modelMatrix = glm::rotate(modelMatrix, planeRotations[i] * toRadians, glm::vec3(1.0f, 0.0f, 0.0f));
glUniformMatrix4fv(lampModelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix));
// Draw primitive(s)
draw();
}
glBindVertexArray(0); // Deactivates vertex array object
glUseProgram(0); // In case different shader will be used after
// Swap front and back buffers
glfwSwapBuffers(window);
// Poll for and process events
glfwPollEvents();
}
glfwTerminate();
return 0;
}
// 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);
float cameraSpeed = cameraSpeedPerSecond * deltaTime;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
cameraPosition += cameraSpeed * cameraDirection;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
cameraPosition -= cameraSpeed * cameraDirection;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
cameraPosition -= glm::normalize(glm::cross(cameraDirection, cameraUp)) * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
cameraPosition += glm::normalize(glm::cross(cameraDirection, cameraUp)) * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
cameraPosition -= cameraSpeed * cameraUp;
if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
cameraPosition += cameraSpeed * cameraUp;
}
// Define Input Callback functions
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
if (action == GLFW_PRESS)
{
keys[key] = true;
if (key == GLFW_KEY_P) {
projectionIsPerspective = !projectionIsPerspective;
}
}
else if (action == GLFW_RELEASE)
keys[key] = false;
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
cameraSpeedPerSecond += yoffset;
if (cameraSpeedPerSecond < 0) {
cameraSpeedPerSecond = 0;
}
}
double oldXPos = 0;
double oldYPos = 0;
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) {
int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
if (state == GLFW_PRESS)
{
float horizontalRotation = (xpos - oldXPos) * 0.01f;
float verticalRotation = (ypos - oldYPos) * -0.01f;
glm::mat4 rotationMat(1);
rotationMat = glm::rotate(rotationMat, horizontalRotation, cameraUp);
rotationMat = glm::rotate(rotationMat, verticalRotation, cameraRight);
cameraDirection = glm::vec3(rotationMat * glm::vec4(cameraDirection, 1.0));
cameraUp = glm::vec3(rotationMat * glm::vec4(cameraUp, 1.0));
cameraRight = glm::vec3(rotationMat * glm::vec4(cameraRight, 1.0));
}
oldXPos = xpos;
oldYPos = ypos;
}
void initCamera() {
cameraPosition = glm::vec3(6.f, 6.f, 6.f);
target = glm::vec3(1.f, 0.f, 0.f);
cameraDirection = glm::normalize(target - cameraPosition);
worldUp = glm::vec3(-1.f, -1.f, 0.f);
cameraRight = glm::normalize(glm::cross(worldUp, cameraDirection));
cameraUp = glm::normalize(glm::cross(cameraDirection, cameraRight));
cameraSpeedPerSecond = 2.5;
}
I am trying to simulate a cube bouncing between walls. For this purpose, I have constructed 2 vertex array objects, one of them representing the cube and the other representing walls. Firstly, I created walls. I am drawing walls with glDrawElements call since I have used index (element) buffers to create it. I have also created a cube model, but I am not using index buffer for it, so I will use glDrawArrays call to draw it as far as I know. My walls are showing up nicely, but I cannot figure out how to draw the cube (at this step, I am not even trying to animate the cube, I just want to draw it) This is what my code looks like:
#include "Cube.h"
#include <cstring>
GLuint vao[2];
void init()
{
cube();
GLuint program = InitShader( "vshader.glsl", "fshader.glsl" );
glUseProgram( program );
GLuint vPosition = glGetAttribLocation(program, "vPosition");
glGenVertexArrays(2, vao);
glBindVertexArray(vao[0]);
GLuint cube_buffer;
glGenBuffers(1, &cube_buffer);
glBindBuffer(GL_ARRAY_BUFFER, cube_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubePoints), cubePoints, GL_STATIC_DRAW);
glEnableVertexAttribArray(vPosition);
glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, (void*)0);
const float mid_value = 0.0f;
const float far_value = 0.35f;
const float near_value = 1.0f;
const float positions[60] = {
/// positions /// colors
mid_value, -near_value, 1.0, 0.0, 0.0, /// 0
near_value, -near_value, 1.0, 0.0, 0.0, /// 1
near_value, mid_value, 0.0, 1.0, 0.0, /// 2
near_value, near_value, 0.0, 1.0, 0.0, /// 3
mid_value, near_value, 1.0, 1.0, 0.0, /// 4
-near_value, near_value, 1.0, 1.0, 0.0, /// 5
-near_value, mid_value, 0.0, 0.0, 1.0, /// 6
-near_value, -near_value, 0.0, 0.0, 1.0, /// 7
far_value, -far_value, 1.0, 0.0, 0.0, /// 8
far_value, far_value, 0.0, 1.0, 0.0, /// 9
-far_value, far_value, 1.0, 1.0, 0.0, /// 10
-far_value, -far_value, 0.0, 0.0, 1.0 /// 11
};
unsigned int indices[36] = {
7,11,0,
0,8,1,
1,8,2,
2,9,3,
3,9,4,
4,10,5,
5,10,6,
6,11,7,
11,0,8,
8,2,9,
9,4,10,
10,6,11,
};
glBindVertexArray(vao[1]);
GLuint room_buffer;
glGenBuffers(1, &room_buffer);
glBindBuffer(GL_ARRAY_BUFFER, room_buffer);
glBufferData(GL_ARRAY_BUFFER, 60 * sizeof(float), positions, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (void*)0); /// positions
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (void*)(2* sizeof(float))); /// colors
GLuint index_buffer;
glGenBuffers(1, &index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 36 * sizeof(unsigned int), indices, GL_STATIC_DRAW);
glClearColor(1.0, 1.0, 1.0, 1.0);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr);
// glDrawArrays(...); --> how to use this, or should I really use this here?
glutSwapBuffers();
}
void idle() {
glutPostRedisplay();
}
void reshape(int width, int height) {
glViewport(0, 0, width, height);
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize( 600, 600 );
glutCreateWindow( "Bouncing Cube" );
glewExperimental = GL_TRUE;
glewInit();
init();
glutDisplayFunc(display);
glutIdleFunc(idle);
glutReshapeFunc(reshape);
glutMainLoop();
}
In this code, cubePoints is filled by cube() method in another translation unit. I am not exactly sure how to draw cube on the screen, and how to use glDrawArrays here? Should I bind or unbind anything to draw it? I feel like I am not using vertex array objects properly. Below is what my walls look like:
I simply want cube to appear on the far side, where the white rectangle is located at. Is it possible to call glDrawArrays with glDrawElements?
You must bind the Vertex Array Object before the "draw" call. The drawing instruction uses the data stored in the currently bound Vertex Array Object:
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vao[0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(vao[1]);
glDrawArrays(...);
glutSwapBuffers();
}
I'm working on a old code that used fixed function pipeline, the scene is a bit complex but works fine. For the sake of simplicity, I replaced it with one blue triangle :
void RenduOpenGL::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glViewport(0, 0, this->width(), this->height());
glBegin(GL_TRIANGLES);
glColor3d(0,0,1);
glVertex3d(0.7, 0.7, 0.0);
glVertex3d(-0.5, 0.7, 0.0);
glVertex3d(0.1, -0.7, 0.0);
glEnd();
}
Now I want to add shaders for new elements in the scene but keep the old elements of the scene like this blue triangle.
I've read here that I can mix the two to produce a scene containing the first then the second.
Therefore I want to add this code after the blue triangle :
float vertices[] = {
0.6, 0.6, 0.0,
-0.6, 0.6, 0.0,
0.0, -0.6, 0.0,
};
vbo.create(); // glGenBuffers(...);
vbo.bind(); // glBindBuffer(GL_ARRAY_BUFFER, vbo);
vbo.allocate(vertices, sizeof(vertices)); // glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), vertices, GL_STATIC_DRAW);
vbo.release(); // glBindBuffer(GL_ARRAY_BUFFER, 0);
prog.addShaderFromSourceFile(QOpenGLShader::Vertex, "shaders/base.vert");
prog.addShaderFromSourceFile(QOpenGLShader::Fragment, "shaders/base.frag");
vao.create(); // glGenVertexArrays(...)
vao.bind(); // glBindVertexArray(vao);
prog.enableAttributeArray("position"); // glEnableVertexAttribArray(VAO_position);
prog.setAttributeBuffer("position", GL_FLOAT, 0, 3); // (offset, size, stride=0); // glVertexAttribPointer(VAO_position, 4, GL_FLOAT, False, 0, reinterpret_cast<const void *>(offset)(0)); (False,
vao.release(); // glBindVertexArray(0);
// draw the triangle
prog.bind(); // glUseProgram(shader_program);
vao.bind(); // glBindVertexArray(vertex_array_object);
glDrawArrays(GL_TRIANGLES, 0, 3);
vao.release(); // glBindVertexArray(0);
prog.release(); // glUseProgram(0);
I use Qt to call the openGL functions, the corresponding opengl functions are in comments.
My shaders are very basic :
// base.vert
#version 330
// vertex shader
in vec3 position;
void main() {
gl_Position = vec4(position.xyz, 1);
}
// base.frag
#version 330
// fragment shader
out vec4 pixel;
void main() {
pixel = vec4(1, 0.5, 0, 1);
}
That is supposed to draw an orange triangle, but when I put the code after the blue triangle code, I don't see the orange triangle created from shaders.
Short (with code) answer:
The VBO and the prog.enableAttributeArray and prog.setAttributeBuffer should be in the VAO.
Something along the lines:
float vertices[] = {
0.6, 0.6, 0.0,
-0.6, 0.6, 0.0,
0.0, -0.6, 0.0,
};
prog.bind(); // glUseProgram(shader_program);
vao.create(); // glGenVertexArrays(...)
vao.bind(); // glBindVertexArray(vao);
vbo.create(); // glGenBuffers(...);
vbo.bind(); // glBindBuffer(GL_ARRAY_BUFFER, vbo);
vbo.allocate(vertices, sizeof(vertices)); // glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), vertices, GL_STATIC_DRAW);
//vbo.release(); // glBindBuffer(GL_ARRAY_BUFFER, 0);
prog.addShaderFromSourceFile(QOpenGLShader::Vertex, "shaders/base.vert");
prog.addShaderFromSourceFile(QOpenGLShader::Fragment, "shaders/base.frag");
prog.enableAttributeArray("position"); // glEnableVertexAttribArray(VAO_position);
prog.setAttributeBuffer("position", GL_FLOAT, 0, 3); // (offset, size, stride=0); // glVertexAttribPointer(VAO_position, 4, GL_FLOAT, False, 0, reinterpret_cast<const void *>(offset)(0)); (False,
vao.release(); // glBindVertexArray(0);
// draw the triangle
prog.bind(); // glUseProgram(shader_program);
vao.bind(); // glBindVertexArray(vertex_array_object);
glDrawArrays(GL_TRIANGLES, 0, 3);
vao.release(); // glBindVertexArray(0);
prog.release(); // glUseProgram(0);
Not so long but textual answer: OpenGL is a state machine, you need to link together: the VBO and how to read its data, inside the VAO. However, IMHO, Qt people have sadly chosen their abstractions poorly: enableAttributeArray and setAttributeBuffer would be clearer as members of the VAO class instead of the prog class.
I using OpenGL 4.1 and GLSL 410. I am attempting to texture a square that I made using the following coordinates:
float points[] = {
-0.5, 0.5,
-0.5, -0.5,
0.5, -0.5,
-0.5, 0.5,
0.5, -0.5,
0.5, 0.5
};
I draw the square like this:
glDrawArrays (GL_TRIANGLES, 0, 6);
From all of the tutorials I have read, the author uses an element buffer to draw the square or has just four vertices. This means that all the tutorials I have read have texture coordinates that line up with each vertex. For me, I'm using 6 vertices, so I'm not sure how to line up the texture coordinates.
Would coordinates like this work for my case:
float texcoords[] = {
0.0, 1.0,
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0
};
I've done lots of reading, but haven't come across anyone else who is using six vertices like I am.
Would my texture coordinates work and if not, what is the best way to come up with texture coordinates.
Yes, that will work. You've divided the sqaure into 2 triangles and mapped the tex coords to the vertices of the triangles. What are your results?
See this question. The code uses one array for the vertices (although there each vertex has xyz values) and another array for the texture coords.
You need to be careful when defining the vertex attributes.
E.g. to setup the vertex data uisng 2 buffers
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glGenBuffers(1, &texbuffer);
glBindBuffer(GL_ARRAY_BUFFER, texbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords), texcoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0, // attribute 0
2, // 2 floats per vertex
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride -> tightly packed so make it zero
0); // array buffer offset
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, texbuffer);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glDrawArrays(GL_TRIANGLES, 0, 6);
To load the texture (Update and setup the sampler, see comments)
glGenTextures(1, &tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
GLuint TextureID = glGetUniformLocation(programID, "texture");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
Vertex shader
#version 410 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texcoord;
out vec2 texture_coordinates;
uniform mat4 MVP;
void main() {
gl_Position = position;
texture_coordinates = texcoord;
}
Fragment shader
in vec2 texture_coordinates;
uniform sampler2D texture;
out vec4 colour;
void main() {
colour = texture2D(basic_texture, texture_coordinates);
}