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 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. * * @namespace 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 = {}; Object.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.createSilhouetteStage([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
.