0

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

我的想法是它们的加权平均值:

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

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

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

(EDITED TO BACK-PATCH) Backpatch Culling:我遇到的另一个问题是背面剔除。正如我所说,我正在使用四边形贴片,因此可能不会躺在平面上。对于三角形,我会将法线与眼睛方向进行比较,但在四边形上我不能,或者不知道该怎么做。

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

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 个(上、左上、左)象限,按pow(2,LOD). 然后用一个常数(gridscale)缩放整个网格。

由于整个网格被放置在摄像机前面的每一帧中,因此网格总是从视图原点逐个象限地渲染。也许它可以用于镶嵌控制着色器中的一些剔除,如early-z遮挡?

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

4

1 回答 1

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 个角点形成 4 个三角形来剔除补丁,例如 [\](从左上角到右下角的 2 个三角形)和 [/](从右上角到左下角的 2 个三角形)如果所有 dot(vView, vFaceNormal) < -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;
}
于 2016-05-27T16:08:00.243 回答