PDA

View Full Version : How to properly use QGLShader and QGLShaderProgram



jshafferman
10th July 2014, 20:35
I am unable to get the following code to render anything :(. I am not sure where I might be going wrong, however it appears that when I attempt to compile the vertex shader the shader fails to compile and my program exits. I am not sure as to why it would be failing so I am hoping someone sees something that I do not.



#include "glwidget.h"

#include <GL/glut.h>

#include <QAction>
#include <QContextMenuEvent>
#include <QDebug>
#include <QKeyEvent>
#include <QMenu>
#include <QWheelEvent>

namespace
{
GLint windowWidth = 1024; // window size
GLint windowHeight = 768;

GLboolean useVertexShader = GL_TRUE;
GLboolean useFragmentShader = GL_TRUE;
GLboolean doBlink = GL_FALSE;

GLboolean needsValidation = GL_TRUE;

GLint flickerLocation = -1;

GLfloat cameraPos[] = {100.0f, 150.0f, 200.0f, 1.0f};
GLdouble cameraZoom = 0.6;

const int MAX_INFO_LOG_SIZE = 2048;
}

GLWidget::GLWidget(QWidget *parent)
: QGLWidget(QGLFormat(QGL::DoubleBuffer | QGL::Rgba | QGL::DepthBuffer), parent)
, vShader(QGLShader::Vertex)
, fShader(QGLShader::Fragment)
, program(this)
{
CreateActions();
CreateMenu();

int argc;
char** argv = NULL;

glutInit(&argc, argv);
}

void GLWidget::toggleVertexShader()
{
useVertexShader = !useVertexShader;

if (useVertexShader)
{
toggleVertexShaderAction->setText(tr("Toggle vertex shader (currently ON)"));
program.addShader(&vShader);
}
else
{
toggleVertexShaderAction->setText(tr("Toggle vertex shader (currently OFF)"));
program.removeShader(&vShader);
}

Relink();

update();
}

void GLWidget::toggleFragmentShader()
{
useFragmentShader = !useFragmentShader;

if (useFragmentShader)
{
toggleFragmentShaderAction->setText(tr("Toggle framgent shader (currently ON)"));
program.addShader(&fShader);
}
else
{
toggleFragmentShaderAction->setText(tr("Toggle framgent shader (currently OFF)"));
program.removeShader(&fShader);
}

Relink();

update();
}

void GLWidget::toggleFlicker()
{
doBlink = !doBlink;

if (doBlink)
{
toggleFlickerAction->setText(tr("Toggle flicker (currently ON)"));
}
else
{
toggleFlickerAction->setText(tr("Toggle flicker (currently OFF)"));
}
if (!doBlink && (flickerLocation != -1))
program.setUniformValue(flickerLocation, 1.0f);

update();
}

void GLWidget::initializeGL()
{
bool success;

GLchar vsString[] =
"void main(void)\n"
"{\n"
" // This is our Hello World vertex shader\n"
" // notice how comments are preceded by '//'\n"
"\n"
" // normal MVP transform\n"
" vec4 clipCoord = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
" gl_Position = clipCoord;\n"
"\n"
" // Copy the primary color\n"
" gl_FrontColor = gl_Color;\n"
"\n"
" // Calculate NDC\n"
" vec4 ndc = vec4(clipCoord.xyz, 0) / clipCoord.w;\n"
"\n"
" // Map from [-1,1] to [0,1] before outputting\n"
" gl_FrontSecondaryColor = (ndc * 0.5) + 0.5;\n"
"}\n";

GLchar fsString[] =
"uniform float flickerFactor;\n"
"\n"
"void main(void)\n"
"{\n"
" // Mix primary and secondary colors, 50/50\n"
" vec4 temp = mix(gl_Color, vec4(vec3(gl_SecondaryColor), 1.0), 0.5);\n"
"\n"
" // Multiply by flicker factor\n"
" gl_FragColor = temp * flickerFactor;\n"
"}\n";

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);

// Black background
glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
// glSecondaryColor3f(1.0f, 1.0f, 1.0f);

// Hidden surface removal
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);

glShadeModel(GL_SMOOTH);

qDebug() << "Source code\n" << vsString;
success = vShader.compileSourceCode(vsString);
qDebug() << "Source code" << vShader.sourceCode();
qDebug() << "isCompiled? " << vShader.isCompiled();

if (!success)
{
qDebug() << "Vertex Shader Failed Why?\n" << vShader.log();
swapBuffers();
exit(0);
}

success = fShader.compileSourceCode(fsString);
if (!success)
{
qDebug() << "Fragment Shader Failed Why?\n" << fShader.log();
swapBuffers();
exit(0);
}

QGLShaderProgram program(context());

if (useVertexShader)
program.addShader(&vShader);
if (useFragmentShader)
program.addShader(&fShader);

Link(GL_TRUE);
}

void GLWidget::resizeGL(int w, int h)
{
windowWidth = w;
windowHeight = h;
}

void GLWidget::paintGL()
{
static GLfloat flickerFactor = 1.0f;

// Track camera angle
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (windowWidth > windowHeight)
{
GLdouble ar = (GLdouble)windowWidth / (GLdouble)windowHeight;
glFrustum(-ar * cameraZoom, ar * cameraZoom, -cameraZoom, cameraZoom, 1.0, 1000.0);
}
else
{
GLdouble ar = (GLdouble)windowHeight / (GLdouble)windowWidth;
glFrustum(-cameraZoom, cameraZoom, -ar * cameraZoom, ar * cameraZoom, 1.0, 1000.0);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(cameraPos[0], cameraPos[1], cameraPos[2],
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);

glViewport(0, 0, windowWidth, windowHeight);

// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

if (doBlink && (flickerLocation != -1))
{
// Pick a random flicker factor
flickerFactor += ((((GLfloat)rand())/((GLfloat)RAND_MAX)) - 0.5f) * 0.1f;
if (flickerFactor > 1.0f) flickerFactor = 1.0f;
if (flickerFactor < 0.0f) flickerFactor = 0.0f;
program.setUniformValue(flickerLocation, flickerFactor);
}

// Validate our shader before first use
if (needsValidation)
{
needsValidation = GL_FALSE;
}

// Draw objects in the scene
DrawModels();

glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glDisable(GL_DEPTH_TEST);
glEnable(GL_DEPTH_TEST);

if (glGetError() != GL_NO_ERROR)
{
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
}

// Flush drawing commands
swapBuffers();

if (doBlink && (flickerLocation != -1))
update();
}

void GLWidget::Link(GLboolean firstTime)
{
bool success;

success = program.link();

if (!success)
{
qDebug() << "Program link failed, Why?\n" << program.log();
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
swapBuffers();
exit(0);
}

if (firstTime)
program.bind();

flickerLocation = program.uniformLocation("flickerFactor");

// Initially set the blink parameter to 1 (no flicker)
if (flickerLocation != -1)
program.setUniformValue(flickerLocation, 1.0f);

// Program object has changed, so we should revalidate
needsValidation = GL_TRUE;
}

void GLWidget::Relink()
{
Link(GL_FALSE);
}



In initializeGL() you can see where I call vShader.compileSourceCode(vsString) and I can see the debug statement Vertex Shader Failed Why? followed by an empty string "", so I am not sure how to proceed when the vShader.log() doesn't tell me anything. Any ideas???? Thanks for the help!

jshafferman
11th July 2014, 13:57
Ok so apparantly I was doing things very wrong. I was able to get the program to work perfectly fine when I changed the members vShader, fShader, and program to pointers. I simply created them inside of the initializeGL and the program started working. I am not sure but maybe it both shaders and the program need to explicity call the QGLContext that is the QGLWidget's context. Either it works now! If anyone else has a question feel free to ask.