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

Add Material Support to Globe #5919

Merged
merged 35 commits into from
Nov 25, 2017
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
24ff46b
Added material support to the globe
jasonbeverage Oct 20, 2017
4e3ae37
Removed SlopeMaterial shader in favor of the SlopeRampMaterial which …
jasonbeverage Oct 20, 2017
6c2d17c
Got rid of multiple enableLighting calls
jasonbeverage Oct 20, 2017
ce71917
Unsetting uniformMap if there is no material
jasonbeverage Oct 20, 2017
a2152cc
Updated CHANGES.md
jasonbeverage Oct 20, 2017
5139bad
Updated CHANGES.md with PR reference
jasonbeverage Oct 20, 2017
29d4ae2
Fix eslint warning
jasonbeverage Oct 20, 2017
11325f2
Merge remote-tracking branch 'upstream/master' into globematerials
jasonbeverage Oct 20, 2017
9b7f7d9
Merge branch 'master' into globematerials
jasonbeverage Nov 1, 2017
60c0121
Style tweaks
lilleyse Nov 3, 2017
46d1a17
Merge branch 'master' into globematerials
lilleyse Nov 3, 2017
3ba02db
Merge branch 'master' into globematerials
lilleyse Nov 3, 2017
cbcaea1
Setting initial time in Globe Materials demo to make lighting look de…
jasonbeverage Nov 13, 2017
cff763d
Using defined to check for material in Globe
jasonbeverage Nov 13, 2017
5c619a9
Using defined to check for uniformMap
jasonbeverage Nov 13, 2017
7493d7c
Wrapping slope and height and globe shaders with APPLY_MATERIAL ifdef.
jasonbeverage Nov 13, 2017
5e4aab6
Renamed minHeight/maxHeight => minimumHeight/maximumHeight in Elevati…
jasonbeverage Nov 13, 2017
c045a6c
Added lineThickness uniform to ElevationContourMaterial
jasonbeverage Nov 13, 2017
8f4a8a1
fancy sandcastle demo
Nov 17, 2017
e8f9b04
Removed trailing whitespace to fix travis
jasonbeverage Nov 21, 2017
8ca9ac9
Changed link in CHANGES.md to Globe Material sandcastle demo
jasonbeverage Nov 25, 2017
0697c45
Changed dirtyShaders to makeShadersDirty and made it a file level fun…
jasonbeverage Nov 25, 2017
83dedf0
Remove comment
jasonbeverage Nov 25, 2017
a5fd43f
Formatting
jasonbeverage Nov 25, 2017
e469dd7
Renamed lineThickness to width for ElevationContourMaterial
jasonbeverage Nov 25, 2017
560caa5
Clarification of height in materialInput
jasonbeverage Nov 25, 2017
cc77f3a
Commenting slope in materialInput
jasonbeverage Nov 25, 2017
8c30e90
Not normalizing v_normalMC in GlobeVS.glsl
jasonbeverage Nov 25, 2017
5bd104f
Not reading varying values in GlobeVS
jasonbeverage Nov 25, 2017
a71d73a
Changed default viewpoint of GlobeMaterials to the Himalayas
jasonbeverage Nov 25, 2017
b42d079
Added unit tests for rendering a globe with materials
jasonbeverage Nov 25, 2017
0264ab1
Added sets material test for Globe
jasonbeverage Nov 25, 2017
8eb3bd4
Tweak CHANGES.md
pjcozzi Nov 25, 2017
217ce3a
Whitespace
pjcozzi Nov 25, 2017
fc88b02
Default Globe Material Sandcastle example to elevation shading
pjcozzi Nov 25, 2017
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
210 changes: 210 additions & 0 deletions Apps/Sandcastle/gallery/Globe Materials.html
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;
Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

@lilleyse lilleyse Nov 8, 2017

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.

Copy link
Contributor

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:

image

image

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));

Copy link
Contributor

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.

Copy link
Contributor Author

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.


// 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',
Copy link
Contributor

Choose a reason for hiding this comment

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

This material doesn't work with enableLighting off.

If the material requires normals you can pass in the define GENERATE_POSITION_AND_NORMAL to the globe vertex shader.

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>
Binary file added Apps/Sandcastle/gallery/Globe Materials.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Change Log
* Added `eyeSeparation` and `focalLength` properties to `Scene` to configure VR settings. [#5917](https://github.com/AnalyticalGraphicsInc/cesium/pull/5917)
* Added `customTags` property to the UrlTemplateImageryProvider to allow custom keywords in the template URL. [#5696](https://github.com/AnalyticalGraphicsInc/cesium/pull/5696)
* Improved CZML Reference Properties example [#5754](https://github.com/AnalyticalGraphicsInc/cesium/pull/5754)
* Adds Material support to Globe. [#5919](https://github.com/AnalyticalGraphicsInc/cesium/pull/5919)
* Fixed bug with placemarks in imported KML: placemarks with no specified icon would be displayed with default icon. [#5819](https://github.com/AnalyticalGraphicsInc/cesium/issues/5819)
* Fixed flickering artifacts on tilesets with thin walls. [#5940](https://github.com/AnalyticalGraphicsInc/cesium/pull/5940)
* Fixed bright fog when terrain lighting is enabled and added `Fog.minimumBrightness` to affect how bright the fog will be when in complete darkness. [#5934](https://github.com/AnalyticalGraphicsInc/cesium/pull/5934)
Expand Down
64 changes: 56 additions & 8 deletions Source/Scene/Globe.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ define([
'./GlobeSurfaceShaderSet',
'./GlobeSurfaceTileProvider',
'./ImageryLayerCollection',
'./Material',
'./QuadtreePrimitive',
'./SceneMode',
'./ShadowMode'
Expand Down Expand Up @@ -53,6 +54,7 @@ define([
GlobeSurfaceShaderSet,
GlobeSurfaceTileProvider,
ImageryLayerCollection,
Material,
QuadtreePrimitive,
SceneMode,
ShadowMode) {
Expand All @@ -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({
Expand All @@ -99,6 +94,8 @@ define([
this._terrainProvider = terrainProvider;
this._terrainProviderChanged = new Event();

this.dirtyShaders();

/**
* Determines if the globe will be shown.
*
Expand Down Expand Up @@ -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();
}
}
}
});

Expand Down Expand Up @@ -525,6 +540,10 @@ define([
return;
}

if (this._material) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Use defined(this._material).

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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;

Expand All @@ -550,6 +569,35 @@ define([
}
};

/**
* @private
*/
Globe.prototype.dirtyShaders = function() {
Copy link
Contributor

Choose a reason for hiding this comment

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

We would generally name this a verb like makeShadersDirty and not make it on the Globe object; instead, it would be a stand-alone function at file level scope and then we pass in a Globe object. This provides better encapsulation.

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

var fragmentSources = [];
var fragmentDefines = [];
if (this._material) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The 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;
Copy link
Contributor

Choose a reason for hiding this comment

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

uniformMap should be defined in the constructor of GlobeSurfaceTileProvider.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also a better name would be materialUniformMap.

}
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 />
Expand Down
12 changes: 8 additions & 4 deletions Source/Scene/GlobeSurfaceShaderSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ define([
SceneMode) {
'use strict';

function GlobeSurfaceShader(numberOfDayTextures, flags, shaderProgram) {
function GlobeSurfaceShader(numberOfDayTextures, flags, material, shaderProgram) {
this.numberOfDayTextures = numberOfDayTextures;
this.flags = flags;
this.shaderProgram = shaderProgram;
this.material = material;
}

/**
Expand All @@ -30,6 +31,8 @@ define([

this._shadersByTexturesFlags = [];
this._pickShaderPrograms = [];

this.material = undefined;
}

function getPositionMode(sceneMode) {
Expand Down Expand Up @@ -92,7 +95,8 @@ define([
var surfaceShader = surfaceTile.surfaceShader;
if (defined(surfaceShader) &&
surfaceShader.numberOfDayTextures === numberOfDayTextures &&
surfaceShader.flags === flags) {
surfaceShader.flags === flags &&
surfaceShader.material === this.material) {

return surfaceShader.shaderProgram;
}
Expand All @@ -104,7 +108,7 @@ define([
}

surfaceShader = shadersByFlags[flags];
if (!defined(surfaceShader)) {
if (!defined(surfaceShader) || surfaceShader.material !== this.material) {
// Cache miss - we've never seen this combination of numberOfDayTextures and flags before.
var vs = this.baseVertexShaderSource.clone();
var fs = this.baseFragmentShaderSource.clone();
Expand Down Expand Up @@ -199,7 +203,7 @@ define([
attributeLocations : terrainEncoding.getAttributeLocations()
});

surfaceShader = shadersByFlags[flags] = new GlobeSurfaceShader(numberOfDayTextures, flags, shader);
surfaceShader = shadersByFlags[flags] = new GlobeSurfaceShader(numberOfDayTextures, flags, this.material, shader);
}

surfaceTile.surfaceShader = surfaceShader;
Expand Down
Loading