曲面细分优化[OpenGL]

时间:2013-12-05 21:59:00

标签: performance opengl tessellation

地形细分: 我正在使用剪贴图视锥体剔除和曲面细分着色器渲染我的地形。现在为了更好地提高性能,我想以更有效的方式使用一些镶嵌着色器。我的目标是实现相当高的(~100 FPS)帧速率和良好的视觉质量,因此我将结合3个曲面细分因子,曲面细分贴图,视图相关(每边缘像素)曲面细分和轮廓曲面细分。

我的想法是加权平均值:

tessfac = tesscoeff*(w1*tessmapfactor+w2*silhtessfactor+w3*ppetessfactor)/(w1+w2+w3);

3个因子在0 ... 1之间变化,而tesscoeff也可以是一个统一来调整水平。我有地图和边缘半径因子但是......

剪影: 如何在使用简单y(x,z)函数描述的网格上找到轮廓补丁?我正在使用vertex-texture-fetch,所以我知道相邻的顶点/法线。如果我使用四边形补丁而不是三角形,或者它不会让它更难找到它,这是一个问题吗?

(编辑回到补丁) Backpatch剔除:我遇到的另一个问题是背面剔除。正如我所说,我正在使用四边形补丁,所以人们可能不会躺在飞机上。使用三角形,我会将法线与眼睛方向进行比较,但在四边形上我不能,或者不知道该怎么做。

遮挡剔除:我使用几何剪贴图渲染地形,使用算法:

foreach(LOD)
    foreach(quarter)
        foreach(quad in quarter) //I mean x+z+, x-z+, x-z- and x+z- by quarters
            quad.clipFrustum();
            if(inFrustum) quad.render();
        endloop
    endloop
endloop

我有一个单一的顶点缓冲区用于简单的n*n四方形混乱。我有4个索引缓冲区用于此网格,一个用于此四边形的每个象限。对于LOD=0我渲染中心/左下角四边形,而对于其他级别我只渲染L形混乱与其他3 (顶部,顶部,左边)< / em>象限,按pow(2,LOD)缩放。然后使用常量(网格尺度)缩放整个网格。

由于整个网格位于摄像机前面的每一帧,因此网格总是从视图原点按象限呈现象限。也许它可以用于在曲面细分控制着色器中进行某些剔除,例如 early-z 遮挡

我正在寻找一些关于这些的指针,因为我发现的是一些没有太多技术背景的NVIDIA / AMD论文。 http://www.geeks3d.com/20101201/amd-graphics-blog-tessellation-for-all/完整文章的链接也被破坏了......(来自这篇文章:OpenGL Low-Level Performance Questions

1 个答案:

答案 0 :(得分:3)

您可以使用以下内容剔除三角形(3分),

float3 vEdge0 = patch[1].PosW - patch[0].PosW;
float3 vEdge1 = patch[2].PosW - patch[0].PosW;

float3 vFaceNormal0 = normalize(cross(vEdge1, vEdge0));
float2 vView0 = normalize(patch[0].PosW - gEyePosW);

if (dot(vView0, vFaceNormal0) < -0.25f)
{
    pt.EdgeTess[0] = 0.0f;
    pt.EdgeTess[1] = 0.0f;
    pt.EdgeTess[2] = 0.0f;

    pt.InsideTess = 0.0f;

    return pt;
}

您应该能够通过形成4个三角形来剔除补丁,如[\](从左上角到右下角的2个三角形)和[/](从右上角到左下角的2个三角形)从4个角点补丁和如果所有点(vView,vFaceNormal)&lt; -0.25f,可以很好地说贴片背离用户的眼睛。但这是平均值的近似值(角点处的4个三角形)。根据您的补丁大小,以及您在补丁中发生了多少疯狂的东西(山脉和山谷),这可能不适用于所有情况,这可能是网络上没有太多信息的原因。你只需要测试一下。

我会说你甚至可以更进一步,如果由于某种原因你看到这在你的所有情况下都不起作用并且绝对想要在船体着色器中剔除你可以在HeightMap中作为纹理和样本传递更多的三角形(比如得到补丁的中间点)使[x]得到4个以上的三角形,甚至[*]再得到8个三角形。

在没有大量工作的情况下完成同样事情的更安全的方法是截止剔除,通过你的边界相机平面的平面并检查补丁的边界框。这是着色器代码;

float3 vMin = float3(patch[0].PosW.x, minY, patch[0].PosW.z);
float3 vMax = float3(patch[3].PosW.x, maxY, patch[3].PosW.z);

if (!IntersectsOrContainsBoundingBox(vMin.x, vMin.y, vMin.z, vMax.x, vMax.y, vMax.z))
{
    pt.EdgeTess[0] = 0.0f;
    pt.EdgeTess[1] = 0.0f;
    pt.EdgeTess[2] = 0.0f;
    pt.EdgeTess[3] = 0.0f;

    pt.InsideTess[0] = 0.0f;
    pt.InsideTess[1] = 0.0f;

    return pt;
}

bool IntersectsOrContainsBoundingBox(float minWidth, float minHeight, float minDepth, float maxWidth, float maxHeight, float maxDepth)
{
// check box outside/inside of frustum
for (int i = 0; i < 6; i++)
{
    int output = 0;
    output += (((gWorldFrustumPlanes[i].x * minWidth) + (gWorldFrustumPlanes[i].y * minHeight) + (gWorldFrustumPlanes[i].z * minDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0);
    output += (((gWorldFrustumPlanes[i].x * maxWidth) + (gWorldFrustumPlanes[i].y * minHeight) + (gWorldFrustumPlanes[i].z * minDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0);
    output += (((gWorldFrustumPlanes[i].x * minWidth) + (gWorldFrustumPlanes[i].y * maxHeight) + (gWorldFrustumPlanes[i].z * minDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0);
    output += (((gWorldFrustumPlanes[i].x * maxWidth) + (gWorldFrustumPlanes[i].y * maxHeight) + (gWorldFrustumPlanes[i].z * minDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0);
    output += (((gWorldFrustumPlanes[i].x * minWidth) + (gWorldFrustumPlanes[i].y * minHeight) + (gWorldFrustumPlanes[i].z * maxDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0);
    output += (((gWorldFrustumPlanes[i].x * maxWidth) + (gWorldFrustumPlanes[i].y * minHeight) + (gWorldFrustumPlanes[i].z * maxDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0);
    output += (((gWorldFrustumPlanes[i].x * minWidth) + (gWorldFrustumPlanes[i].y * maxHeight) + (gWorldFrustumPlanes[i].z * maxDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0);
    output += (((gWorldFrustumPlanes[i].x * maxWidth) + (gWorldFrustumPlanes[i].y * maxHeight) + (gWorldFrustumPlanes[i].z * maxDepth) + (gWorldFrustumPlanes[i].w * 1.0f) < 0.0) ? 1 : 0);
    if (output == 8)
    {
        return false;
    }
}

return true;
}