Ok, I have the current distance based LOD scheme set up in my hull shader. It works pretty well, but has some non-optimal aspects. cp[0], cp[1] and cp[2] are the corners of my triangle patch.
PatchConstants PatchHS(InputPatch<VertexOutput,10> cp, uint patchID : SV_PrimitiveID)
{
PatchConstants pt;
float3 mid0 = lerp(cp[1].PositionWorld,cp[2].PositionWorld,0.5f);
float3 mid1 = lerp(cp[2].PositionWorld,cp[0].PositionWorld,0.5f);
float3 mid2 = lerp(cp[0].PositionWorld,cp[1].PositionWorld,0.5f);
const float dMax = 250.0f;
float d = distance(mid0,vecEye.xyz);
pt.EdgeTess[0] = 12.0f * pow(saturate((dMax - d)/dMax),3);
d = distance(mid1,vecEye.xyz);
pt.EdgeTess[1] = 12.0f * pow(saturate((dMax - d)/dMax),3);
d = distance(mid2,vecEye.xyz);
pt.EdgeTess[2] = 12.0f * pow(saturate((dMax - d)/dMax),3);
d = distance(cp[9].PositionWorld,vecEye.xyz);
pt.InsideTess = 16.0f * pow(saturate((dMax - d)/dMax),2);
return pt;
}
I'm using the midpoint of my triangle patch edges to calculate distance to the camera. Visually, the need for more or less triangles is nowhere near linear in it's relationship to distance, so I am also applying an exponential curve that sort-of, kind-of helps. This scheme is an improvement over simply using fixed tessellation factors, but it seems that it should be possible to come up with something better. The following screenshot shows one of the weaknesses of a distance based scheme.
[attachment=15203:TessFactors.jpg]
You can see a mountain in the foreground and a valley between this mountain and other mountains in the background. The tiles in the valley are both relatively flat and also oblique to the camera so that they need very little tessellation, yet they are being rendered with more triangles than the mountains in the background that could actually use some extra triangles. Wasteful in the former case and sort of ugly in the latter.
Before I tried the distance scheme, I tried to tessellate based on the screen length of the respective patch edges, but I couldn't figure out how to get it working. Such a scheme would be much more efficient and would also preserve water tight stitching since neighbor edges would have the exact same length. Does anybody know how I can calculate that in the hull shader? I tried multiplying my corner vertices by my ProjectionView matrix and then measuring length, but I couldn't figure out what to do with the results of that calculation. How long is a pixel in my world? I have no idea. If an edge goes from one corner of the screen to the other, how long is that? 100? 0.01? I couldnt find a useful context for the distance between my transformed corner control points.