Drawing edge on a wall

Let me first say I’m very much the newbie regarding GLSL. What I’m trying to do is use a shader to put an “edge” on a wall. It’s a single tri-strip, all one height and at 90 degrees to the ground which is flat i.e. Y=0.

So I want to put a different color along the top, bottom and two sides of the quad formed by two triangles in the strip. Or I’d settle for a vertical line at a set distance since I’m not sure the other is possible (but what do I know).

I’ve been mucking about with the brick shader, but I’m getting nowhere. Anyone got any pointers?

The best way to do it is with texture coordinates.


1,0 _________ 1,1
   |\   |\   |
   | \  | \  |
   |  \ |  \ |
   |___\|___\|
0,0           0,1

You then look at the texture coordinates - kinda like this (I might have gotten U and V confused…)


if(texcoord.u < 0.1 || texcoord.u > 0.9)
{
  draw_top_bottom_stripe()
}

if(texcoord.v < 0.1 || texcoord.v > 0.9)
{
  draw_left_right_stripe()
}

This will, naturally, scale the stripes based on the size of the wall. If you want to readjust that, you’ll need to pass the size of the wall into the shader as a uniform.

You can’t use a tiling texture this way, though - you’ll need to use a uniform (could be the same one described in the previous paragraph) as a texcoord multiplier to get the tiling to work right. The other option is to pass in multiple sets of texture coordinates - one for the stripe, and one for the tiled texture.

So does that mean I have to store texture coords for all my tri-strip vertices? I wanted to avoid that mainly because I had a notion that I shouldn’t need to.

You can compute texture coordinates in a vertex shader if you want to - if you pass in the length and height of the wall, you can compute how far along the wall the vertex is, and use that as a texture coordinate.

Of course! Thanks for the help.

How about using GL_LINES? You can also set the line-width to 2-5px.

I tried that, but I get z-fighting since the wall and line use the same points.

One way to solve it is with polygon-offset (z bias).
Another is to draw the each triangle that is near an edge with a shader, where you pass to the three vertices the same three attributes. Those attribute will contain… the 3D positions of the 3 vertices of the triangle. This is done to let your vtx shader and frag shader actually know the triangle they’re drawing. Also, a fourth same attribute per vertex to serve as a flag which of the 3 edges are to be drawn. Then, in the frag shader you calculate the minimum distance between the current pixel’s position and the 3 edges. And draw with your edge-color, but change the alpha value to reflect whether the edge is 1px near an edge or not (use alpha-test or KIL/discard). To convert clipspace coords to screenspace, you’ll need the screen-size as a uniform vec2.

I’ve done something like that for edge antialiasing, here is some useful code to use straight away:


varying vec2 vert0,vert1,vert2; // these are those 3 attributes
varying vec3 gcolor;

uniform float IsLine;

float linedist(vec2 v0,vec2 v1,vec2 v2){ // v0 is the point,   the line is given by v1:v2

	// |(x2-x1)(y1-y0)-(x1-x0)(y2-y1)|
	// -------------------------------
	// sqrt( (x2-x1)^2 + (y2-y1)^2)

	vec2 d21 = v2-v1;
	vec2 d10 = v1-v0;
	
	return -((d21.x*d10.y)-(d10.x*d21.y)) / length(d21); // !! toy around with the "-" sign in the beginning of this formula
}


void main(){
	float alpha=1;

	if(IsLine>0){ // this is true when drawing the edges
		float d0,d1,d2;
		d0 = linedist(gl_FragCoord.xy,vert0,vert1);
		d1 = linedist(gl_FragCoord.xy,vert1,vert2);
		d2 = linedist(gl_FragCoord.xy,vert2,vert0);
		 

		d0 = min(d0,d1);
		d0 = min(d0,d2);

		
		alpha=d0/1.9+0.7;

		
		if(alpha>=1)discard;
		if(alpha<0.01)discard;		
	}
	gl_FragColor = vec4(gcolor,alpha);
}

Another way to draw edges is by all those methods of cel-shading anime games. Toying with flipping the backface culling, enlarging polygons, … I can’t provide pointers there, search for some tutes.

Thanks for all the help. I’ve got it working, but now I’ve got a similar problem for the top of the wall (it’s a maze I’m drawing). For example


             |     |
            d|     |
c-------------     |
 |---___           |
 |      ---___     |
b-------------     |
            a|     |
             |     |

So for the triangle a,c,b I don’t want to draw an edge on a->c and for the a,d,c I only want to draw an edge on d->c.

a fourth same attribute per vertex to serve as a flag which of the 3 edges are to be drawn

@Ilian: How would I know which edge was being drawn to actually use the flag? Sorry I’m very new to shaders.

Or is some other approach? For example I could create a line loop of the top of the wall and use two passes, one for the triangles and then another for the loop?

Thinking about it some more could I pass in the sides to draw in terms of limits on the texture coords?

That “fourth same attribute”, I’m afraid will have to be somehow manually or procedurally generated.
Procedurally, you probably just need to mark which edges have been used only once, and if used twice - measure the angle between the two triangles that use it (flat - no edge, 90 degrees - edge).

The GL_LINES method will be least wasteful and fastest, you just need to apply some useful z-bias. Those lines again can be generated with the “used only once” method.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.