【问题标题】:GLSL-ES3(webGL2): how to test extensions from fragment shader?GLSL-ES3(webGL2):如何从片段着色器测试扩展?
【发布时间】:2021-01-09 19:42:56
【问题描述】:

在 webGL1 中,可以使用(例如)#ifdef GL_EXT_shader_texture_lod 从片段着色器测试 GLSL 扩展的可用性。 它似乎不再在 webGL2 (=GLSL-ES3.0) 中工作:扩展不一样,但例如 #ifdef GL_EXT_color_buffer_float 似乎是错误的,尽管 https://webglreport.com/?v=2 告诉扩展存在。 还是我做错了什么?

【问题讨论】:

    标签: glsl fragment-shader glsles webgl2 webgl-extensions


    【解决方案1】:

    是否向 GLSL 添加标志取决于扩展程序

    EXT_shader_texture_lod 是专门影响 GLSL 的扩展。 It's spec 说它添加了那个宏

    GLSL 宏 GL_EXT_shader_texture_lod 定义为 1。

    EXT_color_buffer_float 不是影响 GLSL 的扩展。 It's spec 没有提到任何 GLSL 宏。与 WebGL1 没有变化

    无论如何,这些标志在 WebGL 中大多是无意义的。您可以轻松地进行自己的字符串操作

    const shaderTextureLodExt = gl.getExtension('EXT_shader_texture_lod');
    
    
    const shader = `
    #if ${shaderTextureLodExt ? 1 : 0}
       ... code if shader texture lod exists
    #else
       ... code if shader texture lod does not exist
    #endif
    
      ...
    `;
    

    或一千种其他方式来操作着色器字符串。

    还有一个

    const colorBufferFloatExt = gl.getExtension('EXT_color_buffer_float');
    
    function replaceIfDefs(s) {
      return `
      ${colorBufferExtension ? '#define EXTENSION_color_buffer_float' : ''}
      ${s.replace(/GL_EXT_color_buffer_float/g 'EXTENSION_color_buffer_float')}
      `;
    }
    const shader = replaceIfDefs(`
    #ifdef GL_EXT_color_buffer_float
       ...
    #endif
       ...
    `);
    

    等等……

    此外,由于即使在 OpenGL 中也从来没有 GL_EXT_color_buffer_float,所以调用宏 GL_EXT_color_buffer_float 没有多大意义。事实上,这可以说是一个坏主意,因为它最终看起来像一个官方指定的宏,即使它不是。最好选择不以GL_ 开头的自己的名字。

    还要考虑使用#ifdef 甚至可能不是一个好主意,因为您可以只使用字符串操作。例如

    const colorBufferFloatExt = gl.getExtension('EXT_color_buffer_float');
    
    const snippet = colorBufferFloatExt
      ? `
          float decode_float(vec4 v) {
            return v;
          }
        `
      : `
          float decode_float(vec4 v) {
             vec4 bits = v * 255.0;
             float sign = mix(-1.0, 1.0, step(bits[3], 128.0));
             float expo = floor(mod(bits[3] + 0.1, 128.0)) * 2.0 +
                          floor((bits[2] + 0.1) / 128.0) - 127.0;
             float sig = bits[0] +
                         bits[1] * 256.0 +
                         floor(mod(bits[2] + 0.1, 128.0)) * 256.0 * 256.0;
             return sign * (1.0 + sig / 8388607.0) * pow(2.0, expo);
           }
       `;
    
    const shader = `
    precision highp float;
    
    ${snippet}
    
    uniform sampler2D data;
    uniform vec2 dataSize;
    
    void main(
       vec4 d = texture2D(data, gl_FragCoord.xy / dataSize);
       vec4 v = decode_float(d) * 2.0;
       gl_FragColor = v;
    }
    `;
    
    
    ...etc...
    

    【讨论】:

    • 谢谢!关于字符串操作:在各种情况下你不能,因为在多平台上导出的唯一东西是片段着色器本身(所以它是唯一可以测试系统相关功能的地方,例如 webGL1 vs 2 via VERSION ):通常在 Shadertoy、Unity、MaterialZ 和各种在线或多平台工具中。此外,出于某种原因,该语言在着色器中提供了 VERSION_EXT_ ;-)
    • 你确定没有误会?没有宏 GL_EXT_color_buffer_float 句号。 WebGL 并没有缺少它。它不存在,也从来没有。 VERSION 也对条件编程没有用处,因为它必须是着色器的第一行。因此,您不能让着色器进行某种版本检查,因为无论如何您都必须使用字符串操作来设置第一行中的版本。
    • __ VERSION__ :因为我不知道,所以我使用它并且它工作;-) 无论如何,我认为它不应该在第一行,而#version 是。
    • GL_EXT_color_buffer_float:是的,您已经在主要答案中解释说这个 GL_EXT_ 不存在,而其他人确实存在。我首先虽然每个扩展都应该是可测试的。
    • 是的,#version 应该是我想说的第一行(如果不清楚,抱歉)。关键是您已经必须进行字符串操作来设置第一行。如果你正在做一些字符串操作来设置第一行,你可以做更多的字符串操作来设置其他行。插入#version 300 es\n#define EXT_color_buffer_float\n 而不仅仅是#version 300 es 作为最简单的例子
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-03
    • 2017-04-12
    • 2013-07-30
    • 1970-01-01
    • 2020-11-20
    • 2014-07-26
    • 1970-01-01
    相关资源
    最近更新 更多