Hello,
I’m learning OpenGL and I have a (potentially stupid) question. My main objective is to draw a cube and a triangle in different locations by using two separated arrays, two MVP (Model, View and Projection) matrices and one vertex shader. If I draw my cube alone it works, and the same with my triangle, but when I try to draw both of them at the same time I don’t get the desired result :dejection:
This is my C++ code:
#define GLEW_STATIC
#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <glm\glm.hpp>
#include <glm\gtx ransform.hpp>
#include <glm\gtc\matrix_transform.hpp>
#include <vector>
#include <iostream>
#include "ShaderFile.hpp" //My own shader wrapper
//Using the OpenGL 4.1 version
#define OPENGL_MAJOR 4
#define OPENGL_MINOR 1
//#define FULLSCREEN
#define WINDOW_TITLE "Color Cube and The Lone Triangle"
#ifdef FULLSCREEN
#define SCREEN_WIDTH 1366
#define SCREEN_HEIGHT 768
#else
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#endif
///My cube
static const GLfloat vertex_buffer_array[] = {
-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
};
//Colors for my cube
static const GLfloat color_buffer_data[] = {
0.583f, 0.771f, 0.014f,
0.609f, 0.115f, 0.436f,
0.327f, 0.483f, 0.844f,
0.822f, 0.569f, 0.201f,
0.435f, 0.602f, 0.223f,
0.310f, 0.747f, 0.185f,
0.597f, 0.770f, 0.761f,
0.559f, 0.436f, 0.730f,
0.359f, 0.583f, 0.152f,
0.483f, 0.596f, 0.789f,
0.559f, 0.861f, 0.639f,
0.195f, 0.548f, 0.859f,
0.014f, 0.184f, 0.576f,
0.771f, 0.328f, 0.970f,
0.406f, 0.615f, 0.116f,
0.676f, 0.977f, 0.133f,
0.971f, 0.572f, 0.833f,
0.140f, 0.616f, 0.489f,
0.997f, 0.513f, 0.064f,
0.945f, 0.719f, 0.592f,
0.543f, 0.021f, 0.978f,
0.279f, 0.317f, 0.505f,
0.167f, 0.620f, 0.077f,
0.347f, 0.857f, 0.137f,
0.055f, 0.953f, 0.042f,
0.714f, 0.505f, 0.345f,
0.783f, 0.290f, 0.734f,
0.722f, 0.645f, 0.174f,
0.302f, 0.455f, 0.848f,
0.225f, 0.587f, 0.040f,
0.517f, 0.713f, 0.338f,
0.053f, 0.959f, 0.120f,
0.393f, 0.621f, 0.362f,
0.673f, 0.211f, 0.457f,
0.820f, 0.883f, 0.371f,
0.982f, 0.099f, 0.879f
};
//The triangle
static const GLfloat triangle_data_array[] = {
-1.0F, -1.0F, 0.0F,
1.0F, -1.0F, 0.0F,
0.0F, 1.0F, 0.0F
};
//////////////////////////////////////////////////////////////////////////
// Functions prototypes
//////////////////////////////////////////////////////////////////////////
//It creates the main UI window
GLFWwindow* createContext(void);
//It configures OpenGL and the context
void configureGLFWWindow(void);
//Vertex Array Object: It stores all of the links between the attributes
//and your Vertex Buffer Objects with raw vertex data
GLuint inline createVAO(void);
//It draws the vertex data
void inline draw(GLuint&, GLuint&);
void inline drawTriangle(GLuint&);
//It creates the shader program
GLuint createProgram(void);
//This function compile the referenced shader ID with the shader file string.
void compileShader(GLuint&, const GLchar* const);
//It shows information about the render and the OpenGL version
void showInfo(void);
//It computes and returns the Model, View and Projection matrix
glm::mat4 createMVPMatrix(bool is_triangle = false);
glm::mat4 createModelMatrix(void);
glm::mat4 createModelMatrixForTriangle(void);
int main()
{
auto window = createContext();
if (window == nullptr) return EXIT_FAILURE;
showInfo(); //Show info about the rendered and the OpenGL version
GLuint programID = createProgram(); //Create the shader program
//Get a handle for our "MVP" uniform.
GLuint MVPmatrixID = glGetUniformLocation(programID, "MVP");
glm::mat4 MVPmatrix = createMVPMatrix();
//The MVP for the triangle
GLuint MPVtriangleID = glGetUniformLocation(programID, "MVP_triangle");
glm::mat4 MVPmatrix_triangle = createMVPMatrix(true); //true for the triangle!
//The color of the background when you clear the screen
glClearColor(0.2f, 0.1f, 0.3f, 0.0f);
//The Z-Buffer
glEnable(GL_DEPTH_TEST); //Enable depth test
glDepthFunc(GL_LESS); //Accept fragment if it closer to the camera than the former one
//Create the Vertex Array Object
auto VAO_id = createVAO();
//Create the buffers: vertices
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_buffer_array),
vertex_buffer_array, GL_STATIC_DRAW);
//Create the buffers: colors
GLuint colorBuffer;
glGenBuffers(1, &colorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(color_buffer_data),
color_buffer_data, GL_STATIC_DRAW);
//The Lone Triangle
GLuint triangleBuffer;
glGenBuffers(1, &triangleBuffer);
glBindBuffer(GL_ARRAY_BUFFER, triangleBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_data_array),
triangle_data_array, GL_STATIC_DRAW);
//The main loop!
while (!glfwWindowShouldClose(window)) {
//Tell GLFW to retrieve window events...
glfwSwapBuffers(window);
glfwPollEvents();
//Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Use the shader program!
glUseProgram(programID);
//Send our transformation to the currently bound shader
glUniformMatrix4fv(MVPmatrixID, 1, GL_FALSE, &MVPmatrix[0][0]);
draw(vertexBuffer, colorBuffer);
//Draw the triangle!
glUniformMatrix4fv(MPVtriangleID, 1, GL_FALSE, &MVPmatrix_triangle[0][0]);
drawTriangle(triangleBuffer);
//If you press escape key, break the loop and finish execution
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
// Cleanup VBO and shader
glDeleteBuffers(1, &vertexBuffer);
glDeleteBuffers(1, &colorBuffer);
glDeleteBuffers(1, &triangleBuffer);
glDeleteProgram(programID);
glDeleteVertexArrays(1, &VAO_id);
glfwTerminate();
return 0;
}
//////////////////////////////////////////////////////////////////////////
// Prototypes implementation
//////////////////////////////////////////////////////////////////////////
GLFWwindow* createContext(void)
{
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW =(" << std::endl;
return nullptr;
}
configureGLFWWindow();
GLFWwindow* window;
#ifdef FULLSCREEN
window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, WINDOW_TITLE,
glfwGetPrimaryMonitor(), nullptr);
#else
window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, WINDOW_TITLE,
nullptr, nullptr);
#endif
glfwMakeContextCurrent(window);
//Prepare GLEW
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to initialize GLEW =(" << std::endl;
return nullptr;
}
return window;
}
void configureGLFWWindow(void)
{
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, OPENGL_MAJOR);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, OPENGL_MINOR);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
}
GLuint inline createVAO(void)
{
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
return VertexArrayID;
}
void inline draw(GLuint& vertex, GLuint& colors)
{
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertex);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
//Second buffer attributes: the colors
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colors);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
//Draw: 12 * 3 indices starting at 0 -> 12 triangles -> 6 squares
glDrawArrays(GL_TRIANGLES, 0, 12 * 3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
void inline drawTriangle(GLuint& buffer)
{
glEnableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(3);
}
GLuint createProgram(void)
{
//Create and compile the shaders
GLuint vertexID = glCreateShader(GL_VERTEX_SHADER);
compileShader(vertexID, "shader.vert");
GLuint fragmentID = glCreateShader(GL_FRAGMENT_SHADER);
compileShader(fragmentID, "shader.frag");
//Link the program with the shaders
std::cout << "--> Linking the program..." << std::endl;
GLuint programID = glCreateProgram();
glAttachShader(programID, vertexID);
glAttachShader(programID, fragmentID);
glLinkProgram(programID);
//Check the program for any error
GLint result = GL_FALSE;
GLint infoLogLength;
glGetProgramiv(programID, GL_LINK_STATUS, &result);
if (result == GL_TRUE)
std::cout << " Program #" << programID << " OK!" << std::endl;
else {
glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength);
std::vector<char> programInfoMsg(infoLogLength);
glGetProgramInfoLog(programID, infoLogLength, nullptr,
&programInfoMsg[0]);
std::cout << " Program #" << programID << " info log:
"
<< &programInfoMsg[0] << std::endl;
}
glDeleteShader(vertexID);
glDeleteShader(fragmentID);
return programID;
}
void compileShader(GLuint& shaderID, const GLchar* const shaderFile)
{
Utils::ShaderFile shader(shaderFile);
//Get the vertex shader source and compile it
std::string shaderString = shader.getShaderStringSource();
const GLchar* vertSrc = const_cast<GLchar*>(shaderString.c_str());
std::cout << "--> Compiling Shader #"
<< shaderID << "... " << std::endl;
glShaderSource(shaderID, 1, &vertSrc, nullptr);
glCompileShader(shaderID);
//Check the vertex shader compilation
GLint result = GL_FALSE;
int infoLogLength;
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &result);
if (result == GL_TRUE)
std::cout << " Shader #" << shaderID << " OK!" << std::endl;
else {
glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
std::vector<GLchar> vertexShaderInfoMsg(infoLogLength);
glGetShaderInfoLog(shaderID, infoLogLength, nullptr,
&vertexShaderInfoMsg[0]);
std::cout << " Shader #" << shaderID << " info log:
"
<< &vertexShaderInfoMsg[0] << std::endl;
}
}
void showInfo(void)
{
std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl;
std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
}
glm::mat4 createMVPMatrix(bool is_triangle)
{
//Projection matrix: 45° Field of View, 4:3 ratio
glm::mat4 projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
//View matrix
glm::mat4 view = glm::lookAt(glm::vec3(4, 3, -3), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
//Model matrix
glm::mat4 model = is_triangle ? createModelMatrixForTriangle() : createModelMatrix();
//Return the Model-View-Projection matrix
return projection * view * model;
}
//The cube is in the upper right corner
glm::mat4 createModelMatrix(void)
{
glm::mat4 translation = glm::translate(glm::vec3(-3.3F, 0.0F, 0.0F));
glm::mat4 scaling = glm::mat4(1.0F);
glm::mat4 rotation = glm::mat4(1.0F);
return translation * rotation * scaling;
}
//The triangle is in the lower left corner
glm::mat4 createModelMatrixForTriangle(void)
{
glm::mat4 translation = glm::translate(glm::vec3(1.3F, 0.0F, 0.0F));
glm::mat4 scaling = glm::mat4(1.0F);
glm::mat4 rotation = glm::mat4(1.0F);
return translation * rotation * scaling;
}
And my vertex shader code where (I think) I have the problem:
#version 410 core
layout(location = 0) in vec3 cube_position;
layout(location = 1) in vec3 vertexColor;
layout(location = 3) in vec3 triangle_position;
out vec3 fragmentColor;
uniform mat4 MVP; //Model-View-Projection
uniform mat4 MVP_triangle;
void main() {
vec4 cube_pos = (MVP * vec4(cube_position, 1));
vec4 triangle_pos = (MVP_triangle * vec4(triangle_position, 1));
gl_Position = triangle_pos;// * cube_pos; ????
// The color of each vertex will be interpolated to produce the color of each fragment
fragmentColor = vertexColor;
}
I don’t know if this is the right way… Can someone give me a hand?
Thank you =)