繁体   English   中英

更好地控制OpenGL中的Tessellation?

[英]Better control over Tessellation in OpenGL?

我花了一天时间研究一个OpenGL应用程序,它将对网格进行细分并应用镜头失真。 目标是能够为各种不同的镜头渲染广角镜头。 到目前为止,我已经让着色器正确应用了失真,但我一直在按照我想要的方式控制曲面细分。 现在我的曲面细分控制着色器只是将一个三角形分成一组较小的三角形,然后我在曲面细分评估着色器中应用了镜头失真。

我采用这种方法的问题是,当我在场景中有非常大的三角形时,它们往往需要更多的翘曲。 这意味着他们需要进行更多镶嵌,以确保获得良好的效果。 遗憾的是,我无法在“顶点着色器”或“曲面细分控制着色器”中计算三角形的大小(在屏幕空间中),但我需要在“细分控制”着色器中定义曲面细分量。

那么我的问题是,有没有办法在OpenGL的可编程管道中保存整个原语,计算一些关于它的指标,然后用这些信息来控制曲面细分?

为清晰起见,这里是问题的一些示例图像......

小三角形看起来不错

图1(上图):每个红色或绿色方块最初是2个三角形,这个例子看起来很好,因为三角形很小。

大三角看起来很糟糕

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

小三角形再次

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

真的很大的三角形坏

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

在曲面细分控制着色器(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]妥善处理这些情况。 看起来比它值得更麻烦。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM