ArcGIS 结合 three.js 渲染 3D 场景

ArcGIS 提供了非常强大的 JavaScript API,允许用户方便地在浏览器中展现 3D 地形等场景。同时,ArcGIS 也提供了一个底层接口 externalRenderers 来访问 SceneView 的 WebGL 上下文,这进一步地拓展了用户自定义的自由度。一些第三方 WebGL 库,例如 three.js,与这一功能兼容。ArcGIS 官方提供了一个样例,能够用 three.js 的 WebGLRenderer 实时渲染国际空间站的位置:Use three.js from an external renderer

在 externalRenderers 的官方文档中,提到了 Binding the correct render target 的问题。原因是 ArcGIS 的 SceneView 并没有使用 WebGL 默认的 framebuffer,如果调用 gl.bindFramebuffer(null),之后的渲染将不能够正确的显示在屏幕上。ArcGIS 提供了一个名为 bindRenderTarget() 的方法,用于解决这一问题。在官方样例中,可以找到修改 three.js 行为的代码:

1
2
3
4
5
6
7
8
9
10
// The ArcGIS API for JavaScript renders to custom offscreen buffers, and not to the default framebuffers.
// We have to inject this bit of code into the three.js runtime in order for it to bind those
// buffers instead of the default ones.
var originalSetRenderTarget = this.renderer.setRenderTarget.bind(this.renderer);
this.renderer.setRenderTarget = function(target) {
originalSetRenderTarget(target);
if (target == null) {
context.bindRenderTarget();
}
};

这一段代码在 three.js r79 版本中是有效的,不过在 r127 版本中,WebGLRenderer 的 framebuffer state 被重构了,使得 context.bindRenderTarget 未能正确地执行,造成无法渲染的问题。

解决方案是,在 render 方法中的 this.renderer.state.reset(); 之后,加入一行 context.bindRenderTarget();。而 ArcGIS 官方样例中对 setRenderTarget 的修改则不再被需要了。