Drawing a cube and a triangle in different positions

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 =)

You seem very confused about how a vertex shader works. It takes 1 vertex and applies the transformation to it. Therefore you should have only 1 input vertex and 1 MVP in the shader.
your sequence is basically

  1. load the shader porgram
  2. bind the cube vertex buffer
  3. set the MVP in the shader to the cube matrix
  4. do draw of cube
  5. bind the triangle buffer
  6. set the MVP in the shader to the triangle matrix
  7. do draw triangle

Thank you very much for your reply, I got it! :slight_smile: