import buildModuleUrl from '../Core/buildModuleUrl.js'; import Color from '../Core/Color.js'; import createGuid from '../Core/createGuid.js'; import defined from '../Core/defined.js'; import defineProperties from '../Core/defineProperties.js'; import Ellipsoid from '../Core/Ellipsoid.js'; import AcesTonemapping from '../Shaders/PostProcessStages/AcesTonemappingStage.js'; import AmbientOcclusionGenerate from '../Shaders/PostProcessStages/AmbientOcclusionGenerate.js'; import AmbientOcclusionModulate from '../Shaders/PostProcessStages/AmbientOcclusionModulate.js'; import BlackAndWhite from '../Shaders/PostProcessStages/BlackAndWhite.js'; import BloomComposite from '../Shaders/PostProcessStages/BloomComposite.js'; import Brightness from '../Shaders/PostProcessStages/Brightness.js'; import ContrastBias from '../Shaders/PostProcessStages/ContrastBias.js'; import DepthOfField from '../Shaders/PostProcessStages/DepthOfField.js'; import DepthView from '../Shaders/PostProcessStages/DepthView.js'; import EdgeDetection from '../Shaders/PostProcessStages/EdgeDetection.js'; import FilmicTonemapping from '../Shaders/PostProcessStages/FilmicTonemapping.js'; import FXAA from '../Shaders/PostProcessStages/FXAA.js'; import GaussianBlur1D from '../Shaders/PostProcessStages/GaussianBlur1D.js'; import LensFlare from '../Shaders/PostProcessStages/LensFlare.js'; import ModifiedReinhardTonemapping from '../Shaders/PostProcessStages/ModifiedReinhardTonemapping.js'; import NightVision from '../Shaders/PostProcessStages/NightVision.js'; import ReinhardTonemapping from '../Shaders/PostProcessStages/ReinhardTonemapping.js'; import Silhouette from '../Shaders/PostProcessStages/Silhouette.js'; import FXAA3_11 from '../ThirdParty/Shaders/FXAA3_11.js'; import AutoExposure from './AutoExposure.js'; import PostProcessStage from './PostProcessStage.js'; import PostProcessStageComposite from './PostProcessStageComposite.js'; import PostProcessStageSampleMode from './PostProcessStageSampleMode.js'; /** * Contains functions for creating common post-process stages. * * @exports PostProcessStageLibrary */ var PostProcessStageLibrary = {}; function createBlur(name) { var delta = 1.0; var sigma = 2.0; var stepSize = 1.0; var blurShader = '#define USE_STEP_SIZE\n' + GaussianBlur1D; var blurX = new PostProcessStage({ name : name + '_x_direction', fragmentShader : blurShader, uniforms: { delta : delta, sigma : sigma, stepSize : stepSize, direction : 0.0 }, sampleMode : PostProcessStageSampleMode.LINEAR }); var blurY = new PostProcessStage({ name : name + '_y_direction', fragmentShader : blurShader, uniforms: { delta : delta, sigma : sigma, stepSize : stepSize, direction : 1.0 }, sampleMode : PostProcessStageSampleMode.LINEAR }); var uniforms = {}; defineProperties(uniforms, { delta : { get : function() { return blurX.uniforms.delta; }, set : function(value) { var blurXUniforms = blurX.uniforms; var blurYUniforms = blurY.uniforms; blurXUniforms.delta = blurYUniforms.delta = value; } }, sigma : { get : function() { return blurX.uniforms.sigma; }, set : function(value) { var blurXUniforms = blurX.uniforms; var blurYUniforms = blurY.uniforms; blurXUniforms.sigma = blurYUniforms.sigma = value; } }, stepSize : { get : function() { return blurX.uniforms.stepSize; }, set : function(value) { var blurXUniforms = blurX.uniforms; var blurYUniforms = blurY.uniforms; blurXUniforms.stepSize = blurYUniforms.stepSize = value; } } }); return new PostProcessStageComposite({ name : name, stages : [blurX, blurY], uniforms : uniforms }); } /** * Creates a post-process stage that applies a Gaussian blur to the input texture. This stage is usually applied in conjunction with another stage. *
* This stage has the following uniforms: delta
, sigma
, and stepSize
.
*
* delta
and sigma
are used to compute the weights of a Gaussian filter. The equation is exp((-0.5 * delta * delta) / (sigma * sigma))
.
* The default value for delta
is 1.0
. The default value for sigma
is 2.0
.
* stepSize
is the distance to the next texel. The default is 1.0
.
*
* Depth of field simulates camera focus. Objects in the scene that are in focus * will be clear whereas objects not in focus will be blurred. *
*
* This stage has the following uniforms: focalDistance
, delta
, sigma
, and stepSize
.
*
* focalDistance
is the distance in meters from the camera to set the camera focus.
*
* delta
, sigma
, and stepSize
are the same properties as {@link PostProcessStageLibrary#createBlurStage}.
* The blur is applied to the areas out of focus.
*
* This stage requires the WEBGL_depth_texture extension. *
* * @param {Scene} scene The scene. * @return {Boolean} Whether this post process stage is supported. * * @see {Context#depthTexture} * @see {@link http://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/|WEBGL_depth_texture} */ PostProcessStageLibrary.isDepthOfFieldSupported = function(scene) { return scene.context.depthTexture; }; /** * Creates a post-process stage that detects edges. ** Writes the color to the output texture with alpha set to 1.0 when it is on an edge. *
*
* This stage has the following uniforms: color
and length
*
color
is the color of the highlighted edge. The default is {@link Color#BLACK}.length
is the length of the edges in pixels. The default is 0.5
.* This stage is not supported in 2D. *
* @return {PostProcessStageComposite} A post-process stage that applies an edge detection effect. * * @example * // multiple silhouette effects * var yellowEdge = Cesium.PostProcessLibrary.createEdgeDetectionStage(); * yellowEdge.uniforms.color = Cesium.Color.YELLOW; * yellowEdge.selected = [feature0]; * * var greenEdge = Cesium.PostProcessLibrary.createEdgeDetectionStage(); * greenEdge.uniforms.color = Cesium.Color.LIME; * greenEdge.selected = [feature1]; * * // draw edges around feature0 and feature1 * postProcessStages.add(Cesium.PostProcessLibrary.createSilhouetteEffect([yellowEdge, greenEdge]); */ PostProcessStageLibrary.createEdgeDetectionStage = function() { // unique name generated on call so more than one effect can be added var name = createGuid(); return new PostProcessStage({ name : 'czm_edge_detection_' + name, fragmentShader : EdgeDetection, uniforms : { length : 0.25, color : Color.clone(Color.BLACK) } }); }; /** * Whether or not an edge detection stage is supported. ** This stage requires the WEBGL_depth_texture extension. *
* * @param {Scene} scene The scene. * @return {Boolean} Whether this post process stage is supported. * * @see {Context#depthTexture} * @see {@link http://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/|WEBGL_depth_texture} */ PostProcessStageLibrary.isEdgeDetectionSupported = function(scene) { return scene.context.depthTexture; }; function getSilhouetteEdgeDetection(edgeDetectionStages) { if (!defined(edgeDetectionStages)) { return PostProcessStageLibrary.createEdgeDetectionStage(); } var edgeDetection = new PostProcessStageComposite({ name : 'czm_edge_detection_multiple', stages : edgeDetectionStages, inputPreviousStageTexture : false }); var compositeUniforms = {}; var fsDecl = ''; var fsLoop = ''; for (var i = 0; i < edgeDetectionStages.length; ++i) { fsDecl += 'uniform sampler2D edgeTexture' + i + '; \n'; fsLoop += ' vec4 edge' + i + ' = texture2D(edgeTexture' + i + ', v_textureCoordinates); \n' + ' if (edge' + i + '.a > 0.0) \n' + ' { \n' + ' color = edge' + i + '; \n' + ' break; \n' + ' } \n'; compositeUniforms['edgeTexture' + i] = edgeDetectionStages[i].name; } var fs = fsDecl + 'varying vec2 v_textureCoordinates; \n' + 'void main() { \n' + ' vec4 color = vec4(0.0); \n' + ' for (int i = 0; i < ' + edgeDetectionStages.length + '; i++) \n' + ' { \n' + fsLoop + ' } \n' + ' gl_FragColor = color; \n' + '} \n'; var edgeComposite = new PostProcessStage({ name : 'czm_edge_detection_combine', fragmentShader : fs, uniforms : compositeUniforms }); return new PostProcessStageComposite({ name : 'czm_edge_detection_composite', stages : [edgeDetection, edgeComposite] }); } /** * Creates a post-process stage that applies a silhouette effect. ** A silhouette effect composites the color from the edge detection pass with input color texture. *
*
* This stage has the following uniforms when edgeDetectionStages
is undefined
: color
and length
*
* color
is the color of the highlighted edge. The default is {@link Color#BLACK}.
* length
is the length of the edges in pixels. The default is 0.5
.
*
* This stage requires the WEBGL_depth_texture extension. *
* * @param {Scene} scene The scene. * @return {Boolean} Whether this post process stage is supported. * * @see {Context#depthTexture} * @see {@link http://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/|WEBGL_depth_texture} */ PostProcessStageLibrary.isSilhouetteSupported = function(scene) { return scene.context.depthTexture; }; /** * Creates a post-process stage that applies a bloom effect to the input texture. ** A bloom effect adds glow effect, makes bright areas brighter, and dark areas darker. *
*
* This post-process stage has the following uniforms: contrast
, brightness
, glowOnly
,
* delta
, sigma
, and stepSize
.
*
contrast
is a scalar value in the range [-255.0, 255.0] and affects the contract of the effect. The default value is 128.0
.brightness
is a scalar value. The input texture RGB value is converted to hue, saturation, and brightness (HSB) then this value is
* added to the brightness. The default value is -0.3
.glowOnly
is a boolean value. When true
, only the glow effect will be shown. When false
, the glow will be added to the input texture.
* The default value is false
. This is a debug option for viewing the effects when changing the other uniform values.
* delta
, sigma
, and stepSize
are the same properties as {@link PostProcessStageLibrary#createBlurStage}.
*
* Ambient occlusion simulates shadows from ambient light. These shadows would always be present when the * surface receives light and regardless of the light's position. *
*
* The uniforms have the following properties: intensity
, bias
, lengthCap
,
* stepSize
, frustumLength
, randomTexture
, ambientOcclusionOnly
,
* delta
, sigma
, and blurStepSize
.
*
intensity
is a scalar value used to lighten or darken the shadows exponentially. Higher values make the shadows darker. The default value is 3.0
.bias
is a scalar value representing an angle in radians. If the dot product between the normal of the sample and the vector to the camera is less than this value,
* sampling stops in the current direction. This is used to remove shadows from near planar edges. The default value is 0.1
.lengthCap
is a scalar value representing a length in meters. If the distance from the current sample to first sample is greater than this value,
* sampling stops in the current direction. The default value is 0.26
.stepSize
is a scalar value indicating the distance to the next texel sample in the current direction. The default value is 1.95
.frustumLength
is a scalar value in meters. If the current fragment has a distance from the camera greater than this value, ambient occlusion is not computed for the fragment.
* The default value is 1000.0
.randomTexture
is a texture where the red channel is a random value in [0.0, 1.0]. The default value is undefined
. This texture needs to be set.ambientOcclusionOnly
is a boolean value. When true
, only the shadows generated are written to the output. When false
, the input texture is modulated
* with the ambient occlusion. This is a useful debug option for seeing the effects of changing the uniform values. The default value is false
.
* delta
, sigma
, and blurStepSize
are the same properties as {@link PostProcessStageLibrary#createBlurStage}.
* The blur is applied to the shadows generated from the image to make them smoother.
*
* This stage requires the WEBGL_depth_texture extension. *
* * @param {Scene} scene The scene. * @return {Boolean} Whether this post process stage is supported. * * @see {Context#depthTexture} * @see {@link http://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/|WEBGL_depth_texture} */ PostProcessStageLibrary.isAmbientOcclusionSupported = function(scene) { return scene.context.depthTexture; }; var fxaaFS = '#define FXAA_QUALITY_PRESET 39 \n' + FXAA3_11 + '\n' + FXAA; /** * Creates a post-process stage that applies Fast Approximate Anti-aliasing (FXAA) to the input texture. * @return {PostProcessStage} A post-process stage that applies Fast Approximate Anti-aliasing to the input texture. * * @private */ PostProcessStageLibrary.createFXAAStage = function() { return new PostProcessStage({ name : 'czm_FXAA', fragmentShader : fxaaFS, sampleMode : PostProcessStageSampleMode.LINEAR }); }; /** * Creates a post-process stage that applies ACES tonemapping operator. * @param {Boolean} useAutoExposure Whether or not to use auto-exposure. * @return {PostProcessStage} A post-process stage that applies ACES tonemapping operator. * @private */ PostProcessStageLibrary.createAcesTonemappingStage = function(useAutoExposure) { var fs = useAutoExposure ? '#define AUTO_EXPOSURE\n' : ''; fs += AcesTonemapping; return new PostProcessStage({ name : 'czm_aces', fragmentShader : fs, uniforms : { autoExposure : undefined } }); }; /** * Creates a post-process stage that applies filmic tonemapping operator. * @param {Boolean} useAutoExposure Whether or not to use auto-exposure. * @return {PostProcessStage} A post-process stage that applies filmic tonemapping operator. * @private */ PostProcessStageLibrary.createFilmicTonemappingStage = function(useAutoExposure) { var fs = useAutoExposure ? '#define AUTO_EXPOSURE\n' : ''; fs += FilmicTonemapping; return new PostProcessStage({ name : 'czm_filmic', fragmentShader : fs, uniforms : { autoExposure : undefined } }); }; /** * Creates a post-process stage that applies Reinhard tonemapping operator. * @param {Boolean} useAutoExposure Whether or not to use auto-exposure. * @return {PostProcessStage} A post-process stage that applies Reinhard tonemapping operator. * @private */ PostProcessStageLibrary.createReinhardTonemappingStage = function(useAutoExposure) { var fs = useAutoExposure ? '#define AUTO_EXPOSURE\n' : ''; fs += ReinhardTonemapping; return new PostProcessStage({ name : 'czm_reinhard', fragmentShader : fs, uniforms : { autoExposure : undefined } }); }; /** * Creates a post-process stage that applies modified Reinhard tonemapping operator. * @param {Boolean} useAutoExposure Whether or not to use auto-exposure. * @return {PostProcessStage} A post-process stage that applies modified Reinhard tonemapping operator. * @private */ PostProcessStageLibrary.createModifiedReinhardTonemappingStage = function(useAutoExposure) { var fs = useAutoExposure ? '#define AUTO_EXPOSURE\n' : ''; fs += ModifiedReinhardTonemapping; return new PostProcessStage({ name : 'czm_modified_reinhard', fragmentShader : fs, uniforms : { white : Color.WHITE, autoExposure : undefined } }); }; /** * Creates a post-process stage that finds the average luminance of the input texture. * @return {PostProcessStage} A post-process stage that finds the average luminance of the input texture. * @private */ PostProcessStageLibrary.createAutoExposureStage = function() { return new AutoExposure(); }; /** * Creates a post-process stage that renders the input texture with black and white gradations. *
* This stage has one uniform value, gradations
, which scales the luminance of each pixel.
*
* This stage has one uniform value, brightness
, which scales the saturation of each pixel.
*
* This stage has the following uniforms: dirtTexture
, starTexture
, intensity
, distortion
, ghostDispersal
,
* haloWidth
, dirtAmount
, and earthRadius
.
*
dirtTexture
is a texture sampled to simulate dirt on the lens.starTexture
is the texture sampled for the star pattern of the flare.intensity
is a scalar multiplied by the result of the lens flare. The default value is 2.0
.distortion
is a scalar value that affects the chromatic effect distortion. The default value is 10.0
.ghostDispersal
is a scalar indicating how far the halo effect is from the center of the texture. The default value is 0.4
.haloWidth
is a scalar representing the width of the halo from the ghost dispersal. The default value is 0.4
.dirtAmount
is a scalar representing the amount of dirt on the lens. The default value is 0.4
.earthRadius
is the maximum radius of the earth. The default value is Ellipsoid.WGS84.maximumRadius
.