Shaders Overview - Part 3

Posted on 21 June 2013

In the previous part we went through the process of creating a simple "pass through" shader, one that did the basics, but in doing so it left a lot of unanswered questions. 

First, since a vertex program only works on a single point, how does this relate to the triangles being drawn?

Second, when we export a variable from each of these single vertices, how does a fragment shader get only one of them?

Lets take a look at a triangle we might draw. The Blue points are vertices, and the yellow point is the current pixel being rasterised by the shader. So how on earth does it all work? Be warned, this section is a little maths heavy, and although the calculations are fairly simple, how they interact can be confusing the first time you see them.

textured triangle

Well, in a word - interpolation. Each vertex is transformed by the vertex shader, as you would expect, but the ouputs of these are then interpolated as the hardware draws the triangle. Lets take a look a the left edge. If it starts at 100,10, and ends at 10,100, thats 90 backwards, by 90 downwards. Halfway would be 45 back and 45 down, giving has a center of 55,55 - as shown below.

Triangle Interpolation

On the right, it's a little more complicated, as we're not quite halfway down, but at line 55, the xcoordinate works out to 106.4285. This gives us a middle span from 55,55 over to 106,55 (rounded down). So this is the line we'll look at. Now.... halfway alone this line, is (106-55)/2 = 51, or 25.5 pixels along, so lets call this 25. Add that to the start of the line (55), we get 80. since it's a horizonal line and Y does not change, the middle of our line is 80,55. If you haven't done this kind of thing before, it can seem quite complicated, so I'd recommend reading over it a few times to try and understand it as much has you can.

Okay, so we have the X,Y pixel that's going to get drawn, so how does the UV's get calculated? Well, in much the same way. The numbers in brackets are the UV coordinates of this triangle (keeping them 0 and 1 to be simple). So we just have to run them through the interpolation in the same way as the coordinates did, and we'll get our new UV coordinates. 

So, for the left edge we start at (0,0) and endup at (1,0). As we're going 50% down this line, we do (1-0)/2 = 0.5, and (0-0)/2 = 0. So the left hand edge coordinate is (0.5,0). For the right edge, it's again, a little more complicated as the line is longer, and we have to find the 45th pixel down. so we start again at (0,0), and end up at (1,1) this time.

The full length of this line, or rather the number of pixels it steps down is 150-10=140. So we divide 1.0/140=0.00714285, which is how much we add on each step, and so to get the 45 pixel down, we simply calculate 0.00714285*45 = 0.3214. Normally, the hardware would start at 0,0 and then simply add on 0.00714285 each time it steps down a line, so as we're going down 45 lines, we just multiply by 45 to get there.

Okay, so for UVs, the line starts at (0.5,0) and ends at (0.3214,0.3214), and so to work out the halfway point, we just get the difference between them, and half it. (0.3214-0.5)=-0.1786. We then divide this by 2 and add to 0.5 which is the START of the line (-0.1786/2)+0.5=0.4107. For V we simply do the same. ((0.3214-0)/2)+0=0.1607.

This means the interpolated UV coordinates are (0.4107, 0.1607), and this is what is handed to the fragment shader, and while these numbers are far from exact, the method is sound.

So how does this all work together? Well.... we first write a vertex shader, and it transforms the input coordinates into something the hardware will use to interpolate the edges of the triangle, and from there the inner spans. Everything from the vertex shader goes through these interpolators, screen coordinates, texture coordinates, colours - even paramaters which the hardware knows nothing about, all are interpolated and then passed into the fragment shader.

Now the final piece of the puzzle. How does it get so damn fast? Well, since each program works in isolation, and works from interpolated values - what's to say that the hardware doesn't just run multiple programs at once? In fact, when you buy a graphics card these days, what your actually paying for (aside from more RAM) is how many of these programs can run together. Cheaper cards will run a few, perhaps around 10 to 20, while top of the range cards may run thousands! As you can imagine, that gives a serious performance boost in todays shader hungry world.

And so there we have it, this is how the hardware runs your programs, and links them together. This info isn't vitial to know, but it seriously helps understanding knowing how interpolation works from the vertex into the fragment shaders.

In the next part, we'll take a look at the new primitive builder, which lets you create your own vertex formats, and allows you to render pretty much whatever you want, however you want.



Continue reading...

Shaders Overview - Part 4 


Back to Top