Instancing with glDrawElementsInstanced and multiple VBOs

Hello. I’m writing a 3D Conway’s Game of Life simulation in C++, using OpenGL with GLEW and GLM. I’m trying to render multiple cubes using glDrawElementsInstanced. Each cube has a color, six brightness parameters for each side, and eight positions representing its vertices. I’ve placed each of the attributes in separate VBO and and used glVertexAttribDivisor to assign the number of instances that has to pass for the attribute to advance. One instance is one side of the cube so the brightness value has vertex attribute divisor of 1, color — 6 and vertices, well, 0. When I try to run this code I get an empty screen and no errors when I tried calling glGetError(). Please ignore the class variables, they’re just a part of interface I created for managing Game of Life sets:

GLuint loadShader(const char * filepath, GLenum type)
{
	GLuint shader = glCreateShader(type);
	ifstream shaderFile(filepath);
	if(!shaderFile.is_open())
	{
		cerr << PROJ_NAME ": failed to open shader file '" << filepath << '\'' << endl;
		exit(EXIT_FAILURE);
	}
	
	shaderFile.seekg(0, shaderFile.end);
	size_t fileSize = shaderFile.tellg();
	shaderFile.seekg(0, shaderFile.beg);
	char * shaderSrc = (char *)malloc(fileSize + 1);
	shaderFile.read(shaderSrc, fileSize);
	shaderSrc[fileSize] = '\0';
	
	glShaderSource(shader, 1, &shaderSrc, nullptr);
	glCompileShader(shader);
	GLint status;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
	if(status != GL_TRUE)
	{
		char buf[4096];
		glGetShaderInfoLog(shader, 4096, nullptr, buf);
		cerr << buf << PROJ_NAME ": failed to compile file '" << filepath << '\'' << endl;
		exit(EXIT_FAILURE);
	}
	free(shaderSrc);
	return shader;
}

void Lifespace::prepareMesh()
{
	if(!s_gfxProgram)
	{
		// Initialize program  and shaders
		GLuint vs, fs;
		vs = loadShader("dat/glsl/Lifespace_vs.glsl", GL_VERTEX_SHADER);
		fs = loadShader("dat/glsl/Lifespace_fs.glsl", GL_FRAGMENT_SHADER);
		s_gfxProgram = glCreateProgram();
		glAttachShader(s_gfxProgram, vs);
		glAttachShader(s_gfxProgram, fs);
		glBindFragDataLocation(s_gfxProgram, 0, "outColor");
		glLinkProgram(s_gfxProgram);
		glUseProgram(s_gfxProgram);
		glDetachShader(s_gfxProgram, vs);
		glDetachShader(s_gfxProgram, fs);
		glDeleteShader(vs);
		glDeleteShader(fs);
	}
	
	glUseProgram(s_gfxProgram);
	
	if(!m_gfx.vao)
	{
		glGenVertexArrays(1, &m_gfx.vao);
		glBindVertexArray(m_gfx.vao);
		
		// Initialize VAO, VBOs and EBO
		GLint posAttr = glGetAttribLocation(s_gfxProgram, "pos"),
			   colAttr = glGetAttribLocation(s_gfxProgram, "col"),
			   shadeAttr = glGetAttribLocation(s_gfxProgram, "bright");
		
		glEnableVertexAttribArray(posAttr);
		glEnableVertexAttribArray(colAttr);
		glEnableVertexAttribArray(shadeAttr);
		
		glGenBuffers(1, &m_gfx.posVbo);
		glBindBuffer(GL_ARRAY_BUFFER, m_gfx.posVbo);
		glVertexAttribPointer(posAttr, 3, GL_FLOAT, GL_FALSE, 0, 0);
		glVertexAttribDivisor(posAttr, 0);
		
		glGenBuffers(1, &m_gfx.colVbo);
		glBindBuffer(GL_ARRAY_BUFFER, m_gfx.colVbo);
		glVertexAttribPointer(colAttr, 3, GL_FLOAT, GL_FALSE, 0, 0);
		glVertexAttribDivisor(colAttr, 6);
		
		glGenBuffers(1, &m_gfx.shadeVbo);
		glBindBuffer(GL_ARRAY_BUFFER, m_gfx.shadeVbo);
		glVertexAttribPointer(shadeAttr, 1, GL_FLOAT, GL_FALSE, 0, 0);
		glVertexAttribDivisor(shadeAttr, 1);
		
		glGenBuffers(1, &m_gfx.ebo);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_gfx.ebo);
	}
	
	glBindVertexArray(m_gfx.vao);
	
	array<float, 6> s_shadeTmpl = { { 0.8, 0.9, 0.8, 0.9, 1.0, 0.7 } };
	
	array<glm::vec3, 8> s_cubeTmpl = { {
		glm::vec3(0, 1, 1), glm::vec3(1, 1, 1), 
		glm::vec3(0, 0, 1), glm::vec3(1, 0, 1),
		glm::vec3(1, 1, 0), glm::vec3(1, 0, 0), 
		glm::vec3(0, 1, 0), glm::vec3(0, 0, 0)
	} };
	
	array<GLuint, 36> s_elemTmpl = { {
		2, 1, 0, 1, 2, 3,
		3, 4, 1, 4, 3, 5,
		5, 6, 4, 6, 5, 7,
		7, 0, 6, 0, 7, 2,
		0, 4, 6, 4, 1, 0,
		7, 3, 2, 3, 7, 5
	} };
	
	m_gfx.mesh.col.clear();
	m_gfx.mesh.pos.clear();
	m_gfx.mesh.bright.clear();
	m_gfx.elements.clear();
	m_gfx.mesh.col.reserve(volume());
	m_gfx.mesh.pos.reserve(volume() * s_cubeTmpl.size());
	m_gfx.mesh.bright.reserve(volume() * s_shadeTmpl.size());
	m_gfx.elements.reserve(volume() * s_elemTmpl.size());
	
	GLuint elemCnt = 0;
	for(int ix = 0; ix < (int)m_sideLen; ++ix)
		for(int iy = 0; iy < (int)m_sideLen; ++iy)
			for(int iz = 0; iz < (int)m_sideLen; ++iz)
				if(m_lifeData[index3D(ix, iy, iz)])
				{
					glm::vec3 pos(ix, iy, iz);
					for(auto it = s_shadeTmpl.begin(); it != s_shadeTmpl.end(); ++it)
						m_gfx.mesh.bright.push_back(*it);
					m_gfx.mesh.col.push_back(m_colData[index3D(ix, iy, iz)]);
					for(auto it = s_cubeTmpl.begin(); it != s_cubeTmpl.end(); ++it)
						m_gfx.mesh.pos.push_back(*it + pos);
					for(auto it = s_elemTmpl.begin(); it != s_elemTmpl.end(); ++it)
						m_gfx.elements.push_back(*it + elemCnt);
					elemCnt += s_cubeTmpl.size();
				}
	
	glBindBuffer(GL_ARRAY_BUFFER, m_gfx.posVbo);
	glBufferData(GL_ARRAY_BUFFER, m_gfx.mesh.pos.size() * sizeof(m_gfx.mesh.pos[0]), m_gfx.mesh.pos.data(), GL_STATIC_DRAW);
	
	glBindBuffer(GL_ARRAY_BUFFER, m_gfx.colVbo);
	glBufferData(GL_ARRAY_BUFFER, m_gfx.mesh.col.size() * sizeof(m_gfx.mesh.col[0]), m_gfx.mesh.col.data(), GL_STATIC_DRAW);
	
	glBindBuffer(GL_ARRAY_BUFFER, m_gfx.shadeVbo);
	glBufferData(GL_ARRAY_BUFFER, m_gfx.mesh.bright.size() * sizeof(m_gfx.mesh.bright[0]), m_gfx.mesh.bright.data(), GL_STATIC_DRAW);
	
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_gfx.ebo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_gfx.elements.size() * sizeof(m_gfx.elements[0]), m_gfx.elements.data(),
	GL_STATIC_DRAW);
}

void Lifespace::render()
{
	if(m_gfx.mesh.pos.empty())
		throw InvalidStateException("call to Lifespace::render() without previous call to Lifespace::prepareMesh()");
	
	glBindVertexArray(m_gfx.vao);
	glUseProgram(s_gfxProgram);
	
	GLint uniModel = glGetUniformLocation(s_gfxProgram, "model");
	glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(g_model.back()));
	GLint uniView = glGetUniformLocation(s_gfxProgram, "view");
	glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(g_view.back()));
	GLint uniProj = glGetUniformLocation(s_gfxProgram, "proj");
	glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(g_proj.back()));
	
	glDrawElementsInstanced(GL_TRIANGLES, m_gfx.elements.size(), GL_UNSIGNED_INT, nullptr, m_gfx.mesh.bright.size());
}

Contents of Lifespace_vs.glsl:

#version 330

in vec3 pos;
in float bright;
in vec3 col;

out float Bright;
out vec3 Col;

uniform mat4 proj; 
uniform mat4 model;
uniform mat4 view;

void main()
{
	gl_Position = proj * view * model * vec4(pos, 1);
	Bright = bright;
	Col = col;
}

…and Lifespace_fs.glsl:

#version 330

in float Bright;
in vec3 Col;

out vec4 outColor;

void main()
{
	outColor = vec4(Col * vec3(Bright, Bright, Bright), 1);
}

I’d really appreciate if you could tell me what it is that I’m doing wrong.