Browsers don't afford a lot of information about the hardware they're running on so it's difficult determine how capable a device is ahead of time. With the WEBGL_debug_renderer_info
extension you can (maybe) get at more details about the graphics hardware being used, but the values returned don't seem consistent and there's no guarantee that the extension will be available. Here's an example of the output:
ANGLE (Intel(R) HD Graphics 4600 Direct3D11 vs_5_0 ps_5_0)
ANGLE (NVIDIA GeForce GTX 770 Direct3D11 vs_5_0 ps_5_0)
Intel(R) HD Graphics 6000
AMD Radeon Pro 460 OpenGL Engine
ANGLE (Intel(R) HD Graphics 4600 Direct3D11 vs_5_0 ps_5_0)
I've created this gist that extracts and roughly parses that information:
function extractValue(reg, str) {
const matches = str.match(reg);
return matches && matches[0];
}
// WebGL Context Setup
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
// Full card description and webGL layer (if present)
const layer = extractValue(/(ANGLE)/g, renderer);
const card = extractValue(/((NVIDIA|AMD|Intel)[^\d]*[^\s]+)/, renderer);
const tokens = card.split(' ');
tokens.shift();
// Split the card description up into pieces
// with brand, manufacturer, card version
const manufacturer = extractValue(/(NVIDIA|AMD|Intel)/g, card);
const cardVersion = tokens.pop();
const brand = tokens.join(' ');
const integrated = manufacturer === 'Intel';
console.log({
card,
manufacturer,
cardVersion,
brand,
integrated,
vendor,
renderer
});
Using that information (if it's available) along with other gl context information (like max texture size, available shader precision, etc) and other device information available through platform.js you might be able to develop a guess as to how powerful the current platform is.
I was looking into this exact problem not too long ago but ultimately it seemed difficult to make a good guess with so many different factors at play. Instead I opted to build a package that iteratively improves modifies the scene to improve performance, which could include loading or swapping out model levels of detail.
Hope that helps a least a little!