问题 使用Three.js将UI元素直接绘制到WebGL区域


在Three.js中,是否可以使用常规HTML5画布元素直接绘制到WebGL区域(例如,抬头显示或UI元素)?

如果是这样,您如何获得上下文以及可用的绘图命令?

如果没有,是否有另一种方法可以通过其他Three.js或特定于WebGL的绘图命令与Three.js合作完成此操作?

我的备份计划是使用HTML div作为叠加层,但我认为应该有更好的解决方案。

谢谢!


4071
2017-10-01 04:20


起源

布兰登琼斯有一个很好的演示由divs制作的hud元素: media.tojicode.com/webgl-samples/hud-test.html - Anton
还看看这个帖子: github.com/mrdoob/three.js/issues/1959 - WestLangley
谢谢你们,这些真的很有帮助 - Dev
在用于VR目的的三个JS中,无法在HTML或2D画布中执行此操作。如果您想从主场景中分离HUD,则必须创建另一个场景。如果你有兴趣,请看看这里 github.com/trinketmage/three.js-vr-hud - Nephelococcygia


答案:


您无法以与使用常规画布相同的方式直接绘制到WebGL画布。但是,还有其他方法,例如,

  • 像往常一样绘制到隐藏的2D画布,并将其作为四边形纹理传递给WebGL
  • 使用纹理映射四边形绘制图像(例如,您的健康框的帧)
  • 通过将它们的顶点放到VBO中绘制路径(和形状),并使用适当的多边形类型绘制它
  • 使用位图字体(基本上是纹理四边形)或真实几何图形来绘制文本(three.js有示例和帮助器)

使用这些通常意味着设置正交相机。

然而,所有这些都是相当多的工作,例如用真实几何图形绘制文本可能很昂贵。如果您可以使用CSS样式处理HTML div,则应该使用它们,因为它可以非常快速地进行设置。此外,绘制WebGL画布(可能使用透明度)应该是浏览器向GPU加速其div绘图的强烈暗示,如果它还没有加速所有内容。

还要记住,你可以用CSS3实现很多,例如圆角,alpha透明度,甚至是3D透视变换,如问题评论中Anton的链接所示。


10
2017-10-01 07:30



很好的答案,谢谢..也看到上面的评论,因为Anton&WestLangley有一些很好的见解 - Dev
嗯......我想知道如果让我的页面的整个背景成为空的webgl画布会强制浏览器根据你的评论加速一切。出于某种原因,我认为它不会起作用。 - trusktr


我有完全相同的问题。我试图创建一个没有DOM的HUD(平视显示器),我最终创建了这个解决方案:

  1. 我用正交相机创建了一个单独的场景。
  2. 我创建了一个canvas元素,并使用2D绘图基元来渲染我的图形。
  3. 然后我创建了一个适合整个屏幕的平面,并使用2D画布元素作为纹理。
  4. 我在原始场景的顶部渲染了次要场景

这就是HUD代码的样子:

// We will use 2D canvas element to render our HUD.  
var hudCanvas = document.createElement('canvas');

// Again, set dimensions to fit the screen.
hudCanvas.width = width;
hudCanvas.height = height;

// Get 2D context and draw something supercool.
var hudBitmap = hudCanvas.getContext('2d');
hudBitmap.font = "Normal 40px Arial";
hudBitmap.textAlign = 'center';
hudBitmap.fillStyle = "rgba(245,245,245,0.75)";
hudBitmap.fillText('Initializing...', width / 2, height / 2);

// Create the camera and set the viewport to match the screen dimensions.
var cameraHUD = new THREE.OrthographicCamera(-width/2, width/2, height/2, -height/2, 0, 30 );

// Create also a custom scene for HUD.
sceneHUD = new THREE.Scene();

// Create texture from rendered graphics.
var hudTexture = new THREE.Texture(hudCanvas) 
hudTexture.needsUpdate = true;

// Create HUD material.
var material = new THREE.MeshBasicMaterial( {map: hudTexture} );
material.transparent = true;

// Create plane to render the HUD. This plane fill the whole screen.
var planeGeometry = new THREE.PlaneGeometry( width, height );
var plane = new THREE.Mesh( planeGeometry, material );
sceneHUD.add( plane );

这就是我添加到渲染循环中的内容:

// Render HUD on top of the scene.
renderer.render(sceneHUD, cameraHUD);

你可以在这里玩完整的源代码: http://codepen.io/jaamo/pen/MaOGZV

并阅读我的博客上有关实施的更多信息: http://www.evermade.fi/pure-three-js-hud/


6
2017-10-19 10:32



并使用 clearDepth 对于渲染器 - Liu Hao