我花了一天的时间在OpenGL应用程序上工作,该应用程序将细分网格并应用镜头变形。目的是能够为各种不同的镜头渲染广角镜头。到目前为止,我已经使着色器正确地应用了变形,但是我一直在以自己想要的方式控制镶嵌的问题。现在,我的镶嵌细分控制着色器将一个三角形分解为一组较小的三角形,然后在镶嵌细分评估着色器中应用镜头失真。

这种方法的问题在于,当场景中有非常大的三角形时,它们往往需要更多的变形。这意味着需要对它们进行细分,以确保获得良好的外观。不幸的是,我无法在“顶点着色器”或“镶嵌细分控制”着色器中计算三角形的大小(在屏幕空间中),但是需要在“镶嵌细分控制”着色器中定义镶嵌数量。

然后我的问题是,是否有某种方法可以在OpenGL的可编程管线中保留整个原语,计算有关它的一些度量,然后使用该信息来控制镶嵌?

为了清晰起见,下面是该问题的一些示例图片...



图1(上图):每个红色或绿色正方形最初都是2个三角形,此示例看起来不错,因为三角形很小。



图2(上图):每个红色或绿色区域最初都是2个三角形,此示例看起来很糟糕,因为三角形很小。



图3(上图):另一个示例,带有小三角形,但网格大得多。注意边缘上有多少东西弯曲。细分水平为4时仍然看起来不错。



图4(上):另一个带有大三角形的示例,仅显示中心4列,因为如果存在更多列,则图像将难以理解。这说明了很大的三角形不能很好地细分。如果我将镶嵌效果设置得很高,那么效果很好。但是,然后我也在较小的三角形上执行大量的细分。

最佳答案

在Tessellation Control Shader(TCS)中,您具有对输入面片基元中每个顶点的读取权限。虽然在纸面上听起来不错,但是如果您尝试计算补丁的最大边缘长度,则实际上意味着在每次TCS调用时都对补丁中的每个顶点进行迭代,但这并不是特别有效。
取而代之的是,在对象空间中预先计算补丁的中心并确定紧密包围补丁的球体的半径可能更实用。将此边界信息存储为每个顶点的额外vec4属性,如下所示打包。
TCS的伪代码,用于计算NDC空间中补丁的最长长度

#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],才能正确处理这些情况。看来麻烦多于其应有的价值。

关于c - 更好地控制OpenGL中的镶嵌 segmentation ?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27652769/

10-09 18:16