UNPKG

itowns

Version:

A JS/WebGL framework for 3D geospatial data visualization

344 lines (298 loc) 20.2 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var THREE = _interopRequireWildcard(require("three")); var _GeometryLayer2 = _interopRequireDefault(require("../../../Layer/GeometryLayer")); var _Coordinates = _interopRequireDefault(require("../../Geographic/Coordinates")); var _Ellipsoid = require("../../Math/Ellipsoid"); var _CoordStars = _interopRequireDefault(require("../../Geographic/CoordStars")); var _SkyShader = _interopRequireDefault(require("./SkyShader")); /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* babel-plugin-inline-import './Shaders/skyFS.glsl' */ var skyFS = "uniform vec3 v3LightPos;\nuniform float g;\nuniform float g2;\n\nvarying vec3 v3Direction;\nvarying vec3 c0;\nvarying vec3 c1;\n\n// Calculates the Mie phase function\nfloat getMiePhase(float fCos, float fCos2, float g, float g2) {\n return 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos2) / pow(1.0 + g2 - 2.0 * g * fCos, 1.5);\n}\n\n// Calculates the Rayleigh phase function\nfloat getRayleighPhase(float fCos2) {\n return 0.75 + 0.75 * fCos2;\n}\n\nvoid main (void) {\n float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);\n float fCos2 = fCos * fCos;\n\n vec3 color = getRayleighPhase(fCos2) * c0 + getMiePhase(fCos, fCos2, g, g2) * c1;\n\n gl_FragColor = vec4(color, 1.0);\n gl_FragColor.a = gl_FragColor.b;\n}"; /* babel-plugin-inline-import './Shaders/skyVS.glsl' */ var skyVS = "uniform vec3 v3LightPosition; // The direction vector to the light source\nuniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels\nuniform float fCameraHeight; // The camera's current height\nuniform float fCameraHeight2; // fCameraHeight^2\nuniform float fOuterRadius; // The outer (atmosphere) radius\nuniform float fOuterRadius2; // fOuterRadius^2\nuniform float fInnerRadius; // The inner (planetary) radius\nuniform float fInnerRadius2; // fInnerRadius^2\nuniform float fKrESun; // Kr * ESun\nuniform float fKmESun; // Km * ESun\nuniform float fKr4PI; // Kr * 4 * PI\nuniform float fKm4PI; // Km * 4 * PI\nuniform float fScale; // 1 / (fOuterRadius - fInnerRadius)\nuniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)\nuniform float fScaleOverScaleDepth; // fScale / fScaleDepth\n\nconst int nSamples = 3;\nconst float fSamples = 3.0;\n\nvarying vec3 v3Direction;\nvarying vec3 c0;\nvarying vec3 c1;\n\nfloat scale(float fCos) {\n float x = 1.0 - fCos;\n return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));\n}\n\nvoid main(void) {\n float lengthCamera = length(cameraPosition);\n float cameraHeight2 = lengthCamera * lengthCamera;\n\n // Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)\n vec3 v3Ray = position - cameraPosition;\n float fFar = length(v3Ray);\n v3Ray /= fFar;\n\n // Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere)\n float B = 2.0 * dot(cameraPosition, v3Ray);\n float C = cameraHeight2 - fOuterRadius2;\n float fDet = max(0.0, B*B - 4.0 * C);\n float fNear = 0.5 * (-B - sqrt(fDet));\n\n // Calculate the ray's starting position, then calculate its scattering offset\n vec3 v3Start = cameraPosition + v3Ray * fNear;\n fFar -= fNear;\n float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;\n float fStartDepth = exp(-1.0 / fScaleDepth);\n float fStartOffset = fStartDepth * scale(fStartAngle);\n\n // Initialize the scattering loop variables\n float fSampleLength = fFar / fSamples;\n float fScaledLength = fSampleLength * fScale;\n vec3 v3SampleRay = v3Ray * fSampleLength;\n vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;\n\n // Now loop through the sample rays\n vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);\n for(int i=0; i<nSamples; i++)\n {\n float fHeight = length(v3SamplePoint);\n float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));\n float fLightAngle = dot(v3LightPosition, v3SamplePoint) / fHeight;\n float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;\n float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));\n vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));\n\n v3FrontColor += v3Attenuate * (fDepth * fScaledLength);\n v3SamplePoint += v3SampleRay;\n }\n\n // Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n c0 = v3FrontColor * (v3InvWavelength * fKrESun);\n c1 = v3FrontColor * fKmESun;\n v3Direction = cameraPosition - position;\n}"; /* babel-plugin-inline-import './Shaders/groundFS.glsl' */ var groundFS = "varying vec3 c0;\nvarying vec3 c1;\n\nvoid main (void) {\n\tgl_FragColor = vec4(c1, 1.0 - c0/4.);\n}"; /* babel-plugin-inline-import './Shaders/groundVS.glsl' */ var groundVS = "uniform vec3 v3LightPosition; // The direction vector to the light source\nuniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels\nuniform float fCameraHeight; // The camera's current height\nuniform float fCameraHeight2; // fCameraHeight^2\nuniform float fOuterRadius; // The outer (atmosphere) radius\nuniform float fOuterRadius2; // fOuterRadius^2\nuniform float fInnerRadius; // The inner (planetary) radius\nuniform float fInnerRadius2; // fInnerRadius^2\nuniform float fKrESun; // Kr * ESun\nuniform float fKmESun; // Km * ESun\nuniform float fKr4PI; // Kr * 4 * PI\nuniform float fKm4PI; // Km * 4 * PI\nuniform float fScale; // 1 / (fOuterRadius - fInnerRadius)\nuniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)\nuniform float fScaleOverScaleDepth; // fScale / fScaleDepth\n\nvarying vec3 c0;\nvarying vec3 c1;\n\nconst int nSamples = 3;\nconst float fSamples = 3.0;\n\nfloat scale(float fCos)\n{\n float x = 1.0 - fCos;\n return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));\n}\n\nvoid main(void) {\n\n float cameraHeight2 = length(cameraPosition) * length(cameraPosition);\n\n // Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)\n vec3 v3Ray = position - cameraPosition;\n float fFar = length(v3Ray);\n v3Ray /= fFar;\n\n // Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere)\n float B = 2.0 * dot(cameraPosition, v3Ray);\n float C = cameraHeight2 - fOuterRadius2;\n float fDet = max(0.0, B*B - 4.0 * C);\n float fNear = 0.5 * (-B - sqrt(fDet));\n\n // Calculate the ray's starting position, then calculate its scattering offset\n vec3 v3Start = cameraPosition + v3Ray * fNear;\n fFar -= fNear;\n float fDepth = exp((fInnerRadius - fOuterRadius) / fScaleDepth);\n float fCameraAngle = dot(-v3Ray, position) / length(position);\n float fLightAngle = dot(v3LightPosition, position) / length(position);\n float fCameraScale = scale(fCameraAngle);\n float fLightScale = scale(fLightAngle);\n float fCameraOffset = fDepth*fCameraScale;\n float fTemp = (fLightScale + fCameraScale);\n\n // Initialize the scattering loop variables\n float fSampleLength = fFar / fSamples;\n float fScaledLength = fSampleLength * fScale;\n vec3 v3SampleRay = v3Ray * fSampleLength;\n vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;\n\n // Now loop through the sample rays\n vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);\n vec3 v3Attenuate = vec3(0.0, 0.0, 0.0);\n for(int i=0; i<nSamples; i++)\n {\n float fHeight = length(v3SamplePoint);\n float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));\n float fScatter = fDepth*fTemp - fCameraOffset;\n v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));\n v3FrontColor += v3Attenuate * (fDepth * fScaledLength);\n v3SamplePoint += v3SampleRay;\n }\n\n // Calculate the attenuation factor for the ground\n c0 = v3Attenuate;\n c1 = v3FrontColor * (v3InvWavelength * fKrESun + fKmESun);\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; /* babel-plugin-inline-import './Shaders/GlowFS.glsl' */ var GlowFS = "#include <logdepthbuf_pars_fragment>\n\nuniform int atmoIN;\nvarying float intensity;\n\nvec4 glowColor = vec4(0.45, 0.74, 1. ,1.0);\n\nvoid main() {\n #include <logdepthbuf_fragment>\n gl_FragColor = glowColor * intensity;\n}\n\n"; /* babel-plugin-inline-import './Shaders/GlowVS.glsl' */ var GlowVS = "#include <common>\n#include <logdepthbuf_pars_vertex>\n\nuniform int atmoIN;\nvarying float intensity;\n\nvoid main()\n{\n vec3 normalES = normalize( normalMatrix * normal );\n vec3 normalCAMES = normalize( normalMatrix * cameraPosition );\n\n if(atmoIN == 0) {\n intensity = pow(0.666 - dot(normalES, normalCAMES), 4. );\n } else {\n intensity = pow( 1. - dot(normalES, normalCAMES), 0.8 );\n }\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n #include <logdepthbuf_vertex>\n}\n\n\n"; var LIGHTING_POSITION = new THREE.Vector3(1, 0, 0); var v = new THREE.Vector3(); var coordCam = new _Coordinates["default"]('EPSG:4326'); var coordGeoCam = new _Coordinates["default"]('EPSG:4326'); var skyBaseColor = new THREE.Color(0x93d5f8); var colorSky = new THREE.Color(); var spaceColor = new THREE.Color(0x030508); var limitAlti = 600000; var mfogDistance = _Ellipsoid.ellipsoidSizes.x * 160.0; var Atmosphere = /*#__PURE__*/ function (_GeometryLayer) { (0, _inherits2["default"])(Atmosphere, _GeometryLayer); function Atmosphere() { var _this; var id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'atmosphere'; var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; (0, _classCallCheck2["default"])(this, Atmosphere); _this = (0, _possibleConstructorReturn2["default"])(this, (0, _getPrototypeOf2["default"])(Atmosphere).call(this, id, new THREE.Object3D(), options)); var material = new THREE.ShaderMaterial({ uniforms: { atmoIN: { type: 'i', value: 0 }, screenSize: { type: 'v2', value: new THREE.Vector2(window.innerWidth, window.innerHeight) } // Should be updated on screen resize... }, vertexShader: GlowVS, fragmentShader: GlowFS, side: THREE.BackSide, blending: THREE.AdditiveBlending, transparent: true, wireframe: false }); var sphereGeometry = new THREE.SphereGeometry(1, 64, 64); var basicAtmosphereOut = new THREE.Mesh(sphereGeometry, material); basicAtmosphereOut.scale.copy(_Ellipsoid.ellipsoidSizes).multiplyScalar(1.14); _this.basicAtmosphere = new THREE.Object3D(); _this.realisticAtmosphere = new THREE.Object3D(); _this.realisticAtmosphere.visible = false; _this.object3d.add(_this.basicAtmosphere); _this.object3d.add(_this.realisticAtmosphere); _this.basicAtmosphere.add(basicAtmosphereOut); var materialAtmoIn = new THREE.ShaderMaterial({ uniforms: { atmoIN: { type: 'i', value: 1 }, screenSize: { type: 'v2', value: new THREE.Vector2(window.innerWidth, window.innerHeight) } // Should be updated on screen resize... }, vertexShader: GlowVS, fragmentShader: GlowFS, side: THREE.FrontSide, blending: THREE.AdditiveBlending, transparent: true, depthWrite: false }); var basicAtmosphereIn = new THREE.Mesh(sphereGeometry, materialAtmoIn); basicAtmosphereIn.scale.copy(_Ellipsoid.ellipsoidSizes).multiplyScalar(1.002); _this.basicAtmosphere.add(basicAtmosphereIn); _this.realisticLightingPosition = { x: -0.5, y: 0.0, z: 1.0 }; _this.fog = { enable: true, distance: mfogDistance }; _this.object3d.updateMatrixWorld(); return _this; } (0, _createClass2["default"])(Atmosphere, [{ key: "update", value: function update(context, layer, node) { // update uniforms node.material.fogDistance = this.fog.distance; node.material.lightingEnabled = this.realisticAtmosphere.visible; node.material.lightPosition = this.realisticLightingPosition; } // eslint-disable-next-line no-unused-vars }, { key: "preUpdate", value: function preUpdate(context) { var cameraPosition = context.view.camera.camera3D.position; if (this.fog.enable) { v.setFromMatrixPosition(context.view.tileLayer.object3d.matrixWorld); var len = v.distanceTo(cameraPosition); // Compute fog distance, this function makes it possible to have a shorter distance // when the camera approaches the ground this.fog.distance = mfogDistance * Math.pow((len - _Ellipsoid.ellipsoidSizes.x * 0.99) * 0.25 / _Ellipsoid.ellipsoidSizes.x, 1.5); } else { this.fog.distance = 10e10; } var renderer = context.view.mainLoop.gfxEngine.renderer; // get altitude camera coordCam.crs = context.view.referenceCrs; coordCam.setFromVector3(cameraPosition).as('EPSG:4326', coordGeoCam); var altitude = coordGeoCam.altitude; // If the camera altitude is below limitAlti, // we interpolate between the sky color and the space color if (altitude < limitAlti) { colorSky.copy(spaceColor).lerp(skyBaseColor, (limitAlti - altitude) / limitAlti); renderer.setClearColor(colorSky, renderer.getClearAlpha()); } else { renderer.setClearColor(spaceColor, renderer.getClearAlpha()); } } // default to non-realistic lightning }, { key: "_initRealisticLighning", value: function _initRealisticLighning() { // Atmosphere Shader From Space (Atmospheric scattering) // http://stainlessbeer.weebly.com/planets-9-atmospheric-scattering.html var atmosphere = { Kr: 0.0025, Km: 0.0010, ESun: 20.0, g: -0.950, innerRadius: 6400000, outerRadius: 6700000, wavelength: [0.650, 0.570, 0.475], scaleDepth: 0.25, mieScaleDepth: 0.1 }; var uniformsAtmosphere = { v3LightPosition: { value: LIGHTING_POSITION.clone().normalize() }, v3InvWavelength: { value: new THREE.Vector3(1 / Math.pow(atmosphere.wavelength[0], 4), 1 / Math.pow(atmosphere.wavelength[1], 4), 1 / Math.pow(atmosphere.wavelength[2], 4)) }, fCameraHeight: { value: 0.0 }, fCameraHeight2: { value: 0.0 }, fInnerRadius: { value: atmosphere.innerRadius }, fInnerRadius2: { value: atmosphere.innerRadius * atmosphere.innerRadius }, fOuterRadius: { value: atmosphere.outerRadius }, fOuterRadius2: { value: atmosphere.outerRadius * atmosphere.outerRadius }, fKrESun: { value: atmosphere.Kr * atmosphere.ESun }, fKmESun: { value: atmosphere.Km * atmosphere.ESun }, fKr4PI: { value: atmosphere.Kr * 4.0 * Math.PI }, fKm4PI: { value: atmosphere.Km * 4.0 * Math.PI }, fScale: { value: 1 / (atmosphere.outerRadius - atmosphere.innerRadius) }, fScaleDepth: { value: atmosphere.scaleDepth }, fScaleOverScaleDepth: { value: 1 / (atmosphere.outerRadius - atmosphere.innerRadius) / atmosphere.scaleDepth }, g: { value: atmosphere.g }, g2: { value: atmosphere.g * atmosphere.g }, nSamples: { value: 3 }, fSamples: { value: 3.0 }, tDisplacement: { value: new THREE.Texture() }, tSkyboxDiffuse: { value: new THREE.Texture() }, fNightScale: { value: 1.0 } }; var geometryAtmosphereIn = new THREE.SphereGeometry(atmosphere.innerRadius, 50, 50); var materialAtmosphereIn = new THREE.ShaderMaterial({ uniforms: uniformsAtmosphere, vertexShader: groundVS, fragmentShader: groundFS, blending: THREE.AdditiveBlending, transparent: true, depthTest: false, depthWrite: false }); var ground = new THREE.Mesh(geometryAtmosphereIn, materialAtmosphereIn); var geometryAtmosphereOut = new THREE.SphereGeometry(atmosphere.outerRadius, 196, 196); var materialAtmosphereOut = new THREE.ShaderMaterial({ uniforms: uniformsAtmosphere, vertexShader: skyVS, fragmentShader: skyFS, transparent: true, side: THREE.BackSide }); var sky = new THREE.Mesh(geometryAtmosphereOut, materialAtmosphereOut); var skyDome = new _SkyShader["default"](); skyDome.frustumCulled = false; ground.layers.mask = this.object3d.layers.mask; sky.layers.mask = this.object3d.layers.mask; skyDome.layers.mask = this.object3d.layers.mask; this.realisticAtmosphere.add(ground); this.realisticAtmosphere.add(sky); this.realisticAtmosphere.add(skyDome); var effectController = { turbidity: 10, reileigh: 2, mieCoefficient: 0.005, mieDirectionalG: 0.8, luminance: 1, inclination: 0.49, // elevation / inclination azimuth: 0.25, // Facing front, sun: !true }; skyDome.material.uniforms.turbidity.value = effectController.turbidity; skyDome.material.uniforms.reileigh.value = effectController.reileigh; skyDome.material.uniforms.luminance.value = effectController.luminance; skyDome.material.uniforms.mieCoefficient.value = effectController.mieCoefficient; skyDome.material.uniforms.mieDirectionalG.value = effectController.mieDirectionalG; skyDome.material.uniforms.up.value = new THREE.Vector3(); // no more necessary, estimate normal from cam.. } }, { key: "setRealisticOn", value: function setRealisticOn(bool) { var _this2 = this; if (bool && !this.sky) { this._initRealisticLighning(); } this.basicAtmosphere.visible = !bool; this.realisticAtmosphere.visible = bool; if (bool) { this.realisticLightingPosition = _CoordStars["default"].getSunPositionInScene(new Date().getTime(), 48.85, 2.35).normalize(); this.realisticAtmosphere.children.forEach(function (obj) { return obj.material.uniforms.v3LightPosition.value.copy(_this2.realisticLightingPosition); }); } } }]); return Atmosphere; }(_GeometryLayer2["default"]); var _default = Atmosphere; exports["default"] = _default;