Suggested replacement for Matrix Stack?

The Matrix Stack functionality is deprecated and I want to draw multiple objects with different transformations.

I imagine I can accomplish different object transformations by manually sending in a matrix via a uniform to a shader. Here is what I have now:


        glUseProgram(shaderProgram);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
	
	GLint posAttrib = glGetAttribLocation(shaderProgram, "vertexPosition");
	glEnableVertexAttribArray(posAttrib);
	GLint colorAttrib = glGetAttribLocation(shaderProgram, "vertexColor");
	glEnableVertexAttribArray(colorAttrib);

	GLfloat ortho = glGetUniformLocation(shaderProgram, "projection");

	float r = 1.875;
	float l = -1.875;
	float b = -1.5;
	float t = 1.5;
	float n = 0;
	float f = 5;

	float orthoElements[] =
	{
		2 / (r - l), 0, 0, -(r + l) / (r - l),
		0, 2 / (t - b), 0, -(t + b) / (t - b),
		0, 0, -2 / (f - n), (f + n) / (f - n),
		0, 0, 0, 1,
	};

	glUniformMatrix4fv(ortho, 1, GL_TRUE, orthoElements);
	
	//Draw AXES
	glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(sizeof(vertices) + sizeof(colors) + sizeof(edgeColors)));
	glVertexAttribPointer(colorAttrib, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(sizeof(vertices) + sizeof(colors) + sizeof(edgeColors) + 3 * sizeof(float)));
	glDrawArrays(GL_LINES, 0, sizeof(axes) / (6 * sizeof(axes[0])));

        GLfloat rot = glGetUniformLocation(shaderProgram, "rotation_y");

	float angle = -45 + persp;

	//rotates "angle" degrees about the y-axis
	float rotElements[] =
	{
		cosf(angle), 0, sinf(angle), 0,
		0, 1, 0, 0,
		-sinf(angle), 0, cosf(angle), 0,
		0, 0, 0, 1,
	};

	glUniformMatrix4fv(rot, 1, GL_TRUE, rotElements);

        //draw other stuff

To sum up the code above, I first apply orthographic projection to the whole scene, then I draw the coordinate axes. After that I apply an extra rotation about the y-axis and then draw extra stuff. Because I have axes’ draw calls after the projection transformation and before the rotation transformation, I expect the axes be affected only by the projection transformation. But it seems that all transformations whose matrices I send to the shader accumulate and affect everything, be it above or below the transformation code.

Why is that happening? And how can I “protect” my draw calls from transformations below affecting them? In other words, I want to have control over which objects are affected by which transformations.

The two matrices always exist in the shader program. glUniform*() changes the value. The values are remembered between invocations. You should assign values to all of the uniform variables before the first draw call which uses the program.

If I understand correctly, you probably want to explicitly assign an identity matrix to [var]projection_y[/var] before the first draw call.

basically you do it like this:

glBindBuffer(…)
glBindBuffer(…)

// activate shader
glUseProgram(…)

// upload a matrix 1
glUniformMatrix4fv(…, matrix1)

// draw a mesh 1
glDrawElements(…)

// upload next matrix 2
glUniformMatrix4fv(…, matrix2)

// draw a mesh 2
glDrawElements(…)

etc.

GLfloat rot = glGetUniformLocation(shaderProgram, "rotation_y");

that is wrong, uniform locations are always “int” (or GLint)
it will be -1 if there is no “rotation_y” variable in your program

if you can use “vertexarray objects” (VAO), you can skip calling each frame “glVertexAttribPointer” / “glBindBuffer” / “glEnableVertexAttribArray”
you would only have to do the setup once, then you just have to call:
glBindVertexArray(VAO)
instead

you can also skip calling “glGetAttribLocation” / “glBindAttribLocation” if you set the attribute location in the shader source code like this:

layout (location = 5) in vec3 position;

instead of just:

in vec3 position;

that way, the attribute “vec3 position” will be 5

Thank you both, that helped. When it comes to more advanced stuff, like using VAOs , I see it is really useful and I will start studying it as well, but as of now I am focusing on how to do the basic stuff in modern OpenGL.

A follow-up question: if I declare a set of uniforms in a shader and have a draw call before every single one of them is filled with some value coming from the application side, do the uniforms have some default value? (Like, if it’s a “uniform mat4 something”, then it’s an identity matrix, if it’s “a uniform float something”, then it’s a zero and so on).

Uniform variables can be initialised in the shader code. In the absence of an initialiser, they’re supposed to be initialised to zero at link time.

The uniform qualifier is used to declare global variables whose values are the same across the entire primitive being processed. All uniform variables are read-only and are initialized externally either at link time or through the API. The link-time initial value is either the value of the variable’s initializer, if present, or 0 if no initializer is present. Opaque types cannot have initializers, or a compile-time error results.

No distinction is made according to type, so matrices should default to zeros rather than an identity matrix.