HTML5   发布时间:2022-04-27  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了iphone – 我如何提高我的自定义OpenGL ES 2.0深度纹理生成的性能?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个开源的iOS应用程序,使用自定义OpenGL ES 2.0着色器来显示分子结构的3-D表示。它通过使用在矩形上绘制的程序生成的球面和柱面假象来实现这一点,而不是使用许多顶点构建这些相同的形状。这种方法的缺点是,这些假冒者对象的每个片段的深度值需要在片段着色器中计算,以在对象重叠时使用。

不幸的是,OpenGL ES 2.0 does not let you write to gl_FragDepth,所以我需要输出这些值到自定义深度纹理。我使用帧缓冲对象(FBO)传递我的场景,只渲染对应于深度值的颜色,结果存储到纹理中。这个纹理然后被加载到我的渲染过程的后半部分,其中生成实际的屏幕图像。如果该阶段的片段在屏幕上该点的深度纹理中存储的深度级别,则显示该片段。如果没有,它被抛。更多关于过程,包括图表,可以在我的帖子here中找到。

生成这种深度纹理是我的渲染过程中的瓶颈,我正在寻找一种方法,使其更快。它似乎慢于应该,但我不知道为什么。为了实现此深度纹理​​的正确生成,禁用GL_DEPTH_TEST,使用glBlendFunc(GL_ONE,GL_ONE)启用GL_BLEND,并将glBlendEquation()设置为GL_MIN_EXT。我知道以这种方式的场景输出不是基于瓦片的延迟渲染器上的最快的,像在iOS设备中的PowerVR系列,但我不能想到一个更好的方法来做到这一点。

我的深度片段着色器球体(最常见的显示元素)看起来是这个瓶颈的核心(Renderer Utilization in instruments)被锁定在99%,表明我受到片段处理的限制)。它目前看起来像下面这样:

precision mediump float;

varying mediump vec2 impostorSpaceCoordinate;
varying mediump float normalizedDepth;
varying mediump float adjustedSphereRadius;

const vec3 stepValues = vec3(2.0,1.0,0.0);
const float scaleDownFactor = 1.0 / 255.0;

void main()
{
    float distanceFromCenter = length(impostorSpaceCoordinatE);
    if (distanceFromCenter > 1.0)
    {
        gl_FragColor = vec4(1.0);
    }
    else
    {
        float calculatedDepth = sqrt(1.0 - distanceFromCenter * distanceFromCenter);
        mediump float currentDepthValue = normalizedDepth - adjustedSphereRadius * calculatedDepth;

        // Inlined color encoding for the depth values
        float ceiledValue = ceil(currentDepthValue * 765.0);

        vec3 intDepthValue = (vec3(ceiledvalue) * scaleDownFactor) - stepValues;

        gl_FragColor = vec4(intDepthValue,1.0);
    }
}

在iPad 1上,使用passthrough着色器显示(在iPhone 4上为18到35 ms)需要35 – 68 ms渲染一个DNA空间填充模型的框架。根据PowerVR PVRUniSCo编译器(their SDK的一部分),此着色器最多使用11个GPU周期,最差为16个周期。我知道你建议不要在着色器中使用分支,但在这种情况下,导致更好的性能,否则。

当我简化它

precision mediump float;

varying mediump vec2 impostorSpaceCoordinate;
varying mediump float normalizedDepth;
varying mediump float adjustedSphereRadius;

void main()
{
    gl_FragColor = vec4(adjustedSphereRadius * normalizedDepth * (impostorSpaceCoordinate + 1.0) / 2.0,normalizedDepth,1.0);
}

它在iPad 1上需要18 – 35 ms,但在iPhone 4上只有1.7 – 2.4 ms。此着色器的GPU周期估计为8个周期。基于循环计数的渲染时间的变化看起来不是线性的。

最后,如果我只输出一个恒定的颜色:

precision mediump float;

void main()
{
    gl_FragColor = vec4(0.5,0.5,1.0);
}

iPad 1的渲染时间降至1.1 – 2.3 ms(iPhone 4上为1.3 ms)。

在第二个着色器的iPad和iPhone 4之间的渲染时间和突然变化的非线性缩放使我认为有一些我在这里丢失。包含这三种着色器变体的全源项目(查看SphereDepth.fsh文件并注释掉相应的部分),如果您想自己尝试,可以从here下载测试模型。

如果你读了这么远,我的问题是:基于这个分析信息,我如何提高我的自定义深度着色器在iOS设备上的渲染性能

解决方法

基于Tommy,Pivot和rotoglup的建议,我已经实现了一些优化,这导致了深度纹理生成和应用程序中的整体渲染管道的渲染速度加倍。

首先,我重新启用了我以前使用的预先计算的球体深度和照明纹理,只有很小的效果,现在只有在处理颜色和纹理的其他值时,才使用适当的lowp精度值。这种组合,连同用于纹理的适当的mip映射,似乎产生〜10%的性能提升。

更重要的是,我现在做一个传递,渲染我的深度纹理和最终的光线追踪假冒者之间,我放下一些不透明的几何,以阻止像素,永远不会被渲染。为此,我启用深度测试,然后绘制出构成我的场景中的对象的正方形,用sqrt(2)/ 2缩小,用一个简单的不透明着色器。这将创建插入正方形覆盖已知在表示球体中不透明的区域。

然后我使用glDepthMask(GL_falSE)禁用深度写入,并在更接近用户一个半径的位置呈现方形球冒充。这允许iOS设备中的基于区块的延迟渲染硬件有效地剥离在任何条件下不会出现在屏幕上但仍然基于每像素深度值在可见球面假冒者之间的平滑交叉的片段。这在我粗略的插图描述如下

在这个例子中,顶部两个冒名顶替者的不透明遮挡方块不防止来自那些可见对象的任何片段被呈现,而是它们阻止来自最低冒充者的一块片段。然后,最前面的冒牌者可以使用每像素测试来生成平滑的交集,而来自后冒牌者的许多像素通过被渲染不会浪费GPU循环。

我没有想到禁用深度写入,而是在最后一个渲染阶段留下深度测试。这是防止冒名顶替者在彼此之间简单堆叠,但仍然使用PowerVR GPU中的一些硬件优化的关键。

在我的基准测试中,渲染我上面使用的测试模型产生的时间为每帧18 – 35 ms,与之前的35 – 68 ms相比,渲染速度接近翻倍。将此相同的不透明几何预渲染应用于光线跟踪通道产生了整体渲染性能的两倍。

奇怪的是,当我尝试通过使用插入和外接的八边形,它应该覆盖约17%的像素,当绘制时,以及更高效的封锁片段进一步细化,性能实际上比使用简单的方块。在最坏的情况下,Tiler利用率仍然小于60%,因此更大的几何结构可能导致更多的缓存缺失。

EDIT(5/31/2011):

基于Pivot的建议,我创建了内雕和外接八边形而不是我的矩形,只有我遵循建议here优化三角形的光栅化。在以前的测试中,八边形产生比正方形更差的性能,尽管去除了许多不必要的碎片,并让您更有效地阻挡覆盖的碎片。通过调整三角形图形如下:

通过从正方形切换到八边形,我能够将总体呈现时间减少平均14%,而不是上述优化。深度纹理现在在19 ms中生成,偶尔下降到2ms,尖峰到35 ms。

EDIT 2(5/31/2011):

我已经回顾了Tommy使用step函数的想法,现在我有更少的片段,由于八边形而丢弃。这与结合球体的深度查找纹理现在导致iPad 1上的平均渲染时间为2ms,用于我的测试模型的深度纹理生成。我认为在这个渲染的情况下,我希望有一样好,并从我开始的一个巨大的改进。对于后代,这里是我现在使用的深度着色器:

precision mediump float;

varying mediump vec2 impostorSpaceCoordinate;
varying mediump float normalizedDepth;
varying mediump float adjustedSphereRadius;
varying mediump vec2 depthLookupCoordinate;

uniform lowp sampler2D sphereDepthMap;

const lowp vec3 stepValues = vec3(2.0,0.0);

void main()
{
    lowp vec2 precalculatedDepthAndAlpha = texture2D(sphereDepthMap,depthLookupCoordinatE).ra;

    float inCircleMultiplier = step(0.5,precalculatedDepthAndAlpha.g);

    float currentDepthValue = normalizedDepth + adjustedSphereRadius - adjustedSphereRadius * precalculatedDepthAndAlpha.r;

    // Inlined color encoding for the depth values
    currentDepthValue = currentDepthValue * 3.0;

    lowp vec3 intDepthValue = vec3(currentDepthvalue) - stepValues;

    gl_FragColor = vec4(1.0 - inCircleMultiplier) + vec4(intDepthValue,inCircleMultiplier);
}

我更新了测试样本here,如果你希望看到这个新的方法在行动比我最初做的。

我仍然对其他建议,但这是一个巨大的进步这个应用程序的一步。

大佬总结

以上是大佬教程为你收集整理的iphone – 我如何提高我的自定义OpenGL ES 2.0深度纹理生成的性能?全部内容,希望文章能够帮你解决iphone – 我如何提高我的自定义OpenGL ES 2.0深度纹理生成的性能?所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。