a little geometry shader demo

Just playing around with Geometry Shaders and happened on something simple+eye-fun enough that might be a nice demo for people. The shader itself is pretty simple. The idea is, basically, get a point in space, and generate a triangle for it along with appropriate texture coordinates for each point.

  
  
// this will be passed in to use as rotations  
uniform float rot;  
// this is our max image height/width. could hard coded  
uniform float imgWidth, imgHeight;  
  
// this is what we'll give to each vertex that we output: info on which part of the texture it should use  
// notice the "out", that means each vertex shader that gets info from this geom shader will get one of these  
// and can use it with "varying vec2 txtCoords"  
varying out vec2 txtCoords;  
  
void main()  
{  
	// just make the positions a little more interesting  
	float cosX = (cos(rot) * imgWidth) * 0.5;  
	float sinY = (sin(rot) * imgHeight) * 0.5;  
	  
// this is the position of the particle passed in. I'm drawing this with points, so it only has a length of 1  
// b/c a point has only 1 vertex. we're copying the positionIn to the position that we'll output  
	gl_Position = gl_PositionIn[0];  
	// now modify our output position a little  
	gl_Position.x += cosX;  
// make good texture coords for it (i.e. bigger than 0 and less than the image height/width and remember that  
// each output vertex will need a tex coord  
	txtCoords.x = imgWidth - clamp(gl_Position.x, 0., imgWidth);  
	txtCoords.y = imgHeight - clamp(gl_Position.y, 0., imgHeight);  
// now spit out the vertex  
	EmitVertex();  
// repeat 2x for the other points of the triangle  
	gl_Position = gl_PositionIn[0];  
	gl_Position.x += cosX;  
	gl_Position.y += sinY;  
  
	txtCoords.x = imgWidth - clamp(gl_Position.x, 0., imgWidth);  
	txtCoords.y = imgHeight - clamp(gl_Position.y, 0., imgHeight);  
  
	EmitVertex();  
  
	gl_Position = gl_PositionIn[0];  
  
	gl_Position.x -= cosX;  
	gl_Position.y -= sinY;  
  
	txtCoords = vec2(gl_Position.x, gl_Position.y);  
	txtCoords.x = imgWidth - clamp(gl_Position.x, 0., imgWidth);  
	txtCoords.y = imgHeight - clamp(gl_Position.y, 0., imgHeight);  
// finally we're all done, so last vertex  
	EmitVertex();  
// and now finish the primitive. you could think of this like glEnd()  
	EndPrimitive();  
}  
  

The rest is very straightforward. The fragment shader uses the txtCoords to set the pixel color from the texture:

  
  
varying vec2 txtCoords;  
uniform sampler2DRect tex;  
  
void main()  
{  
	gl_FragColor = texture2DRect(tex, txtCoords.xy);  
}  
  

and I initialize the shaders uniforms like so:

  
	glPushMatrix();  
	glTranslatef(ofGetWidth()/2, ofGetHeight()/2, 0);  
	glRotatef(rot, 0, 1, 1);  
	  
	grab.getTextureReference().bind();  
	  
	fragmentator.begin();  
	fragmentator.setUniform1f("rot", ofGetElapsedTimef());  
	fragmentator.setUniform1f("imgWidth", (float) vidWidth);  
	fragmentator.setUniform1f("imgHeight", (float) vidHeight);  
  
	glBegin(GL_POINTS);  
	  
	vector<coord>::iterator it = coords.begin();  
	while(it != coords.end()) {  
		glVertex3f( it->pos->x, it->pos->y, it->pos->z);  
		glTexCoord2f(it->tx->x, it->tx->y);  
		++it;  
	}  
	  
	glEnd();  
	grab.getTextureReference().unbind();  
	fragmentator.end();  
	  
	glPopMatrix();  

Screenshot and source are attached. Have fun!

gsDemo.zip

1 Like