UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

143 lines (142 loc) 5.09 kB
"use strict"; import { CoreMapboxTransform } from "../Transform"; import { Matrix4, Vector3, WebGLRenderer } from "three"; import mapboxgl from "mapbox-gl"; const ID = "threejs_layer"; export class ThreejsLayer { constructor(options) { this.id = ID; this.type = "custom"; this.renderingMode = "3d"; // from https://docs.mapbox.com/mapbox-gl-js/example/add-3d-model/ // this now rotates objects correctly this._vX = new Vector3(1, 0, 0); this._vY = new Vector3(0, 1, 0); this._vZ = new Vector3(0, 0, 1); this.mRX = new Matrix4(); this.mRY = new Matrix4(); this.mRZ = new Matrix4(); this.s = new Vector3(); this.m = new Matrix4(); this.l = new Matrix4(); this._map = options.map; this._camera = options.camera; this._lngLat = options.lngLat; this._displayScene = options.scene.threejsScene(); this._renderFunc = options.renderFunc; this._viewer = options.viewer; } onAdd(map, gl) { this.createRenderer(gl); } // onRemove() { // this._renderer?.dispose(); // } createRenderer(gl) { this._renderer = new WebGLRenderer({ // alpha: true antialias: true, canvas: this._map.getCanvas(), context: gl }); this._viewer.setRenderer(this._renderer); this._renderer.autoClear = false; this._renderer.shadowMap.enabled = true; } // resize(size: Vector2) { // // TODO: resize is currently broken. // // re-creating a renderer is the only way I found to reliably resize. // // It seems that if I only resize, // // the render will appear to be the right size (as in no antialiasing issue) // // but 3d object end up slipping on the map (as opposed to staying anchored where they are expected to) // this.createRenderer(); // // this._renderer?.setSize(size.x, size.y); // // this._cssRendererConfig?.cssRenderer.setSize(size.x, size.y); // } async render(gl, matrix) { if (!this._renderer) { console.warn("no renderer"); return; } let previousBackground = this._displayScene.background; if (this._displayScene.background) { this._displayScene.background = null; } this._updateCameraMatrix(matrix); this._renderer.resetState(); this._renderFunc(this._renderer); this._map.triggerRepaint(); this._displayScene.background = previousBackground; } _updateCameraMatrix(matrix) { const mercator = mapboxgl.MercatorCoordinate.fromLngLat([this._lngLat.lng, this._lngLat.lat], 0); const transform = { position: mercator, rotation: { x: Math.PI / 2, y: 0, z: 0 }, scale: CoreMapboxTransform.WORLD_SCALE }; this.mRX.identity(); this.mRY.identity(); this.mRZ.identity(); const rotationX = this.mRX.makeRotationAxis(this._vX, transform.rotation.x); const rotationY = this.mRY.makeRotationAxis(this._vY, transform.rotation.y); const rotationZ = this.mRZ.makeRotationAxis(this._vZ, transform.rotation.z); this.s.x = transform.scale; this.s.y = -transform.scale; this.s.z = transform.scale; this.m.fromArray(matrix); this.l.identity(); this.l.makeTranslation(1 * transform.position.x, 1 * transform.position.y, 1 * (transform.position.z || 0)).scale(this.s).multiply(rotationX).multiply(rotationY).multiply(rotationZ); this._camera.projectionMatrix.elements = matrix; this._camera.projectionMatrix = this.m.multiply(this.l); } // This is a very dirty hack that seems to allow objects to render properly. // If this was not called, // all objects created would render for a couple frames and then disappear. // There sometimes would be an WebGL warning along the lines of "buffer not large enough" // but it is completely unclear what could have caused it. // // What I tried to debug this: // // - upgrade from mapbox 1 to 2 // this made no difference // // - using Babylon Spector // but I was unable to isolate which call was problematic // // - fiddle with renderes options // that solved nothing // // - integrate the mapbox example as a layer instead of this one // When using the example layer and its included THREE.Scene, // it renders just fine. // But as soon as I replace the included scene with the one created by Polygonjs, // Then the problem reappears. // That's even if the scene is as simple as a Hemisphere Light and a Plane. // So that did not allow me to find a solution. // // - use src/debug.js (I forgot now where I copied it from) // to help find bad webgl calls. // but that didn't help. // // - setting Polygonjs scene's objects to // matrixAutoUpdate = true // or // frustumCulled = false // But that solved nothing. // // In short.... WFT?!?! // But for now, with this hack, it seems to work fine. // private _hack() { // const hackObject = new Mesh(new PlaneGeometry()); // hackObject.frustumCulled = false; // hackObject.position.z = -1000; // hackObject.scale.set(0.01, 0.01, 0.01); // const scene = this._scene.threejsScene(); // scene.add(hackObject); // } }