Thats a different question than I originally thought …
first you need to map your shader variable to an ID
glm_ProjectionMatrix_id = glGetUniformLocation(shader_id, “glm_ProjectionMatrix”); //whatever your shader uniform name is
then you need to set the uniform value in your display loop using the ID:
glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, &glm_ProjectionMatrix.top()[0][0] );
Here’s C++ code that is based on glm/freeglut/glew and may help you if you read thru it and try to understand it. It is GL3 and doesn’t use the deprecated matrix manipulation functions. It draws two triangles, when you press T,t they rotate around theta, or P,p they rotates around phi.
Note, the “class CustomGraphicsPipeline” depends only on glm and gl3 so you could probably take that as is if you don’t use freeglut for your window “manager”.
//on linux or mingw: g++ glut_ogl3_helloworld.cpp -lglut -lGLEW -DGL3_PROTOTYPES
// modified to use GLM library from http://pheatt.emporia.edu/courses/2005/cs410f05/hand14/hand14.htm
// modified to use camera at begining of MODELVIEW Transformations, not in the Projection Transform! see http://www.sjbaker.org/steve/omniv/projection_abuse.html
#include <GL/glew.h> // great opengl extensions helper
#include <GL/gl3.h>
#include <GL/freeglut.h> // use of opengl 3.0 context requires freeglut from svn!
#include <glm/glm.h> //OpenGL Mathematics (GLM). A C++ mathematics library for 3D graphics.
#include <glm/glmext.h>
#include <glm/GLM_VIRTREV_address.h> // gives helper function address(X) instead of using &X[0][0]
namespace glm
{
// read glm/gtx/transform.h for function prototypes
using GLM_GTX_transform;
using GLM_GTX_transform2; // for lookAt
using GLM_GTX_matrix_projection;
}
using namespace glm;
//#include <cstdio>
//#include <cmath>
#include <iostream>
//#include <iomanip>
//#include <sstream>
#include <stack>
//#include <cstring>
#include <cassert>
class CustomGraphicsPipeline
{
GLuint shader_id;
std::stack<mat4> glm_ProjectionMatrix; //cpu-side
GLint glm_ProjectionMatrix_id; //cpu-side hook to shader uniform
std::stack<mat4> glm_ModelViewMatrix; //cpu-side
GLint glm_ModelViewMatrix_id; //cpu-side hook to shader uniform
GLuint vao_id[2]; // vertex array object hook id
GLuint vao_elementcount[2]; // number of attribute elements in vao ie number of vertices
GLuint vao_primitivetype[2]; // type [GL_LINE_LOOP|GL_TRIANGLES|etc]
public:
CustomGraphicsPipeline() :
shader_id(NULL),
glm_ProjectionMatrix_id(NULL),
glm_ModelViewMatrix_id(NULL)
{
glm_ProjectionMatrix.push( mat4(1.0f) ); // identity matrix
glm_ModelViewMatrix.push( mat4(1.0f) ), // identity matrix
vao_id[0]=NULL;
vao_id[1]=NULL;
vao_elementcount[0]=0;
vao_elementcount[1]=0;
vao_primitivetype[0] = GL_LINE_LOOP;
vao_primitivetype[1] = GL_TRIANGLES;
}
~CustomGraphicsPipeline() {}
bool Init() // All Setup For OpenGL Goes Here
{
GLint ret = true; // optimistic return value upon completion of execution
std::cout << "press t,T to rotate camera theta" << std::endl;
std::cout << "press p,P to rotate camera phi" << std::endl;
glEnable(GL_DEPTH_TEST);
glClearColor(0.2f, 0.2f, 0.2f, 0.5f);
//Datas destioned for video memory, can be local (and lost after bound to GPU!).
GLfloat vertices0[] = { // dgl_Vertex
1.0, -1.0, 0.0, 1.0, // xyzw
-1.0, -1.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0
};
size_t Nbytes_vertices0=sizeof(vertices0);
GLfloat colors0[] = { // dgl_Color
0.0, 0.0, 1.0, 1.0, //rgba
0.0, 1.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0
};
size_t Nbytes_colors0=sizeof(colors0);
GLfloat vertices1[] = { // dgl_Vertex
0.5, -0.5, 0.0, 1.0, // xyzw
-0.5, -0.5, 0.0, 1.0,
0.0, 0.5, 0.0, 1.0
};
size_t Nbytes_vertices1=sizeof(vertices1);
GLfloat colors1[] = { // dgl_Color
0.0, 0.0, 1.0, 1.0, //rgba
0.0, 1.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0
};
size_t Nbytes_colors1=sizeof(colors1);
const GLchar *g_vertexShader[] = {"#version 130
",
"uniform mat4 glm_ProjectionMatrix;
", // replaces deprecated gl_ProjectionMatrix see http://www.lighthouse3d.com/opengl/glsl/index.php?minimal
"uniform mat4 glm_ModelViewMatrix;
", // replaces deprecated gl_ModelViewMatrix
"in vec4 dgl_Vertex;
", // replaces deprecated gl_Vertex
"in vec4 dgl_Color;
", // replaces deprecated gl_Color
"invariant out vec4 Color;
", // to fragment shader
"void main(void)
",
"{
",
" Color = dgl_Color;
",
" gl_Position = glm_ProjectionMatrix*glm_ModelViewMatrix*dgl_Vertex;
", // replaces deprecated ftransform() see http://www.songho.ca/opengl/gl_transform.html
"}
"
};
const GLchar *g_fragmentShader[] = {"#version 130
",
"invariant in vec4 Color;
", // from vertex shader
"out vec4 dgl_FragColor;
", // replaces deprecated gl_FragColor
"void main(void)
",
"{
",
" dgl_FragColor = Color;
", // gl_FragColor is deprecated
"}
"
};
// compile Vertex shader
GLuint m_vxShaderId = glCreateShader(GL_VERTEX_SHADER);
GLsizei nlines_vx = sizeof(g_vertexShader)/sizeof(const GLchar*);
glShaderSource(m_vxShaderId, nlines_vx, (const GLchar**)g_vertexShader, NULL);
glCompileShader(m_vxShaderId);
CheckShader(m_vxShaderId, GL_COMPILE_STATUS, &ret, "unable to compile the vertex shader!");
// compile Fragment shader
GLuint m_fgShaderId = glCreateShader(GL_FRAGMENT_SHADER);
GLsizei nlines_fg = sizeof(g_fragmentShader)/sizeof(const GLchar*);
glShaderSource(m_fgShaderId, nlines_fg, (const GLchar**)g_fragmentShader, NULL);
glCompileShader(m_fgShaderId);
CheckShader(m_fgShaderId, GL_COMPILE_STATUS, &ret, "unable to compile the fragment shader!");
// link shaders
shader_id = glCreateProgram();
glAttachShader(shader_id, m_vxShaderId);
glAttachShader(shader_id, m_fgShaderId);
glLinkProgram(shader_id);
CheckShader(shader_id, GL_LINK_STATUS, &ret, "unable to link the program!");
//hooks from CPU to GPU
//define Uniform hooks
glm_ProjectionMatrix_id = glGetUniformLocation(shader_id, "glm_ProjectionMatrix");
glm_ModelViewMatrix_id = glGetUniformLocation(shader_id, "glm_ModelViewMatrix");
//guard that all attributes have same number of elements
assert(Nbytes_vertices0/4/sizeof(GLfloat)==Nbytes_colors0/4/sizeof(GLfloat));
vao_elementcount[0]=Nbytes_vertices0/4/sizeof(GLfloat); // number of elements for first VAO
assert(Nbytes_vertices1/4/sizeof(GLfloat)==Nbytes_colors1/4/sizeof(GLfloat));
vao_elementcount[1]=Nbytes_vertices1/4/sizeof(GLfloat); // number of elements for second VAO
//create and define vertex array objects
glGenVertexArrays(2, &vao_id[0]); // vao_id[#] will be referenced in Draw()
defineVertexArrayObject(vao_id[0],Nbytes_vertices0,4,GL_FLOAT,vertices0,colors0); //VertexAttribArray: vertices0, colors0
defineVertexArrayObject(vao_id[1],Nbytes_vertices1,4,GL_FLOAT,vertices1,colors1); //VertexAttribArray: vertices1, colors1
// finally, use the shader for rendering
glUseProgram(shader_id); // select the shaders program
return ret; // Initialization Went OK?
}
void defineVertexArrayObject(GLuint vaoId, size_t Nbytes, GLint size, GLenum type, GLfloat *vertices, GLfloat *colors)
{
//enable vertex array object to be defined
glBindVertexArray(vaoId);
//generate VBO foreach 'in'; dgl_Vertex and dgl_Color
GLuint m_vboId[2];
glGenBuffers(2, &m_vboId[0]);
//"in vec4 dgl_Vertex;",
glBindBuffer(GL_ARRAY_BUFFER, m_vboId[0] ); // enable the 1st VBO
glBufferData(GL_ARRAY_BUFFER, Nbytes, vertices, GL_STATIC_DRAW); // fill the VBO with vertices data
const GLuint index_mPosition = glGetAttribLocation(shader_id,"dgl_Vertex"); // get ID for "dgl_Vertex"
glVertexAttribPointer(index_mPosition, size, type, GL_FALSE, 0, 0); // VBO point to the "dgl_Vertex" attribute
glEnableVertexAttribArray(index_mPosition); // enable VBO vertex attribute ("dgl_Vertex")
//"in vec4 dgl_Color;",
glBindBuffer(GL_ARRAY_BUFFER, m_vboId[1]); // enable the 2nd VBO
glBufferData(GL_ARRAY_BUFFER, Nbytes , colors, GL_STATIC_DRAW); // fill the 2nd VBO with colors data
const GLuint index_mcolor = glGetAttribLocation(shader_id,"dgl_Color"); // get ID for "dgl_Color"
glVertexAttribPointer(index_mcolor, size, type, GL_FALSE, 0, 0); // VBO point to the "dgl_Color" attribute
glEnableVertexAttribArray(index_mcolor); // enable VBO vertex attribute ("dgl_Color")
}
void CheckShader(GLuint id, GLuint type, GLint *ret, const char *onfail)
{
//Check if something is wrong with the shader
switch(type) {
case(GL_COMPILE_STATUS):
glGetShaderiv(id, type, ret);
if(*ret == false){
int infologLength = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &infologLength);
GLchar buffer[infologLength];
GLsizei charsWritten = 0;
std::cout << onfail << std::endl;
glGetShaderInfoLog(id, infologLength, &charsWritten, buffer);
std::cout << buffer << std::endl;
}
break;
case(GL_LINK_STATUS):
glGetProgramiv(id, type, ret);
if(*ret == false){
int infologLength = 0;
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infologLength);
GLchar buffer[infologLength];
GLsizei charsWritten = 0;
std::cout << onfail << std::endl;
glGetProgramInfoLog(id, infologLength, &charsWritten, buffer);
std::cout << buffer << std::endl;
}
default:
break;
};
}
void Draw_vao(size_t index)
{
glBindVertexArray(vao_id[index]); // select the vertex array object:vao_id[index] by definiton using vertices_index,colors_index
glDrawArrays(vao_primitivetype[index], 0, vao_elementcount[index]); // draw the array (at the speed of light)
}
void Draw() // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, &glm_ProjectionMatrix.top()[0][0] ); // set the rotation/translation/scale matrix
//glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, address(glm_ProjectionMatrix.top()) ); // set the rotation/translation/scale matrix
{
glm_ModelViewMatrix.push(glm_ModelViewMatrix.top());
//glm_ModelViewMatrix.top() *= translate( vec3(0.5, 0.5, 0.0) );
glm_ModelViewMatrix.top() *= rotate(45.0f, vec3(0.0, 0.0, 1.0) );
glm_ModelViewMatrix.top() *= scale( vec3(0.2, 0.2, 0.2) );
glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] ); // set the rotation/translation/scale matrix
//glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, address(glm_ModelViewMatrix.top()) ); // set the rotation/translation/scale matrix
Draw_vao(0);
glm_ModelViewMatrix.pop();
}
{
glm_ModelViewMatrix.push(glm_ModelViewMatrix.top());
glm_ModelViewMatrix.top() *= translate( vec3(0.0, 0.0, 0.25) );
//glm_ModelViewMatrix.top() *= rotate(45.0f, vec3(1.0, 1.0, 0.0) );
glm_ModelViewMatrix.top() *= scale( vec3(0.2, 0.2, 0.2) );
glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] ); // set the rotation/translation/scale matrix
//glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, address(glm_ModelViewMatrix.top()) ); // set the rotation/translation/scale matrix
Draw_vao(1);
glm_ModelViewMatrix.pop();
}
}
bool Reshape(GLfloat ratio)
{
//glMatrixMode(GL_PROJECTION);
glm_ProjectionMatrix.top() = mat4(1.0); //glLoadIdentity
glm_ProjectionMatrix.top() *= perspective(20.0f,ratio,1.0f,3.0f);
//glLoadMatrixf(address(glm_ProjectionMatrix.top()));
glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, &glm_ProjectionMatrix.top()[0][0] ); // set the rotation/translation/scale matrix
}
bool SetCamera(GLfloat theta, GLfloat phi)
{
//////////////
// Set the camera view.
static const double radianFactor = acos(0.0) / 90.0;
float r = 1.0f*2.0; // approx. want half way between near + far (see perspective)
float eyeX = r * sin(theta * radianFactor) * cos(phi * radianFactor);
float eyeY = r * sin(theta * radianFactor) * sin(phi * radianFactor);
float eyeZ = r * cos(radianFactor * theta);
float centerX = 0, centerY = 0, centerZ = 0;
float upX = 0, upY = 1.0f, upZ = 0;
//glMatrixMode(GL_MODELVIEW);
glm_ModelViewMatrix.top() = mat4(1.0); // LoadIdentity
glm_ModelViewMatrix.top() *= lookAt( vec3(eyeX, eyeY, eyeZ), vec3(centerX, centerY, centerZ), vec3(upX, upY, upZ));
//glLoadMatrixf(address(glm_ModelViewMatrix.top()));
glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] );
return true;
}
};
// GLOBAL ///////////////////////////////////////////////////////////
CustomGraphicsPipeline Scene;
/////////////////////////////////////////////////////////////////////
namespace global {
int theta = 0;
int phi = 0;
GLfloat ratio = 1.0;
int width = 512;
int height = 512;
};
static void timer(int dt_msec)
{
static GLfloat time_msec = 0.0;
time_msec += dt_msec; // absolute time
Scene.SetCamera(global::theta, global::phi);
glutPostRedisplay();
glutTimerFunc(30,timer,30); // come back in 30msec
}
static void display(void)
{
Scene.Draw();
glutSwapBuffers();
}
static void reshape(int w, int h)
{
// Set the viewport to be the entire window
glViewport(0, 0, w, h);
// Prevent a divide by zero, when window is too short
if(h == 0) h = 1;
global::width = w;
global::height = h;
global::ratio = 1.0 * w / h;
Scene.Reshape(global::ratio);
}
static void keyboard(unsigned char k, int x, int y)
{
switch (k) {
case 't' : global::theta++; if(global::theta > 360) global::theta = 1; break;
case 'p' : global::phi++; if(global::phi > 360) global::phi = 1; break;
case 'T' : global::theta--; if(global::theta < 0) global::theta = 359; break;
case 'P' : global::phi--; if(global::phi < 0) global::phi = 359; break;
case 27 : exit(0); break;
}
}
int main( int argc, char *argv[] )
{
glutInit( &argc, argv );
//opengl 3.0 with freeglut requires to install latest version from svn
//but not necessary to actually get openGL context since code will run anyhow.
//glutInitContextVersion( 3, 0 ); // freeglut is so cool! get openGL 3.0 context
//glutInitContextFlags( int flags )
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(global::width, global::height);
glutCreateWindow("demo opengl 3.0 matrix transformations");
glewInit();
assert( Scene.Init() ); // bail if scene initialization fails
glutTimerFunc(0,timer,0);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}