Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm not sure how possible this is, but I'm trying to use a fragment shader to draw a portion of a texture in the middle of a quad. This is all 2D. The quads consist of four vertices from (0, 0) to (width, height). The modelview matrix is transformed to position the quads.

I have a sprite sheet of 32x32 icons and a 32x32 quad that one of the icons is mapped to. In a vertex shader, I'm creating a 2 pixel 'border' around the quad by moving it's vertices out by 2 pixels. In a fragment shader, I want to display the texture with it's original size, in it's original position; basically, there should be no visible difference between the original 32x32 quad and the 36x36 quad. The result should be an invisible 'border'.

The only solution I can come up with is calculating the window coordinate for the corner of the quad in the vertex shader, then passing it to the fragment shader and subtracting it from gl_FragCoord, in order to get the position of each pixel relative to the corner of the quad. With this information, I can display the texture in the center of the quad, with it's original size.

Is there any easier way to accomplish this?

share|improve this question
add comment

2 Answers 2

up vote 3 down vote accepted

I can't try it out right now, but try this:

In the vertex shader take the value of gl_VertexID and give it to the fragment shader in a flat attribute (flat so it doesn't interpolate). Also push the untransformed vertex, also flat, and the interpolated but untransformed vertex (non-flat) to the fragment shader.

In the fragment shader look at the value of the vertex id attribute. You can possibly find out in which corner of the quad you are by looking at this value. Then you can use a simple if discard the border frames:

if(vertexIDAttribute indicates that we are in the top left corner
   && interpolatedVertex.x < uninterpolatedVertex.x + 2
   && interpolatedVertex.y < uninterpolatedVertex.y + 2

   || vertexIDAttribute indicates that we are in the top right corner
   && interpolatedVertex.x > uininterpolatedVertex.x - 2
   && interpolatedVertex.y < uninterpolatedVertex.y + 2
   // etc
) {
    discard;
} else {
    render the fragment
}

(old answer is below for history)


One solution I can think of is to calculate the ratio of the size of the bordered quad by the size of the unbordered quad and transform the texture matrix accordingly. For example,

// quadSize would be 32 in your case
float border = 2.0f;
float scale = (quadSize + border) / quadSize;

glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glScalef(scale, scale, 1.0f);
glTranslatef(-border/2, -border/2, 0.0f);
glMatrixMode(GL_MODELVIEW);

(You should store that matrix somewhere so you don't have to calculate it every frame. You can also precalcuate it if the border size stays the same.)

This scales and positions the texture correctly. However, this leaves a 2px size border around the texture, which you can easily discard in your fragment shader. Simply export an uniform describing the quad rectangle and check if the fragment is in the "border". If yes, discard the fragment, else render it just like you did before.

Edit: Copy/Paste mess up, it should be (quadSize+border) / quadSize, not vice-versa.

share|improve this answer
    
Sorry, I should have clarified, I'm working around a third party library and would like to completely avoid doing it in the application, unless it's not possible to easily do it in a shader. –  rawrgoesthelion Sep 18 '11 at 19:15
    
I edited the answer to include a somewhat hackish possibility which I can't try out right now. –  Raphael R. Sep 18 '11 at 19:49
    
Thanks. I've also tried this, but a few problems: I can't use flat varying variables for some reason (my OpenGL version should support them, but I get errors when I declare them), and the value of gl_VertexID is 0 for every vertex. –  rawrgoesthelion Sep 18 '11 at 20:29
    
Ah, I managed to solve it with something similar. Thanks for the help. –  rawrgoesthelion Sep 18 '11 at 22:21
add comment

Presumably the simplest way to do this would be to leave the sprite alone, and make the border out of 4 additional quads that you add around the edges.

However, if you can't add additional quads, you should be able to do this by manipulating the UVs of the quad. When you push the vertices out by two pixels, also push the UVs out by two pixels as well.

If your sprites are packed together very tightly, this could cause problems with neighboring sprites in the sheet becoming visible in the borders. You could fix this up in the shader by storing the original UV rectangle (before the 2px expansion) and sending it down to the fragment shader. Then check to see whether the interpolated expanded UVs fall outside this rectangle, and if so, discard the pixel (or replace the color with black, or whatever you want to do in the border). This'll make the shader more expensive, of course.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.