I am trying to create a simple program with openGL. The goal is to create a triangle with colours for every vertex. The problem is that I can not figure out how to apply the colours to the triangle's vertices.
My vertex shader:
#version 330
layout(location = 0) in vec4 vertex_position;
layout(location = 1) in vec4 vertex_color;
smooth out vec4 theColor;
void main()
{
gl_Position = vec4(vertex_position.x, vertex_position.y, vertex_position.z, 1.0);
theColor = vertex_color;
}
My fragment shader:
#version 330
smooth in vec4 theColor;
out vec4 outColor;
void main()
{
outColor = theColor;
}
main code:
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.5f, 0.6f, 0.1f,
0.2f, 0.6, 0.3f,
0.1f, 0.23f, 0.78f
};
GLuint my_vao, my_vbo;
glGenVertexArrays(1, &my_vao);
glBindVertexArray(my_vao);
glGenBuffers(1, &my_vbo);
glBindBuffer(GL_ARRAY_BUFFER, my_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
// glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);
// glVertexAttribPointer(3,4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (void*)0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(vao);
glViewport(0, 0, viewport_width, viewport_height);
glDrawArrays(GL_TRIANGLES, 0, 3);
swapBuffers();
The array vertices consists of the vertex points (first 3 vectors) and the color values (second 3 vectors). You can see my result in the following picture:
I have been trying to apply the colours with the following code:
glEnableVertexAttribArray(1);
glVertexAttribPointer(3,4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (void*)0);
Unfortunately it does not work and I have no idea how to fix that. Can anyone help me out here?
For compiling and loading my shaders I use:
std::string loadVertexShader(const char* vertexPath)
{
std::string vertexCode;
std::ifstream vShaderFile;
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
vShaderFile.open(vertexPath);
std::stringstream vShaderStream;
vShaderStream << vShaderFile.rdbuf();
vShaderFile.close();
vertexCode = vShaderStream.str();
}
catch (std::ifstream::failure e)
{
std::cout << "ERROR::VERTEXSHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
return vertexCode;
}
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
std::string vertexVal = loadVertexShader("shader/vertexshader.shader");
const char* vShaderCode = vertexVal.c_str();
std::string fragmentVal = loadFragmentShader("shader/fragmentshader.shader");
const char* fShaderCode = fragmentVal.c_str();
glShaderSource(vertexShader, 1, &vShaderCode, NULL);
glCompileShader(vertexShader);
glShaderSource(fragmentShader, 1, &fShaderCode, NULL);
glCompileShader(fragmentShader);
GLint vertexStatus;
char vertexInfoLog[512];
char fragmentInfoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &vertexStatus);
GLint fragmentStatus;
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentStatus);
if (!vertexStatus)
{
glGetShaderInfoLog(vertexShader, 512, NULL, fragmentInfoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << fragmentInfoLog << std::endl;
}
if (!fragmentStatus)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, vertexInfoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << vertexInfoLog << std::endl;
}
First of all, as was revealed in the discussion in comments, you don't link your program. A typical shader program setup looks like this:
GLuint program = glCreateProgram();
glAttachShader(program, shader1);
glAttachShader(program, shader2);
...
glAttachShader(program, shaderN);
glLinkProgram(program); // <<<<<<<<< a-ha!
After that, a good idea is to check if program linkage was OK. A good example of the full shaders & program setup can be found on OpenGL wiki.
After successful program linkage, you can even detach the shaders from the program (glDetachShader) and delete them (glDeleteShader) - the program is already linked, shaders are of no use now (unless you intend to attach them to another program, of course).
Secondly, your arguments to glVertexAttribPointer are slightly messed up (which is totally OK - it takes time and effort to get used to them).
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized,
GLsizei stride, const GLvoid * pointer);
index is the attribute index - same as location as specified in shader, so for your color attribute it should be 1.
size is the attribute's dimension, i.e. number of components; supposing that you are using 3-float RGB, size should be 3
type is the actual type of the components; in you case these are floating-points too, so GL_FLOAT
stride is the distance between attributes of adjacent vertices, which is 3 floats in your case, i.e. 12 bytes; since there's nothing in between adjacent attributes in your vertices array, we can actually leave this zero (both for coordinates & colors)
pointer is the pointer to actual attributes data (or, in your case, offset in VBO); you are passing the same pointer to both glVertexAttribPointer calls, while your color values are 9 floats after the beginning of coordinate values
So, it should be
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (float const *)(nullptr) + 9);
Related
I want to draw different figures using triangle fans but I am not sure how to make the program draw the second figure. Do I need a second vertexShaderSource and a second fragmentShaderSource each time I want to change the color or draw a new figure?
Here is the code:
#include <GL/glew.h>
#include <GL/glut.h>
#include <stdio.h>
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n""void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.0f, 0.0f, 0.0f);\n" // To set the color.
"}\n\0";
// Set of vertices for the different figures that make up the drawing.
float vertices[] = {
-0.8f, 0.6f, 0.0f, // Center.
-0.8f, 0.4f, 0.0f,
-0.83f, 0.44f, 0.0f,
-0.87f, 0.51f, 0.0f,
-0.9f, 0.57f, 0.0f,
-0.93f, 0.63f, 0.0f,
-0.95f, 0.69f, 0.0f,
-0.97f, 0.75f, 0.0f,
-0.98f, 0.8f, 0.0f,
-0.91f, 0.8f, 0.0f,
-0.85f, 0.79f, 0.0f,
-0.8f, 0.77f, 0.0f,
};
unsigned int VBO, VAO;
GLuint vertexShader;
GLuint fragmentShader;
GLuint shaderProgram;
void display(void){
// Background color.
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLE_FAN, 0, 12);
glBindVertexArray(0);
glFlush();
}
// Main.
int main(int argc, char** argv){
glutInit(&argc, argv);
// Color mode.
glutInitDisplayMode(GLUT_RGBA);
// Window size.
glutInitWindowSize(500, 500);
// Title.
glutCreateWindow("Tarea 3: Figura con curvas");
GLenum err = glewInit();
if(err!=GLEW_OK) {
printf("glewInit failed: %s",glewGetErrorString(err));
exit(1);
}
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glutDisplayFunc(display);
glutMainLoop();
}
No is not necessary (or recommended) to use different shaders for the meshes. If you want to draw multiple objects, then you can put the vertex attributes of the meshes to separate Vertex Buffer Objects:
GLuint VBOs[2];
glGenBuffers(2, VBOs);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices_1, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices_2, GL_STATIC_DRAW);
Specify a Vertex Array Object for each mesh:
GLuint VAOs[2];
glGenVertexArrays(2, VAOs);
glBindVertexArray(VAOs[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(VAOs[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
Bind the VAO, before the draw call:
glBindVertexArray(VAOs[0]);
glDrawArrays(GL_TRIANGLE_FAN, 0, 12);
glBindVertexArray(VAOs[1]);
glDrawArrays(...);
Of course it is also possible to put all the vertex attributes of the different meshes consecutively in the data store of one VBO. If the vertex specification is identically, then it is event possible to use one single VAO.
Different locations of different meshes can be achieved by vertex transformation in the vertex shader. Use a Uniform of type mat4, to transform the vertices of a mesh:
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 u_model;
void main()
{
gl_Position = u_model * vec4(aPos.xyz, 1.0);
}
See further LearnOpenGL - Transformations.
If the 2 figures are identical, but have just a different location, then you can draw the same mesh twice, but you have to change the model transformation u_model.
You are looking for Uniform buffer objects.
If you have only a single value for a whole draw call, then your shader should be parametrized. The obvious thing you want to parametrize first is the color in the fragment shader, followed by adding a projection matrix to the vertex shader.
From that point onwards it's just alternating between setting new values to uniforms and draw-calls as long as it is the same 3D model.
For different models refer to #rabbid76's answer.
I want to create 2 triangles with different colors that they change to wireframe mode when I press "Tab" my problem is that I have two VBO and two shaders programs but it only compile one triangle
#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <iostream>
bool flag;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
const char* vertex_shader =
"#version 110 \n"
"attribute vec3 in_position; \n"
"void main() \n"
"{ \n"
" gl_Position = vec4(in_position.x, in_position.y, in_position.z, 1.0);\n"
"} \n";
const char* fragment_shader =
"#version 110 \n"
"void main (void) \n"
"{ \n"
" gl_FragColor = vec4(0.7,0.3,0.3, 1.0); \n"
"} \n";
const char* vertex_shader1 =
"#version 110 \n"
"attribute vec3 in_position; \n"
"void main() \n"
"{ \n"
" gl_Position1 = vec4(in_position.x, in_position.y, in_position.z, 1.0);\n"
"} \n";
const char* fragment_shader1 =
"#version 110 \n"
"void main (void) \n"
"{ \n"
" gl_FragColor1 = vec4(0.4,0.7,0.3, 1.0); \n"
"} \n";
int main()
{
//Initialize GLFW
if (!glfwInit()) //if GLFW is not initialized correctly, exit
{
std::cout << "Failed to initialize GLFW" << std::endl;
return -1;
}
//Create the window
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL) //if the window was not created correctly, exit
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
//Specify OpenGL version
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
//Make the context that was created the current one
glfwMakeContextCurrent(window);
//Initialize GLEW
if (glewInit() != GLEW_OK) //if GLEW was not initialized correctly, exit
{
std::cout << "Failed to initialize GLEW" << std::endl;
glfwTerminate();
return -1;
}
//Set the viewport size changing function
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//Rectangle vertices, to uncomment select the area and press Ctr+K,Ctr+U
float vertices[] =
{
// first triangle
0.55f, 0.5f, 0.0f, // top right
0.55f, -0.5f, 0.0f, // bottom right
-0.45f, 0.5f, 0.0f, // top left
};
float vertices1[] =
{
// second triangle
0.45f, -0.5f, 0.0f, // bottom right
-0.55f, -0.5f, 0.0f, // bottom left
-0.55f, 0.5f, 0.0f // top left
};
//Create the triangle VBO
GLuint triangle_vbo;
glGenBuffers(1, &triangle_vbo); //generate a unique buffer ID
glBindBuffer(GL_ARRAY_BUFFER, triangle_vbo); //bind the VBO to the context
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//copy user-defined data into the currently bound buffer
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind the VBO
//Create a vertex shader object
GLuint vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER); //ID of the shader object
glShaderSource(vertexShader, 1, &vertex_shader, NULL); //attach the shader source code to the shader object
glCompileShader(vertexShader);//compile the shader
//Create a fragment shader object
GLuint fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragment_shader, NULL);
glCompileShader(fragmentShader);
//Create a shader program object
GLuint shaderProgram;
shaderProgram = glCreateProgram(); //create the program ID
glAttachShader(shaderProgram, vertexShader); //attach the shaders to the program
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram); // link the program
//Delete the vertex andd fragment shader objects
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
//Create the triangle VBO
GLuint triangle_vbo1;
glGenBuffers(1, &triangle_vbo1); //generate a unique buffer ID
glBindBuffer(GL_ARRAY_BUFFER, triangle_vbo1); //bind the VBO to the context
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW);//copy user-defined data into the currently bound buffer
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind the VBO
//Create a vertex shader object
GLuint vertexShader1;
vertexShader1 = glCreateShader(GL_VERTEX_SHADER); //ID of the shader object
glShaderSource(vertexShader1, 1, &vertex_shader1, NULL); //attach the shader source code to the shader object
glCompileShader(vertexShader1);//compile the shader
//Create a fragment shader object
GLuint fragmentShader1;
fragmentShader1 = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader1, 1, &fragment_shader1, NULL);
glCompileShader(fragmentShader1);
//Create a shader program object
GLuint shaderProgram1;
shaderProgram1 = glCreateProgram(); //create the program ID
glAttachShader(shaderProgram1, vertexShader1); //attach the shaders to the program
glAttachShader(shaderProgram1, fragmentShader1);
glLinkProgram(shaderProgram1); // link the program
//Delete the vertex andd fragment shader objects
glDeleteShader(vertexShader1);
glDeleteShader(fragmentShader1);
//Rendering loop
while(!glfwWindowShouldClose(window))
{
//Process input
processInput(window);
//Clear the buffers
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); //dark green
//glClearColor(0.5f, 0.0f, 0.0f, 1.0f); //maroon
glClear(GL_COLOR_BUFFER_BIT);
if(flag==true)
{
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
}
else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//Render objects...
glUseProgram(shaderProgram); //use a shader program
glBindBuffer(GL_ARRAY_BUFFER, triangle_vbo); //bind the VBO
//tell OpenGL how to read and assign the VBO to the attribute
GLint in_pos = glGetAttribLocation(shaderProgram, "in_position");
glVertexAttribPointer(in_pos, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GL_FLOAT), (void*)0);
glEnableVertexAttribArray(in_pos);
glUseProgram(shaderProgram);
glUseProgram(shaderProgram1);
glBindBuffer(GL_ARRAY_BUFFER, triangle_vbo1);
GLint in_pos1 = glGetAttribLocation(shaderProgram1, "in_position");
glVertexAttribPointer(in_pos1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GL_FLOAT), (void*)0);
glEnableVertexAttribArray(in_pos1);
glDrawArrays(GL_TRIANGLES, 0, 6); //draw the triangle
//Swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
glfwSwapBuffers(window);
glfwPollEvents();
}
//Terminate GLFW before exit
glfwTerminate();
return 0;
}
//Viewport size changing function
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
//Input
void processInput(GLFWwindow *window)
{
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if(glfwGetKey(window, GLFW_KEY_TAB) == GLFW_PRESS)
flag=true;
else flag=false;
}
The Tab switch changes to wireframe mode as I long keep pressing the "Tab". I want to change only with one click and when click again to change to default
The 2nd vertex shader and fragment shader won't compile, because gl_Position1 and gl_FragColor1 are not valid output variables. You have to use gl_Position and gl_FragColor. See Vertex Shader and Fragment Shader
const char* vertex_shader1 =
"#version 110 \n"
"attribute vec3 in_position; \n"
"void main() \n"
"{ \n"
" gl_Position = vec4(in_position.x, in_position.y, in_position.z, 1.0);\n"
"} \n";
const char* fragment_shader1 =
"#version 110 \n"
"void main (void) \n"
"{ \n"
" gl_FragColor = vec4(0.4,0.7,0.3, 1.0); \n"
"} \n";
I recommend to use glGetShaderiv to verify if the shader code was compiled successfully.
e.g.
GLint status;
glGetShaderiv(vertex_shader1, GL_COMPILE_STATUS, &status);
Use glGetProgramiv with the GL_LINK_STATUS parameter to check if the program was linked successfully.
You have 2 vertex buffers with each 3 vertices, so you have to call glDrawArrays(GL_TRIANGLES, 0, 3); twice and not one time glDrawArrays(GL_TRIANGLES, 0, 6);.
Bind the buffer, define and enable the array of generic vertex attribute data and then draw the triangle:
glUseProgram(shaderProgram);
glBindBuffer(GL_ARRAY_BUFFER, triangle_vbo); //bind the VBO
GLint in_pos = glGetAttribLocation(shaderProgram, "in_position");
glVertexAttribPointer(in_pos, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GL_FLOAT), (void*)0);
glEnableVertexAttribArray(in_pos);
glDrawArrays(GL_TRIANGLES, 0, 3); //draw the 1st triangle
glUseProgram(shaderProgram1);
glBindBuffer(GL_ARRAY_BUFFER, triangle_vbo1);
GLint in_pos1 = glGetAttribLocation(shaderProgram1, "in_position");
glVertexAttribPointer(in_pos1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GL_FLOAT), (void*)0);
glEnableVertexAttribArray(in_pos1);
glDrawArrays(GL_TRIANGLES, 0, 3); //draw the 2nd triangle
See the preview:
I'm definitely doing something extremely rookie here, but I simply cannot draw a square with index buffers. I'm following the intructions in this video. But I just don't get the expected output.
If I comment out one of the vertices in the array, it draws second triangle. Also, the drawElement() call seems to be working as intended as there is definitely linking between ELEMENT_ARRAY and ARRAY_BUFFER in my code, but I cannot get a square for the life of me. I checked and rechecked my code a lot. Does anyone know what I might be missing? Here's my code:
#include <GL\glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#define print(x) std::cout << x << std::endl
static unsigned int CompileShader(unsigned int type, const std::string& source) {
// returns an empty shader object of type specified
unsigned int shader = glCreateShader(type);
// because one of the arguments requires a double pointer
const char* src = source.c_str();
// Replaces(in this case writes) the source code of a shader object
glShaderSource(shader, 1, &src, nullptr);
// Compiles the shader
glCompileShader(shader);
// Finds compile status of shader
int result;
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
char* message = new char[length];
glGetShaderInfoLog(shader, length, &length, message);
print("Failed to compile shader");
std::cout << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << std::endl;
glDeleteShader(shader);
return 0;
}
return shader;
}
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader) {
// All shaders must be attached to a program object before executed. This returns an empyty program object
unsigned int program = glCreateProgram();
// get shaders
unsigned vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
// Attaches the shader to the program
glAttachShader(program, vs);
glAttachShader(program, fs);
// creates shader executables
glLinkProgram(program);
// validates success/failure/performance of program. stores in program's log
glValidateProgram(program);
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
print("Error");
}
float positions[8] = {
-0.5f, -0.5f, // 0
0.5f, -0.5f, // 1
-0.5f, 0.5f, // 2
0.5f, 0.5f // 3
};
unsigned int indices[6] = {
0, 1, 2,
1, 2, 3
};
// Assigns a memory to GL_ARRAY_BUFFER
unsigned int triangleBuffer;
glGenBuffers(1, &triangleBuffer);
glBindBuffer(GL_ARRAY_BUFFER, triangleBuffer);
// Fills in data to GL_ARRAY_BUFFER memory
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), positions, GL_STATIC_DRAW);
// Defines where positions are located in GL_ARRAY_BUFFER and how to draw them configurations
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
// Enables this vertex to be drawn using glDrawArrays().
glEnableVertexAttribArray(0);
// Shader programs in GLSL
std::string vertexShader =
// opengl version 3.3
"#version 330 core\n"
"\n"
// select vertex attribute 0. vec4 because gl_Position requires vec4 argument. vertex shaders are 'in'
"layout(location = 0) in vec4 position;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = position;\n"
"}\n";
std::string fragmentShader =
// opengl version 3.3
"#version 330 core\n"
"\n"
// select vertex attribute 0. vec4 because color requires vec4 argument. fragment shader have 'out'
"layout(location = 0) out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
// colors in graphics are usually in 0-1 range. RGBA
" color = vec4(0.2, 0.3, 0.8, 1.0);\n"
"}\n";
// generate index buffers
unsigned int ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), &indices, GL_STATIC_DRAW);
// Use Shaders
unsigned int shaderProgram = CreateShader(vertexShader, fragmentShader);
glUseProgram(shaderProgram);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
In general your code is fine, but the specification of the vertex array buffer size is wrong. The 4 verex coordinates
float positions[8] = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f };
consists of 8 floats, not of 6.
This means you have the sie of the vertex array is 8*sizeof(float). Change your code like this:
glBufferData(
GL_ARRAY_BUFFER,
8 * sizeof(float), // <----- 8 instead of 6
positions,
GL_STATIC_DRAW );
Note, you can use the sizeof operator to determine the size of the array in bytes:
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
In c++ I would prefer something like this:
const std::vector<float> positions{ -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f };
glBufferData(GL_ARRAY_BUFFER, positions.size()*sizeof(positions[0]), positions.data(), GL_STATIC_DRAW);
I am fallowing this tutorial http://learnopengl.com/#!Getting-started/Hello-Triangle and problem with this tutorials is that there is no full code example, and it's little hard to fallow. My code run successful, but my triangle is blank / white. And I think some functions is called twice, and program still can run successful if I delete some of that commands.
// SHADERS
GLuint VBO;
GLuint VAO = 0;
GLuint program;
GLuint vertexShader;
GLuint fragmentShader;
const char* vertexShaderSource =
"#version 330"
"layout (location = 0) in vec3 position;"
"void main(){"
"gl_Position = vec4(position.x, position.y, position.z, 1.0);"
"}";
const char* fragmentShaderSource =
"#version 330"
"out vec4 color;"
"void main(){"
"color = vec4(1.0, 0.5, 1.0, 1.0);"
"}";
void compileShaders() {
vertexShader = glCreateShader(GL_VERTEX_SHADER); // pravi vertex shader
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); // Odredjuje izvor vertex shadera
glCompileShader(vertexShader); // kompajlira shader
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertexShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
}
void linkShaders() {
program = glCreateProgram(); // pravi program ID
// Linkuje shaderse i program
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
glUseProgram(program); // koristi program
// Brise shaderse jer vise nisu potrebni i tako oslobadja memoriju
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0); // MISLIM DA JE OVO VISAK
}
void initVBO() {
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
}
void initVAO() {
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
}
void Init() {
glClearColor(0.20, 0.63, 0.67, 1.0);
glViewport(0, 0, WIDTH, HEIGHT);
compileShaders();
linkShaders();
}
void Render() {
glClear(GL_COLOR_BUFFER_BIT);
initVAO();
initVBO();
glUseProgram(program);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0); // oslobadja momoriju
glutSwapBuffers();
}
Your shaders shouldn't compile. As a result, you don't have a valid program. Depending on the profile of the GL context - and the actual GL implementation - you will get different results. With nvidia drivers, you will typically see a white triangle in that scenario.
The reason why your shaders are invalid is because you forgot to add a newline \n after the #version 330 directive.
You are using C/C++'s syntax for concatenating strings by combining "string1" "string2". The fact that you have a newline outside of the quotes is totally irrelevant, the string you are specifying is
#version 330layout (location = 0) in vec3 position;[...]
all in one line, and that is not a valid preprocessor statement...
You always should check the compile status of your shaders, and the link status of your program. And you should always query the compiler and linker info logs. Have a look at the OpenGL wiki artice about shader compilation for details of how to do that.
I am trying to use OpenGL shaders to draw a simple triangle. I have tried to split up the code into separate methods inside one overarching rendering class, however, I cannot seem to get my triangle to render on the screen. This is my compileShaders() method which compiles and loads my shader source code:
static const GLchar* vertexShaderSource[] = {
"#version 430 core \n"
"in vec4 vPosition; \n"
"in vec4 vColor; \n"
"out vec4 color; \n"
" \n"
"void main() { \n"
" color = vColor; \n"
" gl_Position = vPosition; \n"
"} \n"
};
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, vertexShaderSource, NULL);
glCompileShader(vertexShader);
program = glCreateProgram();
glAttachShader(program, vertexShader);
glLinkProgram(program);
glDeleteShader(vertexShader);
return program;
In a different method I am calling glewInit(), compileShaders() and am then setting up the vertex array and vertex buffer objects. In this method triangleVertices[] and triangleColors[] are two arrays containing the position (x,y,z) and colour values (r,g,b,a) for each vertex the triangle.
glewInit();
renderingProgram = compileShaders();
glEnable(GL_ARRAY_BUFFER);
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, numberOfVertices*7*sizeof(GLfloat), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, numberOfVertices*3*sizeof(GLfloat), triangleVertices);
glBufferSubData(GL_ARRAY_BUFFER, numberOfVertices*3*sizeof(GLfloat), numberOfVertices*4*sizeof(GLfloat), triangleColors);
GLuint vpos = glGetAttribLocation(renderingProgram, "vPosition");
glVertexAttribPointer(vpos, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLuint cpos = glGetAttribLocation(renderingProgram, "vColor");
glVertexAttribPointer(cpos, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(numberOfVertices*3*sizeof(GLfloat)));
glUseProgram(renderingProgram);
glEnableVertexAttribArray(vpos);
glEnableVertexAttribArray(cpos);
Finally my render() method in which I try and draw the Triangle loaded into the Array Buffer:
const GLfloat color[] = {0.0f, 0.0f, 1.0f, 1.0f};
glClearBufferfv(GL_COLOR, 0, color);
glUseProgram(renderingProgram);
glDrawArrays(GL_TRIANGLES, 0, 3);
SwapBuffers(hDC_);
I am rendering to a Win32 window which is setup in a different class. After rendering I can see a blue screen, so it appears as if the glClearBufferfv call is working correctly. However my triangle is nowhere to be seen. If I change the rendering mode to glDrawArrays(GL_POINTS, 0, 1) I see one white pixel in the middle of the screen.
What am I doing wrong?
As others have pointed out, you need a fragment shader too, e.g.,
#version 430
in vec4 color;
out vec4 frag_rgba; // default index (0) (glFragBindDataLocation)
void main (void) {
frag_rgba = color;
}
Attach this shader to the program along with the vertex shader prior to linking. You can detach the shaders from the program after linking. You might also consider using explicit attribute indices in the vertex shader.