@philippkoelmel/arcgis-threejs-externalrenderer

Takes away the boilerplate from integrating Three.js to ArcGIS.

Usage no npm install needed!

<script type="module">
  import philippkoelmelArcgisThreejsExternalrenderer from 'https://cdn.skypack.dev/@philippkoelmel/arcgis-threejs-externalrenderer';
</script>

README

Arcgis three.js external renderer

Takes away the boilerplate from integrating Three.js to ArcGIS.

Install

npm install @philippkoelmel/arcgis-threejs-externalrenderer

Usage

This module exposes a convenient wrapper around ArcGIS's externalRenderers and an interface which you implement to manage your Three.js scene.

Let us implement the interface ExternalRendererThreeCallback first:

import * as externalRenderers from "@arcgis/core/views/3d/externalRenderers";
import { WebGLRenderer, Scene, BoxGeometry, Mesh, Clock, MathUtils, MeshPhongMaterial, Material, BufferGeometry } from "three";
import SpatialReference from "@arcgis/core/geometry/SpatialReference"
import { ExternalRendererThreeCallback } from "@philippkoelmel/arcgis-threejs-externalrenderer";

class Example implements ExternalRendererThreeCallback {

    private clock: Clock = new Clock();
    private mesh?: Mesh<BufferGeometry, Material>;

    private radiansPerSecond: number = MathUtils.degToRad(30);;

    setup(context: any, renderer: WebGLRenderer, scene: Scene): void {
        let geometry = new BoxGeometry(10000, 10000, 10000);
        let material = new MeshPhongMaterial({
            color: 0xFF0000,
            flatShading: true,
        });

        this.mesh = new Mesh(geometry, material);
        this.mesh.scale.set(10, 10, 10);
        scene.add(this.mesh);

        let posEst = [9.993, 53.679, 400000];
        let renderPos = [0, 0, 0];
        externalRenderers.toRenderCoordinates(context.view, posEst, 0, SpatialReference.WGS84, renderPos, 0, 1);

        this.mesh.position.set(renderPos[0], renderPos[1], renderPos[2]);

        context.view.goTo({
            target: [posEst[0], posEst[1]],
            zoom: 5,
        });
    }

    render(context: any): void {
        const clockDelta = this.clock.getDelta();

        this.mesh!.rotation.x += this.radiansPerSecond * clockDelta;
        this.mesh!.rotation.y += this.radiansPerSecond * clockDelta;
        this.mesh!.rotation.z += this.radiansPerSecond * clockDelta;
    }

    dispose(context: any): void {
        this.mesh!.material.dispose();
        this.mesh!.geometry.dispose();
    }
}

export default Example;

This will create a rotating red box 400km above ground.

Now you need to tell ArcGIS to execute this implementation, here an example for that:

import Map from "@arcgis/core/Map";
import SceneView from "@arcgis/core/views/SceneView";
import config from "@arcgis/core/config";
import Example from './Example';
import { ExternalRendererThree } from "@philippkoelmel/arcgis-threejs-externalrenderer";

[...]
    const map = new Map({
      basemap: "arcgis-light-gray"
    });

    const view = new SceneView({
      container: "arcgis_view",
      map: map,
      viewingMode: "global",
      camera: {
        // ??
        position: {
          x: -9932671,
          y: 2380007,
          z: 1687219,
          spatialReference: { wkid: 102100 }
        },
        heading: 0,
        tilt: 35
      },
    });
    if (view.environment.lighting !== undefined) {
      view.environment.lighting.cameraTrackingEnabled = false;
      view.environment.lighting.date = new Date();
    }

    ExternalRendererThree.start(view, new Example());
[...]

The key lines are:

[...]
import Example from './Example';
import { ExternalRendererThree } from "@philippkoelmel/arcgis-threejs-externalrenderer";
[...]
ExternalRendererThree.start(view, new Example());
[...]

The ExternalRendererThree.start method will fill in the boilerplate code for you and connect implementation with ArcGIS.