PBO Motion Blur

Notes:

This modifies the Diffuse Shader lesson to have a pixel buffer object and motion blur.

IMPORTANT: This example throws an OpenGL Error and I have no idea why.

Vertex Shader:

// blur.vs
// outputs: position and texture coord 0

#version 330 core

uniform mat4 mvpMatrix;
in vec3 vVertex;
in vec2 texCoord0;
out vec2 vTexCoord;

void main(void) 
{ 
	vTexCoord = texCoord0;
	gl_Position = mvpMatrix * vec4(vVertex, 1.0); 
}

Fragment Shader:

// blur.fs
// outputs weighted, blended result of four textures

#version 150 

in vec2 vTexCoord;
uniform sampler2D textureUnit0;
uniform sampler2D textureUnit1;
uniform sampler2D textureUnit2;
uniform sampler2D textureUnit3;
uniform sampler2D textureUnit4;
uniform sampler2D textureUnit5;
void main(void) 
{ 
	// 0 is the newest image and 5 is the oldest
	vec4 blur0 = texture(textureUnit0, vTexCoord); 
	vec4 blur1 = texture(textureUnit1, vTexCoord); 
	vec4 blur2 = texture(textureUnit2, vTexCoord); 
	vec4 blur3 = texture(textureUnit3, vTexCoord); 
	vec4 blur4 = texture(textureUnit4, vTexCoord); 
	vec4 blur5 = texture(textureUnit5, vTexCoord); 
	
	vec4 summedBlur = blur0	+ blur1 + blur2 +blur3 + blur4 + blur5;
	gl_FragColor = summedBlur/6;
}

Source:

// PixBuff.cpp
//
// Convert the Diffuse Shader example to add PBO and motion blue

#include <GLTools.h>	// OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <math.h>

#include <stdio.h>
#include <GL/glew.h>    // glew likes to be before other GL stuff
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <GL/glu.h>

// OGLSB5 variables
GLShaderManager         shaderManager;
GLMatrixStack           modelViewMatrix;
GLMatrixStack           projectionMatrix;
M3DMatrix44f            orthoMatrix;
GLFrustum               viewFrustum;
GLFrame                 viewFrame;
GLGeometryTransform     transformPipeline;

GLTriangleBatch         torusBatch;
GLBatch                 screenQuad;

GLuint                  diffuseLightShader; // The diffuse light shader
GLuint                  blurProg;           // The blur shader
GLuint                  pixBuffObjs[1];     // Our pixel buffer object
GLuint                  blurTextures[6];    // Textures to draw the old screen to

GLint                   locBlurMVP;

GLint                   locColor;      // The location of the light color
GLint                   locLight;   // The location of the light in eye coordinates
GLint                   locMVP;
GLint                   locMV;
GLint                   locNM;

// for bluring texture units
GLuint                  curBlurTarget = 0;
void                    AdvanceBlurTarget() { curBlurTarget = ((curBlurTarget + 1) % 6); }
GLuint                  GetBlurTarget0() { return (1 + ((curBlurTarget + 5) % 6)); }
GLuint                  GetBlurTarget1() { return (1 + ((curBlurTarget + 4) % 6)); }
GLuint                  GetBlurTarget2() { return (1 + ((curBlurTarget + 3) % 6)); }
GLuint                  GetBlurTarget3() { return (1 + ((curBlurTarget + 2) % 6)); }
GLuint                  GetBlurTarget4() { return (1 + ((curBlurTarget + 1) % 6)); }
GLuint                  GetBlurTarget5() { return (1 + ((curBlurTarget) % 6)); }
void                    *pixelData;
GLuint                  pixelDataSize;

//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

//Starts up SDL, creates window, and initializes OpenGL
bool init();

//Initializes rendering program and clear color
bool initGL();

//Input handler
int handleKeys(unsigned char key, int x, int y);

//Per frame update
void update();

//Renders quad to the screen
void render();

//Frees media and shuts down SDL
void close();

//The window we'll be rendering to
SDL_Window* gWindow = NULL;

//OpenGL context
SDL_GLContext gContext;

bool init()
{
	//Initialization flag
	bool success = true;

	//Initialize SDL
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
		success = false;
	}
	else
	{
		//Use OpenGL 3.3 core
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

		//Create window
		gWindow = SDL_CreateWindow("Pixel Buffer", 
                                    SDL_WINDOWPOS_UNDEFINED, 
                                    SDL_WINDOWPOS_UNDEFINED, 
                                    SCREEN_WIDTH, 
                                    SCREEN_HEIGHT, 
                                    SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
		if(gWindow == NULL)
		{
			printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
			success = false;
		}
		else
		{
			//Create context
			gContext = SDL_GL_CreateContext(gWindow);
			if(gContext == NULL)
			{
				printf("OpenGL context could not be created! SDL Error: %s\n", SDL_GetError());
				success = false;
			}
			else
			{
				//Initialize GLEW
				glewExperimental = GL_TRUE; 
				GLenum glewError = glewInit();
				if(glewError != GLEW_OK)
				{
					printf("Error initializing GLEW! %s\n", glewGetErrorString(glewError));
				}

				//Use Vsync
				if(SDL_GL_SetSwapInterval(1) < 0)
				{
					printf("Warning: Unable to set VSync! SDL Error: %s\n", SDL_GetError());
				}

				//Initialize OpenGL
				if(!initGL())
				{
					printf("Unable to initialize OpenGL!\n");
					success = false;
				}
			}
		}
	}
    // setup blur program
    blurProg = gltLoadShaderPairWithAttributes("blur.vs", "blur.fs", 2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_TEXTURE0, "texCoord0");

    // create blur textures
    glGenTextures(6, blurTextures);

    // pixel data
    pixelDataSize = (SCREEN_WIDTH * SCREEN_HEIGHT) * 3 * sizeof(uint8_t);
    void *data = malloc(pixelDataSize);
    memset(data, 0x00, pixelDataSize);
    for (int i = 0; i < 6; i++)
    {
        glActiveTexture(GL_TEXTURE1+i);
        glBindTexture(GL_TEXTURE_2D, blurTextures[i]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH, SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
    }

    // setup pixel buffer
    glGenBuffers(1, pixBuffObjs);
    glBindBuffer(GL_PIXEL_PACK_BUFFER, pixBuffObjs[0]);
    glBufferData(GL_PIXEL_PACK_BUFFER, pixelDataSize, pixelData, GL_DYNAMIC_COPY);

    // setup ortho matrix
    gltGenerateOrtho2DMat(SCREEN_WIDTH, SCREEN_HEIGHT, orthoMatrix, screenQuad);

    gltCheckErrors();

    return success;
}

bool initGL()
{
    //Success flag
    bool success = true;

    //Initialize clear color
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);

    // Enable depth testing
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_STENCIL_TEST);
    glEnable(GL_CULL_FACE);
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // Initialize the shader manger
    shaderManager.InitializeStockShaders();
    
    // set the object forward 
    viewFrame.MoveForward(4.0f);

    // Make the Torus
    gltMakeTorus(torusBatch, 0.8f, 0.25f, 52, 26);

	//Generate program
    diffuseLightShader = gltLoadShaderPairWithAttributes("glsl.vs", 
                                                         "glsl.fs", 
                                                         2, 
                                                         GLT_ATTRIBUTE_VERTEX, 
                                                         "vFragPos",
                                                         GLT_ATTRIBUTE_NORMAL,
                                                         "vNormal");

    locColor        =   glGetUniformLocation(diffuseLightShader, "diffuseColor");
    locLight        =   glGetUniformLocation(diffuseLightShader, "vLightPos");
    locMVP          =   glGetUniformLocation(diffuseLightShader, "mvpMatrix");
    locMV           =   glGetUniformLocation(diffuseLightShader, "mvMatrix");
    locNM           =   glGetUniformLocation(diffuseLightShader, "normalMatrix");

    viewFrustum.SetPerspective(35.0f, float(SCREEN_WIDTH) / float(SCREEN_HEIGHT), 1.0f, 100.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

    return success;
}

void SetupBlurProg(void)
{
    // Set the blur program to active
    glUseProgram(blurProg);

    // Set MVP matrix location
    locBlurMVP = glGetUniformLocation(blurProg, "mvpMatrix");

    // Setup the texture units for the blur targets, these rotate every frame
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit0"), GetBlurTarget0());
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit1"), GetBlurTarget1());
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit2"), GetBlurTarget2());
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit3"), GetBlurTarget3());
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit4"), GetBlurTarget4());
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit5"), GetBlurTarget5());
}

int handleKeys(unsigned char key, int x, int y)
{
	//Toggle triangle
	if(key == 'q')
	{
        return 1;
	}
    
	return 0;
}

void update()
{
	//No per frame update needed
}

void render()
{
	//Clear color buffer
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Prepare or matrices
    modelViewMatrix.PushMatrix(viewFrame);
        modelViewMatrix.Rotate(SDL_GetTicks() * 0.2f, 0.0f, 1.0f, 0.0f); // modified for SDL
        // light position
        GLfloat vEyeLight[] = { -100.0f, 100.0f, 100.0f };
        // our object color
        GLfloat vDiffuseColor[] = { 0.0f, 1.0f, 0.0f, 1.0f };
        //Bind program
        glUseProgram(diffuseLightShader);
        // send variables to shader
        glUniform4fv(locColor, 1, vDiffuseColor);
        glUniform3fv(locLight, 1, vEyeLight);
        glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
        glUniformMatrix4fv(locMV, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
        glUniformMatrix3fv(locNM, 1, GL_FALSE, transformPipeline.GetNormalMatrix());
        //Render
        torusBatch.Draw();
    modelViewMatrix.PopMatrix();

    // use pixel buffer object
    
    // First pack the buffer
    glBindBuffer(GL_PIXEL_PACK_BUFFER, pixBuffObjs[0]);
    glReadPixels(0, 0,SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);

    // Then unpack the buffer
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixBuffObjs[0]);
    glActiveTexture(GL_TEXTURE0 + GetBlurTarget0());
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, SCREEN_WIDTH, SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

    // ortho view
    projectionMatrix.PushMatrix();
        projectionMatrix.LoadIdentity();
        projectionMatrix.LoadMatrix(orthoMatrix);
        modelViewMatrix.PushMatrix();
            modelViewMatrix.LoadIdentity();
            glDisable(GL_DEPTH_TEST);
            SetupBlurProg();
            glUniformMatrix4fv(locBlurMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
            screenQuad.Draw();
            glEnable(GL_DEPTH_TEST);
        modelViewMatrix.PopMatrix();
    projectionMatrix.PopMatrix();
    // Advance to next blur frame
    AdvanceBlurTarget();
}

void close()
{
	//Deallocate program
	glDeleteProgram(diffuseLightShader);

	//Destroy window	
	SDL_DestroyWindow(gWindow);
	gWindow = NULL;

	//Quit SDL subsystems
	SDL_Quit();
}

int main(int argc, char* args[])
{
	//Start up SDL and create window
	if(!init())
	{
		printf("Failed to initialize!\n");
	}
	else
	{
		//Main loop flag
		bool quit = false;

		// Time variables
		unsigned int lastTime = 0, currentTime = 0;

		//Event handler
		SDL_Event e;
		
		//Enable text input
		SDL_StartTextInput();

		//While application is running
		while(!quit)
		{
			//Handle events on queue
			while(SDL_PollEvent(&e) != 0)
			{
				//User requests quit
				if(e.type == SDL_QUIT)
				{
					quit = true;
				}
				//Handle keypress with current mouse position
				else if(e.type == SDL_TEXTINPUT)
				{
					int x = 0, y = 0;
					SDL_GetMouseState(&x, &y);
					if (handleKeys(e.text.text[0], x, y))
					{
						quit = true;
					}
				}
			}
			//Render quad
			render();
			
			//Update screen
			SDL_GL_SwapWindow(gWindow);
		}
		//Disable text input
		SDL_StopTextInput();
	}

	//Free resources and close SDL
	close();

	return 0;
}

Answer:


Back to index