在 Tessellation Control Shader (TCS) 中,您可以读取输入补丁基元中的每个顶点。虽然这在纸面上听起来不错,但如果您尝试计算补丁的最大边长,这实际上意味着在每次 TCS 调用时迭代补丁中的每个顶点,这并不是特别有效。
相反,在对象空间中预先计算补丁的中心并确定紧密绑定补丁的球体的半径可能更实用。将此边界信息存储为每个顶点的额外vec4
属性,如下所示打包。
计算 NDC 空间中补丁最长长度的 TCS 的伪代码
#version 420
uniform mat4 model_view_proj;
in vec4 bounding_sphere []; // xyz = center (object-space), w = radius
void main (void)
{
vec4 center = vec4 (bounding_sphere [0].xyz, 1.0f);
float radius = bounding_sphere [0].w;
// Transform object-space X extremes into clip-space
vec4 min_0 = model_view_proj * (center - vec4 (radius, 0.0f, 0.0f, 0.0f));
vec4 max_0 = model_view_proj * (center + vec4 (radius, 0.0f, 0.0f, 0.0f));
// Transform object-space Y extremes into clip-space
vec4 min_1 = model_view_proj * (center - vec4 (0.0f, radius, 0.0f, 0.0f));
vec4 max_1 = model_view_proj * (center + vec4 (0.0f, radius, 0.0f, 0.0f));
// Transform object-space Z extremes into clip-space
vec4 min_2 = model_view_proj * (center - vec4 (0.0f, 0.0f, radius, 0.0f));
vec4 max_2 = model_view_proj * (center + vec4 (0.0f, 0.0f, radius, 0.0f));
// Transform from clip-space to NDC
min_0 /= min_0.w; max_0 /= max_0.w;
min_1 /= min_1.w; max_1 /= max_1.w;
min_2 /= min_2.w; max_2 /= max_2.w;
// Calculate the distance (ignore depth) covered by all three pairs of extremes
float dist_0 = distance (min_0.xy, max_0.xy);
float dist_1 = distance (min_1.xy, max_1.xy);
float dist_2 = distance (min_2.xy, max_2.xy);
// A max_dist >= 2.0 indicates the patch spans the entire screen in one direction
float max_dist = max (dist_0, max (dist_1, dist_2));
// ...
}
如果您通过此 TCS 运行您的第 4个图表,您应该得出一个max_dist
非常接近2.0的值,这意味着您需要尽可能多的细分。同时,第三张图中球体外围的许多补丁将接近0.0;他们不需要太多的细分。
这不能正确处理部分补丁在屏幕外的情况。您需要将 NDC 极端值限制为 [ -1.0 , 1.0 ] 以正确处理这些情况。看起来麻烦多于它的价值。