-
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
Add Material Support to Globe #5919
Changes from 9 commits
24ff46b
4e3ae37
6c2d17c
ce71917
a2152cc
5139bad
29d4ae2
11325f2
9b7f7d9
60c0121
46d1a17
3ba02db
cbcaea1
cff763d
5c619a9
7493d7c
5e4aab6
c045a6c
8f4a8a1
e8f9b04
8ca9ac9
0697c45
83dedf0
a5fd43f
e469dd7
560caa5
cc77f3a
8c30e90
5bd104f
a71d73a
b42d079
0264ab1
8eb3bd4
217ce3a
fc88b02
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,210 @@ | ||
<!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="Shader composition demos"> | ||
<meta name="cesium-sandcastle-labels" content="Tutorials, 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); | ||
</style> | ||
<div id="cesiumContainer" class="fullSize"></div> | ||
<div id="loadingOverlay"><h1>Loading...</h1></div> | ||
<div id="toolbar"> | ||
<div id="terrainMenu"></div> | ||
<div id="materialMenu"></div> | ||
<div id="zoomButtons"></div> | ||
<div id="sampleButtons"></div> | ||
<table><tbody> | ||
<tr> | ||
<td>Contour Spacing</td> | ||
<td> | ||
<input type="range" min="1.0" max="500.0 step="1.0" data-bind="value: spacing, valueUpdate: 'input'"> | ||
</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</div> | ||
<script id="cesium_sandcastle_script"> | ||
function startup(Cesium) { | ||
'use strict'; | ||
//Sandcastle_Begin | ||
var viewer = new Cesium.Viewer('cesiumContainer'); | ||
var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({ | ||
url : 'https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles', | ||
requestWaterMask : true, | ||
requestVertexNormals : true | ||
}); | ||
viewer.terrainProvider = cesiumTerrainProviderMeshes; | ||
|
||
viewer.scene.globe.enableLighting = true; | ||
|
||
// The viewModel tracks the state of our mini application. | ||
var viewModel = { | ||
spacing: 100.0 | ||
}; | ||
|
||
function getColorRamp() { | ||
var ramp = document.createElement('canvas'); | ||
ramp.width = 100; | ||
ramp.height = 1; | ||
var ctx = ramp.getContext('2d'); | ||
|
||
var grd = ctx.createLinearGradient(0, 0, 100, 0); | ||
grd.addColorStop(0, "black"); | ||
|
||
grd.addColorStop(0.25, "red"); | ||
|
||
grd.addColorStop(0.5, "blue"); | ||
|
||
grd.addColorStop(0.75, "green"); | ||
|
||
grd.addColorStop(1.0, "white"); | ||
|
||
|
||
ctx.fillStyle = grd; | ||
ctx.fillRect(0, 0, 100, 1); | ||
return ramp; | ||
} | ||
|
||
// 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); | ||
|
||
// setup alternative terrain providers | ||
var ellipsoidProvider = new Cesium.EllipsoidTerrainProvider(); | ||
|
||
var vrTheWorldProvider = new Cesium.VRTheWorldTerrainProvider({ | ||
url : 'http://www.vr-theworld.com/vr-theworld/tiles1.0.0/73/', | ||
credit : 'Terrain data courtesy VT MÄK' | ||
}); | ||
|
||
Sandcastle.addToolbarMenu([{ | ||
text : 'CesiumTerrainProvider - STK World Terrain', | ||
onselect : function() { | ||
viewer.terrainProvider = cesiumTerrainProviderMeshes; | ||
} | ||
}, { | ||
text : 'CesiumTerrainProvider - STK World Terrain - no effects', | ||
onselect : function() { | ||
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({ | ||
url : 'https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles' | ||
}); | ||
} | ||
}, { | ||
text : 'CesiumTerrainProvider - STK World Terrain w/ Lighting', | ||
onselect : function() { | ||
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({ | ||
url : 'https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles', | ||
requestVertexNormals : true | ||
}); | ||
} | ||
}, { | ||
text : 'CesiumTerrainProvider - STK World Terrain w/ Water', | ||
onselect : function() { | ||
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({ | ||
url : 'https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles', | ||
requestWaterMask : true | ||
}); | ||
} | ||
}, { | ||
text : 'EllipsoidTerrainProvider', | ||
onselect : function() { | ||
viewer.terrainProvider = ellipsoidProvider; | ||
} | ||
}, { | ||
text : 'VRTheWorldTerrainProvider', | ||
onselect : function() { | ||
viewer.terrainProvider = vrTheWorldProvider; | ||
} | ||
}], 'terrainMenu'); | ||
|
||
Sandcastle.addDefaultToolbarMenu([{ | ||
text : 'Mount Everest', | ||
onselect : function() { | ||
lookAtMtEverest(); | ||
} | ||
}, { | ||
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 : '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'); | ||
|
||
function lookAtMtEverest() { | ||
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); | ||
} | ||
|
||
Sandcastle.addToolbarMenu([{ | ||
text : 'No Material', | ||
onselect : function() { | ||
viewer.scene.globe.material = undefined; | ||
} | ||
}, { | ||
text : 'Elevation Color Ramp Material', | ||
onselect : function() { | ||
viewer.scene.globe.material = Cesium.Material.fromType('ElevationRamp'); | ||
viewer.scene.globe.material.uniforms.image = getColorRamp(); | ||
} | ||
}, { | ||
text : 'Elevation Contour Material', | ||
onselect : function() { | ||
viewer.scene.globe.material = Cesium.Material.fromType('ElevationContour'); | ||
viewer.scene.globe.material.uniforms.color = Cesium.Color.RED; | ||
} | ||
}, { | ||
text : 'Slope Color Ramp Material', | ||
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. This material doesn't work with If the material requires normals you can pass in the define For terrain that doesn't contain normals the material should be ignored so it doesn't appear black. |
||
onselect : function() { | ||
viewer.scene.globe.material = Cesium.Material.fromType('SlopeRamp'); | ||
viewer.scene.globe.material.uniforms.image = getColorRamp(); | ||
} | ||
}], 'materialMenu'); | ||
|
||
Cesium.knockout.getObservable(viewModel, 'spacing').subscribe( | ||
function(newValue) { | ||
if (viewer.scene.globe.material) { | ||
viewer.scene.globe.material.uniforms.spacing = parseFloat(newValue); | ||
} | ||
} | ||
); | ||
|
||
//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 |
---|---|---|
|
@@ -24,6 +24,7 @@ define([ | |
'./GlobeSurfaceShaderSet', | ||
'./GlobeSurfaceTileProvider', | ||
'./ImageryLayerCollection', | ||
'./Material', | ||
'./QuadtreePrimitive', | ||
'./SceneMode', | ||
'./ShadowMode' | ||
|
@@ -53,6 +54,7 @@ define([ | |
GlobeSurfaceShaderSet, | ||
GlobeSurfaceTileProvider, | ||
ImageryLayerCollection, | ||
Material, | ||
QuadtreePrimitive, | ||
SceneMode, | ||
ShadowMode) { | ||
|
@@ -79,14 +81,7 @@ define([ | |
this._imageryLayerCollection = imageryLayerCollection; | ||
|
||
this._surfaceShaderSet = new GlobeSurfaceShaderSet(); | ||
|
||
this._surfaceShaderSet.baseVertexShaderSource = new ShaderSource({ | ||
sources : [GroundAtmosphere, GlobeVS] | ||
}); | ||
|
||
this._surfaceShaderSet.baseFragmentShaderSource = new ShaderSource({ | ||
sources : [GlobeFS] | ||
}); | ||
this._material = undefined; | ||
|
||
this._surface = new QuadtreePrimitive({ | ||
tileProvider : new GlobeSurfaceTileProvider({ | ||
|
@@ -99,6 +94,8 @@ define([ | |
this._terrainProvider = terrainProvider; | ||
this._terrainProviderChanged = new Event(); | ||
|
||
this.dirtyShaders(); | ||
|
||
/** | ||
* Determines if the globe will be shown. | ||
* | ||
|
@@ -276,6 +273,24 @@ define([ | |
get: function() { | ||
return this._surface.tileLoadProgressEvent; | ||
} | ||
}, | ||
|
||
/** | ||
* Gets or sets the material appearance of the Globe. This can be one of several built-in {@link Material} objects or a custom material, scripted with | ||
* {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}. | ||
* @memberof Globe.prototype | ||
* @type {Material} | ||
*/ | ||
material: { | ||
get: function() { | ||
return this._material; | ||
}, | ||
set: function(material) { | ||
if (this._material !== material) { | ||
this._material = material; | ||
this.dirtyShaders(); | ||
} | ||
} | ||
} | ||
}); | ||
|
||
|
@@ -525,6 +540,10 @@ define([ | |
return; | ||
} | ||
|
||
if (this._material) { | ||
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. Use 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. Fixed. |
||
this._material.update(frameState.context); | ||
} | ||
|
||
var surface = this._surface; | ||
var pass = frameState.passes; | ||
|
||
|
@@ -550,6 +569,35 @@ define([ | |
} | ||
}; | ||
|
||
/** | ||
* @private | ||
*/ | ||
Globe.prototype.dirtyShaders = 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. We would generally name this a verb like |
||
this._surfaceShaderSet.baseVertexShaderSource = new ShaderSource({ | ||
sources : [GroundAtmosphere, GlobeVS] | ||
}); | ||
|
||
var fragmentSources = []; | ||
var fragmentDefines = []; | ||
if (this._material) { | ||
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. 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. Fixed. |
||
fragmentSources.push(this._material.shaderSource); | ||
fragmentDefines.push('APPLY_MATERIAL'); | ||
|
||
// Set the material uniform map to the materials | ||
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. Probably don't need this comment. |
||
this._surface._tileProvider.uniformMap = this._material._uniforms; | ||
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.
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. Also a better name would be |
||
} | ||
else { | ||
this._surface._tileProvider.uniformMap = undefined; | ||
} | ||
fragmentSources.push(GlobeFS); | ||
|
||
this._surfaceShaderSet.baseFragmentShaderSource = new ShaderSource({ | ||
sources : fragmentSources, | ||
defines: fragmentDefines | ||
}); | ||
this._surfaceShaderSet.material = this._material; | ||
}; | ||
|
||
/** | ||
* Returns true if this object was destroyed; otherwise, false. | ||
* <br /><br /> | ||
|
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.
The demo works better without lighting. Related to my comment below, we should be able to get the normals properly without this being set.
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.
The color ramps are better with lighting so you can see the terrain features. The terrain all blends together without the shadows.
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.
The lighting does look fine most of the time, it's mainly when it's completely dark that it's hard to see what's going on.
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.
I disagree. For example, there are some random Appalachian mountains with and without lighting:
Having the lighting enabled makes a big difference.
To make sure the lighting always looks good with the preset views, we can add a line to set the clock time:
viewer.clockViewModel.currentTime = Cesium.JulianDate.fromDate(new Date(2017, 8, 22, 0, 0, 0));
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.
Ok yeah, setting the clock is good. I should have been clearer, my main issue was that whenever I would open the demo it would be night at Everest and just hard to see anything.
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.
I've pushed a change to set the clock time.