Putting a calculation in the vertex shader vs. pixel shader

Started by
4 comments, last by MJP 9 years, 4 months ago

Hi,

I'm having a bit of trouble getting my head around how interpolation works in HLSL when sending values from the vertex shader to the pixel shader. I've attached a shader I'm working with at the moment for rendering a water plane:

[attachment=24796:water_shader_snippet.txt]

So I understand that HLSL will interpolate everything I've put in the vertex shader across the face of the current triangle when it is sent to the pixel shader, so I was wondering, could I move some of my other calculations across into the vertex shader? For example, my 'attenuation' calculation uses LightDirTS as a variable - would it still get interpolated properly if I move it over into the vertex shader and passed it in? Same with 'projTexCoord'.

Likewise I understand that things like 'reflectionVector' and 'specularLightingFactor' can't be in the VS because they are calculated using texture values (which are sampled per-pixel).

Can anyone help me understand exactly what should and shouldn't be in the vertex shader?

Thanks :)

Advertisement

Think about these calculations as functions that you can plot on graph paper. Make the X axis the incoming value and the Y axis the result, or vice-versa. If you can plot it as a straight line, then the calculation can be in the vertex shader, because values going from the vertex shader to the pixel shader are linearly interpolated. If it plots as a curve, a wave, or anything but a straight line, then it needs to go in the pixel shader (sometimes an intermediate calculation can be per-vertex but the final calculation is per-pixel).

Note that I said "can be in the vertex shader", not "should be in the vertex shader". This is because there is no one rule to rule them all. What you're aiming to achieve is a good balance of work so that your GPU is kept busy. The days when there were separate shader stages are (thankfully) behind us, but you still need to balance things because otherwise you could end up doing a calculation tens of thousands of times versus thousands of times (or some similar order of magnitude difference).

This is something I can't give you one answer to, because it is going to be different for different programs. A rule of thumb is that you can normally expect there to be more pixels than vertices, but that doesn't always hold true (also beware of passing too many interpolants between shader stages). So you really do need visibility into your program's behaviour, and that means using a profiling tool to collect real data on how your program works, then making judgements based on those results.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

What mhagain said is exactly right: if you move a calculation to the vertex shader, you're only going to get the same result if the value is the result of a linear function. So for your attenuation example, it would depend on how you calculate your attenuation factor. If your factor is linear like this:


float attenuation = (100.0f - lightDistance);

then you can use linear interpolation and get the same result. If it's non-linear, like this:


float attenuation = 1.0f / (lightDistance * lightDistance);

then interpolation won't give you the same results.

lightDistance itself isn't linear though (abs(sqrt(xx+yy+zz))).

The easily mentally verifiable example I use is a massive triangle, say the size of a football field with me (a small camera) and a small light standing in the middle of the triangle.

Using vertex based calculations, maybe it's 50m to each vertex. Interpolate these 3 values and we get an interpolated result of 50m.
However, I'm actually standing 1m above the triangle...
Obviously vertex calculations plus interpolation are not correct for distance(as earlier- distance is not a linear function)


So I understand that HLSL will interpolate everything I've put in the vertex shader across the face of the current triangle when it is sent to the pixel shader,


Just to clarify ( mhagain already mention this ), but I think once you understand this then all that was mentioned before will make sense. HLSL does not interpolate everything in the vertex shader. Values passed from the vertex to the frapgment shader are interpolated, ie. vertex shader output only.

lightDistance itself isn't linear though (abs(sqrt(xx+yy+zz))).

The easily mentally verifiable example I use is a massive triangle, say the size of a football field with me (a small camera) and a small light standing in the middle of the triangle.

Using vertex based calculations, maybe it's 50m to each vertex. Interpolate these 3 values and we get an interpolated result of 50m.
However, I'm actually standing 1m above the triangle...
Obviously vertex calculations plus interpolation are not correct for distance(as earlier- distance is not a linear function)

Yes that's correct, and a terrible example on my part. I must have turkey brain. sad.png

This topic is closed to new replies.

Advertisement