A nice way is using Uniform Buffer Objects (OpenGL) which buffer uniform variable information which can be shared across multiple programs. Inside every shader one will declare an uniform block, which has the layout of the uniform buffer.
For example:
// Vertex shader:
#version 150 core
in vec3 position;
uniform mat4 Model;
layout (std140) uniform Camera{
mat4 View;
mat4 Proj;
} Cam;
void main(){
gl_Position = Cam.Proj * Cam.View * Model * vec4(position, 1.0);
}
Then use a struct to fill a layout (C/C++):
typedef struct Something{
glm::mat4 View;
glm::mat4 Proj;
} Layout;
and to create the buffer the usual way:
GLuint ID;
Layout layout{glm::mat4(1.0), glm::mat4(1.0)};
glGenBuffers(1, &ID);
glBindBuffer(GL_UNIFORM_BUFFER, ID);
glBufferData(GL_UNIFORM_BUFFER, sizeof layout, &layout, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, ID);
How to set and update the data:
void *data = glMapBuffer(GL_UNIFORM_BUFFER, GL_READ_WRITE);
memcpy(data, &layout, sizeof layout);
glUnmapBuffer(GL_UNIFORM_BUFFER);
To every shader program you must bind the location:
GLuint camloc = glGetUniformBlockIndex(programID, "Camera");
glUniformBlockBinding(programID, camloc, 0);
See the documentation for additional information about the functions and parameters.