Shaped Sprites

Notes:

Modify the last exercise to shape our particles.

Vertex Shader:

// Star vertex shader
#version 330 core

in vec4 vVertex;
in vec4 vColor;

uniform mat4 mvpMatrix;
uniform float timeStamp;

out vec4 vStarColor;

void main(void)
{
    vec4 vNewVertex = vVertex;
    vStarColor = vColor;

    // Offset by running time, makes it move close
    vNewVertex.z += timeStamp;

    // If out of range, adjust
    if (vNewVertex.z > -1.0)
    {
        vNewVertex.z -= 999.0;
    }
    gl_PointSize = 30.0 + (vNewVertex.z / sqrt(-vNewVertex.z));

    // If they are very small, fade them up
    if (gl_PointSize < 4.0)
    {
        vStarColor = smoothstep(0.0, 4.0, gl_PointSize) * vStarColor; 
    }

    // Transform the geometry
    gl_Position = mvpMatrix * vNewVertex;
}

Fragment Shader:

// Star fragment shader
#version 330 core

out vec4 vFragColor;

in vec4 vStarColor;

uniform sampler2D starImage;

void main()
{
    vec2 p = gl_PointCoord * 2.0 - vec2(1.0);
    if (dot(p, p) > sin(atan(p.y, p.x) * 5.0))
    {
        discard;
    }
    vFragColor = texture(starImage, gl_PointCoord) * vStarColor;
}

Source:

// ShapedPoint.cpp
// Modify the last exercise to shape our particles

#include <GLTools.h>	// OpenGL toolkit
#include <GLFrustum.h>
//#include <GLBatch.h>

#include <math.h>
#include <stdlib.h>

#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <GL/glu.h>

#define NUM_STARS 1000

GLFrustum           viewFrustum;
GLBatch             starsBatch;

GLuint              starFieldShader;

GLint               locMVP;
GLint               locTimeStamp;
GLint               locTexture;

GLuint              starTexture;

// time variables
float               oldTime = 0;
float               currentTime = 0;
float               fTime = 0;

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

// Load a TGA as a 2D Texture. Completely initialize the state
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
	GLbyte *pBits;
	int nWidth, nHeight, nComponents;
	GLenum eFormat;
	
	// Read the texture bits
	pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
	if(pBits == NULL) 
		return false;
	
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
	
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
    
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
				 eFormat, GL_UNSIGNED_BYTE, pBits);
	
    free(pBits);
    
    if(minFilter == GL_LINEAR_MIPMAP_LINEAR || 
       minFilter == GL_LINEAR_MIPMAP_NEAREST ||
       minFilter == GL_NEAREST_MIPMAP_LINEAR ||
       minFilter == GL_NEAREST_MIPMAP_NEAREST)
        glGenerateMipmap(GL_TEXTURE_2D);
    
	return true;
}

// This function does any needed initialization on the rendering
// context. 
bool SetupRC(void)
{
    bool success = true;

    // Background
    glClearColor( 0.0f, 0.0f, 0.0f, 1.0f);

    GLfloat fColors[4][4] = {{ 1.0f, 1.0f, 1.0f, 1.0f},     // White
                             { 0.67, 0.6f, 0.8f, 1.0f},     // Blue
                             { 1.0f, 0.5f, 0.5f, 1.0f},     // Reddish
                             { 1.0f, 0.8f, 0.6f, 1.0f}};    // Orange

    starsBatch.Begin(GL_POINTS, NUM_STARS);
    for (int i = 0; i < NUM_STARS; ++i)
    {
		int iColor = 0;		// All stars start as white

		// One in five will be blue
        if(rand() % 5 == 1)
        {
			iColor = 1;
        }
		// One in 50 red
		if(rand() % 50 == 1)
        {
			iColor = 2;
        }
		// One in 100 is amber
		if(rand() % 100 == 1)
        {
			iColor = 3;
        }
		starsBatch.Color4fv(fColors[iColor]);
			    
		M3DVector3f vPosition;
		vPosition[0] = float(3000 - (rand() % 6000)) * 0.1f;
		vPosition[1] = float(3000 - (rand() % 6000)) * 0.1f;
		vPosition[2] = -float(rand() % 1000)-1.0f;  // -1 to -1000.0f

		starsBatch.Vertex3fv(vPosition);
    }
    starsBatch.End();

    starFieldShader = gltLoadShaderPairWithAttributes("SpaceFlight.vs", "SpaceFlight.fs", 2, GLT_ATTRIBUTE_VERTEX, "vVertex",
                                                      GLT_ATTRIBUTE_COLOR, "vColor");
    
    locMVP          = glGetUniformLocation(starFieldShader, "mvpMatrix");
    locTexture      = glGetUniformLocation(starFieldShader, "starImage");
    locTimeStamp    = glGetUniformLocation(starFieldShader, "timeStamp");

    glGenTextures(1, &starTexture);
    glBindTexture(GL_TEXTURE_2D, starTexture);
    LoadTGATexture("star.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
    
    viewFrustum.SetPerspective(35.0f, float(SCREEN_WIDTH)/float(SCREEN_HEIGHT), 1.0f, 1000.0f);

    return success;
}

// Called to draw scene
void RenderScene(void)
{
    // Clear the window
    glClear(GL_COLOR_BUFFER_BIT);
        
    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE);

    // Let the vertex program determine the size of point
    glEnable(GL_PROGRAM_POINT_SIZE);
    
    glUseProgram(starFieldShader);
    glUniformMatrix4fv(locMVP, 1, GL_FALSE, viewFrustum.GetProjectionMatrix());
    glUniform1i(locTexture, 0);

    // Time goes from 0.0 to 999.0 and recycles
    oldTime = currentTime;
    currentTime = SDL_GetTicks();
    fTime += currentTime - oldTime;
    if (fTime > 999.0f)
    {
        fTime = 0;
    }
    glUniform1f(locTimeStamp, fTime);

    starsBatch.Draw();
}

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

//OpenGL context
SDL_GLContext gContext;

bool init()
{
    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("Shaped Sprites", 
                                    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(!SetupRC())
				{
					printf("Unable to initialize OpenGL!\n");
					success = false;
				}
			}
		}
	}
    return success;
}

void ShutdownRC(void)
{
    glDeleteTextures(1, &starTexture);

    glDeleteProgram(starFieldShader);

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

    SDL_Quit();
}

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

		//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)
			{
				switch( e.type )
				{
				    /* Look for a keypress */
				    case SDL_KEYDOWN:
					/* Check the SDLKey values and move change the coords */
					switch( e.key.keysym.sym )
					{
					    case SDLK_q:
						quit = true;
					    default:
						break;
					}
					break;
				    default:
					break;
				}
				//User requests quit
				if (e.type == SDL_QUIT)
				{
				    quit = true;
				}
			}
			//Render
			RenderScene();
			
			//Update screen
			SDL_GL_SwapWindow(gWindow);
		}
		//Disable text input
		SDL_StopTextInput();
	}
	//Free resources and close SDL
    ShutdownRC();
        
    return 0;
}

Answer:


Back to index