cione-comp-lib
Version:
`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`
332 lines (331 loc) • 13.7 kB
JavaScript
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 };