有没有办法在着色器中测试 GLSL-ES 版本?

Is there a way to test the GLSL-ES version in the shader?

shadertoy 等网络工具中,我的片段着色器源包含在我无法控制或看到的 main() 中。如果我正在分发一些 GLSL 库,那将是相同的。

我的问题是确保 webGL2 和 1 之间的兼容性:如果浏览器或 OS 仅支持 WebGL1,我想编写 GLSL 回退来模拟缺少的内置 webGL2。 -> 有没有办法从着色器测试当前的 webGL/GLSL 版本,就像我们为扩展的可用性所做的那样?

( 顺便说一句,测试扩展变得越来越复杂,因为语言中包含一些扩展:例如,尽管函数存在,但 webGL2 中未定义 GL_EXT_shader_texture_lod。因此能够测试 GLSL 版本至关重要。 )

AFAICT 没有好的测试方法。规范说预处理器宏 __VERSION__ 将设置为 GLSL 3.00 版的整数 300 中的版本

#if __VERSION__ == 300
   // use 300 es stuff
#else  
   // use 100 es tuff
#endif

问题是 WebGL2 在使用 300 es 着色器时着色器的第一行必须是

 #version 300 es

所以你不能这样做

 #if IMAGINARY_WEBGL2_FLAG
     #version 300 es         // BAD!! This has to be the first line
     ...
 #else 
     ...
 #

因此,鉴于您已经必须更新第一行,为什么不只使用 2 个着色器,一个用于 WebGL1,另一个用于 WebGL2。否则所有主要引擎都会生成它们的着色器,因此如果您想沿着这条路走下去,在您的代码中生成 WebGL1 或 WebGL2 应该是非常简单的。

首先,如果您可以使用 WebGL1,就没有理由使用 WebGL2 着色器功能,如果您使用的是 WebGL2 功能,那么它们就不再是同一个着色器了,对吗?他们需要不同的设置、不同的输入等...

假设我们可以在 GLSL 中完成所有操作,您希望它看起来像什么?

 // IMAGINARY WHAT IF EXAMPLE ....

 #if WEBGL2
   #version 300 es
   #define texture2D texture
   #define textureCube texture
 #else
   #define in varying
   #define out varying
 #endif

 in vec4 position;
 in vec2 texcoord;

 out vec2 v_texcoord;

 uniform sampler2D u_tex;
 uniform mat4 u_matrix;

 void main() {
    gl_Position = u_matrix * (position + texture2D(u_tex, texcoord));
    v_texcoord = texcoord;
 }

假设您想要这样做。你可以在JavaScript中做(不建议这样做,只是举个例子)

 const webgl2Header = `#version 300 es
   #define texture2D texture
   #define textureCube texture
 `;
 const webglHeader = `
   #define in varying
   #define out varying
 `;

 function prepShader(gl, source) {
   const isWebGL2 = gl.texImage3D !== undefined
   const header = isWebGL2 ? webgl2Header : webglHeader;
   return header + source;
 }

 const vs = `
 in vec4 position;
 in vec2 texcoord;

 out vec2 v_texcoord;

 uniform sampler2D u_tex;
 uniform mat4 u_matrix;

 void main() {
    gl_Position = u_matrix * (position + texture2D(u_tex, texcoord));
    v_texcoord = texcoord;
 }
 `;

 const vsSrc = prepSource(gl, vs);

您可以根据需要使 JavaScript 替换变得复杂。例如this library