I have been studying on glsl lately, starting from very simple vertex and fragment shaders creation for Blender3d, I was quickly drawn to writing the OpenGL context in C++. I find it difficult to understand the process of drawing on screen from matrices data, especially the way I am supposed to work with uniform variables: here in this code I created an uniform mat4 in my vertex shader, which index is retrieved with glGetUniformLocation() in DoShader() and filled with data with glUniformMatrix4fv() in the IdleFunc This way I can use my projection matrix in the shader program, shouldn't it be enough for displaying a perspective ?
I am obliviously missing something because my square is not appearing at all. Thanks for your help.
#include <GL/glew.h>
#include <GL/glu.h>
#include <GL/freeglut.h>
#include <string.h>
#include "math_3d.h"
static GLuint vbo;
GLint gWorldLocation;
class Pipeline
{
public:
Pipeline(){};
void InitPersProjTrans(Matrix4f& m);
Matrix4f* GetTrans();
void setPerspectiveProj(float fov, float width, float height, float znear, float zfar);
private:
Matrix4f m_transformation;
struct {
float FOV;
float Width;
float Height;
float zNear;
float zFar;
} m_persProj;
};
void Pipeline::setPerspectiveProj(float fov, float width, float height, float znear, float zfar)
{
m_persProj.FOV = fov;
m_persProj.Width = width;
m_persProj.Height = height;
m_persProj.zNear = znear;
m_persProj.zFar = zfar;
}
void Pipeline::InitPersProjTrans(Matrix4f& m)
{
const float ar = m_persProj.Width / m_persProj.Height;
const float zNear = m_persProj.zNear;
const float zFar = m_persProj.zFar;
float zRange = zNear - zFar;
const float tanHalfFOV = tanf(ToRadian(m_persProj.FOV / 2.0));
m.m[0][0] = 1.0f / (tanHalfFOV * ar);
m.m[0][1] = 0.0f;
m.m[0][2] = 0.0f;
m.m[0][3] = 0.0f;
m.m[1][0] = 0.0f;
m.m[1][1] = 1.0f / tanHalfFOV;
m.m[1][2] = 0.0f;
m.m[1][3] = 0.0f;
m.m[2][0] = 0.0f;
m.m[2][1] = 0.0f;
m.m[2][2] = (zNear - zFar) / zRange;
m.m[2][3] = 2.0f * zFar * zNear / zRange;
m.m[3][0] = 0.0f;
m.m[3][1] = 0.0f;
m.m[3][2] = 1.0f;
m.m[3][3] = 0.0f;
}
Matrix4f* Pipeline::GetTrans()
{
Matrix4f PersProjTrans;
InitPersProjTrans(PersProjTrans);
m_transformation = PersProjTrans;
return &m_transformation;
}
static void createShader(GLuint program, const char *shader, GLenum type){
GLuint obj = glCreateShader(type);
if (!obj){
fprintf(stderr, "fail during shader creation: %d", type);
exit(1);
}
const GLchar *p[1];
p[0] = shader;
GLint len[1];
len[0] = strlen(shader);
glShaderSource(obj, 1, &shader, NULL);
glCompileShader(obj);
GLint test;
glGetShaderiv(obj, GL_COMPILE_STATUS, &test);
if (!test){
GLchar log[1024];
glGetShaderInfoLog(obj, 1024, NULL, log);
fprintf(stderr, "fail during shader compilation:\n%s", log);
exit(1);
}
glAttachShader(program, obj);
}
#define RAW(X) "#version 330\n" #X
static const char *vertex_shader = RAW(
layout (location = 0) in vec3 Position;
uniform mat4 World;
void main(void)
{
gl_Position = World * vec4(Position.x, Position.y, Position.z, 1.0);
}
);
static const char *fragment_shader = RAW(
out vec4 fragColor;
void main(void)
{
fragColor = vec4(0.5, 0.15, 1.0, 1.0);
}
);
static void DoShaders(){
GLuint prog = glCreateProgram();
if (!prog){
fprintf(stderr, "fail while creating shader program\n");
exit(1);
}
createShader(prog, vertex_shader, GL_VERTEX_SHADER);
createShader(prog, fragment_shader, GL_FRAGMENT_SHADER);
glLinkProgram(prog);
gWorldLocation = glGetUniformLocation(prog, "World");
GLint test = 0;
GLchar log[1024] = { 0 };
glGetProgramiv(prog, GL_LINK_STATUS, &test);
if (!test){
glGetProgramInfoLog(prog, sizeof(log), NULL, log);
fprintf(stderr,"error link%s\n", log);
exit(1);
}
glValidateProgram(prog);
glGetProgramiv(prog, GL_VALIDATE_STATUS, &test);
if (!test){
glGetProgramInfoLog(prog, sizeof(log), NULL, log);
fprintf(stderr,"error validate%s\n", log);
exit(1);
}
glUseProgram(prog);
}
static void ObjectRenderInfo(){
Vector3f verts[4];
verts[0] = Vector3f(-1.0f, -0.1f, -1.0f);
verts[1] = Vector3f(-1.0f, -0.1f, 1.0f);
verts[2] = Vector3f(1.0f, -0.1f, -1.0f);
verts[3] = Vector3f(1.0f, -0.1f, 1.0f);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
}
static void IdleFunc(){
glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
Pipeline p;
p.setPerspectiveProj(50, 1024, 768, 1, 1000);
glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, (const GLfloat*)p.GetTrans());
glDrawArrays(GL_QUADS, 0, 4);
glDisableVertexAttribArray(0);
glutSwapBuffers();
}
int main (int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(1024, 768);
glutInitWindowPosition(100, 100);
glutCreateWindow("MyProject");
GLenum test = glewInit();
if (test != GLEW_OK){
fprintf(stderr, "failed to start glew%s\n", glewGetErrorString(test));
return 1;
}
glutIdleFunc(&IdleFunc);
ObjectRenderInfo();
DoShaders();
glClearColor(0.0f,0.0f,0.0f,0.0f);
glutMainLoop();
}
get the header file