text: // All material copyright ESRI, All Rights Reserved, unless otherwise specified.
  // See https://js.arcgis.com/4.6/esri/copyright.txt for details.
  //>>built
  require({cache:{"url:esri/views/3d/environment/materials/RealisticAtmosphereMaterial.xml":'\x3c?xml version\x3d"1.0" encoding\x3d"UTF-8"?\x3e\r\n\r\n\x3csnippets\x3e\r\n\r\n\x3c!--Vertex Shader for Atmosphere--\x3e\r\n\x3csnippet name\x3d"vsRealisticAtmosphere"\x3e\x3c![CDATA[\r\n//\r\n// Based on Atmospheric scattering vertex shader by Sean O\'Neil from GPU Gems 2 Chapter 16.\r\n//\r\n// Link:                   http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html\r\n// Download Portal:        http://http.download.nvidia.com/developer/GPU_Gems_2/CD/Index.html\r\n// Unmodified Source Code: http://http.download.nvidia.com/developer/GPU_Gems_2/CD/Content/16.zip\r\n//\r\n// Adapted for WebGIS by Jascha Gr\u00fcbel (jgruebel@esri.com), Z\u00fcrich 2015\r\n//\r\n\r\n  $vsprecisionf\r\n\r\n  //Camera\r\n  uniform vec2 halfSizeNearPlane;\r\n  uniform vec3 v3CameraUp;\r\n  uniform vec3 v3CameraRight;\r\n  uniform vec3 v3CameraDir;\r\n  uniform vec2 v2CameraCenterOffset;\r\n\r\n  //Attributes\r\n  attribute vec3 $position;\r\n  attribute vec2 $uv0;\r\n\r\n  //Varyings\r\n  varying vec3 v3WorldRay;\r\n  varying vec2 vtc;\r\n\r\n#ifdef HAZE\r\n  varying vec3 v3EyeDir;\r\n#endif\r\n\r\n  void main(void) {\r\n    vec3 v3Pos \x3d $position;\r\n    vtc \x3d $uv0;\r\n    vec2 rayvtc \x3d $uv0 - v2CameraCenterOffset;\r\n\r\n#ifdef HAZE\r\n    v3EyeDir \x3d vec3((2.0*halfSizeNearPlane *rayvtc)-halfSizeNearPlane,-1.0);\r\n#else\r\n    vec3 v3EyeDir \x3d vec3((2.0*halfSizeNearPlane *rayvtc)-halfSizeNearPlane,-1.0);\r\n#endif\r\n    v3WorldRay \x3d v3EyeDir.z*v3CameraDir + v3EyeDir.y*v3CameraUp + v3EyeDir.x*v3CameraRight;\r\n    gl_Position \x3d vec4(v3Pos, 1.0);\r\n  }\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\x3csnippet name\x3d"atmosphereScaleFunction"\x3e\x3c![CDATA[\r\n  //Approximation for inner integral based on a radii ratio of 10.25:10\r\n  float scale(float fCos){\r\n    float x \x3d 1.0 - fCos;\r\n    return exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));\r\n  }\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\x3csnippet name\x3d"toneMapperConstants"\x3e\x3c![CDATA[\r\n#ifdef HAZE\r\n  const float fOneOverGamma \x3d 1.0;//Gamma \x3d 1.0\r\n#else\r\n  const float fOneOverGamma \x3d 0.454545; // Gamma \x3d 2.2\r\n#endif\r\n  const vec3 v3OneOverGamma \x3d vec3(fOneOverGamma);\r\n\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\x3csnippet name\x3d"exponentialToneMapper"\x3e\x3c![CDATA[\r\n  //ToneMapping operators\r\n  vec3 expTM(vec3 inputColor,float exposure){\r\n      return pow(1.0 - exp(inputColor * -exposure), v3OneOverGamma);\r\n  }\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\x3csnippet name\x3d"reinhardToneMapper"\x3e\x3c![CDATA[\r\n  vec3 reinhardTM(vec3 inputColor, float exposure){\r\n      vec3 intermediate \x3d inputColor *exposure;\r\n      intermediate /\x3d (1.0+intermediate);\r\n      return pow(intermediate, v3OneOverGamma);\r\n  }\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\r\n\x3csnippet name\x3d"HSVColorSpace"\x3e\x3c![CDATA[\r\n//based on http://gamedev.stackexchange.com/a/59808\r\n// Hue in range [0,1] instead of 360\u00b0\r\nvec3 rgb2hsv(vec3 c)\r\n{\r\n    vec4 K \x3d vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\r\n    vec4 p \x3d mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\r\n    vec4 q \x3d mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\r\n\r\n    float d \x3d q.x - min(q.w, q.y);\r\n    float e \x3d 1.0e-10;\r\n    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\r\n}\r\n\r\nvec3 hsv2rgb(vec3 c)\r\n{\r\n    vec4 K \x3d vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\r\n    vec3 p \x3d abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\r\n    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\r\n}\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\x3csnippet name\x3d"atmosphereUniformsConstantsVaryings"\x3e\x3c![CDATA[\r\n\r\n  //Light\r\n  uniform vec3 v3LightDir;      // The direction vector to the light source\r\n  uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels\r\n  uniform vec3 v3InvWavelengthScaled; //v3InvWavelength * fKr4PI + fKm4PI\r\n\r\n  //Radii\r\n  uniform vec4 v4Radii; // inner, inner^2, outer, outer^2,\r\n\r\n  //Atmosphere\r\n  const float fKrESun \x3d 0.075;        // Kr * ESun \x3d 0.005 * 15.0\r\n  const float fKmESun \x3d 0.015;        // Km * ESun \x3d 0.005 * 15\r\n  //uniform float fScale;         // 1 / (fOuterRadius - fInnerRadius)\r\n  //uniform float fScaleDepth;    // The scale depth (i.e. the altitude at which the atmosphere\'s average density is found)\r\n  //uniform float fScaleOverScaleDepth; // fScale / fScaleDepth\r\n  //uniform float fOneOverScaleDepth; // 1.0 / fScaleDepth\r\n\r\n  //uniform float fScaleDepthBlue;    // The scale depth (i.e. the altitude at which the atmosphere\'s average density is found)\r\n  //uniform float fScaleOverScaleDepthBlue; // fScale / fScaleDepth\r\n  //uniform float fOneOverScaleDepthBlue; // 1.0 / fScaleDepth\r\n\r\n  uniform vec4 v4AtmosParams1; //(fScale,fScaleDepth,fScaleOverScaleDepth,fOneOverScaleDepth)\r\n  uniform vec4 v4AtmosParams2; //(g,fScaleDepthBlue,fScaleOverScaleDepthBlue,fOneOverScaleDepthBlue)\r\n#ifndef HAZE\r\n  uniform vec4 v4AtmosParams3; //(g2,fMiePhaseCoefficients,fLowerAlphaBlendBound,fOneOverOuterRadiusMinusAlphaBlendBound)\r\n#endif\r\n\r\n  //Camera\r\n  uniform vec3 v3CameraPos;     // The camera\'s current position\r\n  //uniform float fCameraHeight;  // The camera\'s current height\r\n  //uniform float fCameraHeight2; // fCameraHeight^2\r\n  //uniform float fC; //fCameraHeight2 - fOuterRadius2; // C \x3d ||o-c||^2 - r^2\r\n  //uniform float fCSur; //fCameraHeight2 - (fInnerRadius2 - 63756370000.0); // C \x3d ||o-c||^2 - r^2\r\n  uniform vec4 v4SphereComp; //The camera\'s current height, CameraHeight^2,fC,fCSur\r\n  uniform vec2 nearFar;\r\n\r\n  //Camera HDR\r\n#ifdef HAZE\r\n  const float fExposure \x3d 1.5;\r\n#else\r\n  const float fExposure \x3d 2.0;\r\n#endif\r\n\r\n#ifdef HAZE\r\n  //Depth texture\r\n  uniform sampler2D tDepth;\r\n#endif\r\n\r\n  //Testing variables\r\n  uniform float showTest;\r\n\r\n  //Varyings\r\n  varying vec3 v3EyeDir;\r\n  varying vec3 v3WorldRay;\r\n  varying vec2 vtc;\r\n\r\n  //Loop constants for integral approximation\r\n  const float fSamples \x3d 5.0;\r\n  const int maxSamples \x3d 5;\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\r\n\x3csnippet name\x3d"atmospherePrecomputation"\x3e\x3c![CDATA[\r\n    float fInnerRadius \x3d v4Radii[0];   // The inner (planetary) radius\r\n    float fInnerRadius2 \x3d v4Radii[1];  // fInnerRadius^2\r\n    float fOuterRadius \x3d v4Radii[2];   // The outer (atmosphere) radius\r\n    float fOuterRadius2 \x3d v4Radii[3];  // fOuterRadius^2\r\n\r\n    float fCameraHeight \x3d v4SphereComp[0];\r\n    float fCameraHeight2 \x3d v4SphereComp[1];\r\n    float fC \x3d v4SphereComp[2];\r\n    float fCSur \x3d v4SphereComp[3];\r\n\r\n#ifdef PLANAR\r\n    vec3 cameraPosition \x3d vec3(0.0,0.0,fCameraHeight);\r\n#else\r\n    vec3 cameraPosition \x3d v3CameraPos;\r\n#endif\r\n\r\n    //Debug variables\r\n    vec3 test \x3d vec3(0.0,0.0,0.0);\r\n\r\n    //Obtain ray from Camera\r\n    vec3 worldSpaceRay \x3d normalize(v3WorldRay);\r\n\r\n    //Compute Atmosphere intersection; i.e. ray/sphere intersection\r\n    float B \x3d 2.0 * dot(cameraPosition, worldSpaceRay); // B \x3d 2(l * (o-c))\r\n    float det \x3d B*B - 4.0 * fC; // det \x3d B^2 - 4.0* C\r\n\r\n    //idealized sphere intersection to discard early some pixels\r\n    float detSur \x3d B*B - 4.0 * fCSur; // det \x3d B^2 - 4.0* C\r\n\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\r\n\x3csnippet name\x3d"atmosphereDiscardPixels"\x3e\x3c![CDATA[\r\n      bool continueComputation \x3d true;\r\n#ifdef HAZE\r\n      // only use red channel from depth texture.\r\n      // see \'Issues\' at https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture\r\n      float depthSample \x3d texture2D(tDepth, vtc).r;\r\n\r\n      float zNear \x3d nearFar[0];\r\n      float zFar \x3d nearFar[1];\r\n\r\n      // http://web.archive.org/web/20130416194336/http://olivers.posterous.com/linear-depth-in-glsl-for-real\r\n      float zNorm \x3d 2.0 * depthSample - 1.0;\r\n      float linDepth \x3d 2.0 * zNear * zFar /\r\n        (zFar + zNear - zNorm * (zFar - zNear));\r\n\r\n      float nearSurfaceT;\r\n      if (detSur\x3e0.0){\r\n        nearSurfaceT \x3d 0.5 *(-B - sqrt(detSur));\r\n      }\r\n\r\n      float rayEndT;\r\n\r\n      // find intersections with ground, but only between the near and far\r\n      // clipping planes.\r\n      if (depthSample \x3c 1.0 \x26\x26 depthSample \x3e 0.0) {\r\n        vec3 cameraSpaceRay \x3d normalize(v3EyeDir);\r\n        cameraSpaceRay /\x3d cameraSpaceRay.z;\r\n        cameraSpaceRay *\x3d linDepth;\r\n#ifndef PLANAR\r\n        if((fCameraHeight-fInnerRadius)\x3e8000000.0 \x26\x26 detSur\x3e0.0){\r\n          rayEndT \x3d nearSurfaceT;\r\n        } else  if ((fCameraHeight-fInnerRadius)\x3e2000000.0 \x26\x26 detSur\x3e0.0){\r\n          rayEndT \x3d mix(length(cameraSpaceRay),nearSurfaceT,((fCameraHeight-fInnerRadius)-2000000.0)/6000000.0);\r\n        } else {\r\n          rayEndT \x3d length(cameraSpaceRay);\r\n        }\r\n#else\r\n        rayEndT \x3d length(cameraSpaceRay);\r\n#endif\r\n      } else {\r\n        continueComputation \x3d false;\r\n      }\r\n#ifdef PLANAR\r\n      if (16500.0+ fInnerRadius \x3c fCameraHeight){\r\n        continueComputation \x3d false;\r\n      }\r\n#endif\r\n#else\r\n      if (detSur\x3e0.0){\r\n        float nearSurfaceT \x3d 0.5 *(-B - sqrt(detSur));\r\n        if (nearSurfaceT \x3e 0.0){\r\n          continueComputation \x3d false;\r\n        }\r\n      }\r\n#endif\r\n\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\x3csnippet name\x3d"atmosphereUnpackAddUniforms"\x3e\x3c![CDATA[\r\n        float fScale \x3d v4AtmosParams1.x;\r\n        vec2 v2ScaleDepth \x3d vec2(v4AtmosParams1.y,v4AtmosParams2.y);//fScaleDepth, fScaleDepthBlue\r\n        vec2 v2ScaleOverScaleDepth \x3d vec2(v4AtmosParams1.z,v4AtmosParams2.z);//fScaleOverScaleDepth, fScaleOverScaleDepthBlue\r\n        vec2 v2OneOverScaleDepth \x3d vec2(v4AtmosParams1.w,v4AtmosParams2.w);//fOneOverScaleDepth, fOneOverScaleDepthBlue\r\n\r\n#ifndef HAZE\r\n        float g \x3d v4AtmosParams2.x;\r\n        float g2 \x3d v4AtmosParams3.x;\r\n        float fMiePhaseCoefficients \x3d v4AtmosParams3.y;\r\n        float fLowerAlphaBlendBound \x3d v4AtmosParams3.z;\r\n        float fOneOverOuterRadiusMinusAlphaBlendBound \x3d v4AtmosParams3.w;\r\n#endif\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\r\n\x3csnippet name\x3d"atmosphereComputeRayAndLoopSetup"\x3e\x3c![CDATA[\r\n        float rayStartT \x3d 0.5 *(-B - sqrt(det)); //near intersection with atmosphere\r\n#ifdef HAZE\r\n        float nearT \x3d abs(rayStartT);\r\n        float farT \x3d abs(rayEndT);\r\n#else\r\n        float rayEndT \x3d 0.5 *(-B + sqrt(det)); //far intersection with atmosphere\r\n\r\n#endif\r\n\r\n        float fDistance;//calculate its scattering offset\r\n        // Calculate the ray\'s starting position\r\n        if (rayStartT \x3c 0.0)\r\n        { //ray starts from camera to far\r\n          rayStartT \x3d 0.0;\r\n#ifndef HAZE\r\n          fDistance \x3d fScale*(fInnerRadius - fCameraHeight);\r\n#endif\r\n        }\r\n#ifndef HAZE\r\n        else\r\n        {//outside atmosphere\r\n          fDistance \x3d -1.0;\r\n        }\r\n#endif\r\n\r\n        // Initialize the scattering loop variables\r\n        vec3 v3Start \x3d cameraPosition + worldSpaceRay * rayStartT;\r\n\r\n#ifdef HAZE\r\n        vec3 v3End \x3d cameraPosition + worldSpaceRay * rayEndT;\r\n\r\n        float fEndLength \x3d length(v3End);\r\n        float fLocalCameraHeight \x3d length(v3Start);\r\n\r\n        //computed for the original end point to get consistent light angles after possible inversions\r\n        float fLightAngle \x3d dot(v3LightDir, v3End) / fEndLength;\r\n\r\n        if (nearT \x3e farT)\r\n        {\r\n          if (fLocalCameraHeight \x3c fEndLength)\r\n          {\r\n            //Switch positive slopes for flipped rays\r\n            v3End \x3d cameraPosition + worldSpaceRay * rayStartT;\r\n            v3Start \x3d cameraPosition + worldSpaceRay * rayEndT;\r\n            worldSpaceRay *\x3d -1.0;\r\n            fEndLength \x3d length(v3End);\r\n            fLocalCameraHeight \x3d length(v3Start);\r\n          }\r\n          else if (fLocalCameraHeight \x3d\x3d fEndLength)\r\n          {// create minuscule fake slope for integration if the slope is zero\r\n            fLocalCameraHeight +\x3d 1.0; //BUGFIX, if the height of camera and ground is equal the equation breaks, add fake meter to camera height to get\r\n            //slope for the camera function\r\n          }\r\n        }\r\n\r\n        //Calculate its scattering offset\r\n        // Assumes camera constrains of WSV 3.8\r\n        float fCameraDepth;\r\n        float fCameraDepthBlue;\r\n        if (fLocalCameraHeight \x3e fOuterRadius)\r\n        {\r\n          fDistance \x3d fInnerRadius - fOuterRadius;\r\n        } else\r\n        {//outside atmosphere\r\n          fDistance \x3d fEndLength - fLocalCameraHeight;\r\n        }\r\n\r\n#endif\r\n        vec2 v2OpticalStartDepth \x3d exp(fDistance * v2OneOverScaleDepth);\r\n\r\n        float fRayLength \x3d rayEndT - rayStartT;\r\n        float fSampleLength \x3d fRayLength / fSamples;\r\n        float fScaledLength \x3d fSampleLength * fScale;\r\n        vec3 v3SampleRay \x3d worldSpaceRay * fSampleLength;\r\n        vec3 v3SamplePoint \x3d v3Start + v3SampleRay * 0.5;\r\n\r\n#ifdef HAZE\r\n        float fCameraAngle \x3d dot(-worldSpaceRay, v3End) / fEndLength;\r\n        float fScaleCameraAngle \x3d scale(fCameraAngle);\r\n        vec2 v2CameraOffset \x3d fScaleCameraAngle*v2OpticalStartDepth;\r\n\r\n        float scaledValues \x3d scale(fLightAngle) + fScaleCameraAngle;\r\n        vec2 v2ScaledValuesDepth \x3d scaledValues * v2ScaleDepth;\r\n#else\r\n        float fCameraAngle \x3d dot(worldSpaceRay, v3Start / length(v3Start));\r\n        float angleMultiplier \x3d fCameraAngle\x3e0.0?fCameraAngle:0.0;\r\n\r\n        float fScaleCameraAngle \x3d scale(fCameraAngle);\r\n        vec2 v2CameraOffset \x3d fScaleCameraAngle*v2OpticalStartDepth * v2ScaleDepth;\r\n#endif\r\n\r\n        //Loop variables\r\n        vec3 v3FrontColor \x3d vec3(0.0, 0.0, 0.0);\r\n        vec3 v3FrontColorBlue \x3d vec3(0.0, 0.0, 0.0);\r\n        vec3 v3Attenuate\x3d vec3(0.0, 0.0, 0.0);\r\n        vec3 v3AttenuateBlue \x3d vec3(0.0, 0.0, 0.0);\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\r\n\x3csnippet name\x3d"atmosphereComputeSampleContribution"\x3e\x3c![CDATA[\r\n          float fHeight \x3d length(v3SamplePoint);\r\n          vec2 v2Depth \x3d exp(v2ScaleOverScaleDepth * (fInnerRadius - fHeight));\r\n#ifdef HAZE\r\n          vec2 v2Scatter \x3d v2Depth*v2ScaledValuesDepth-v2CameraOffset;\r\n#else\r\n          float fLightAngle \x3d dot(v3LightDir, v3SamplePoint) / fHeight;\r\n          float fCameraAngle \x3d dot(worldSpaceRay, v3SamplePoint) / fHeight;\r\n          float fTempScaledValues \x3d scale(fLightAngle) - scale(fCameraAngle);\r\n          vec2 v2Scatter \x3d v2CameraOffset + fTempScaledValues*v2Depth* v2ScaleDepth;\r\n#endif\r\n          v3Attenuate \x3d exp(-v2Scatter.x * v3InvWavelengthScaled);\r\n          v3AttenuateBlue \x3d exp(-v2Scatter.y * v3InvWavelengthScaled);\r\n\r\n          v3FrontColor +\x3d v3Attenuate * v2Depth.x;\r\n          v3FrontColorBlue +\x3d v3AttenuateBlue * v2Depth.y;\r\n\r\n          v3SamplePoint +\x3d v3SampleRay;\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\r\n\x3csnippet name\x3d"atmosphereComputeHDRColors"\x3e\x3c![CDATA[\r\n        //Phase computation\r\n        //clamp to avoid numerical instability at fCos \x3d\x3d -1.0 (and close values) to display fake sun\r\n        float fCos \x3d clamp(dot(v3LightDir, -worldSpaceRay ),-0.9999999,1.0);\r\n        float fOnePlusCos2 \x3d fCos*fCos + 1.0;\r\n#ifdef HAZE\r\n        // Finally, scale the Rayleigh colors and set up the varying variables for the pixel shader\r\n        vec3 colorCoefficients \x3d (fScaledLength* 0.75 * fOnePlusCos2)*(fKrESun*v3InvWavelength+fKmESun);\r\n\r\n        //Scaled Length is only applied afterwards to save multiplications\r\n        vec3 v3Color \x3d colorCoefficients *v3FrontColor;\r\n        vec3 v3ColorBlue \x3d colorCoefficients *v3FrontColorBlue;\r\n#else\r\n        vec3 v3RayleighCoefficients \x3d (fScaledLength*0.75 * fOnePlusCos2*fKrESun)*v3InvWavelength;\r\n        float fMieCoefficients \x3d fScaledLength*fKmESun * fMiePhaseCoefficients * fOnePlusCos2 / pow(1.0 + g2 - 2.0*g*fCos, 1.5);\r\n\r\n        // Calculate the attenuation factor for the ground\r\n        vec3 v3Color \x3d v3RayleighCoefficients * v3FrontColor + fMieCoefficients * v3FrontColor;\r\n        vec3 v3ColorBlue \x3d v3RayleighCoefficients * v3FrontColorBlue + fMieCoefficients * v3FrontColorBlue;\r\n#endif\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\r\n\x3csnippet name\x3d"atmosphereComputePixelColor"\x3e\x3c![CDATA[\r\n\r\n\r\n        //HDR to LDR conversion\r\n        vec3 ldrBlue \x3d expTM(v3ColorBlue,2.0*fExposure);\r\n        vec3 ldrRed \x3d expTM(v3Color,fExposure);\r\n\r\n        //mix reddish and blueish atmosphere\r\n        vec3 LDR \x3d mix(ldrBlue,ldrRed,0.2);\r\n#ifdef HAZE\r\n        LDR *\x3d (1.0-fCameraAngle);\r\n        vec3 hsv \x3d rgb2hsv(LDR);\r\n        hsv.y \x3d clamp(hsv.y*1.5,0.0,1.0);//boost haze saturation by 50%\r\n        LDR \x3d hsv2rgb(hsv);\r\n        vec3 finalColor \x3d LDR;\r\n        // when rendering we specify the blend functions such that\r\n        // newDestColor \x3d oldDestColor*(1.0-finalColor) + finalColor\r\n#else\r\n        //reinhard tonemapper for looking upwards\r\n        vec3 ldrReinhard \x3d reinhardTM(v3Color,fExposure);\r\n        LDR +\x3d angleMultiplier*ldrReinhard;\r\n\r\n        //height dependent parameter to smooth out reddish atmosphere\r\n        float side \x3d (rayEndT+rayStartT)*0.5;\r\n        float atmoHeight \x3d sqrt(fCameraHeight2 - side*side);\r\n        float h2 \x3d clamp(1.0-(atmoHeight-fLowerAlphaBlendBound)/(fOuterRadius-fLowerAlphaBlendBound),0.0,1.0);\r\n\r\n        vec3 finalColor \x3d LDR*h2;\r\n        vec3 hsv \x3d rgb2hsv(finalColor);\r\n        hsv.y \x3d clamp(hsv.y*1.5,0.0,1.0);//boost sky saturation by 50%\r\n        finalColor \x3d hsv2rgb(hsv);\r\n#endif\r\n#ifdef PLANAR\r\n#ifndef HAZE\r\n        float alpha \x3d clamp(fCameraHeight-fInnerRadius,7000.0,30000.0);\r\n        alpha \x3d alpha / (30000.0-7000.0);\r\n        gl_FragColor \x3d vec4(finalColor, 1.0-alpha);\r\n#else\r\n        float alpha \x3d clamp(fCameraHeight-fInnerRadius,0.0,16500.0);\r\n        alpha \x3d alpha / (16500.0-0.0);\r\n        gl_FragColor \x3d vec4(finalColor, 1.0-alpha);\r\n#endif\r\n#else\r\n#ifndef HAZE\r\n        float alpha \x3d clamp(fCameraHeight-fInnerRadius,7000.0,30000.0);\r\n        alpha \x3d alpha / (30000.0-7000.0);\r\n        float atmosStrength \x3d clamp((length(ldrRed)-0.05)*1.05,0.0,1.0);\r\n        gl_FragColor \x3d vec4(finalColor, atmosStrength*clamp(1.0-(atmoHeight-fInnerRadius)/(fOuterRadius-fInnerRadius),0.0,1.0));\r\n#else\r\n        gl_FragColor \x3d vec4(finalColor, 1.0);\r\n#endif\r\n#endif\r\n\r\n\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\x3c!--Fragment Shader for Atmosphere--\x3e\r\n\x3csnippet name\x3d"fsRealisticAtmosphere"\x3e\x3c![CDATA[\r\n\r\n  $fsprecisionf\r\n\r\n$atmosphereUniformsConstantsVaryings\r\n\r\n$atmosphereScaleFunction\r\n\r\n  //Conversion implementation found in util.xml\r\n$rgba2float\r\n\r\n\r\n$toneMapperConstants\r\n$exponentialToneMapper\r\n#ifndef HAZE\r\n$reinhardToneMapper\r\n#endif\r\n\r\n$HSVColorSpace\r\n\r\n  void main()\r\n  {\r\n\r\n    $atmospherePrecomputation\r\n\r\n    //Inside Atmosphere\r\n    if (det \x3e\x3d 0.0){\r\n\r\n      $atmosphereDiscardPixels\r\n\r\n      if(continueComputation){\r\n\r\n        $atmosphereUnpackAddUniforms\r\n\r\n        $atmosphereComputeRayAndLoopSetup\r\n\r\n        // Now loop through the sample rays\r\n        for(int i\x3d0; i\x3cmaxSamples; i++)\r\n        {\r\n          $atmosphereComputeSampleContribution\r\n        }\r\n\r\n        $atmosphereComputeHDRColors\r\n\r\n        $atmosphereComputePixelColor\r\n\r\n        //Debug variable overlay\r\n        if(showTest\x3e0.0){\r\n          gl_FragColor \x3d vec4(test,1.0);\r\n        }\r\n\r\n      } else {//Not on surface\r\n        gl_FragColor \x3d vec4(0.0);\r\n      }\r\n    } else {//Outside Atmosphere\r\n      gl_FragColor \x3d vec4(0.0);\r\n    }\r\n  }\r\n]]\x3e\x3c/snippet\x3e\r\n\r\n\x3c/snippets\x3e\r\n'}});
  define("dojo/text!./materials/RealisticAtmosphereMaterial.xml ../../../core/watchUtils ../../../core/HandleRegistry ../support/ExternalRenderer ../lib/glMatrix ../webgl-engine/lib/GeometryRenderer ../webgl-engine/lib/GeometryUtil ../webgl-engine/lib/RenderPass ../webgl-engine/lib/RenderSlot ../webgl-engine/lib/OffscreenRenderingHelper ../support/earthUtils ../../webgl/Program ../webgl-engine/lib/DefaultVertexBufferLayouts ../webgl-engine/lib/DefaultVertexAttributeLocations".split(" "),function(w,
  q,x,h,k,y,z,A,t,B,l,n,C,p){var g=l.earthRadius,b=k.vec3d,e=k.vec2d,f=k.vec4d;k=.02*Math.PI;l=.004*Math.PI;var u=b.createFrom(1/Math.pow(.65,4),1/Math.pow(.57,4),1/Math.pow(.475,4)),r=b.create(u);b.scale(r,k);b.add(r,b.createFrom(l,l,l));var v=(1- -.99999*-.99999)/(2+-.99999*-.99999)*1.5;h=h.createSubclass({declaredClass:"esri.views.3d.environment.RealisticAtmosphere",properties:{view:{},planar:{value:!1,set:function(a){a=!!a;a!==this.planar&&this._update();this._set("planar",a)}},needsRender:{value:!1}},
  constructor:function(){this._handles=new x;this._lowerElevationBoundRadius=0;this._earthRadius=g;this._renderer=this._skyPlanarProgram=this._skyProgram=this._hazePlanarProgram=this._hazeProgram=null;this._renderData={texDepth:e.create(),v3CameraPos:b.create(),v3CameraUp:b.create(),v3CameraRight:b.create(),v3CameraDir:b.create(),halfSizeNearPlane:e.create(),v2CameraCenterOffset:e.create(),v4SphereComp:f.create(),v4AtmosParams1:f.create(),v4AtmosParams2:f.create(),v4AtmosParams3:f.create(),v3InvWavelength:u,
  v3InvWavelengthScaled:r,v4Radii:f.create(),fScale:0,fScaleDepth:.25,fLowerAlphaBlendBound:0,fScaleOverScaleDepth:0,fOneOverScaleDepth:0,fScaleDepthBlue:.05,fOneOverScaleDepthBlue:20,fScaleOverScaleDepthBlue:0,g:-.99999,g2:-.99999*-.99999,fMiePhaseCoefficients:v,showTest:0,nearFar:e.create()};this._updateRadius(g);this._hazeSlot=t.POSTPROCESSING_ATMOSPHERE;this._skySlot=t.BACKGROUND},destroy:function(){this._handles&&(this._handles.destroy(),this._handles=null);this._hazeProgram&&(this._hazeProgram.dispose(),
  this._hazeProgram=null);this._hazePlanarProgram&&(this._hazePlanarProgram.dispose(),this._hazePlanarProgram=null);this._skyProgram&&(this._skyProgram.dispose(),this._skyProgram=null);this._skyPlanarProgram&&(this._skyPlanarProgram.dispose(),this._skyPlanarProgram=null)},setup:function(a){var c=z.createSquareGeometry().toRenderData(),d=this.renderContext.rctx;this._renderer=new y(c,C.Pos3Tex,null,d);c=this._update.bind(this);this._handles.add(q.init(this,"view.state.camera",c,!0));var c=this._updateElevation.bind(this),
  D=function(){this._updateElevation({tile:this.view.basemapTerrain.rootTiles[0]})}.bind(this),b=this._updateVisibleElevationBounds.bind(this);this._handles.add(q.on(this,"view.basemapTerrain","elevation-change",c,D));this._handles.add(q.on(this,"view.basemapTerrain","elevation-bounds-change",b,b));a.shaderSnippets.fsRealisticAtmosphere||a.shaderSnippets._parse(w);this._hazeProgram=new n(d,a.shaderSnippets.vsRealisticAtmosphere,a.shaderSnippets.fsRealisticAtmosphere,p.Default3D,["HAZE"]);this._skyProgram=
  new n(d,a.shaderSnippets.vsRealisticAtmosphere,a.shaderSnippets.fsRealisticAtmosphere,p.Default3D);this._hazePlanarProgram=new n(d,a.shaderSnippets.vsRealisticAtmosphere,a.shaderSnippets.fsRealisticAtmosphere,p.Default3D,["HAZE","PLANAR"]);this._skyPlanarProgram=new n(d,a.shaderSnippets.vsRealisticAtmosphere,a.shaderSnippets.fsRealisticAtmosphere,p.Default3D,["PLANAR"])},render:function(a){if(!(a.slot!=this._hazeSlot&&a.slot!=this._skySlot||a.pass!=A.MATERIAL||a.slot==this._hazeSlot&&a.options.earlyOcclusionPixelDraw)){var c,
  d=this.renderContext.rctx,b=d.gl,f=a.offscreenRenderingHelper,g=!1;if(a.slot==this._hazeSlot){c=this.planar?this._hazePlanarProgram:this._hazeProgram;d.bindProgram(c);d.setBlendFunctionSeparate(b.ONE,b.ONE_MINUS_SRC_COLOR,b.ZERO,b.ONE);f.detachDepthTextureFromBuffer();var g=!0,e=f.getDepthTexture();d.bindTexture(e,0);c.setUniform1i("tDepth",0);c.setUniform4fv("v4SphereComp",this._renderData.v4SphereComp)}a.slot==this._skySlot&&(c=this.planar?this._skyPlanarProgram:this._skyProgram,d.bindProgram(c),
  d.setBlendFunctionSeparate(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA,b.ONE,b.ONE_MINUS_SRC_ALPHA),c.setUniform4fv("v4SphereComp",this._renderData.v4SphereComp),c.setUniform4fv("v4AtmosParams3",this._renderData.v4AtmosParams3));c.setUniform3fv("v3InvWavelength",this._renderData.v3InvWavelength);c.setUniform3fv("v3InvWavelengthScaled",this._renderData.v3InvWavelengthScaled);c.setUniform3fv("v3LightDir",a.lightingData.direction);c.setUniform3fv("v3CameraPos",this._renderData.v3CameraPos);c.setUniform3fv("v3CameraUp",
  this._renderData.v3CameraUp);c.setUniform3fv("v3CameraRight",this._renderData.v3CameraRight);c.setUniform3fv("v3CameraDir",this._renderData.v3CameraDir);c.setUniform2fv("nearFar",this._renderData.nearFar);c.setUniform2fv("halfSizeNearPlane",this._renderData.halfSizeNearPlane);c.setUniform2fv("v2CameraCenterOffset",this._renderData.v2CameraCenterOffset);c.setUniform4fv("v4Radii",this._renderData.v4Radii);c.setUniform4fv("v4AtmosParams1",this._renderData.v4AtmosParams1);c.setUniform4fv("v4AtmosParams2",
  this._renderData.v4AtmosParams2);c.setUniform1f("showTest",this._renderData.showTest);d.setDepthTestEnabled(!1);d.setBlendingEnabled(!0);this._renderer.render(c);d.setBlendingEnabled(!1);d.setDepthTestEnabled(!0);d.setBlendFunctionSeparate(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA,b.ONE,b.ONE_MINUS_SRC_ALPHA);g&&f.restoreDepthTextureToBuffer();return!0}},_setEnableTestImage:function(a){this._renderData.showTest=a?1:0;this.needsRender=!0},_adjustRadiusForTesselation:function(a){return a*Math.cos(Math.PI/Math.pow(2,
  4)/16)},_normalizeRadius:function(a){a=this._adjustRadiusForTesselation(a);return Math.max(g-1E4,Math.min(a,g))},_updateElevation:function(a){0===a.tile.lij[0]&&(a=this._adjustRadiusForTesselation(g+a.tile.elevationBounds[0]),a!==this._lowerElevationBoundRadius&&(this._lowerElevationBoundRadius=a,this._earthRadius=-1,this._updateVisibleElevationBounds()))},_updateVisibleElevationBounds:function(){var a=this._adjustRadiusForTesselation(g+this.view.basemapTerrain.getElevationBounds()[0]);return 0>this._earthRadius||
  a<this._earthRadius?this._updateRadius(a):!1},_updateRadius:function(a){this._earthRadius=a;var c=a*a,b=a/10*10.25,g=b*b,e=1/(b-a),k=e/.25,l=e/.05,h=.3*(b-a)+a,n=1/(b-h),m=this._renderData;f.set4(e,.25,k,4,m.v4AtmosParams1);f.set4(-.99999,.05,l,20,m.v4AtmosParams2);f.set4(-.99999*-.99999,v,h,n,m.v4AtmosParams3);f.set4(a,c,b,g,m.v4Radii);m.fScale=e;m.fLowerAlphaBlendBound=h;m.fScaleOverScaleDepth=k;m.fScaleOverScaleDepthBlue=l;this._update();return!0},_update:function(a){if(a=a||this.get("view.state.camera")){b.negate(a.viewForward,
  this._renderData.v3CameraDir);b.set(a.viewUp,this._renderData.v3CameraUp);b.set(a.viewRight,this._renderData.v3CameraRight);if(this.planar){var c=this.view.renderCoordsHelper;this._renderData.fCameraHeight=c.getAltitude(a.eye)/c.unitInMeters+g}else this._renderData.fCameraHeight=b.length(a.eye);this._renderData.fCameraHeight2=this._renderData.fCameraHeight*this._renderData.fCameraHeight;this._renderData.fC=this._renderData.fCameraHeight2-this._renderData.v4Radii[3];this._renderData.fCSur=this._renderData.fCameraHeight2-
  this._renderData.v4Radii[1];this._renderData.v4SphereComp=f.createFrom(this._renderData.fCameraHeight,this._renderData.fCameraHeight2,this._renderData.fC,this._renderData.fCSur);b.set(a.eye,this._renderData.v3CameraPos);e.set2(Math.tan(a.fovX/2)/(a.width/a.fullWidth),Math.tan(a.fovY/2)/(a.height/a.fullHeight),this._renderData.halfSizeNearPlane);e.set2((a.padding[3]+a.width/2)/a.fullWidth-.5,(a.padding[2]+a.height/2)/a.fullHeight-.5,this._renderData.v2CameraCenterOffset);e.set2(a.near,a.far,this._renderData.nearFar);
  this.needsRender=!0}}});h.isSupported=function(a){return B.supportsDepthTexture(a.rctx.extensions)};return h});