layers_environment_NOAA_NOAAGFSCloudsLayer.js
import * as THREE from 'three';
import {CloudsLayer} from '../CloudsLayer'
import {realtimeWeather} from './RealtimeWeather.js'
let defaultSampleDensityFunction = `
float sampleDensity(vec3 samplePosition, float lod){
vec3 samplePositionNormalized = normalize(samplePosition);
vec2 lonlatSample = vec2(atan(samplePositionNormalized.y, samplePositionNormalized.x),asin(samplePositionNormalized.z));
float localRadius = getEarthRadiusAtLatitude(lonlatSample.y);
float heightMeters = length(samplePosition)-localRadius;
float height = (heightMeters-startRadius) / (endRadius-startRadius);
float sm= smoothstep(0.0,0.01,height) * (smoothstep(1.0,0.95,height)); // smoothstep to prevent hard transition at the clouds lower and upper limits
vec3 cover = texture(realTimeCoverage, vec3(lonlatSample.x/6.28318, 0.5+lonlatSample.y/3.1416, mix(0.25,0.75,realTimeLerp))).rgb;
float coverage = 0.0;
if(heightMeters<4000.0){
float t = max(0.0,(heightMeters - 1200.0) / (4000.0 - 1200.0));
coverage = mix(cover.r, cover.g, t);
}else {
float t = min(1.0,(heightMeters - 4000.0) / (9000.0 - 4000.0));
coverage = mix(cover.g, cover.b, t);
}
if(coverage<=0.0) return -1.0;
float lod3 = coverage-0.4-(1.0-sm);
if(lod>=3.0)return lod3;
float mediumFrequencyCoverage = coverage*0.2;
float mediumFrequency = 1.0e-5;
float density = 0.55*((texture(perlinWorley, samplePosition*mediumFrequency).r-(1.0-mediumFrequencyCoverage))/mediumFrequencyCoverage*0.7);
if(density<-0.25) return -1.0;
float lod2 = density-(1.0-sm);
if(lod>=2.0) return mix(lod2, lod3, pow(lod-2.0,2.0));
density+= 0.3*((texture(perlinWorley, samplePosition*8.5e-5).r-0.8)/0.6);
if(density<-0.1) return -1.0;
float lod1 = density-(1.0-sm);
if(lod>=1.0) return mix(lod1, lod2, pow(lod-1.0,2.0));
density+= (texture(perlinWorley, samplePosition*1.5e-4).r-0.8)/0.6;
return mix(density -(1.0-sm), lod1, pow(lod,2.0));
}
`;
/**
* A clouds layer where the clouds are distributed according to NOAA GFS weather forecast.
* GFS provides cloud coverage estimates for low, medium and high clouds. Noise functions
* are used for high frequency cloud details while the low frequency cloud distribution comes
* directly from NOAA GFS forecasts.
*
*
* @class
* @extends CloudsLayer
*/
class NOAAGFSCloudsLayer extends CloudsLayer {
/**
* A volumetric clouds layer for the entire planet with cloud coverage based of NOAA weather forecast
*
* Only one visible CloudsLayer (first in list) will be taken into account at a time.
*
* @param {Object} properties
* @param {String|Number} properties.id layer id should be unique
* @param {String} properties.name the name can be anything you want and is intended for labeling
* @param {Number} [properties.quality = 0.5] a quality that affects the resolution and number of samples for volumetric clouds. lower the quality to improve performance.
* @param {Number} [properties.density = 0.5] cloud density multiplier
* @param {Number} [properties.luminance = 1] sun intensity multiplier
* @param {Boolean} [properties.debug = false] wind direction
* @param {THREE.Vector3} [properties.color = new THREE.Vector3(1.0,1.0,1.0)] base cloud color.
* @param {Boolean} [properties.visible = true] layer will be rendered if true (true by default)
*
*/
constructor(properties) {
properties.sampleDensityFunction = defaultSampleDensityFunction;
properties.extraUniforms = {"realTimeLerp": 0.0, "realTimeCoverage": new THREE.Data3DTexture(new Uint8Array(0),0,0,0)};
properties.maxHeight = 12000;
properties.minHeight = 500;
properties.windSpeed = 0;
super(properties);
}
init(map){
super.init(map);
realtimeWeather(super.getUniforms(), map.ultraClock)
}
}
export { NOAAGFSCloudsLayer }