1270 lines
48 KiB
JavaScript
1270 lines
48 KiB
JavaScript
/*
|
|
* @Descripttion:
|
|
* @version: 1.0
|
|
* @Author: zhangti
|
|
* @Date: 2019-11-20 12:17:21
|
|
* @LastEditors : sueRimn
|
|
* @LastEditTime : 2020-01-10 18:06:41
|
|
*/
|
|
/**
|
|
* wind3D
|
|
* 封装风场洋流等效果
|
|
* 对winds改版
|
|
*/
|
|
const fileOptions = {
|
|
dataDirectory: demo ? 'https://raw.githubusercontent.com/RaymanNg/3D-Wind-Field/master/data/' : config.DATADIR + '/3DWind/data/',
|
|
dataFile: "",
|
|
glslDirectory: demo ? '../Cesium-3D-Wind/glsl/' : config.DATADIR + '/3DWind/glsl/'
|
|
}
|
|
const defaultParticleSystemOptions = {
|
|
maxParticles: 128 * 128,
|
|
particleHeight: 100.0,
|
|
fadeOpacity: 0.996,
|
|
dropRate: 0.003,
|
|
dropRateBump: 0.01,
|
|
speedFactor: 4.0,
|
|
lineWidth: 4.0
|
|
}
|
|
const globeLayers = [
|
|
{ name: "GOOGLEIMAGERY", type: "GOOGLEIMAGERY" },
|
|
{ name: "NaturalEarthII", type: "NaturalEarthII" },
|
|
{ name: "WMS:Rainfall", type: "WMS", layer: "Precipitable_water_entire_atmosphere_single_layer", ColorScaleRange: '0.1,66.8' },
|
|
{ name: "WMS:Air Pressure", type: "WMS", layer: "Pressure_surface", ColorScaleRange: '51640,103500' },
|
|
{ name: "WMS:Temperature", type: "WMS", layer: "Temperature_surface", ColorScaleRange: '204.1,317.5' },
|
|
{ name: "WMS:Wind Speed", type: "WMS", layer: "Wind_speed_gust_surface", ColorScaleRange: '0.1095,35.31' },
|
|
{ name: "WorldTerrain", type: "WorldTerrain" }
|
|
]
|
|
const defaultLayerOptions = {
|
|
"globeLayer": globeLayers[0],
|
|
"WMS_URL": "https://www.ncei.noaa.gov/thredds/wms/model-gfs-g4-anl-files/201809/20180916/gfsanl_4_20180916_0000_000.grb2",
|
|
}
|
|
var demo = false;
|
|
const mode = {
|
|
debug: demo ? false : true
|
|
};
|
|
import {TAG} from './tag.js';
|
|
import config from './config.js';
|
|
export default class Wind3D {
|
|
/**
|
|
* 初始化
|
|
*/
|
|
constructor(opt) {
|
|
if(!opt)return false;
|
|
if(!opt.data)return false;
|
|
if (mode.debug) {
|
|
//options.useDefaultRenderLoop = false;
|
|
}
|
|
this.viewer = opt.viewer;
|
|
fileOptions.dataFile = config.DATADIR + '/3DWind/data/demo.nc'
|
|
this.scene = opt.viewer.scene;
|
|
this.camera = opt.viewer.camera;
|
|
this.primitivesObj = [];
|
|
this.panel = new Panel();
|
|
|
|
this.viewerParameters = {
|
|
lonRange: new Cesium.Cartesian2(),
|
|
latRange: new Cesium.Cartesian2(),
|
|
pixelSize: 0.0
|
|
};
|
|
// use a smaller earth radius to make sure distance to camera > 0
|
|
this.globeBoundingSphere = new Cesium.BoundingSphere(Cesium.Cartesian3.ZERO, 0.99 * 6378137.0);
|
|
this.updateViewerParameters();
|
|
|
|
DataProcess.loadData().then(
|
|
(data) => {
|
|
this.particleSystem = new ParticleSystem(this.scene.context, data,
|
|
this.panel.getUserInput(), this.viewerParameters);
|
|
this.addPrimitives();
|
|
|
|
this.setupEventListeners();
|
|
|
|
if (mode.debug) {
|
|
this.debug();
|
|
}
|
|
//新增
|
|
setTimeout(function(){
|
|
$($($('.captureMenuComponent')[0]).parent()).css('display','none')
|
|
$('.myPanel').css("position","absolute").css("top","6%").css("left","5%");
|
|
$('.myPanel select').css('color','black');
|
|
},80);
|
|
});
|
|
this.imageryLayers = this.viewer.imageryLayers;
|
|
this.setGlobeLayer(this.panel.getUserInput());
|
|
}
|
|
remove(){
|
|
if(this.primitivesObj != undefined){
|
|
for(let i in this.primitivesObj){
|
|
this.scene.primitives.remove(this.primitivesObj[i]);
|
|
}
|
|
$('.myPanel').remove();
|
|
//初始化
|
|
this.scene.primitives.removeAll();
|
|
this.viewer.imageryLayers.removeAll();
|
|
this.viewer.imageryLayers.addImageryProvider(TAG.BASELAYER.GOOGLEIMAGERY());
|
|
}
|
|
|
|
}
|
|
addPrimitives() {
|
|
// the order of primitives.add() should respect the dependency of primitives
|
|
this.primitivesObj.push(this.scene.primitives.add(this.particleSystem.particlesComputing.primitives.getWind));
|
|
this.primitivesObj.push(this.scene.primitives.add(this.particleSystem.particlesComputing.primitives.updateSpeed));
|
|
this.primitivesObj.push(this.scene.primitives.add(this.particleSystem.particlesComputing.primitives.updatePosition));
|
|
this.primitivesObj.push(this.scene.primitives.add(this.particleSystem.particlesComputing.primitives.postProcessingPosition));
|
|
this.primitivesObj.push(this.scene.primitives.add(this.particleSystem.particlesComputing.primitives.postProcessingSpeed));
|
|
|
|
this.primitivesObj.push(this.scene.primitives.add(this.particleSystem.particlesRendering.primitives.segments));
|
|
this.primitivesObj.push(this.scene.primitives.add(this.particleSystem.particlesRendering.primitives.trails));
|
|
this.primitivesObj.push(this.scene.primitives.add(this.particleSystem.particlesRendering.primitives.screen));
|
|
}
|
|
|
|
updateViewerParameters() {
|
|
var viewRectangle = this.camera.computeViewRectangle(this.scene.globe.ellipsoid);
|
|
var lonLatRange = Util.viewRectangleToLonLatRange(viewRectangle);
|
|
this.viewerParameters.lonRange.x = lonLatRange.lon.min;
|
|
this.viewerParameters.lonRange.y = lonLatRange.lon.max;
|
|
this.viewerParameters.latRange.x = lonLatRange.lat.min;
|
|
this.viewerParameters.latRange.y = lonLatRange.lat.max;
|
|
|
|
var pixelSize = this.camera.getPixelSize(
|
|
this.globeBoundingSphere,
|
|
this.scene.drawingBufferWidth,
|
|
this.scene.drawingBufferHeight
|
|
);
|
|
|
|
if (pixelSize > 0) {
|
|
this.viewerParameters.pixelSize = pixelSize;
|
|
}
|
|
}
|
|
|
|
setGlobeLayer(userInput) {
|
|
this.viewer.imageryLayers.removeAll();
|
|
this.viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider();
|
|
|
|
var globeLayer = userInput.globeLayer;
|
|
switch (globeLayer.type) {
|
|
case "GOOGLEIMAGERY":this.viewer.imageryLayers.addImageryProvider(TAG.BASELAYER.GOOGLEIMAGERY());
|
|
break;
|
|
case "NaturalEarthII": {
|
|
this.viewer.imageryLayers.addImageryProvider(
|
|
Cesium.createTileMapServiceImageryProvider({
|
|
url: Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')
|
|
})
|
|
);
|
|
break;
|
|
}
|
|
case "WMS": {
|
|
this.viewer.imageryLayers.addImageryProvider(new Cesium.WebMapServiceImageryProvider({
|
|
url: userInput.WMS_URL,
|
|
layers: globeLayer.layer,
|
|
parameters: {
|
|
ColorScaleRange: globeLayer.ColorScaleRange
|
|
}
|
|
}));
|
|
break;
|
|
}
|
|
case "WorldTerrain": {
|
|
this.viewer.imageryLayers.addImageryProvider(
|
|
Cesium.createWorldImagery()
|
|
);
|
|
this.viewer.terrainProvider = Cesium.createWorldTerrain();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
setupEventListeners() {
|
|
const that = this;
|
|
|
|
this.camera.moveStart.addEventListener(function () {
|
|
that.scene.primitives.show = false;
|
|
});
|
|
|
|
this.camera.moveEnd.addEventListener(function () {
|
|
that.updateViewerParameters();
|
|
that.particleSystem.applyViewerParameters(that.viewerParameters);
|
|
that.scene.primitives.show = true;
|
|
});
|
|
|
|
var resized = false;
|
|
window.addEventListener("resize", function () {
|
|
resized = true;
|
|
that.scene.primitives.show = false;
|
|
that.scene.primitives.removeAll();
|
|
});
|
|
|
|
this.scene.preRender.addEventListener(function () {
|
|
if (resized) {
|
|
that.particleSystem.canvasResize(that.scene.context);
|
|
resized = false;
|
|
that.addPrimitives();
|
|
that.scene.primitives.show = true;
|
|
}
|
|
});
|
|
|
|
window.addEventListener('particleSystemOptionsChanged', function () {
|
|
that.particleSystem.applyUserInput(that.panel.getUserInput());
|
|
});
|
|
window.addEventListener('layerOptionsChanged', function () {
|
|
that.setGlobeLayer(that.panel.getUserInput());
|
|
});
|
|
}
|
|
|
|
debug() {
|
|
const that = this;
|
|
|
|
var animate = function () {
|
|
that.viewer.resize();
|
|
that.viewer.render();
|
|
requestAnimationFrame(animate);
|
|
}
|
|
|
|
var spector = new SPECTOR.Spector();
|
|
spector.displayUI();
|
|
spector.spyCanvases();
|
|
|
|
animate();
|
|
}
|
|
}
|
|
/**
|
|
* CustomPrimitive
|
|
*/
|
|
class CustomPrimitive {
|
|
constructor(options) {
|
|
this.commandType = options.commandType;
|
|
|
|
this.geometry = options.geometry;
|
|
this.attributeLocations = options.attributeLocations;
|
|
this.primitiveType = options.primitiveType;
|
|
|
|
this.uniformMap = options.uniformMap;
|
|
|
|
this.vertexShaderSource = options.vertexShaderSource;
|
|
this.fragmentShaderSource = options.fragmentShaderSource;
|
|
|
|
this.rawRenderState = options.rawRenderState;
|
|
this.framebuffer = options.framebuffer;
|
|
|
|
this.outputTexture = options.outputTexture;
|
|
|
|
this.autoClear = Cesium.defaultValue(options.autoClear, false);
|
|
this.preExecute = options.preExecute;
|
|
|
|
this.show = true;
|
|
this.commandToExecute = undefined;
|
|
this.clearCommand = undefined;
|
|
if (this.autoClear) {
|
|
this.clearCommand = new Cesium.ClearCommand({
|
|
color: new Cesium.Color(0.0, 0.0, 0.0, 0.0),
|
|
depth: 1.0,
|
|
framebuffer: this.framebuffer,
|
|
pass: Cesium.Pass.OPAQUE
|
|
});
|
|
}
|
|
}
|
|
|
|
createCommand(context) {
|
|
switch (this.commandType) {
|
|
case 'Draw': {
|
|
var vertexArray = Cesium.VertexArray.fromGeometry({
|
|
context: context,
|
|
geometry: this.geometry,
|
|
attributeLocations: this.attributeLocations,
|
|
bufferUsage: Cesium.BufferUsage.STATIC_DRAW,
|
|
});
|
|
|
|
var shaderProgram = Cesium.ShaderProgram.fromCache({
|
|
context: context,
|
|
attributeLocations: this.attributeLocations,
|
|
vertexShaderSource: this.vertexShaderSource,
|
|
fragmentShaderSource: this.fragmentShaderSource
|
|
});
|
|
|
|
var renderState = Cesium.RenderState.fromCache(this.rawRenderState);
|
|
return new Cesium.DrawCommand({
|
|
owner: this,
|
|
vertexArray: vertexArray,
|
|
primitiveType: this.primitiveType,
|
|
uniformMap: this.uniformMap,
|
|
modelMatrix: Cesium.Matrix4.IDENTITY,
|
|
shaderProgram: shaderProgram,
|
|
framebuffer: this.framebuffer,
|
|
renderState: renderState,
|
|
pass: Cesium.Pass.OPAQUE
|
|
});
|
|
}
|
|
case 'Compute': {
|
|
return new Cesium.ComputeCommand({
|
|
owner: this,
|
|
fragmentShaderSource: this.fragmentShaderSource,
|
|
uniformMap: this.uniformMap,
|
|
outputTexture: this.outputTexture,
|
|
persists: true
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
setGeometry(context, geometry) {
|
|
this.geometry = geometry;
|
|
var vertexArray = Cesium.VertexArray.fromGeometry({
|
|
context: context,
|
|
geometry: this.geometry,
|
|
attributeLocations: this.attributeLocations,
|
|
bufferUsage: Cesium.BufferUsage.STATIC_DRAW,
|
|
});
|
|
this.commandToExecute.vertexArray = vertexArray;
|
|
}
|
|
|
|
update(frameState) {
|
|
if (!this.show) {
|
|
return;
|
|
}
|
|
|
|
if (!Cesium.defined(this.commandToExecute)) {
|
|
this.commandToExecute = this.createCommand(frameState.context);
|
|
}
|
|
|
|
if (Cesium.defined(this.preExecute)) {
|
|
this.preExecute();
|
|
}
|
|
|
|
if (Cesium.defined(this.clearCommand)) {
|
|
frameState.commandList.push(this.clearCommand);
|
|
}
|
|
frameState.commandList.push(this.commandToExecute);
|
|
}
|
|
|
|
isDestroyed() {
|
|
return false;
|
|
}
|
|
|
|
destroy() {
|
|
if (Cesium.defined(this.commandToExecute)) {
|
|
this.commandToExecute.shaderProgram = this.commandToExecute.shaderProgram && this.commandToExecute.shaderProgram.destroy();
|
|
}
|
|
return Cesium.destroyObject(this);
|
|
}
|
|
}
|
|
/**
|
|
* ParticlesComputing
|
|
*/
|
|
class ParticlesComputing {
|
|
constructor(context, data, userInput, viewerParameters) {
|
|
this.createWindTextures(context, data);
|
|
this.createParticlesTextures(context, userInput, viewerParameters);
|
|
this.createComputingPrimitives(data, userInput, viewerParameters);
|
|
}
|
|
|
|
createWindTextures(context, data) {
|
|
var windTextureOptions = {
|
|
context: context,
|
|
width: data.dimensions.lon,
|
|
height: data.dimensions.lat * data.dimensions.lev,
|
|
pixelFormat: Cesium.PixelFormat.LUMINANCE,
|
|
pixelDatatype: Cesium.PixelDatatype.FLOAT,
|
|
flipY: false,
|
|
sampler: new Cesium.Sampler({
|
|
// the values of texture will not be interpolated
|
|
minificationFilter: Cesium.TextureMinificationFilter.NEAREST,
|
|
magnificationFilter: Cesium.TextureMagnificationFilter.NEAREST
|
|
})
|
|
};
|
|
|
|
this.windTextures = {
|
|
U: Util.createTexture(windTextureOptions, data.U.array),
|
|
V: Util.createTexture(windTextureOptions, data.V.array)
|
|
};
|
|
}
|
|
|
|
createParticlesTextures(context, userInput, viewerParameters) {
|
|
var particlesTextureOptions = {
|
|
context: context,
|
|
width: userInput.particlesTextureSize,
|
|
height: userInput.particlesTextureSize,
|
|
pixelFormat: Cesium.PixelFormat.RGBA,
|
|
pixelDatatype: Cesium.PixelDatatype.FLOAT,
|
|
flipY: false,
|
|
sampler: new Cesium.Sampler({
|
|
// the values of texture will not be interpolated
|
|
minificationFilter: Cesium.TextureMinificationFilter.NEAREST,
|
|
magnificationFilter: Cesium.TextureMagnificationFilter.NEAREST
|
|
})
|
|
};
|
|
|
|
var particlesArray = DataProcess.randomizeParticles(userInput.maxParticles, viewerParameters)
|
|
|
|
this.particlesTextures = {
|
|
particlesWind: Util.createTexture(particlesTextureOptions),
|
|
|
|
currentParticlesPosition: Util.createTexture(particlesTextureOptions, particlesArray),
|
|
nextParticlesPosition: Util.createTexture(particlesTextureOptions, particlesArray),
|
|
|
|
currentParticlesSpeed: Util.createTexture(particlesTextureOptions),
|
|
nextParticlesSpeed: Util.createTexture(particlesTextureOptions),
|
|
|
|
postProcessingPosition: Util.createTexture(particlesTextureOptions, particlesArray),
|
|
postProcessingSpeed: Util.createTexture(particlesTextureOptions)
|
|
};
|
|
}
|
|
|
|
destroyParticlesTextures() {
|
|
Object.keys(this.particlesTextures).forEach((key) => {
|
|
this.particlesTextures[key].destroy();
|
|
});
|
|
}
|
|
|
|
createComputingPrimitives(data, userInput, viewerParameters) {
|
|
const dimension = new Cesium.Cartesian3(data.dimensions.lon, data.dimensions.lat, data.dimensions.lev);
|
|
const minimum = new Cesium.Cartesian3(data.lon.min, data.lat.min, data.lev.min);
|
|
const maximum = new Cesium.Cartesian3(data.lon.max, data.lat.max, data.lev.max);
|
|
const interval = new Cesium.Cartesian3(
|
|
(maximum.x - minimum.x) / (dimension.x - 1),
|
|
(maximum.y - minimum.y) / (dimension.y - 1),
|
|
dimension.z > 1 ? (maximum.z - minimum.z) / (dimension.z - 1) : 1.0
|
|
);
|
|
const uSpeedRange = new Cesium.Cartesian2(data.U.min, data.U.max);
|
|
const vSpeedRange = new Cesium.Cartesian2(data.V.min, data.V.max);
|
|
|
|
const that = this;
|
|
|
|
this.primitives = {
|
|
getWind: new CustomPrimitive({
|
|
commandType: 'Compute',
|
|
uniformMap: {
|
|
U: function () {
|
|
return that.windTextures.U;
|
|
},
|
|
V: function () {
|
|
return that.windTextures.V;
|
|
},
|
|
currentParticlesPosition: function () {
|
|
return that.particlesTextures.currentParticlesPosition;
|
|
},
|
|
dimension: function () {
|
|
return dimension;
|
|
},
|
|
minimum: function () {
|
|
return minimum;
|
|
},
|
|
maximum: function () {
|
|
return maximum;
|
|
},
|
|
interval: function () {
|
|
return interval;
|
|
}
|
|
},
|
|
fragmentShaderSource: new Cesium.ShaderSource({
|
|
sources: [Util.loadText(fileOptions.glslDirectory + 'getWind.frag')]
|
|
}),
|
|
outputTexture: this.particlesTextures.particlesWind,
|
|
preExecute: function () {
|
|
// keep the outputTexture up to date
|
|
that.primitives.getWind.commandToExecute.outputTexture = that.particlesTextures.particlesWind;
|
|
}
|
|
}),
|
|
|
|
updateSpeed: new CustomPrimitive({
|
|
commandType: 'Compute',
|
|
uniformMap: {
|
|
currentParticlesSpeed: function () {
|
|
return that.particlesTextures.currentParticlesSpeed;
|
|
},
|
|
particlesWind: function () {
|
|
return that.particlesTextures.particlesWind;
|
|
},
|
|
uSpeedRange: function () {
|
|
return uSpeedRange;
|
|
},
|
|
vSpeedRange: function () {
|
|
return vSpeedRange;
|
|
},
|
|
pixelSize: function () {
|
|
return viewerParameters.pixelSize;
|
|
},
|
|
speedFactor: function () {
|
|
return userInput.speedFactor;
|
|
}
|
|
},
|
|
fragmentShaderSource: new Cesium.ShaderSource({
|
|
sources: [Util.loadText(fileOptions.glslDirectory + 'updateSpeed.frag')]
|
|
}),
|
|
outputTexture: this.particlesTextures.nextParticlesSpeed,
|
|
preExecute: function () {
|
|
// swap textures before binding
|
|
var temp;
|
|
temp = that.particlesTextures.currentParticlesSpeed;
|
|
that.particlesTextures.currentParticlesSpeed = that.particlesTextures.postProcessingSpeed;
|
|
that.particlesTextures.postProcessingSpeed = temp;
|
|
|
|
// keep the outputTexture up to date
|
|
that.primitives.updateSpeed.commandToExecute.outputTexture = that.particlesTextures.nextParticlesSpeed;
|
|
}
|
|
}),
|
|
|
|
updatePosition: new CustomPrimitive({
|
|
commandType: 'Compute',
|
|
uniformMap: {
|
|
currentParticlesPosition: function () {
|
|
return that.particlesTextures.currentParticlesPosition;
|
|
},
|
|
currentParticlesSpeed: function () {
|
|
return that.particlesTextures.currentParticlesSpeed;
|
|
}
|
|
},
|
|
fragmentShaderSource: new Cesium.ShaderSource({
|
|
sources: [Util.loadText(fileOptions.glslDirectory + 'updatePosition.frag')]
|
|
}),
|
|
outputTexture: this.particlesTextures.nextParticlesPosition,
|
|
preExecute: function () {
|
|
// swap textures before binding
|
|
var temp;
|
|
temp = that.particlesTextures.currentParticlesPosition;
|
|
that.particlesTextures.currentParticlesPosition = that.particlesTextures.postProcessingPosition;
|
|
that.particlesTextures.postProcessingPosition = temp;
|
|
|
|
// keep the outputTexture up to date
|
|
that.primitives.updatePosition.commandToExecute.outputTexture = that.particlesTextures.nextParticlesPosition;
|
|
}
|
|
}),
|
|
|
|
postProcessingPosition: new CustomPrimitive({
|
|
commandType: 'Compute',
|
|
uniformMap: {
|
|
nextParticlesPosition: function () {
|
|
return that.particlesTextures.nextParticlesPosition;
|
|
},
|
|
nextParticlesSpeed: function () {
|
|
return that.particlesTextures.nextParticlesSpeed;
|
|
},
|
|
lonRange: function () {
|
|
return viewerParameters.lonRange;
|
|
},
|
|
latRange: function () {
|
|
return viewerParameters.latRange;
|
|
},
|
|
randomCoef: function () {
|
|
var randomCoef = Math.random();
|
|
return randomCoef;
|
|
},
|
|
dropRate: function () {
|
|
return userInput.dropRate;
|
|
},
|
|
dropRateBump: function () {
|
|
return userInput.dropRateBump;
|
|
}
|
|
},
|
|
fragmentShaderSource: new Cesium.ShaderSource({
|
|
sources: [Util.loadText(fileOptions.glslDirectory + 'postProcessingPosition.frag')]
|
|
}),
|
|
outputTexture: this.particlesTextures.postProcessingPosition,
|
|
preExecute: function () {
|
|
// keep the outputTexture up to date
|
|
that.primitives.postProcessingPosition.commandToExecute.outputTexture = that.particlesTextures.postProcessingPosition;
|
|
}
|
|
}),
|
|
|
|
postProcessingSpeed: new CustomPrimitive({
|
|
commandType: 'Compute',
|
|
uniformMap: {
|
|
postProcessingPosition: function () {
|
|
return that.particlesTextures.postProcessingPosition;
|
|
},
|
|
nextParticlesSpeed: function () {
|
|
return that.particlesTextures.nextParticlesSpeed;
|
|
}
|
|
},
|
|
fragmentShaderSource: new Cesium.ShaderSource({
|
|
sources: [Util.loadText(fileOptions.glslDirectory + 'postProcessingSpeed.frag')]
|
|
}),
|
|
outputTexture: this.particlesTextures.postProcessingSpeed,
|
|
preExecute: function () {
|
|
// keep the outputTexture up to date
|
|
that.primitives.postProcessingSpeed.commandToExecute.outputTexture = that.particlesTextures.postProcessingSpeed;
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* ParticlesRendering
|
|
*/
|
|
class ParticlesRendering {
|
|
constructor(context, data, userInput, viewerParameters, particlesComputing) {
|
|
this.createRenderingTextures(context, data);
|
|
this.createRenderingFramebuffers(context);
|
|
this.createRenderingPrimitives(context, userInput, viewerParameters, particlesComputing);
|
|
}
|
|
|
|
createRenderingTextures(context, data) {
|
|
const colorTextureOptions = {
|
|
context: context,
|
|
width: context.drawingBufferWidth,
|
|
height: context.drawingBufferHeight,
|
|
pixelFormat: Cesium.PixelFormat.RGBA,
|
|
pixelDatatype: Cesium.PixelDatatype.UNSIGNED_BYTE
|
|
};
|
|
const depthTextureOptions = {
|
|
context: context,
|
|
width: context.drawingBufferWidth,
|
|
height: context.drawingBufferHeight,
|
|
pixelFormat: Cesium.PixelFormat.DEPTH_COMPONENT,
|
|
pixelDatatype: Cesium.PixelDatatype.UNSIGNED_INT
|
|
};
|
|
const colorTableTextureOptions = {
|
|
context: context,
|
|
width: data.colorTable.colorNum,
|
|
height: 1,
|
|
pixelFormat: Cesium.PixelFormat.RGB,
|
|
pixelDatatype: Cesium.PixelDatatype.FLOAT,
|
|
sampler: new Cesium.Sampler({
|
|
minificationFilter: Cesium.TextureMinificationFilter.LINEAR,
|
|
magnificationFilter: Cesium.TextureMagnificationFilter.LINEAR
|
|
})
|
|
};
|
|
|
|
this.textures = {
|
|
segmentsColor: Util.createTexture(colorTextureOptions),
|
|
segmentsDepth: Util.createTexture(depthTextureOptions),
|
|
|
|
currentTrailsColor: Util.createTexture(colorTextureOptions),
|
|
currentTrailsDepth: Util.createTexture(depthTextureOptions),
|
|
|
|
nextTrailsColor: Util.createTexture(colorTextureOptions),
|
|
nextTrailsDepth: Util.createTexture(depthTextureOptions),
|
|
|
|
colorTable: Util.createTexture(colorTableTextureOptions, data.colorTable.array)
|
|
};
|
|
}
|
|
|
|
createRenderingFramebuffers(context) {
|
|
this.framebuffers = {
|
|
segments: Util.createFramebuffer(context, this.textures.segmentsColor, this.textures.segmentsDepth),
|
|
currentTrails: Util.createFramebuffer(context, this.textures.currentTrailsColor, this.textures.currentTrailsDepth),
|
|
nextTrails: Util.createFramebuffer(context, this.textures.nextTrailsColor, this.textures.nextTrailsDepth)
|
|
}
|
|
}
|
|
|
|
createSegmentsGeometry(userInput) {
|
|
const repeatVertex = 4;
|
|
|
|
var st = [];
|
|
for (var s = 0; s < userInput.particlesTextureSize; s++) {
|
|
for (var t = 0; t < userInput.particlesTextureSize; t++) {
|
|
for (var i = 0; i < repeatVertex; i++) {
|
|
st.push(s / userInput.particlesTextureSize);
|
|
st.push(t / userInput.particlesTextureSize);
|
|
}
|
|
}
|
|
}
|
|
st = new Float32Array(st);
|
|
|
|
var normal = [];
|
|
const pointToUse = [-1, 1];
|
|
const offsetSign = [-1, 1];
|
|
for (var i = 0; i < userInput.maxParticles; i++) {
|
|
for (var j = 0; j < repeatVertex / 2; j++) {
|
|
for (var k = 0; k < repeatVertex / 2; k++) {
|
|
normal.push(pointToUse[j]);
|
|
normal.push(offsetSign[k]);
|
|
normal.push(0);
|
|
}
|
|
}
|
|
}
|
|
normal = new Float32Array(normal);
|
|
|
|
const indexSize = 6 * userInput.maxParticles;
|
|
var vertexIndexes = new Uint32Array(indexSize);
|
|
for (var i = 0, j = 0, vertex = 0; i < userInput.maxParticles; i++) {
|
|
vertexIndexes[j++] = vertex + 0;
|
|
vertexIndexes[j++] = vertex + 1;
|
|
vertexIndexes[j++] = vertex + 2;
|
|
vertexIndexes[j++] = vertex + 2;
|
|
vertexIndexes[j++] = vertex + 1;
|
|
vertexIndexes[j++] = vertex + 3;
|
|
vertex += 4;
|
|
}
|
|
|
|
var geometry = new Cesium.Geometry({
|
|
attributes: new Cesium.GeometryAttributes({
|
|
st: new Cesium.GeometryAttribute({
|
|
componentDatatype: Cesium.ComponentDatatype.FLOAT,
|
|
componentsPerAttribute: 2,
|
|
values: st
|
|
}),
|
|
normal: new Cesium.GeometryAttribute({
|
|
componentDatatype: Cesium.ComponentDatatype.FLOAT,
|
|
componentsPerAttribute: 3,
|
|
values: normal
|
|
}),
|
|
}),
|
|
indices: vertexIndexes
|
|
});
|
|
|
|
return geometry;
|
|
}
|
|
|
|
createRenderingPrimitives(context, userInput, viewerParameters, particlesComputing) {
|
|
const that = this;
|
|
this.primitives = {
|
|
segments: new CustomPrimitive({
|
|
commandType: 'Draw',
|
|
attributeLocations: {
|
|
st: 0,
|
|
normal: 1
|
|
},
|
|
geometry: this.createSegmentsGeometry(userInput),
|
|
primitiveType: Cesium.PrimitiveType.TRIANGLES,
|
|
uniformMap: {
|
|
currentParticlesPosition: function () {
|
|
return particlesComputing.particlesTextures.currentParticlesPosition;
|
|
},
|
|
postProcessingPosition: function () {
|
|
return particlesComputing.particlesTextures.postProcessingPosition;
|
|
},
|
|
postProcessingSpeed: function () {
|
|
return particlesComputing.particlesTextures.postProcessingSpeed;
|
|
},
|
|
colorTable: function () {
|
|
return that.textures.colorTable;
|
|
},
|
|
aspect: function () {
|
|
return context.drawingBufferWidth / context.drawingBufferHeight;
|
|
},
|
|
pixelSize: function () {
|
|
return viewerParameters.pixelSize;
|
|
},
|
|
lineWidth: function () {
|
|
return userInput.lineWidth;
|
|
},
|
|
particleHeight: function () {
|
|
return userInput.particleHeight;
|
|
}
|
|
},
|
|
vertexShaderSource: new Cesium.ShaderSource({
|
|
sources: [Util.loadText(fileOptions.glslDirectory + 'segmentDraw.vert')]
|
|
}),
|
|
fragmentShaderSource: new Cesium.ShaderSource({
|
|
sources: [Util.loadText(fileOptions.glslDirectory + 'segmentDraw.frag')]
|
|
}),
|
|
rawRenderState: Util.createRawRenderState({
|
|
// undefined value means let Cesium deal with it
|
|
viewport: undefined,
|
|
depthTest: {
|
|
enabled: true
|
|
},
|
|
depthMask: true
|
|
}),
|
|
framebuffer: this.framebuffers.segments,
|
|
autoClear: true
|
|
}),
|
|
|
|
trails: new CustomPrimitive({
|
|
commandType: 'Draw',
|
|
attributeLocations: {
|
|
position: 0,
|
|
st: 1
|
|
},
|
|
geometry: Util.getFullscreenQuad(),
|
|
primitiveType: Cesium.PrimitiveType.TRIANGLES,
|
|
uniformMap: {
|
|
segmentsColorTexture: function () {
|
|
return that.textures.segmentsColor;
|
|
},
|
|
segmentsDepthTexture: function () {
|
|
return that.textures.segmentsDepth;
|
|
},
|
|
currentTrailsColor: function () {
|
|
return that.framebuffers.currentTrails.getColorTexture(0);
|
|
},
|
|
trailsDepthTexture: function () {
|
|
return that.framebuffers.currentTrails.depthTexture;
|
|
},
|
|
fadeOpacity: function () {
|
|
return userInput.fadeOpacity;
|
|
}
|
|
},
|
|
// prevent Cesium from writing depth because the depth here should be written manually
|
|
vertexShaderSource: new Cesium.ShaderSource({
|
|
defines: ['DISABLE_GL_POSITION_LOG_DEPTH'],
|
|
sources: [Util.loadText(fileOptions.glslDirectory + 'fullscreen.vert')]
|
|
}),
|
|
fragmentShaderSource: new Cesium.ShaderSource({
|
|
defines: ['DISABLE_LOG_DEPTH_FRAGMENT_WRITE'],
|
|
sources: [Util.loadText(fileOptions.glslDirectory + 'trailDraw.frag')]
|
|
}),
|
|
rawRenderState: Util.createRawRenderState({
|
|
viewport: undefined,
|
|
depthTest: {
|
|
enabled: true,
|
|
func: Cesium.DepthFunction.ALWAYS // always pass depth test for full control of depth information
|
|
},
|
|
depthMask: true
|
|
}),
|
|
framebuffer: this.framebuffers.nextTrails,
|
|
autoClear: true,
|
|
preExecute: function () {
|
|
// swap framebuffers before binding
|
|
var temp;
|
|
temp = that.framebuffers.currentTrails;
|
|
that.framebuffers.currentTrails = that.framebuffers.nextTrails;
|
|
that.framebuffers.nextTrails = temp;
|
|
|
|
// keep the framebuffers up to date
|
|
that.primitives.trails.commandToExecute.framebuffer = that.framebuffers.nextTrails;
|
|
that.primitives.trails.clearCommand.framebuffer = that.framebuffers.nextTrails;
|
|
}
|
|
}),
|
|
|
|
screen: new CustomPrimitive({
|
|
commandType: 'Draw',
|
|
attributeLocations: {
|
|
position: 0,
|
|
st: 1
|
|
},
|
|
geometry: Util.getFullscreenQuad(),
|
|
primitiveType: Cesium.PrimitiveType.TRIANGLES,
|
|
uniformMap: {
|
|
trailsColorTexture: function () {
|
|
return that.framebuffers.nextTrails.getColorTexture(0);
|
|
},
|
|
trailsDepthTexture: function () {
|
|
return that.framebuffers.nextTrails.depthTexture;
|
|
}
|
|
},
|
|
// prevent Cesium from writing depth because the depth here should be written manually
|
|
vertexShaderSource: new Cesium.ShaderSource({
|
|
defines: ['DISABLE_GL_POSITION_LOG_DEPTH'],
|
|
sources: [Util.loadText(fileOptions.glslDirectory + 'fullscreen.vert')]
|
|
}),
|
|
fragmentShaderSource: new Cesium.ShaderSource({
|
|
defines: ['DISABLE_LOG_DEPTH_FRAGMENT_WRITE'],
|
|
sources: [Util.loadText(fileOptions.glslDirectory + 'screenDraw.frag')]
|
|
}),
|
|
rawRenderState: Util.createRawRenderState({
|
|
viewport: undefined,
|
|
depthTest: {
|
|
enabled: false
|
|
},
|
|
depthMask: true,
|
|
blending: {
|
|
enabled: true
|
|
}
|
|
}),
|
|
framebuffer: undefined // undefined value means let Cesium deal with it
|
|
})
|
|
};
|
|
}
|
|
}
|
|
/**
|
|
* ParticleSystem
|
|
*/
|
|
class ParticleSystem {
|
|
constructor(context, data, userInput, viewerParameters) {
|
|
this.context = context;
|
|
this.data = data;
|
|
this.userInput = userInput;
|
|
this.viewerParameters = viewerParameters;
|
|
|
|
this.particlesComputing = new ParticlesComputing(
|
|
this.context, this.data,
|
|
this.userInput, this.viewerParameters
|
|
);
|
|
this.particlesRendering = new ParticlesRendering(
|
|
this.context, this.data,
|
|
this.userInput, this.viewerParameters,
|
|
this.particlesComputing
|
|
);
|
|
}
|
|
|
|
canvasResize(context) {
|
|
this.particlesComputing.destroyParticlesTextures();
|
|
Object.keys(this.particlesComputing.windTextures).forEach((key) => {
|
|
this.particlesComputing.windTextures[key].destroy();
|
|
});
|
|
|
|
this.particlesRendering.textures.colorTable.destroy();
|
|
Object.keys(this.particlesRendering.framebuffers).forEach((key) => {
|
|
this.particlesRendering.framebuffers[key].destroy();
|
|
});
|
|
|
|
this.context = context;
|
|
this.particlesComputing = new ParticlesComputing(
|
|
this.context, this.data,
|
|
this.userInput, this.viewerParameters
|
|
);
|
|
this.particlesRendering = new ParticlesRendering(
|
|
this.context, this.data,
|
|
this.userInput, this.viewerParameters,
|
|
this.particlesComputing
|
|
);
|
|
}
|
|
|
|
clearFramebuffers() {
|
|
var clearCommand = new Cesium.ClearCommand({
|
|
color: new Cesium.Color(0.0, 0.0, 0.0, 0.0),
|
|
depth: 1.0,
|
|
framebuffer: undefined,
|
|
pass: Cesium.Pass.OPAQUE
|
|
});
|
|
|
|
Object.keys(this.particlesRendering.framebuffers).forEach((key) => {
|
|
clearCommand.framebuffer = this.particlesRendering.framebuffers[key];
|
|
clearCommand.execute(this.context);
|
|
});
|
|
}
|
|
|
|
refreshParticles(maxParticlesChanged) {
|
|
this.clearFramebuffers();
|
|
|
|
this.particlesComputing.destroyParticlesTextures();
|
|
this.particlesComputing.createParticlesTextures(this.context, this.userInput, this.viewerParameters);
|
|
|
|
if (maxParticlesChanged) {
|
|
var geometry = this.particlesRendering.createSegmentsGeometry(this.userInput);
|
|
this.particlesRendering.primitives.segments.geometry = geometry;
|
|
var vertexArray = Cesium.VertexArray.fromGeometry({
|
|
context: this.context,
|
|
geometry: geometry,
|
|
attributeLocations: this.particlesRendering.primitives.segments.attributeLocations,
|
|
bufferUsage: Cesium.BufferUsage.STATIC_DRAW,
|
|
});
|
|
this.particlesRendering.primitives.segments.commandToExecute.vertexArray = vertexArray;
|
|
}
|
|
}
|
|
|
|
applyUserInput(userInput) {
|
|
var maxParticlesChanged = false;
|
|
if (this.userInput.maxParticles != userInput.maxParticles) {
|
|
maxParticlesChanged = true;
|
|
}
|
|
|
|
Object.keys(userInput).forEach((key) => {
|
|
this.userInput[key] = userInput[key];
|
|
});
|
|
this.refreshParticles(maxParticlesChanged);
|
|
}
|
|
|
|
applyViewerParameters(viewerParameters) {
|
|
Object.keys(viewerParameters).forEach((key) => {
|
|
this.viewerParameters[key] = viewerParameters[key];
|
|
});
|
|
this.refreshParticles(false);
|
|
}
|
|
}
|
|
|
|
class Panel {
|
|
constructor() {
|
|
this.maxParticles = defaultParticleSystemOptions.maxParticles;
|
|
this.particleHeight = defaultParticleSystemOptions.particleHeight;
|
|
this.fadeOpacity = defaultParticleSystemOptions.fadeOpacity;
|
|
this.dropRate = defaultParticleSystemOptions.dropRate;
|
|
this.dropRateBump = defaultParticleSystemOptions.dropRateBump;
|
|
this.speedFactor = defaultParticleSystemOptions.speedFactor;
|
|
this.lineWidth = defaultParticleSystemOptions.lineWidth;
|
|
|
|
this.globeLayer = defaultLayerOptions.globeLayer;
|
|
this.WMS_URL = defaultLayerOptions.WMS_URL;
|
|
|
|
var layerNames = [];
|
|
globeLayers.forEach(function (layer) {
|
|
layerNames.push(layer.name);
|
|
});
|
|
this.layerToShow = layerNames[0];
|
|
|
|
var onParticleSystemOptionsChange = function () {
|
|
var event = new CustomEvent('particleSystemOptionsChanged');
|
|
window.dispatchEvent(event);
|
|
}
|
|
|
|
const that = this;
|
|
var onLayerOptionsChange = function () {
|
|
for (var i = 0; i < globeLayers.length; i++) {
|
|
if (that.layerToShow == globeLayers[i].name) {
|
|
that.globeLayer = globeLayers[i];
|
|
break;
|
|
}
|
|
}
|
|
var event = new CustomEvent('layerOptionsChanged');
|
|
window.dispatchEvent(event);
|
|
}
|
|
//创建控制面版
|
|
var gui = new dat.GUI({ autoPlace: false });
|
|
gui.add(that, 'maxParticles', 1, 256 * 256, 1).onFinishChange(onParticleSystemOptionsChange);
|
|
gui.add(that, 'particleHeight', 1, 10000, 1).onFinishChange(onParticleSystemOptionsChange);
|
|
gui.add(that, 'fadeOpacity', 0.90, 0.999, 0.001).onFinishChange(onParticleSystemOptionsChange);
|
|
gui.add(that, 'dropRate', 0.0, 0.1).onFinishChange(onParticleSystemOptionsChange);
|
|
gui.add(that, 'dropRateBump', 0, 0.2).onFinishChange(onParticleSystemOptionsChange);
|
|
gui.add(that, 'speedFactor', 0.5, 100).onFinishChange(onParticleSystemOptionsChange);
|
|
gui.add(that, 'lineWidth', 0.01, 16.0).onFinishChange(onParticleSystemOptionsChange);
|
|
gui.add(that, 'layerToShow', layerNames).onFinishChange(onLayerOptionsChange);
|
|
var panelContainer = document.getElementsByClassName('cesium-widget').item(0);
|
|
gui.domElement.classList.add('myPanel');
|
|
panelContainer.appendChild(gui.domElement);
|
|
}
|
|
|
|
getUserInput() {
|
|
// make sure maxParticles is exactly the square of particlesTextureSize
|
|
var particlesTextureSize = Math.ceil(Math.sqrt(this.maxParticles));
|
|
this.maxParticles = particlesTextureSize * particlesTextureSize;
|
|
|
|
return {
|
|
particlesTextureSize: particlesTextureSize,
|
|
maxParticles: this.maxParticles,
|
|
particleHeight: this.particleHeight,
|
|
fadeOpacity: this.fadeOpacity,
|
|
dropRate: this.dropRate,
|
|
dropRateBump: this.dropRateBump,
|
|
speedFactor: this.speedFactor,
|
|
lineWidth: this.lineWidth,
|
|
globeLayer: this.globeLayer,
|
|
WMS_URL: this.WMS_URL
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* 工具
|
|
*/
|
|
var Util = (function () {
|
|
var loadText = function (filePath) {
|
|
var request = new XMLHttpRequest();
|
|
request.open('GET', filePath, false);
|
|
request.send();
|
|
return request.responseText;
|
|
}
|
|
var getFullscreenQuad = function () {
|
|
var fullscreenQuad = new Cesium.Geometry({
|
|
attributes: new Cesium.GeometryAttributes({
|
|
position: new Cesium.GeometryAttribute({
|
|
componentDatatype: Cesium.ComponentDatatype.FLOAT,
|
|
componentsPerAttribute: 3,
|
|
// v3----v2
|
|
// | |
|
|
// | |
|
|
// v0----v1
|
|
values: new Float32Array([
|
|
-1, -1, 0, // v0
|
|
1, -1, 0, // v1
|
|
1, 1, 0, // v2
|
|
-1, 1, 0, // v3
|
|
])
|
|
}),
|
|
st: new Cesium.GeometryAttribute({
|
|
componentDatatype: Cesium.ComponentDatatype.FLOAT,
|
|
componentsPerAttribute: 2,
|
|
values: new Float32Array([
|
|
0, 0,
|
|
1, 0,
|
|
1, 1,
|
|
0, 1,
|
|
])
|
|
})
|
|
}),
|
|
indices: new Uint32Array([3, 2, 0, 0, 2, 1])
|
|
});
|
|
return fullscreenQuad;
|
|
}
|
|
|
|
var createTexture = function (options, typedArray) {
|
|
if (Cesium.defined(typedArray)) {
|
|
// typed array needs to be passed as source option, this is required by Cesium.Texture
|
|
var source = {};
|
|
source.arrayBufferView = typedArray;
|
|
options.source = source;
|
|
}
|
|
var texture = new Cesium.Texture(options);
|
|
return texture;
|
|
}
|
|
|
|
var createFramebuffer = function (context, colorTexture, depthTexture) {
|
|
var framebuffer = new Cesium.Framebuffer({
|
|
context: context,
|
|
colorTextures: [colorTexture],
|
|
depthTexture: depthTexture
|
|
});
|
|
return framebuffer;
|
|
}
|
|
|
|
var createRawRenderState = function (options) {
|
|
var translucent = true;
|
|
var closed = false;
|
|
var existing = {
|
|
viewport: options.viewport,
|
|
depthTest: options.depthTest,
|
|
depthMask: options.depthMask,
|
|
blending: options.blending
|
|
};
|
|
|
|
var rawRenderState = Cesium.Appearance.getDefaultRenderState(translucent, closed, existing);
|
|
return rawRenderState;
|
|
}
|
|
|
|
var viewRectangleToLonLatRange = function (viewRectangle) {
|
|
var range = {};
|
|
|
|
var postiveWest = Cesium.Math.mod(viewRectangle.west, Cesium.Math.TWO_PI);
|
|
var postiveEast = Cesium.Math.mod(viewRectangle.east, Cesium.Math.TWO_PI);
|
|
var width = viewRectangle.width;
|
|
|
|
var longitudeMin;
|
|
var longitudeMax;
|
|
if (width > Cesium.Math.THREE_PI_OVER_TWO) {
|
|
longitudeMin = 0.0;
|
|
longitudeMax = Cesium.Math.TWO_PI;
|
|
} else {
|
|
if (postiveEast - postiveWest < width) {
|
|
longitudeMin = postiveWest;
|
|
longitudeMax = postiveWest + width;
|
|
} else {
|
|
longitudeMin = postiveWest;
|
|
longitudeMax = postiveEast;
|
|
}
|
|
}
|
|
|
|
range.lon = {
|
|
min: Cesium.Math.toDegrees(longitudeMin),
|
|
max: Cesium.Math.toDegrees(longitudeMax)
|
|
}
|
|
|
|
var south = viewRectangle.south;
|
|
var north = viewRectangle.north;
|
|
var height = viewRectangle.height;
|
|
|
|
var extendHeight = height > Cesium.Math.PI / 12 ? height / 2 : 0;
|
|
var extendedSouth = Cesium.Math.clampToLatitudeRange(south - extendHeight);
|
|
var extendedNorth = Cesium.Math.clampToLatitudeRange(north + extendHeight);
|
|
|
|
// extend the bound in high latitude area to make sure it can cover all the visible area
|
|
if (extendedSouth < -Cesium.Math.PI_OVER_THREE) {
|
|
extendedSouth = -Cesium.Math.PI_OVER_TWO;
|
|
}
|
|
if (extendedNorth > Cesium.Math.PI_OVER_THREE) {
|
|
extendedNorth = Cesium.Math.PI_OVER_TWO;
|
|
}
|
|
|
|
range.lat = {
|
|
min: Cesium.Math.toDegrees(extendedSouth),
|
|
max: Cesium.Math.toDegrees(extendedNorth)
|
|
}
|
|
|
|
return range;
|
|
}
|
|
|
|
return {
|
|
loadText: loadText,
|
|
getFullscreenQuad: getFullscreenQuad,
|
|
createTexture: createTexture,
|
|
createFramebuffer: createFramebuffer,
|
|
createRawRenderState: createRawRenderState,
|
|
viewRectangleToLonLatRange: viewRectangleToLonLatRange
|
|
};
|
|
})();
|
|
var DataProcess = (function () {
|
|
var data;
|
|
|
|
var loadNetCDF = function (filePath) {
|
|
return new Promise(function (resolve) {
|
|
var request = new XMLHttpRequest();
|
|
request.open('GET', filePath);
|
|
request.responseType = 'arraybuffer';
|
|
|
|
request.onload = function () {
|
|
var arrayToMap = function (array) {
|
|
return array.reduce(function (map, object) {
|
|
map[object.name] = object;
|
|
return map;
|
|
}, {});
|
|
}
|
|
|
|
var NetCDF = new netcdfjs(request.response);
|
|
data = {};
|
|
|
|
var dimensions = arrayToMap(NetCDF.dimensions);
|
|
console.log(dimensions);
|
|
data.dimensions = {};
|
|
data.dimensions.lon = dimensions['lon'].size;
|
|
data.dimensions.lat = dimensions['lat'].size;
|
|
data.dimensions.lev = dimensions['lev'].size;
|
|
|
|
var variables = arrayToMap(NetCDF.variables);
|
|
var uAttributes = arrayToMap(variables['U'].attributes);
|
|
var vAttributes = arrayToMap(variables['V'].attributes);
|
|
|
|
data.lon = {};
|
|
data.lon.array = new Float32Array(NetCDF.getDataVariable('lon').flat());
|
|
data.lon.min = Math.min(...data.lon.array);
|
|
data.lon.max = Math.max(...data.lon.array);
|
|
|
|
data.lat = {};
|
|
data.lat.array = new Float32Array(NetCDF.getDataVariable('lat').flat());
|
|
data.lat.min = Math.min(...data.lat.array);
|
|
data.lat.max = Math.max(...data.lat.array);
|
|
|
|
data.lev = {};
|
|
data.lev.array = new Float32Array(NetCDF.getDataVariable('lev').flat());
|
|
data.lev.min = Math.min(...data.lev.array);
|
|
data.lev.max = Math.max(...data.lev.array);
|
|
|
|
data.U = {};
|
|
data.U.array = new Float32Array(NetCDF.getDataVariable('U').flat());
|
|
data.U.min = uAttributes['min'].value;
|
|
data.U.max = uAttributes['max'].value;
|
|
|
|
data.V = {};
|
|
data.V.array = new Float32Array(NetCDF.getDataVariable('V').flat());
|
|
data.V.min = vAttributes['min'].value;
|
|
data.V.max = vAttributes['max'].value;
|
|
|
|
resolve(data);
|
|
};
|
|
|
|
request.send();
|
|
});
|
|
}
|
|
|
|
var loadColorTable = function (filePath) {
|
|
var string = Util.loadText(filePath);
|
|
var json = JSON.parse(string);
|
|
|
|
var colorNum = json['ncolors'];
|
|
var colorTable = json['colorTable'];
|
|
|
|
var colorsArray = new Float32Array(3 * colorNum);
|
|
for (var i = 0; i < colorNum; i++) {
|
|
colorsArray[3 * i] = colorTable[3 * i];
|
|
colorsArray[3 * i + 1] = colorTable[3 * i + 1];
|
|
colorsArray[3 * i + 2] = colorTable[3 * i + 2];
|
|
}
|
|
|
|
data.colorTable = {};
|
|
data.colorTable.colorNum = colorNum;
|
|
data.colorTable.array = colorsArray;
|
|
}
|
|
|
|
var loadData = async function () {
|
|
var ncFilePath = fileOptions.dataFile;
|
|
await loadNetCDF(ncFilePath);
|
|
var colorTableFilePath = fileOptions.dataDirectory + 'colorTable.json';
|
|
loadColorTable(colorTableFilePath);
|
|
|
|
return data;
|
|
}
|
|
|
|
var randomizeParticles = function (maxParticles, viewerParameters) {
|
|
var array = new Float32Array(4 * maxParticles);
|
|
for (var i = 0; i < maxParticles; i++) {
|
|
array[4 * i] = Cesium.Math.randomBetween(viewerParameters.lonRange.x, viewerParameters.lonRange.y);
|
|
array[4 * i + 1] = Cesium.Math.randomBetween(viewerParameters.latRange.x, viewerParameters.latRange.y);
|
|
array[4 * i + 2] = Cesium.Math.randomBetween(data.lev.min, data.lev.max);
|
|
array[4 * i + 3] = 0.0;
|
|
}
|
|
return array;
|
|
}
|
|
|
|
return {
|
|
loadData: loadData,
|
|
randomizeParticles: randomizeParticles
|
|
};
|
|
|
|
})();
|
|
|