diff --git a/ShadowEditor.Web/src/gis/Globe.js b/ShadowEditor.Web/src/gis/Globe.js index 1c6e2866..ed2c11df 100644 --- a/ShadowEditor.Web/src/gis/Globe.js +++ b/ShadowEditor.Web/src/gis/Globe.js @@ -33,11 +33,12 @@ function Globe(camera, renderer, options = {}) { this.lat = 0; this.alt = GeoUtils.zoomToAlt(0); + this.thread = 0; this.matrixAutoUpdate = false; // 不能命名为layers,否则跟three.js的layers冲突 this.layerList = [ - new GoogleTiledLayer(), + new GoogleTiledLayer(this), ]; this.renderers = new Renderers(this); diff --git a/ShadowEditor.Web/src/gis/layer/tiled/TiledImageLayer.js b/ShadowEditor.Web/src/gis/layer/tiled/TiledImageLayer.js index 6c9820aa..6295b236 100644 --- a/ShadowEditor.Web/src/gis/layer/tiled/TiledImageLayer.js +++ b/ShadowEditor.Web/src/gis/layer/tiled/TiledImageLayer.js @@ -1,4 +1,5 @@ import ImageLayer from '../ImageLayer'; +import TileCache from '../../utils/TileCache'; /** * 图片瓦片图层 @@ -8,13 +9,19 @@ import ImageLayer from '../ImageLayer'; function TiledImageLayer(globe) { ImageLayer.call(this, globe); - this.tree = rbush(); + this.cache = new TileCache(); } TiledImageLayer.prototype = Object.create(ImageLayer.prototype); TiledImageLayer.prototype.constructor = TiledImageLayer; -TiledImageLayer.prototype.get = function (aabb) { +/** + * 获取图片数据 + * @param {*} x + * @param {*} y + * @param {*} z + */ +TiledImageLayer.prototype.get = function (x, y, z) { }; diff --git a/ShadowEditor.Web/src/gis/layer/tiled/image/GoogleTiledLayer.js b/ShadowEditor.Web/src/gis/layer/tiled/image/GoogleTiledLayer.js index 5cd26703..91132199 100644 --- a/ShadowEditor.Web/src/gis/layer/tiled/image/GoogleTiledLayer.js +++ b/ShadowEditor.Web/src/gis/layer/tiled/image/GoogleTiledLayer.js @@ -14,21 +14,63 @@ GoogleTiledLayer.prototype = Object.create(TiledImageLayer.prototype); GoogleTiledLayer.prototype.constructor = GoogleTiledLayer; /** - * 获取某个经纬度范围内的资源 - * @param {THREE.Box2} aabb - * @param {Number} z 层级 + * 获取图片数据 + * @param {*} x + * @param {*} y + * @param {*} z */ -GoogleTiledLayer.prototype.get = function (aabb, z) { - var minLon = aabb.min.x, - minLat = GeoUtils._mercatorLat(aabb.min.y), - maxLon = aabb.max.x, - maxLat = GeoUtils._mercatorLat(aabb.max.y); +GoogleTiledLayer.prototype.get = function (x, y, z) { + var img = this.cache.get(x, y, z); - var size = Math.PI * 2 / 2 ** z, - minX = Math.floor(minLon / size), - minY = Math.floor(minLat / size), - maxX = Math.ceil(maxLon / size), - maxY = Math.ceil(maxLat / size); + if (img && img.loaded) { + return img; + } + + if (img && (img.loading || img.error)) { + return null; + } + + if (this.globe.thread < this.globe.options.maxThread) { + this._create(x, y, z); + } + + return null; +}; + +GoogleTiledLayer.prototype._create = function (x, y, z) { + var img = document.createElement('img'); + + img._x = x; + img._y = y; + img._z = z; + img.crossOrigin = 'anonymous'; + img.loading = true; + + this.cache.set(x, y, z, img); + + img.onload = () => { + img.onload = null; + img.onerror = null; + + img.loaded = true; + delete img.loading; + + this.globe.thread--; + }; + + img.onerror = () => { + img.onload = null; + img.onerror = null; + + img.error = true; + delete img.loading; + + this.globe.thread--; + }; + + img.src = `http://www.google.cn/maps/vt?lyrs=s@821&gl=cn&x=${x}&y=${y}&z=${z}`; + + this.globe.thread++; }; export default GoogleTiledLayer; \ No newline at end of file diff --git a/ShadowEditor.Web/src/gis/render/TiledLayerRenderer.js b/ShadowEditor.Web/src/gis/render/TiledLayerRenderer.js index f14a0494..cf84b1b0 100644 --- a/ShadowEditor.Web/src/gis/render/TiledLayerRenderer.js +++ b/ShadowEditor.Web/src/gis/render/TiledLayerRenderer.js @@ -14,17 +14,16 @@ function TiledLayerRenderer(globe) { this.creator = new SphereTileCreator(this.globe); - var geometry = new THREE.PlaneBufferGeometry(1, 1, 16, 16); - - this.mesh = new THREE.Mesh(geometry, []); - this.mesh.matrix.copy(this.globe.matrix); - this.mesh.matrixAutoUpdate = false; + this.geometry = new THREE.PlaneBufferGeometry(1, 1, 16, 16); + this.modelMatrix = new THREE.Matrix4(); this.program = null; this.attributes = {}; this.uniforms = {}; this.buffers = {}; + this.tiles = []; + this.initProgram(); this.initBuffers(); } @@ -93,7 +92,7 @@ TiledLayerRenderer.prototype.initProgram = function () { TiledLayerRenderer.prototype.initBuffers = function () { var gl = this.gl; - var geometry = this.mesh.geometry; + var geometry = this.geometry; var attributes = geometry.attributes; var positionBuffer = gl.createBuffer(); @@ -121,14 +120,7 @@ TiledLayerRenderer.prototype.initBuffers = function () { }; TiledLayerRenderer.prototype.render = function () { - this.mesh.material.length = 0; - - this.creator.get().forEach((n, i) => { - if (n.material) { - this.mesh.material.push(n.material); - } - }); - + this.creator.get(this.tiles); this.renderMesh(); this.renderer.state.reset(); }; @@ -136,8 +128,6 @@ TiledLayerRenderer.prototype.render = function () { TiledLayerRenderer.prototype.renderMesh = function () { var gl = this.gl; var camera = this.camera; - var geometry = this.mesh.geometry; - var materials = this.mesh.material; gl.useProgram(this.program); @@ -149,7 +139,7 @@ TiledLayerRenderer.prototype.renderMesh = function () { // gl.depthFunc(gl.LEQUAL); gl.depthMask(true); - gl.uniformMatrix4fv(this.uniforms.modelMatrix, false, this.mesh.matrix.elements); + gl.uniformMatrix4fv(this.uniforms.modelMatrix, false, this.modelMatrix.elements); gl.uniformMatrix4fv(this.uniforms.viewMatrix, false, camera.matrixWorldInverse.elements); gl.uniformMatrix4fv(this.uniforms.projectionMatrix, false, camera.projectionMatrix.elements); @@ -168,32 +158,32 @@ TiledLayerRenderer.prototype.renderMesh = function () { gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.buffers.index); // x, y, z - materials.forEach(n => { - gl.uniform1i(this.uniforms.x, n.x); - gl.uniform1i(this.uniforms.y, n.y); - gl.uniform1i(this.uniforms.z, n.z); + this.tiles.forEach(tile => { + tile.images.forEach(n => { + gl.uniform1i(this.uniforms.x, n._x); + gl.uniform1i(this.uniforms.y, n._y); + gl.uniform1i(this.uniforms.z, n._z); - if (!n.texture && n.loaded) { - var texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, n.image); + if (!n.texture) { + var texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, n); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.bindTexture(gl.TEXTURE_2D, null); + gl.bindTexture(gl.TEXTURE_2D, null); - n.texture = texture; - } + n.texture = texture; + } else { + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, n.texture); + gl.uniform1i(this.uniforms.map, 0); + } - if (n.texture) { - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, n.texture); - gl.uniform1i(this.uniforms.map, 0); - } - - gl.drawElements(gl.TRIANGLES, geometry.index.count, gl.UNSIGNED_SHORT, 0); + gl.drawElements(gl.TRIANGLES, this.geometry.index.count, gl.UNSIGNED_SHORT, 0); + }); }); gl.bindBuffer(gl.ARRAY_BUFFER, null); @@ -213,8 +203,6 @@ TiledLayerRenderer.prototype.dispose = function () { this.buffers = {}; - delete this.mesh; - this.creator.dispose(); Renderer.prototype.dispose.call(this); diff --git a/ShadowEditor.Web/src/gis/tile/SphereTileCreator.js b/ShadowEditor.Web/src/gis/tile/SphereTileCreator.js index b5c8a3b4..86502f31 100644 --- a/ShadowEditor.Web/src/gis/tile/SphereTileCreator.js +++ b/ShadowEditor.Web/src/gis/tile/SphereTileCreator.js @@ -1,7 +1,6 @@ import WGS84 from '../core/WGS84'; import TileCreator from './TileCreator'; import Tile from './Tile'; -import TiledMaterial from '../render/tiled/TiledMaterial'; import GeoUtils from '../utils/GeoUtils'; /** @@ -15,24 +14,23 @@ function SphereTileCreator(globe) { this.cache = new Map(); this._centerZoom = 0; - - this.tiles = []; } SphereTileCreator.prototype = Object.create(TileCreator.prototype); SphereTileCreator.prototype.constructor = SphereTileCreator; -SphereTileCreator.prototype.get = function () { - this.tiles.length = 0; +SphereTileCreator.prototype.get = function (tiles) { + tiles.length = 0; this._centerZoom = ~~GeoUtils.altToZoom(this.camera.position.length() - WGS84.a) + 3; - this.fork(0, 0, 1); - this.fork(1, 0, 1); - this.fork(0, 1, 1); - this.fork(1, 1, 1); + this.fork(0, 0, 1, tiles); + this.fork(1, 0, 1, tiles); + this.fork(0, 1, 1, tiles); + this.fork(1, 1, 1, tiles); - this.tiles = this.tiles.sort((a, b) => { + // 排序 + tiles = tiles.sort((a, b) => { if (a.z > b.z) { return 1; } else if (a.z < b.z) { @@ -42,7 +40,18 @@ SphereTileCreator.prototype.get = function () { } }); - return this.tiles; + // 获取图层数据 + tiles.forEach(tile => { + tile.images.length = 0; + this.globe.layerList.forEach(n => { + var image = n.get(tile.x, tile.y, tile.z); + if (image) { + tile.images.push(image); + } + }); + }); + + return tiles; }; /** @@ -50,24 +59,25 @@ SphereTileCreator.prototype.get = function () { * @param {*} x * @param {*} y * @param {*} z + * @param {*} tiles */ -SphereTileCreator.prototype.fork = function (x, y, z) { +SphereTileCreator.prototype.fork = function (x, y, z, tiles) { var tile = this.getTile(x, y, z); if (!this.isVisible(tile)) { return; } - this.tiles.push(tile); + tiles.push(tile); if (tile.z > this._centerZoom) { return; } - this.fork(x * 2, y * 2, z + 1); - this.fork(x * 2 + 1, y * 2, z + 1); - this.fork(x * 2, y * 2 + 1, z + 1); - this.fork(x * 2 + 1, y * 2 + 1, z + 1); + this.fork(x * 2, y * 2, z + 1, tiles); + this.fork(x * 2 + 1, y * 2, z + 1, tiles); + this.fork(x * 2, y * 2 + 1, z + 1, tiles); + this.fork(x * 2 + 1, y * 2 + 1, z + 1, tiles); }; /** @@ -83,8 +93,6 @@ SphereTileCreator.prototype.getTile = function (x, y, z) { if (!tile) { tile = new Tile(x, y, z); - tile.material = new TiledMaterial(x, y, z, this.options); - tile.material.load(); this.cache.set(id, tile); } @@ -98,15 +106,10 @@ SphereTileCreator.prototype.getTile = function (x, y, z) { * @param {*} tile */ SphereTileCreator.prototype.isVisible = function (tile) { - if (!tile.material.loaded) { - return false; - } - return this.globe.viewer.aabb.intersectsBox(tile._aabb); }; SphereTileCreator.prototype.dispose = function () { - this.tiles.length = 0; this.cache.clear(); TileCreator.prototype.dispose.call(this); }; diff --git a/ShadowEditor.Web/src/gis/tile/Tile.js b/ShadowEditor.Web/src/gis/tile/Tile.js index a03c1489..19fa3fcf 100644 --- a/ShadowEditor.Web/src/gis/tile/Tile.js +++ b/ShadowEditor.Web/src/gis/tile/Tile.js @@ -13,6 +13,8 @@ function Tile(x = 0, y = 0, z = 0) { this.y = y; this.z = z; + this.images = []; + this._aabb = this._getBox(x, y, z); this._center = this._getCenter(this._aabb); this._vertices = this._getVertices(this._aabb, this._center);