在一个着色器通道中渲染多个纹理

时间:2013-03-02 04:33:40

标签: opengl-es branch webgl

在WebGL中,在一次传递中渲染多个纹理可能会更快,如:

varying float materialIndex;
varying vec2 textureCoord; 

uniform sampler2D textureSampler1;
uniform sampler2D textureSampler2;
uniform sampler2D textureSampler3;
uniform sampler2D textureSampler4;

vec4 getMaterial(float materialId, textureCoord) {
    vec4 color;

    if (materialId == 1.0)
    {
        color = texture2D( textureSampler1, textureCoord );
    }
    else if (materialId == 2.0)
    {
        color = texture2D( textureSampler2, textureCoord );
    }
    else if (materialId == 3.0)
    {
        color = texture2D( textureSampler3, textureCoord );
    }
    else
    {
        color = texture2D( textureSampler4, textureCoord );
    }

    return color;
}

void main()               
{                  
    vec4 color = getMaterial(materialIndex, textureCoord);
    gl_FragColor = color;        
}

因为这将节省CPU必须发送到GPU的指令的四分之一,除了顶点着色器必须传递的额外信息之外,在大多数情况下它不会比4倍的程序调用更快,我已经读过,即使在opengl中,最大的性能打击是到目前为止的cpu,我敢打赌,这对Webgl来说更是如此。或者这可能更快?

uniform float materialIndex;
varying vec2 textureCoord; 

uniform sampler2D textureSampler1;
uniform sampler2D textureSampler2;
uniform sampler2D textureSampler3;
uniform sampler2D textureSampler4;


void main()               
{                  
    vec4 color = getMaterial(materialIndex, textureCoord);
    gl_FragColor = color;        
}

或者更改一个功能性的制服就像加载一个新的着色器一样坏,而不是CPU必须做的调用次数?

1 个答案:

答案 0 :(得分:2)

批处理很重要,是的。但 并不重要。特别是面对某些硬件可以从所有四种纹理中采样的可能性,无论如何。

在不同的情况下,编译器不知道值如何变化。因此,它将假设任何片段都可以获得任何值。所以它必须为所有事情做一个运行时分支。由于条件分支的成本,编译器通常会尝试通过简单地执行所有可用路径并使用非分支逻辑来计算最终结果来避免执行4个连续的条件分支。

由于某些旧硬件在功能上无法对重要指令进行条件分支,因此您的统一案例也无法避免此类“优化”。因此,他们别无选择,只能在每次更换制服时重新编译着色器(并且这不是夸张;旧硬件上的NVIDIA编译器实际上就是这样做)或者进行所有4次纹理访问。

哦,还有一件事:texture2D函数在非均匀控制流中变得不确定(就像在有条件执行的块中一样)。现在,由于你如何使用它,它可能不会伤到你。但一般来说,您需要使用显式渐变或从条件块中删除纹理访问函数。我记得,WebGL没有渐变纹理功能。

简而言之,只需更改纹理并再次渲染即可。即使在JavaScript中,也不会像可能进行4次纹理访问那样杀死你的性能。只要您只在渲染之间绑定纹理(即:您没有更改程序或其他状态),并且您正在观察良好实践(在状态更改之间尽可能合理地渲染),您应该相对正常

相关问题