Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fog #3154

Merged
merged 47 commits into from
Nov 9, 2015
Merged

Fog #3154

Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e0efc3a
Initial fog. WIP.
bagnell Oct 22, 2015
7655844
Fog color WIP.
bagnell Oct 23, 2015
7e59d39
Clean up different fog equations and remove uniform fog color.
bagnell Oct 23, 2015
60e8bd5
More clean up.
bagnell Oct 23, 2015
b05a074
More fog color WIP.
bagnell Oct 23, 2015
9b690c7
Merge branch 'master' into fog
bagnell Oct 23, 2015
7894da3
Merge branch 'master' into fog
bagnell Oct 28, 2015
d397e32
Use atmosphere color for fog.
bagnell Oct 29, 2015
8fd263d
Merge branch 'master' into fog
bagnell Oct 29, 2015
41b9330
Minor shader clean up.
bagnell Oct 29, 2015
bebe65c
Add fog parameters to frame state. Cull globe tiles based on fog WIP.
bagnell Oct 29, 2015
01f6a6c
Update density from experimentation. Fog culling WIP.
bagnell Oct 29, 2015
9d3b07a
Interpolate fog density based on camera height.
bagnell Oct 30, 2015
ca742f9
Use preprocessor to enable fog.
bagnell Oct 30, 2015
9d6a8e6
Make scene.fog property. Factor out fog computations. When getting th…
bagnell Nov 2, 2015
80f3f28
Update Sandcastle example locations. Try new density function.
bagnell Nov 2, 2015
8a8c75d
Remove fog density function, use look up table.
bagnell Nov 3, 2015
d2df9a1
Remove fog after zooming out a certain distance.
bagnell Nov 3, 2015
d2c927b
Clean up unused code and Sandcastle example.
bagnell Nov 3, 2015
64a2be8
Increase SSE when tile is in fog.
bagnell Nov 3, 2015
95048fd
Swap shader when tile is in/out of fog.
bagnell Nov 3, 2015
582426a
Explicitly tag CesiumMath.fog private
pjcozzi Nov 4, 2015
dd54283
Doc tweak
pjcozzi Nov 4, 2015
1a194b7
Add comment
pjcozzi Nov 4, 2015
d84186f
Add comment
pjcozzi Nov 4, 2015
f07d538
Fix whitespace
pjcozzi Nov 4, 2015
c5d7341
Tweak density look up table.
bagnell Nov 4, 2015
325d393
Merge branch 'master' into fog
bagnell Nov 4, 2015
35295de
Exploit temporal coherence of zoom level in table look up.
bagnell Nov 4, 2015
ff61da5
Clean up searching for height interval.
bagnell Nov 4, 2015
d11c50b
Only compute distance to tile once. Tweak frame state.
bagnell Nov 4, 2015
85cc52b
Re-add ability to change the density by scaling the table.
bagnell Nov 5, 2015
7902c29
Fade fog in as the camera is tilted towards the horizon.
bagnell Nov 5, 2015
5420561
Fix tests.
bagnell Nov 5, 2015
64828bc
Add fog tests.
bagnell Nov 5, 2015
22de5d1
Add fog documentation.
bagnell Nov 5, 2015
6f8fb41
Merge branch 'master' into fog
bagnell Nov 5, 2015
403b049
Update fog Sandcastle example with positions that demonstrate perform…
bagnell Nov 5, 2015
10a3b97
Fix cracking between the globe and the atmosphere.
bagnell Nov 6, 2015
c6ce4c2
Fix fog for views with negative altitude.
bagnell Nov 6, 2015
333c8f0
Move fog code from scene to new Fog object.
bagnell Nov 6, 2015
186c63f
Enable fog in the tests.
bagnell Nov 6, 2015
7d7c3b2
Tweak CHANGES.md
pjcozzi Nov 7, 2015
ed30aa0
Merge branch 'master' into fog
bagnell Nov 9, 2015
28d15df
Fix shader compile in Firefox/IE.
bagnell Nov 9, 2015
4cccade
Only render atmosphere when terrain tiles are rendered.
bagnell Nov 9, 2015
3ba3717
Add checkbox to enable/disable fog in the terrain sandcastle example.
bagnell Nov 9, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 181 additions & 0 deletions Apps/Sandcastle/gallery/development/Fog.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
<!DOCTYPE html>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The globe is not visible in the default view. Should we update this?

<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="description" content="Control fog parameters.">
<meta name="cesium-sandcastle-labels" content="Development">
<title>Cesium Demo</title>
<script type="text/javascript" src="../Sandcastle-header.js"></script>
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.9/require.js"></script>
<script type="text/javascript">
require.config({
baseUrl : '../../../Source',
waitSeconds : 60
});
</script>
</head>
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
<style>
@import url(../templates/bucket.css);
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar">
<table><tbody>
<tr>
<td>enabled</td>
<td><input type="checkbox" data-bind="checked: enabled"/></td>
</tr>
<tr>
<td>start height</td>
<td><input type="text" size="5" data-bind="value: startHeight"></td>
</tr>
<tr>
<td>start density</td>
<td><input type="text" size="5" data-bind="value: startDensity"></td>
</tr>
<tr>
<td>end height</td>
<td><input type="text" size="5" data-bind="value: endHeight"></td>
</tr>
<tr>
<td>end density</td>
<td><input type="text" size="5" data-bind="value: endDensity"></td>
</tr>
</tbody></table>
<div id="zoomButtons"></div>
</div>
<script id="cesium_sandcastle_script">
function startup(Cesium) {
"use strict";
//Sandcastle_Begin
var viewer = new Cesium.Viewer('cesiumContainer');
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
url : '//assets.agi.com/stk-terrain/world',
requestWaterMask : true,
requestVertexNormals : true
});

viewer.extend(Cesium.viewerCesiumInspectorMixin);

/*
viewer.imageryLayers.removeAll();
viewer.imageryLayers.addImageryProvider(new Cesium.TileMapServiceImageryProvider({
url : require.toUrl('Assets/Textures/NaturalEarthII')
}));
*/

//viewer.scene.globe.enableLighting = true;

//The viewModel tracks the state of our mini application.
var viewModel = {
enabled : true,
startDensity : 0,
endDensity : 0,
startHeight : 0,
endHeight : 0
};
// Convert the viewModel members into knockout observables.
Cesium.knockout.track(viewModel);

// Bind the viewModel to the DOM elements of the UI that call for it.
var toolbar = document.getElementById('toolbar');
Cesium.knockout.applyBindings(viewModel, toolbar);

Cesium.knockout.getObservable(viewModel, 'enabled').subscribe(
function(newValue) {
viewer.scene.fogEnabled = newValue;
}
);

Cesium.knockout.getObservable(viewModel, 'startDensity').subscribe(
function(newValue) {
viewer.scene.fogStartDensity = newValue;
}
);

Cesium.knockout.getObservable(viewModel, 'endDensity').subscribe(
function(newValue) {
viewer.scene.fogEndDensity = newValue;
}
);

Cesium.knockout.getObservable(viewModel, 'startHeight').subscribe(
function(newValue) {
viewer.scene.fogStartHeight = newValue;
}
);

Cesium.knockout.getObservable(viewModel, 'endHeight').subscribe(
function(newValue) {
viewer.scene.fogEndHeight = newValue;
}
);

viewModel.enabled = viewer.scene.fogEnabled;
viewModel.startDensity = viewer.scene.fogStartDensity;
viewModel.endDensity = viewer.scene.fogEndDensity;
viewModel.startHeight = viewer.scene.fogStartHeight;
viewModel.endHeight = viewer.scene.fogEndHeight;

/*
Sandcastle.addToolbarMenu([{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using the same views we used for OBBs: http://cesiumjs.org/2015/06/24/Oriented-Bounding-Boxes/

Instead of commenting them out, they could be in a drop down for future testing.

text : 'Half Dome',
onselect : function() {
var target = new Cesium.Cartesian3(-2489625.0836225147, -4393941.44443024, 3882535.9454173897);
var offset = new Cesium.Cartesian3(-6857.40902037546, 412.3284835694358, 2147.5545426812023);
viewer.camera.lookAt(target, offset);
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}
}, {
text : 'Mount Everest',
onselect : function() {
var target = new Cesium.Cartesian3(300770.50872389384, 5634912.131394585, 2978152.2865545116);
var offset = new Cesium.Cartesian3(6344.974098678562, -793.3419798081741, 2499.9508860763162);
viewer.camera.lookAt(target, offset);
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}
}, {
text : 'San Francisco Bay',
onselect : function() {
var target = new Cesium.Cartesian3(-2708814.85583248, -4254159.450845907, 3891403.9457429945);
var offset = new Cesium.Cartesian3(70642.66030209465, -31661.517948317807, 35505.179997143336);
viewer.camera.lookAt(target, offset);
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}
}], 'zoomButtons');
*/

var scene = viewer.scene;
var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function(movement) {
var ray = scene.camera.getPickRay(movement.position);
var pickedPosition = scene.globe.pick(ray, scene);
if (Cesium.defined(pickedPosition)) {
console.log(Cesium.Cartesian3.distance(pickedPosition, scene.camera.position));
}
}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);

scene.camera.setView({
destination : new Cesium.Cartesian3(-2467070.494299382, -4414079.174382873, 3880669.8976452565),
orientation : {
heading : 1.7833456822869636,
pitch : -0.1764684555868994
}
});

scene.globe._surface._debug.enableDebugOutput = true;

//Sandcastle_End
Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
startup(Cesium);
} else if (typeof require === "function") {
require(["Cesium"], startup);
}
</script>
</body>
</html>
10 changes: 10 additions & 0 deletions Source/Core/Math.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,16 @@ define([
return ((1.0 - time) * p) + (time * q);
};

CesiumMath.smoothstep = function(edge0, edge1, x) {
x = CesiumMath.clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return x * x * (3.0 - x * 1.0);
};

CesiumMath.smootherstep = function(edge0, edge1, x) {
x = CesiumMath.clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return x * x * x * (10.0 + x * (-15.0 + x * 6.0));
};

/**
* pi
*
Expand Down
8 changes: 8 additions & 0 deletions Source/Renderer/AutomaticUniforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -1396,6 +1396,14 @@ define([
getValue : function(uniformState) {
return uniformState.resolutionScale;
}
}),

czm_fogDensity : new AutomaticUniform({
size : 1,
datatype : WebGLConstants.FLOAT,
getValue : function(uniformState) {
return uniformState.fogDensity;
}
})
};

Expand Down
10 changes: 10 additions & 0 deletions Source/Renderer/UniformState.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ define([
this._frustum2DWidth = 0.0;
this._eyeHeight2D = new Cartesian2();
this._resolutionScale = 1.0;

this._fogDensity = undefined;
};

defineProperties(UniformState.prototype, {
Expand Down Expand Up @@ -764,6 +766,12 @@ define([
get : function() {
return this._resolutionScale;
}
},

fogDensity : {
get : function() {
return this._fogDensity;
}
}
});

Expand Down Expand Up @@ -904,6 +912,8 @@ define([
this._entireFrustum.y = camera.frustum.far;
this.updateFrustum(camera.frustum);

this._fogDensity = frameState.fogDensity;

this._frameState = frameState;
this._temeToPseudoFixed = Transforms.computeTemeToPseudoFixedMatrix(frameState.time, this._temeToPseudoFixed);
};
Expand Down
3 changes: 3 additions & 0 deletions Source/Scene/FrameState.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ define([
* @default false
*/
this.scene3DOnly = false;

this.fogEnabled = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps put these in one fog object like this.passes above?

this.fogDensity = undefined;
};

/**
Expand Down
4 changes: 3 additions & 1 deletion Source/Scene/Globe.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ define([
'../Shaders/GlobeFSPole',
'../Shaders/GlobeVS',
'../Shaders/GlobeVSPole',
'../Shaders/GroundAtmosphere',
'../ThirdParty/when',
'./GlobeSurfaceShaderSet',
'./GlobeSurfaceTileProvider',
Expand Down Expand Up @@ -89,6 +90,7 @@ define([
GlobeFSPole,
GlobeVS,
GlobeVSPole,
GroundAtmosphere,
when,
GlobeSurfaceShaderSet,
GlobeSurfaceTileProvider,
Expand Down Expand Up @@ -122,7 +124,7 @@ define([
this._surfaceShaderSet = new GlobeSurfaceShaderSet();

this._surfaceShaderSet.baseVertexShaderSource = new ShaderSource({
sources : [GlobeVS]
sources : [GroundAtmosphere, GlobeVS]
});

this._surfaceShaderSet.baseFragmentShaderSource = new ShaderSource({
Expand Down
10 changes: 8 additions & 2 deletions Source/Scene/GlobeSurfaceShaderSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ define([
return useWebMercatorProjection ? get2DYPositionFractionMercatorProjection : get2DYPositionFractionGeographicProjection;
}

GlobeSurfaceShaderSet.prototype.getShaderProgram = function(context, sceneMode, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, enableLighting, hasVertexNormals, useWebMercatorProjection) {
GlobeSurfaceShaderSet.prototype.getShaderProgram = function(context, sceneMode, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, enableLighting, hasVertexNormals, useWebMercatorProjection, enableFog) {
var flags = sceneMode |
(applyBrightness << 2) |
(applyContrast << 3) |
Expand All @@ -78,7 +78,8 @@ define([
(showOceanWaves << 9) |
(enableLighting << 10) |
(hasVertexNormals << 11) |
(useWebMercatorProjection << 12);
(useWebMercatorProjection << 12) |
(enableFog << 13);

var surfaceShader = surfaceTile.surfaceShader;
if (defined(surfaceShader) &&
Expand Down Expand Up @@ -138,6 +139,11 @@ define([
}
}

if (enableFog) {
vs.defines.push('FOG');
fs.defines.push('FOG');
}

var computeDayColor = '\
vec4 computeDayColor(vec4 initialColor, vec2 textureCoordinates)\n\
{\n\
Expand Down
15 changes: 12 additions & 3 deletions Source/Scene/GlobeSurfaceTileProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -438,10 +438,18 @@ define([
* @returns {Visibility} The visibility of the tile.
*/
GlobeSurfaceTileProvider.prototype.computeTileVisibility = function(tile, frameState, occluders) {
var surfaceTile = tile.data;
if (frameState.fogEnabled) {
var distance = this.computeDistanceToTile(tile, frameState);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are now computing this distance more than once per frame, right? It burns a good bit of CPU (profile, but I bet it is non-trivial). Let's cache this like 3D Tiles: https://github.com/AnalyticalGraphicsInc/cesium/blob/3d-tiles/Source/Scene/Cesium3DTileset.js#L389

var scalar = distance * frameState.fogDensity;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move the fog equation to a @private helper function. Keeping it in this file is probably fine for now.

var fog = 1.0 - Math.exp(-(scalar * scalar));

var cullingVolume = frameState.cullingVolume;
if (fog >= 1.0) {
return Visibility.NONE;
}
}

var surfaceTile = tile.data;
var cullingVolume = frameState.cullingVolume;
var boundingVolume = defaultValue(surfaceTile.orientedBoundingBox, surfaceTile.boundingSphere3D);

if (frameState.mode !== SceneMode.SCENE3D) {
Expand Down Expand Up @@ -930,6 +938,7 @@ define([
var oceanNormalMap = tileProvider.oceanNormalMap;
var showOceanWaves = showReflectiveOcean && defined(oceanNormalMap);
var hasVertexNormals = tileProvider.terrainProvider.ready && tileProvider.terrainProvider.hasVertexNormals;
var enableFog = frameState.fogEnabled;

if (showReflectiveOcean) {
--maxTextures;
Expand Down Expand Up @@ -1117,7 +1126,7 @@ define([
uniformMap.waterMask = waterMaskTexture;
Cartesian4.clone(surfaceTile.waterMaskTranslationAndScale, uniformMap.waterMaskTranslationAndScale);

command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(context, frameState.mode, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection);
command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(context, frameState.mode, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, enableFog);
command.renderState = renderState;
command.primitiveType = PrimitiveType.TRIANGLES;
command.vertexArray = surfaceTile.vertexArray;
Expand Down
25 changes: 25 additions & 0 deletions Source/Scene/Scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,12 @@ define([
*/
this.copyGlobeDepth = false;

this.fogEnabled = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should probably be on a new scene.fog object.

this.fogStartDensity = 0.00002;
this.fogEndDensity = 9e-8;
this.fogStartHeight = 2000.0;
this.fogEndHeight = 100000.0;

this._performanceDisplay = undefined;
this._debugVolume = undefined;

Expand Down Expand Up @@ -955,6 +961,24 @@ define([
return undefined;
}

function updateFog(scene) {
var frameState = scene.frameState;
var enabled = frameState.fogEnabled = scene.fogEnabled;
if (enabled) {
var height = scene.camera.positionCartographic.height;

var startHeight = scene.fogStartHeight;
var endHeight = scene.fogEndHeight;

var startDensity = scene.fogStartDensity;
var endDensity = scene.fogEndDensity;

var t = CesiumMath.smoothstep(startHeight, endHeight, height);
t = CesiumMath.clamp(t, 0.0, 1.0);
frameState.fogDensity = CesiumMath.lerp(startDensity, endDensity, t);
}
}

function clearPasses(passes) {
passes.render = false;
passes.pick = false;
Expand All @@ -975,6 +999,7 @@ define([
frameState.occluder = getOccluder(scene);

clearPasses(frameState.passes);
updateFog(scene);
}

function updateFrustums(near, far, farToNearRatio, numFrustums, frustumCommandsList) {
Expand Down
Loading