UNPKG

cione-comp-lib

Version:

`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`

332 lines (331 loc) 13.7 kB
import "../../../../echarts/lib/echarts.mjs"; import graphicGL from "../../util/graphicGL.mjs"; import OrbitControl from "../../util/OrbitControl.mjs"; import SceneHelper from "../common/SceneHelper.mjs"; import sunCalc from "../../util/sunCalc.mjs"; import retrieve from "../../util/retrieve.mjs"; import utilShaderCode from "../../../../claygl/src/shader/source/util.glsl.mjs"; import atmosphereShaderCode from "./atmosphere.glsl.mjs"; import ComponentView from "../../../../echarts/lib/view/Component.mjs"; import { each } from "../../../../zrender/lib/core/util.mjs"; import Model from "../../../../echarts/lib/model/Model.mjs"; import { parseDate } from "../../../../echarts/lib/util/number.mjs"; graphicGL.Shader["import"](utilShaderCode); graphicGL.Shader["import"](atmosphereShaderCode); var GlobeView = ComponentView.extend({ type: "globe", __ecgl__: true, _displacementScale: 0, init: function(ecModel, api) { this.groupGL = new graphicGL.Node(); this._sphereGeometry = new graphicGL.SphereGeometry({ widthSegments: 200, heightSegments: 100, dynamic: true }); this._overlayGeometry = new graphicGL.SphereGeometry({ widthSegments: 80, heightSegments: 40 }); this._planeGeometry = new graphicGL.PlaneGeometry(); this._earthMesh = new graphicGL.Mesh({ renderNormal: true }); this._atmosphereMesh = new graphicGL.Mesh(); this._atmosphereGeometry = new graphicGL.SphereGeometry({ widthSegments: 80, heightSegments: 40 }); this._atmosphereMaterial = new graphicGL.Material({ shader: new graphicGL.Shader(graphicGL.Shader.source("ecgl.atmosphere.vertex"), graphicGL.Shader.source("ecgl.atmosphere.fragment")), transparent: true }); this._atmosphereMesh.geometry = this._atmosphereGeometry; this._atmosphereMesh.material = this._atmosphereMaterial; this._atmosphereMesh.frontFace = graphicGL.Mesh.CW; this._lightRoot = new graphicGL.Node(); this._sceneHelper = new SceneHelper(); this._sceneHelper.initLight(this._lightRoot); this.groupGL.add(this._atmosphereMesh); this.groupGL.add(this._earthMesh); this._control = new OrbitControl({ zr: api.getZr() }); this._control.init(); this._layerMeshes = {}; }, render: function(globeModel, ecModel, api) { var coordSys = globeModel.coordinateSystem; var shading = globeModel.get("shading"); coordSys.viewGL.add(this._lightRoot); if (globeModel.get("show")) { coordSys.viewGL.add(this.groupGL); } else { coordSys.viewGL.remove(this.groupGL); } this._sceneHelper.setScene(coordSys.viewGL.scene); coordSys.viewGL.setPostEffect(globeModel.getModel("postEffect"), api); coordSys.viewGL.setTemporalSuperSampling(globeModel.getModel("temporalSuperSampling")); var earthMesh = this._earthMesh; earthMesh.geometry = this._sphereGeometry; var shadingPrefix = "ecgl." + shading; if (!earthMesh.material || earthMesh.material.shader.name !== shadingPrefix) { earthMesh.material = graphicGL.createMaterial(shadingPrefix); } graphicGL.setMaterialFromModel(shading, earthMesh.material, globeModel, api); ["roughnessMap", "metalnessMap", "detailMap", "normalMap"].forEach(function(texName) { var texture = earthMesh.material.get(texName); if (texture) { texture.flipY = false; } }); earthMesh.material.set("color", graphicGL.parseColor(globeModel.get("baseColor"))); var scale = coordSys.radius * 0.99; earthMesh.scale.set(scale, scale, scale); if (globeModel.get("atmosphere.show")) { earthMesh.material.define("both", "ATMOSPHERE_ENABLED"); this._atmosphereMesh.invisible = false; this._atmosphereMaterial.setUniforms({ glowPower: globeModel.get("atmosphere.glowPower") || 6, glowColor: globeModel.get("atmosphere.color") || "#ffffff" }); earthMesh.material.setUniforms({ glowPower: globeModel.get("atmosphere.innerGlowPower") || 2, glowColor: globeModel.get("atmosphere.color") || "#ffffff" }); var offset = globeModel.get("atmosphere.offset") || 5; this._atmosphereMesh.scale.set(scale + offset, scale + offset, scale + offset); } else { earthMesh.material.undefine("both", "ATMOSPHERE_ENABLED"); this._atmosphereMesh.invisible = true; } var diffuseTexture = earthMesh.material.setTextureImage("diffuseMap", globeModel.get("baseTexture"), api, { flipY: false, anisotropic: 8 }); if (diffuseTexture && diffuseTexture.surface) { diffuseTexture.surface.attachToMesh(earthMesh); } var bumpTexture = earthMesh.material.setTextureImage("bumpMap", globeModel.get("heightTexture"), api, { flipY: false, anisotropic: 8 }); if (bumpTexture && bumpTexture.surface) { bumpTexture.surface.attachToMesh(earthMesh); } earthMesh.material[globeModel.get("postEffect.enable") ? "define" : "undefine"]("fragment", "SRGB_DECODE"); this._updateLight(globeModel, api); this._displaceVertices(globeModel, api); this._updateViewControl(globeModel, api); this._updateLayers(globeModel, api); }, afterRender: function(globeModel, ecModel, api, layerGL) { var renderer = layerGL.renderer; this._sceneHelper.updateAmbientCubemap(renderer, globeModel, api); this._sceneHelper.updateSkybox(renderer, globeModel, api); }, _updateLayers: function(globeModel, api) { var coordSys = globeModel.coordinateSystem; var layers = globeModel.get("layers"); var lastDistance = coordSys.radius; var layerDiffuseTextures = []; var layerDiffuseIntensity = []; var layerEmissiveTextures = []; var layerEmissionIntensity = []; each(layers, function(layerOption) { var layerModel = new Model(layerOption); var layerType = layerModel.get("type"); var texture = graphicGL.loadTexture(layerModel.get("texture"), api, { flipY: false, anisotropic: 8 }); if (texture.surface) { texture.surface.attachToMesh(this._earthMesh); } if (layerType === "blend") { var blendTo = layerModel.get("blendTo"); var intensity = retrieve.firstNotNull(layerModel.get("intensity"), 1); if (blendTo === "emission") { layerEmissiveTextures.push(texture); layerEmissionIntensity.push(intensity); } else { layerDiffuseTextures.push(texture); layerDiffuseIntensity.push(intensity); } } else { var id = layerModel.get("id"); var overlayMesh = this._layerMeshes[id]; if (!overlayMesh) { overlayMesh = this._layerMeshes[id] = new graphicGL.Mesh({ geometry: this._overlayGeometry, castShadow: false, ignorePicking: true }); } var shading = layerModel.get("shading"); if (shading === "lambert") { overlayMesh.material = overlayMesh.__lambertMaterial || new graphicGL.Material({ autoUpdateTextureStatus: false, shader: graphicGL.createShader("ecgl.lambert"), transparent: true, depthMask: false }); overlayMesh.__lambertMaterial = overlayMesh.material; } else { overlayMesh.material = overlayMesh.__colorMaterial || new graphicGL.Material({ autoUpdateTextureStatus: false, shader: graphicGL.createShader("ecgl.color"), transparent: true, depthMask: false }); overlayMesh.__colorMaterial = overlayMesh.material; } overlayMesh.material.enableTexture("diffuseMap"); var distance = layerModel.get("distance"); var radius = lastDistance + (distance == null ? coordSys.radius / 100 : distance); overlayMesh.scale.set(radius, radius, radius); lastDistance = radius; var blankTexture = this._blankTexture || (this._blankTexture = graphicGL.createBlankTexture("rgba(255, 255, 255, 0)")); overlayMesh.material.set("diffuseMap", blankTexture); graphicGL.loadTexture(layerModel.get("texture"), api, { flipY: false, anisotropic: 8 }, function(texture2) { if (texture2.surface) { texture2.surface.attachToMesh(overlayMesh); } overlayMesh.material.set("diffuseMap", texture2); api.getZr().refresh(); }); layerModel.get("show") ? this.groupGL.add(overlayMesh) : this.groupGL.remove(overlayMesh); } }, this); var earthMaterial = this._earthMesh.material; earthMaterial.define("fragment", "LAYER_DIFFUSEMAP_COUNT", layerDiffuseTextures.length); earthMaterial.define("fragment", "LAYER_EMISSIVEMAP_COUNT", layerEmissiveTextures.length); earthMaterial.set("layerDiffuseMap", layerDiffuseTextures); earthMaterial.set("layerDiffuseIntensity", layerDiffuseIntensity); earthMaterial.set("layerEmissiveMap", layerEmissiveTextures); earthMaterial.set("layerEmissionIntensity", layerEmissionIntensity); var debugWireframeModel = globeModel.getModel("debug.wireframe"); if (debugWireframeModel.get("show")) { earthMaterial.define("both", "WIREFRAME_TRIANGLE"); var color = graphicGL.parseColor(debugWireframeModel.get("lineStyle.color") || "rgba(0,0,0,0.5)"); var width = retrieve.firstNotNull(debugWireframeModel.get("lineStyle.width"), 1); earthMaterial.set("wireframeLineWidth", width); earthMaterial.set("wireframeLineColor", color); } else { earthMaterial.undefine("both", "WIREFRAME_TRIANGLE"); } }, _updateViewControl: function(globeModel, api) { var coordSys = globeModel.coordinateSystem; var viewControlModel = globeModel.getModel("viewControl"); coordSys.viewGL.camera; var self = this; function makeAction() { return { type: "globeChangeCamera", alpha: control.getAlpha(), beta: control.getBeta(), distance: control.getDistance() - coordSys.radius, center: control.getCenter(), from: self.uid, globeId: globeModel.id }; } var control = this._control; control.setViewGL(coordSys.viewGL); var coord = viewControlModel.get("targetCoord"); var alpha, beta; if (coord != null) { beta = coord[0] + 90; alpha = coord[1]; } control.setFromViewControlModel(viewControlModel, { baseDistance: coordSys.radius, alpha, beta }); control.off("update"); control.on("update", function() { api.dispatchAction(makeAction()); }); }, _displaceVertices: function(globeModel, api) { var displacementQuality = globeModel.get("displacementQuality"); var showDebugWireframe = globeModel.get("debug.wireframe.show"); var globe = globeModel.coordinateSystem; if (!globeModel.isDisplacementChanged() && displacementQuality === this._displacementQuality && showDebugWireframe === this._showDebugWireframe) { return; } this._displacementQuality = displacementQuality; this._showDebugWireframe = showDebugWireframe; var geometry = this._sphereGeometry; var widthSegments = { low: 100, medium: 200, high: 400, ultra: 800 }[displacementQuality] || 200; var heightSegments = widthSegments / 2; if (geometry.widthSegments !== widthSegments || showDebugWireframe) { geometry.widthSegments = widthSegments; geometry.heightSegments = heightSegments; geometry.build(); } this._doDisplaceVertices(geometry, globe); if (showDebugWireframe) { geometry.generateBarycentric(); } }, _doDisplaceVertices: function(geometry, globe) { var positionArr = geometry.attributes.position.value; var uvArr = geometry.attributes.texcoord0.value; var originalPositionArr = geometry.__originalPosition; if (!originalPositionArr || originalPositionArr.length !== positionArr.length) { originalPositionArr = new Float32Array(positionArr.length); originalPositionArr.set(positionArr); geometry.__originalPosition = originalPositionArr; } var width = globe.displacementWidth; var height = globe.displacementHeight; var data = globe.displacementData; for (var i = 0; i < geometry.vertexCount; i++) { var i3 = i * 3; var i2 = i * 2; var x = originalPositionArr[i3 + 1]; var y = originalPositionArr[i3 + 2]; var z = originalPositionArr[i3 + 3]; var u = uvArr[i2++]; var v = uvArr[i2++]; var j = Math.round(u * (width - 1)); var k = Math.round(v * (height - 1)); var idx = k * width + j; var scale = data ? data[idx] : 0; positionArr[i3 + 1] = x + x * scale; positionArr[i3 + 2] = y + y * scale; positionArr[i3 + 3] = z + z * scale; } geometry.generateVertexNormals(); geometry.dirty(); geometry.updateBoundingBox(); }, _updateLight: function(globeModel, api) { var earthMesh = this._earthMesh; this._sceneHelper.updateLight(globeModel); var mainLight = this._sceneHelper.mainLight; var time = globeModel.get("light.main.time") || new Date(); var pos = sunCalc.getPosition(parseDate(time), 0, 0); var r0 = Math.cos(pos.altitude); mainLight.position.y = -r0 * Math.cos(pos.azimuth); mainLight.position.x = Math.sin(pos.altitude); mainLight.position.z = r0 * Math.sin(pos.azimuth); mainLight.lookAt(earthMesh.getWorldPosition()); }, dispose: function(ecModel, api) { this.groupGL.removeAll(); this._control.dispose(); } }); export { GlobeView as default };