-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Added HSB color adjustment to the atmosphere and a sandcastle demo #3971
Changes from 5 commits
e6d6aa8
8d6d235
078a0b5
6b6b89e
df6cd41
5f48f9b
8c3c489
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
<!DOCTYPE html> | ||
<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="Adjust hue, saturation, and brightness of the sky/atmosphere."> | ||
<meta name="cesium-sandcastle-labels" content="Showcases"> | ||
<title>Cesium Demo</title> | ||
<script type="text/javascript" src="../Sandcastle-header.js"></script> | ||
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.20/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); | ||
#toolbar { | ||
background: rgba(42, 42, 42, 0.8); | ||
padding: 4px; | ||
border-radius: 4px; | ||
} | ||
#toolbar input { | ||
vertical-align: middle; | ||
padding-top: 2px; | ||
padding-bottom: 2px; | ||
} | ||
</style> | ||
<div id="cesiumContainer" class="fullSize"></div> | ||
<div id="loadingOverlay"><h1>Loading...</h1></div> | ||
<div id="toolbar"> | ||
<table> | ||
<tbody><tr> | ||
<td>hueShift</td> | ||
<td> | ||
<input type="range" min="-1" max="1" step="0.01" data-bind="value: hueShift, valueUpdate: 'input'"> | ||
<input type="text" size="5" data-bind="value: hueShift"> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td>saturationShift</td> | ||
<td> | ||
<input type="range" min="-1" max="1" step="0.01" data-bind="value: saturationShift, valueUpdate: 'input'"> | ||
<input type="text" size="5" data-bind="value: saturationShift"> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td>brightnessShift</td> | ||
<td> | ||
<input type="range" min="-1" max="1" step="0.01" data-bind="value: brightnessShift, valueUpdate: 'input'"> | ||
<input type="text" size="5" data-bind="value: brightnessShift"> | ||
</td> | ||
</tr> | ||
</tbody></table> | ||
<div id="toggleLighting"></div> | ||
<div id="toggleFog"></div> | ||
</div> | ||
<script id="cesium_sandcastle_script"> | ||
function startup(Cesium) { | ||
'use strict'; | ||
//Sandcastle_Begin | ||
var viewer = new Cesium.Viewer('cesiumContainer'); | ||
var scene = viewer.scene; | ||
var skyAtmosphere = scene.skyAtmosphere; | ||
|
||
// The viewModel tracks the state of our mini application. | ||
var viewModel = { | ||
hueShift: 0.0, | ||
saturationShift: 0.0, | ||
brightnessShift: 0.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); | ||
|
||
// Make the skyAtmosphere's HSB parameters subscribers of the viewModel. | ||
function subscribeParameter(name) { | ||
Cesium.knockout.getObservable(viewModel, name).subscribe( | ||
function(newValue) { | ||
skyAtmosphere[name] = newValue; | ||
} | ||
); | ||
} | ||
|
||
subscribeParameter('hueShift'); | ||
subscribeParameter('saturationShift'); | ||
subscribeParameter('brightnessShift'); | ||
|
||
Sandcastle.addToolbarButton('Toggle Lighting', function() { | ||
scene.globe.enableLighting = !scene.globe.enableLighting; | ||
}, 'toggleLighting'); | ||
|
||
Sandcastle.addToolbarButton('Toggle Fog', function() { | ||
scene.fog.enabled = !scene.fog.enabled; | ||
}, 'toggleFog'); | ||
|
||
var camera = viewer.camera; | ||
camera.setView({ | ||
destination : Cesium.Cartesian3.fromDegrees(-75.5847, 40.0397, 1000.0), | ||
orientation: { | ||
heading : -Cesium.Math.PI_OVER_TWO, | ||
pitch : 0.2, | ||
roll : 0.0 | ||
} | ||
}); | ||
|
||
//Sandcastle_End | ||
Sandcastle.finishedLoading(); | ||
} | ||
if (typeof Cesium !== "undefined") { | ||
startup(Cesium); | ||
} else if (typeof require === "function") { | ||
require(["Cesium"], startup); | ||
} | ||
</script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ define([ | |
'../Core/Ellipsoid', | ||
'../Core/EllipsoidGeometry', | ||
'../Core/GeometryPipeline', | ||
'../Core/Math', | ||
'../Core/VertexFormat', | ||
'../Renderer/BufferUsage', | ||
'../Renderer/DrawCommand', | ||
|
@@ -31,6 +32,7 @@ define([ | |
Ellipsoid, | ||
EllipsoidGeometry, | ||
GeometryPipeline, | ||
CesiumMath, | ||
VertexFormat, | ||
BufferUsage, | ||
DrawCommand, | ||
|
@@ -81,6 +83,35 @@ define([ | |
this._spSkyFromSpace = undefined; | ||
this._spSkyFromAtmosphere = undefined; | ||
|
||
this._spSkyFromSpaceColorCorrect = undefined; | ||
this._spSkyFromAtmosphereColorCorrect = undefined; | ||
|
||
/** | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the doc for hue, saturation, and brightness, can you provide a bit more info like the range of each value an an example value to get a certain effect? These parameters may not be obvious to all our users. |
||
* The hue shift to apply to the atmosphere. Defaults to 0.0 (no shift). | ||
* A hue shift of 1.0 indicates a complete rotation of the hues available. | ||
* @type {Number} | ||
* @default 0.0 | ||
*/ | ||
this.hueShift = 0.0; | ||
|
||
/** | ||
* The saturation shift to apply to the atmosphere. Defaults to 0.0 (no shift). | ||
* A saturation shift of -1.0 is monochrome. | ||
* @type {Number} | ||
* @default 0.0 | ||
*/ | ||
this.saturationShift = 0.0; | ||
|
||
/** | ||
* The brightness shift to apply to the atmosphere. Defaults to 0.0 (no shift). | ||
* A brightness shift of -1.0 is complete darkness, which will let space show through. | ||
* @type {Number} | ||
* @default 0.0 | ||
*/ | ||
this.brightnessShift = 0.0; | ||
|
||
this._hueSaturationBrightness = new Cartesian3(); | ||
|
||
// camera height, outer radius, inner radius, dynamic atmosphere color flag | ||
var cameraAndRadiiAndDynamicAtmosphereColor = new Cartesian4(); | ||
|
||
|
@@ -94,8 +125,14 @@ define([ | |
var that = this; | ||
|
||
this._command.uniformMap = { | ||
cameraAndRadiiAndDynamicAtmosphereColor : function() { | ||
u_cameraAndRadiiAndDynamicAtmosphereColor : function() { | ||
return that._cameraAndRadiiAndDynamicAtmosphereColor; | ||
}, | ||
u_hsbShift : function() { | ||
that._hueSaturationBrightness.x = that.hueShift; | ||
that._hueSaturationBrightness.y = that.saturationShift; | ||
that._hueSaturationBrightness.z = that.brightnessShift; | ||
return that._hueSaturationBrightness; | ||
} | ||
}; | ||
} | ||
|
@@ -122,6 +159,15 @@ define([ | |
this._cameraAndRadiiAndDynamicAtmosphereColor.w = enableLighting ? 1 : 0; | ||
}; | ||
|
||
/** | ||
* @private | ||
*/ | ||
SkyAtmosphere.prototype.colorCorrect = function() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For better encapsulation, make this a local function and pass |
||
return !(CesiumMath.equalsEpsilon(this.hueShift, 0.0, CesiumMath.EPSILON7) && | ||
CesiumMath.equalsEpsilon(this.saturationShift, 0.0, CesiumMath.EPSILON7) && | ||
CesiumMath.equalsEpsilon(this.brightnessShift, 0.0, CesiumMath.EPSILON7)); | ||
}; | ||
|
||
/** | ||
* @private | ||
*/ | ||
|
@@ -169,6 +215,7 @@ define([ | |
defines : ['SKY_FROM_SPACE'], | ||
sources : [SkyAtmosphereVS] | ||
}); | ||
|
||
this._spSkyFromSpace = ShaderProgram.fromCache({ | ||
context : context, | ||
vertexShaderSource : vs, | ||
|
@@ -186,17 +233,46 @@ define([ | |
}); | ||
} | ||
|
||
// Compile the color correcting versions of the shader on demand | ||
if (this.colorCorrect() && (!defined(this._spSkyFromSpaceColorCorrect) || !defined(this._spSkyFromAtmosphereColorCorrect))) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Call |
||
var contextColorCorrect = frameState.context; | ||
|
||
var vsColorCorrect = new ShaderSource({ | ||
defines : ['SKY_FROM_SPACE'], | ||
sources : [SkyAtmosphereVS] | ||
}); | ||
var fsColorCorrect = new ShaderSource({ | ||
defines : ['COLOR_CORRECT'], | ||
sources : [SkyAtmosphereFS] | ||
}); | ||
|
||
this._spSkyFromSpaceColorCorrect = ShaderProgram.fromCache({ | ||
context : contextColorCorrect, | ||
vertexShaderSource : vsColorCorrect, | ||
fragmentShaderSource : fsColorCorrect | ||
}); | ||
vsColorCorrect = new ShaderSource({ | ||
defines : ['SKY_FROM_ATMOSPHERE'], | ||
sources : [SkyAtmosphereVS] | ||
}); | ||
this._spSkyFromAtmosphereColorCorrect = ShaderProgram.fromCache({ | ||
context : contextColorCorrect, | ||
vertexShaderSource : vsColorCorrect, | ||
fragmentShaderSource : fsColorCorrect | ||
}); | ||
} | ||
|
||
var cameraPosition = frameState.camera.positionWC; | ||
|
||
var cameraHeight = Cartesian3.magnitude(cameraPosition); | ||
this._cameraAndRadiiAndDynamicAtmosphereColor.x = cameraHeight; | ||
|
||
if (cameraHeight > this._cameraAndRadiiAndDynamicAtmosphereColor.y) { | ||
// Camera in space | ||
command.shaderProgram = this._spSkyFromSpace; | ||
command.shaderProgram = this.colorCorrect() ? this._spSkyFromSpaceColorCorrect : this._spSkyFromSpace; | ||
} else { | ||
// Camera in atmosphere | ||
command.shaderProgram = this._spSkyFromAtmosphere; | ||
command.shaderProgram = this.colorCorrect() ? this._spSkyFromAtmosphereColorCorrect : this._spSkyFromAtmosphere; | ||
} | ||
|
||
return command; | ||
|
@@ -239,6 +315,8 @@ define([ | |
command.vertexArray = command.vertexArray && command.vertexArray.destroy(); | ||
this._spSkyFromSpace = this._spSkyFromSpace && this._spSkyFromSpace.destroy(); | ||
this._spSkyFromAtmosphere = this._spSkyFromAtmosphere && this._spSkyFromAtmosphere.destroy(); | ||
this._spSkyFromSpaceColorCorrect = this._spSkyFromSpaceColorCorrect && this._spSkyFromSpaceColorCorrect.destroy(); | ||
this._spSkyFromAtmosphereColorCorrect = this._spSkyFromAtmosphereColorCorrect && this._spSkyFromAtmosphereColorCorrect.destroy(); | ||
return destroyObject(this); | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,15 +32,39 @@ | |
|
||
// Code: http://sponeil.net/ | ||
// GPU Gems 2 Article: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html | ||
|
||
// HSV/HSB <-> RGB conversion with minimal branching: http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl | ||
|
||
#ifdef COLOR_CORRECT | ||
uniform vec3 u_hsbShift; // Hue, saturation, value | ||
#endif | ||
|
||
const float g = -0.95; | ||
const float g2 = g * g; | ||
const vec4 K_RGB2HSB = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); | ||
const vec4 K_HSB2RGB = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); | ||
|
||
varying vec3 v_rayleighColor; | ||
varying vec3 v_mieColor; | ||
varying vec3 v_toCamera; | ||
varying vec3 v_positionEC; | ||
|
||
#ifdef COLOR_CORRECT | ||
vec3 rgb2hsb(vec3 rgbColor) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could also experiment with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the addition of the brightness adjustment makes computing to/from HSB worthwhile. I'm not 100% sure how that works over in just RGB land. I think there's also less trig to do hue this way, czm_hue seems to involve an atan. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah true the brightness is nice to have. I'm fine with keeping it your way, and rgb2hsb and hsb2rgb could even be built-in functions themselves if we ever need them for other areas in the future. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be a new |
||
{ | ||
vec4 p = mix(vec4(rgbColor.bg, K_RGB2HSB.wz), vec4(rgbColor.gb, K_RGB2HSB.xy), step(rgbColor.b, rgbColor.g)); | ||
vec4 q = mix(vec4(p.xyw, rgbColor.r), vec4(rgbColor.r, p.yzx), step(p.x, rgbColor.r)); | ||
|
||
float d = q.x - min(q.w, q.y); | ||
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + czm_epsilon7)), d / (q.x + czm_epsilon7), q.x); | ||
} | ||
|
||
vec3 hsb2rgb(vec3 hsbColor) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment. |
||
{ | ||
vec3 p = abs(fract(hsbColor.xxx + K_HSB2RGB.xyz) * 6.0 - K_HSB2RGB.www); | ||
return hsbColor.z * mix(K_HSB2RGB.xxx, clamp(p - K_HSB2RGB.xxx, 0.0, 1.0), hsbColor.y); | ||
} | ||
#endif | ||
|
||
void main (void) | ||
{ | ||
// Extra normalize added for Android | ||
|
@@ -52,6 +76,22 @@ void main (void) | |
|
||
vec3 rgb = rayleighPhase * v_rayleighColor + miePhase * v_mieColor; | ||
rgb = vec3(1.0) - exp(-exposure * rgb); | ||
// Compute luminance before color correction to avoid strangely gray night skies | ||
float l = czm_luminance(rgb); | ||
|
||
#ifdef COLOR_CORRECT | ||
// Convert rgb color to hsb | ||
vec3 hsb = rgb2hsb(rgb); | ||
// Perform hsb shift | ||
hsb.x += u_hsbShift.x; // hue | ||
hsb.y = clamp(hsb.y + u_hsbShift.y, 0.0, 1.0); // saturation | ||
hsb.z = hsb.z > czm_epsilon7 ? hsb.z + u_hsbShift.z : 0.0; // brightness | ||
// Convert shifted hsb back to rgb | ||
rgb = hsb2rgb(hsb); | ||
|
||
// Check if correction decreased the luminance to 0 | ||
l = min(l, czm_luminance(rgb)); | ||
#endif | ||
|
||
gl_FragColor = vec4(rgb, min(smoothstep(0.0, 0.1, l), 1.0) * smoothstep(0.0, 1.0, czm_morphTime)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also include a link to where the new Sandcastle example will be hosted, e.g., for 3D models, the link is http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=3D%20Models.html&label=Showcases