2
\$\begingroup\$

In OpenGL version 3.x the function glMatrixMode() specifies which matrix is the current matrix, i.e., which matrix stack is currently the target of all matrix operations based on the parameter, the choices being GL_MODELVIEW, GL_PROJECTION, and GL_TEXTURE.

glMatrixMode() had been deprecated in OpenGL version 4.x.

I have tried to find the equivalent way of performing the same effect in 4.x without success.

I suspect there has been a change in philosophy in OpenGL 4 which I am overlooking.

How is the glMatrixMode() equivalent performed in OpenGL version 4.x?

\$\endgroup\$
3
\$\begingroup\$

glMatrixMode has been a legacy function for ages even before OpenGL 4 arrived. Since it only works with immediate mode, it hasn't been supported very well. There's no alternative for it.

You need to learn the programmable pipeline. It uses shaders instead of predefined effects (e.g. you need to create your own distance based fog instead of simply asking the video card to do it). It's obviously much harder to use, but the performance gains far outweigh the negatives.

\$\endgroup\$
  • \$\begingroup\$ Worth noting that the other matrix stack calls that glMatrixMode specifies a current matrix for are also deprecated/removed, so retaining glMatrixMode would make zero sense. If however the OP just wishes to use legacy code with a modern driver, the solution is simple: just create a compatibility context and these calls will be available again. \$\endgroup\$ – Maximus Minimus Jul 19 '19 at 16:38
  • \$\begingroup\$ @MaximusMinimus an answer showing how to do that would be worth an upvote, I'd say. \$\endgroup\$ – DMGregory Jul 19 '19 at 17:02
1
\$\begingroup\$

I found this tutorial to be very helpful in learning how Modern OpenGL does things without glMatrixMode(): LearnOpenGL - Coordinate Systems

Legacy OpenGL implemented a series of transformation matrices that allowed you to define how a vertex would be transformed to get from world space to screen space.

Generally that formula looks like this:

Vec_screen = Mat_projection x Mat_view x Mat_model x Vec_local

So you see the built-in matrix functions from legacy OpenGL allow you to modify these matrices when their respective mode is active. GL_PROJECTION would be the product of your projection and view matrices, and GL_MODELVIEW would be the current model matrix on the stack.

Modern OpenGL does away with the built-in matrices entirely, it's now up to the programmer to implement those transformations from world space to screen space. This is precisely what the Vertex Shader is meant to do! It provides more control & freedom to the programmer and it is trivial to implement once you get the basics of shaders.

Here is a GLSL vertex shader implements the transformation of a vertex from model space into screen space: (taken from the linked tutorial)

#version 330 core
layout (location = 0) in vec3 aPos;
...
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    // note that we read the multiplication from right to left
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    ...
}

Any time you want to draw a model with a particular world-space transformation you just provide that model's local transformation in the model uniform, while your camera implementation would normally provide the other two matrices.

\$\endgroup\$
  • \$\begingroup\$ Thank you for the answers. In fact, I have been using the gl_Position = projection * view * model * vec4(aPos, 1.0); technique for a while, having learned it in the Learn OpenGL series. I was casting about for a solution to a problem and found glMatrixMode() by happenstance. I had never seen it before, for good reason, that being obvious now, as I was casting about for a problem solution. The problem is this. I have a rendered sphere which I want to tilt about z and rotate about the local y-axis as it orbits elliptically about world (0, 0, 0). (continued) \$\endgroup\$ – user34299 Jul 20 '19 at 20:41
  • \$\begingroup\$ (continued from last) I can do all that except that I have to do the rotation about the local y-axis cumulatively rather than incrementally so that rotation presents as a jittery effect. For each rendering loop I am starting with an identity model matrix, translating it to the orbit position, tilting it, and then cumulatively rotating it to the new, cumulative axial position using glm functions. I've not come up with a way to remove the jitter. Any suggestions? \$\endgroup\$ – user34299 Jul 20 '19 at 20:47
0
\$\begingroup\$

In modern OpenGL, you define any matrix you want to use as part of the shader program you load. Get used to the idea that you will write shader code. It is scary, I know. It is not that bad, I promise.

In particular, you will define them as "uniforms", which are data that will be available to the shader (but not associated to a vertex). You could pass other data as uniforms aside, including the inverse of the matrices for those cases where you need it...

For instance, some of my shader code starts like this:

#version 330 core

uniform vec2 resolution;
uniform float time;

uniform mat4 projection;
uniform mat4 inverseProjection;
uniform mat4 view;
uniform mat4 inverseView;   
// ...

Here I am passing the size of the screen as a vec2 resolution, the current time as a float for animating in the GPU, and then some mat4, each one a transformation matrix.

So, how do we specify which of these uniforms we are setting?

We, will call glGetUniformLocation, with the id of our shader program (which you get from glCreateProgram as part of the process of setting your shaders) and the string name of the uniform you want.

Afterwards, you call a glUniform function, according to the datatype you want, passing the location you got from glGetUniformLocation.

Since we will setting a mat4, we will call glUniformMatrix4fv. You will find that you also need to specify a bool if you want to transpose the matrix when setting it (just in case you are using row major order, but OpenGL wants column major order).

Example:

// Get the location of the matrix you want to set
int modelLocation = glGetUniformLocation(shader_id, "model");
// Set it
glUniformMatrix4fv(modelLocation, 1, false, model[0]);
//                 ^              ^  ^      ^
//                 |              |  |      |
//                 |              |  |      pointer to the start of the matrix
//                 |              |  no, do not transpose my matrix
//                 |              only take one matrix from that pointer, thank you
//                 the location on the shader program where we are setting...
//                 ... that identifies what uniform we are setting

Oh, right, you can have an array of mat4 as a uniform, for example:

// somewhere in the shader header
uniform mat4 bones[10];

Then set it in your code:

int bonesLocation = glGetUniformLocation(shader_id, "bones");
glUniformMatrix4fv(bonesLocation, 10, false, bones[0]);
//                                ^
//                                |
//                                Take 10 mat4

So, in a sense glGetUniformLocation is the replacement for glMatrixMode. Please tell me are not using glBegin and glEnd.


Finally, of course, if you want to mimic the old behavior, the matrix multiplication order would be projection * view * model * vector somewhere on your vertex shader.

Know that by writing your own shaders, you can go crazy...

I am currently writing a ray caster, and I have code like this:

// ...
gl_Position = vec4(position.xy, 0.0, 1.0);
cameraRayDirection = ((inverseView * inverseProjection) * gl_Position).xyz;
cameraRayPosition = (inverseView * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
// ...
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.