【问题标题】:Proper way to detect WebGL support?检测 WebGL 支持的正确方法?
【发布时间】:2012-08-05 22:48:21
【问题描述】:

我正在尝试跨多个浏览器检测 WebGL 支持,但遇到了以下情况。即使访问者的视频卡被列入黑名单和/或 WebGL 被禁用,当前版本的 Firefox 似乎也使用以下检查报告了积极的支持:

if (window.WebGLRenderingContext) {
    // This is true in Firefox under certain circumstances,
    // even when WebGL is disabled...
}

我已尝试指导我的用户使用以下步骤启用 WebGL。这在某些情况下有效,但并非总是如此。显然,这不是我可以向公众要求的:

  1. 在 Firefox 的地址栏中输入 about:config
  2. 要启用 WebGL,请将 webgl.force-enabled 设置为 true

这导致我创建了自己的检测支持的方法,它使用 jQuery 注入一个画布元素来检测支持。这借鉴了我在各种 WebGL 库和插件中发现的许多技术。问题是,测试非常困难(非常感谢任何关于以下链接是否适合您的 cmets!)。为了使这个问题成为一个客观的问题,我想知道是否有一种普遍接受的方法来检测所有浏览器对 WebGL 的支持

测试网址:

http://jsfiddle.net/Jn49q/5/

【问题讨论】:

  • eek,我不知道除了experimental-webgl 之外还有更多方法可以获取 webgl 上下文,感谢您指出这一点。
  • 你的方法很难测试是什么意思?您是否担心它会产生误报/误报?在我看来,如果您要求 webgl 上下文但没有得到,那么您的应用程序将无法继续。除非我错过了什么?
  • @MattGreer,很难找到具有 Firefox 和黑名单视频卡和/或不受支持的图形的特定组合的测试机器。具体来说,我试图找出在什么情况下我的测试方法会在最新版本的 Firefox 中返回“false”。
  • 啊,好的。对于它的价值,我有一个基于 webgl 的小网站,并且我有几台机器因 Firefox 而失败。似乎 2009 年左右的机器出现故障(对不起,我没有比这更好的数据了)。我也总是可以通过在 VirtualBox(OSX 作为主机)的 Windows 中运行 Firefox 来让 Firefox 失败,VirtualBox 的 3D 加速支持很弱。
  • 仅仅检测到 WebGL 支持并不意味着它会有任何好处。 WebGL 可以通过“swiftshader”进行模拟,或者,对于 Linux 上的 Firefox,它可以部分或完全通过“mesa 3D”进行模拟。由于 Mesa 可以很好地加速 2D,因此即使 WebGL 似乎可用,手动选择画布也是有意义的。

标签: javascript jquery firefox cross-browser webgl


【解决方案1】:

优秀的 Three 库,其实有一种检测机制:

  1. WebGL 支持
  2. 文件 API 支持
  3. 工人支持

特别是对于 WebGL,这里是使用的代码:

function webgl_support () { 
   try {
    var canvas = document.createElement('canvas'); 
    return !!window.WebGLRenderingContext &&
      (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
   } catch(e) {
     return false;
   }
 };

该代码 sn-p 是 Detector 类的一部分,它还可以向用户显示相应的错误消息。

【讨论】:

  • 美观紧凑。正是作者所要求的。我不明白为什么人们在他们的答案中包含额外不相关的代码
【解决方案2】:

[2014 年 10 月]我已经更新了 modernizrs 示例以匹配他们的 current implementation,这是从下面的 http://get.webgl.org/ 清理后的版本。

Modernizr 会,

var canvas;
var ctx;
var exts;

try {
  canvas = createElement('canvas');
  ctx = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
  exts = ctx.getSupportedExtensions();
}
catch (e) {
  return;
}

if (ctx !== undefined) {
  Modernizr.webglextensions = new Boolean(true);
}

for (var i = -1, len = exts.length; ++i < len; ){
  Modernizr.webglextensions[exts[i]] = true;
}

canvas = undefined;

Chromium 指向 http://get.webgl.org/ 用于规范支持实现,

try { gl = canvas.getContext("webgl"); }
catch (x) { gl = null; }

if (gl == null) {
    try { gl = canvas.getContext("experimental-webgl"); experimental = true; }
    catch (x) { gl = null; }
}

【讨论】:

  • @Cupidvogel:所有canvas-supporting browsers,所以88.94%。您可以通过将其包装在 try-catch statement 中来实现 100%。
  • @Cupidvogel 它不适用于 Safari(从版本 7.0.3 开始),它尚不支持 getContext("webgl"),并且仅适用于 getContext("experimental-webgl")getContext("webkit-3d")
【解决方案3】:

http://www.browserleaks.com/webgl#howto-detect-webgl所见

这是一个检测 WebGL 支持的适当 javascript 函数,具有各种实验性 WebGL 上下文名称并检查特殊情况,例如通过 NoScript 或 TorBrowser 阻止 WebGL 函数。

它将报告三种 WebGL 功能状态之一:

  • WebGL 已启用 — 返回 TRUE,或返回
  • WebGL 对象,如果传递了第一个参数
  • WebGL 已禁用 — 返回 FALSE,如果需要,您可以更改它>
  • WebGL 未实现 — 返回 FALSE
function webgl_detect(return_context)
{
    if (!!window.WebGLRenderingContext) {
        var canvas = document.createElement("canvas"),
             names = ["webgl2", "webgl", "experimental-webgl", "moz-webgl", "webkit-3d"],
           context = false;

        for(var i=0;i< names.length;i++) {
            try {
                context = canvas.getContext(names[i]);
                if (context && typeof context.getParameter == "function") {
                    // WebGL is enabled
                    if (return_context) {
                        // return WebGL object if the function's argument is present
                        return {name:names[i], gl:context};
                    }
                    // else, return just true
                    return true;
                }
            } catch(e) {}
        }

        // WebGL is supported, but disabled
        return false;
    }

    // WebGL not supported
    return false;
}

【讨论】:

  • 为什么对 window.WebGLRenderingContext 进行双重否定?
  • 我真的不确定,我从上面的链接粘贴了对我有用的代码,但这里有一些解释:stackoverflow.com/questions/784929/…
  • @sijpkes 双重否定将真/假值转换为其布尔表示:!!"" === false &amp;&amp; !!1 === true
  • @WickyNilliams 在 PHP 中的类型转换总是令人困惑,但这很容易。
  • return_context 不应该只是context?只有进行此更改,代码才对我有用
【解决方案4】:

除了@Andrew 的回答,还有实验模式可以支持。我写了以下sn-p的代码:

var canvasID = 'webgl',
    canvas = document.getElementById(canvasID),
    gl,
    glExperimental = false;

function hasWebGL() {

    try { gl = canvas.getContext("webgl"); }
    catch (x) { gl = null; }

    if (gl === null) {
        try { gl = canvas.getContext("experimental-webgl"); glExperimental = true; }
        catch (x) { gl = null; }
    }

    if(gl) { return true; }
    else if ("WebGLRenderingContext" in window) { return true; } // not a best way, as you're not 100% sure, so you can change it to false
    else { return false; }
}

根据您的 ID 更改 canvasID 变量。

在 Chrome、Safari、Firefox、Opera 和 IE(8 到 10)上测试。如果是 Safari,请记住它是可用的,但您需要明确启用 WebGL(启用开发人员菜单并在之后启用 Web GL 选项)。

【讨论】:

    【解决方案5】:

    为了检测支持 WebGL 的浏览器,但排除较旧的浏览器可能无法很好地支持它(根据WebGL detected as supported when it is actually not 中的需要以排除 Android 4.4.2 设备),我添加了一个更严格但不相关的检查:

    function hasWebGL() {
        var supported;
    
        try {
            var canvas = document.createElement('canvas');
            supported = !! window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
        } catch(e) { supported = false; }
    
        try {
            // let is by no means required, but will help us rule out some old browsers/devices with potentially buggy implementations: http://caniuse.com/#feat=let
            eval('let foo = 123;');
        } catch (e) { supported = false; }
    
        if (supported === false) {
            console.log("WebGL is not supported");
        }
    
        canvas = undefined;
    
        return supported;
    },
    

    【讨论】:

      【解决方案6】:
      // this code will detect WebGL version until WebGL Version maxVersionTest 
      var
      maxVersionTest = 5,
      canvas = document.createElement('canvas'),
      webglVersion = (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')) ? 1 : null,
      canvas = null; // free context
      
      // range: if maxVersionTest = 5 makes [5, 4, 3, 2]
      Array.apply(null, Array(maxVersionTest - 1))
      .map(function (_, idx) {return idx + 2;})
      .reverse()
      .some(function(version){
          // cant reuse canvas, potential to exceed contexts or mem limit *
          if (document.createElement('canvas').getContext('webgl'+version))
              return !!(webglVersion = version);
      });
      
      console.log(webglVersion);
      

      * re“可能超过上下文或内存限制”见 https://bugs.chromium.org/p/chromium/issues/detail?id=226868

      【讨论】:

      • 难以置信的解决方案。你能解释一下关于 canvas = null; 的更多信息吗?也回来!! ...
      • 创建画布是消耗资源的,设置canvas = null 可以释放第一个版本测试中使用的资源。 Chrome 中至少还有一个最大上下文限制。在循环中创建的画布是匿名的,一旦超出范围就可以释放。 !!value 只是将 value 转换为布尔值,预期返回 Array.prototype.some,例如:!!null == false
      【解决方案7】:

      来自MDN

      // Run everything inside window load event handler, to make sure
      // DOM is fully loaded and styled before trying to manipulate it.
      window.addEventListener("load", function() {
        var paragraph = document.querySelector("p"),
          button = document.querySelector("button");
        // Adding click event handler to button.
        button.addEventListener("click", detectWebGLContext, false);
        function detectWebGLContext () {
          // Create canvas element. The canvas is not added to the
          // document itself, so it is never displayed in the
          // browser window.
          var canvas = document.createElement("canvas");
          // Get WebGLRenderingContext from canvas element.
          var gl = canvas.getContext("webgl")
            || canvas.getContext("experimental-webgl");
          // Report the result.
          if (gl && gl instanceof WebGLRenderingContext) {
            paragraph.innerHTML =
              "Congratulations! Your browser supports WebGL.";
          } else {
            paragraph.innerHTML = "Failed to get WebGL context. "
              + "Your browser or device may not support WebGL.";
          }
        }
      }, false);
      body {
        text-align : center;
      }
      button {
        display : block;
        font-size : inherit;
        margin : auto;
        padding : 0.6em;
      }
      <p>[ Here would go the result of WebGL feature detection ]</p>
      <button>Press here to detect WebGLRenderingContext</button>

      【讨论】:

        猜你喜欢
        • 2017-04-21
        • 2016-01-12
        • 1970-01-01
        • 2016-11-14
        • 2012-04-11
        • 2011-02-14
        • 1970-01-01
        • 2011-01-02
        相关资源
        最近更新 更多