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

Shadows point light #3711

Merged
merged 19 commits into from
Mar 18, 2016
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
270 changes: 270 additions & 0 deletions Apps/SampleData/models/ShadowTester/Shadow_Tester_Point.gltf

Large diffs are not rendered by default.

80 changes: 60 additions & 20 deletions Apps/Sandcastle/gallery/development/Shadows.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
<style>
@import url(../templates/bucket.css);
#toolbar input[type=range] {
width : 70px;
}
#toolbar input {
vertical-align: middle;
padding-top: 2px;
Expand All @@ -44,15 +47,22 @@
</td>
</tr>
<tr>
<td>Shadow Far</td>
<td>Distance Limit</td>
<td>
<input type="range" min="100.0" max="10000.0" step="1.0" data-bind="value: distance, valueUpdate: 'input'">
<input type="text" size="2" data-bind="value: distance">
</td>
</tr>
<tr>
<td>Radius</td>
<td>
<input type="range" min="100.0" max="10000.0" step="1.0" data-bind="value: shadowFar, valueUpdate: 'input'">
<input type="text" size="2" data-bind="value: shadowFar">
<input type="range" min="10.0" max="1000.0" step="1.0" data-bind="value: radius, valueUpdate: 'input'">
<input type="text" size="2" data-bind="value: radius">
</td>
</tr>
<tr>
<td>Shadow Mode</td>
<td><select data-bind="options: shadowModeOptions, value: shadowMode"/></td>
<td>Cascades</td>
<td><select data-bind="options: cascadeOptions, value: cascades"/></td>
</tr>
<tr>
<td>Light Source</td>
Expand All @@ -66,6 +76,10 @@
<td>Enabled</td>
<td><input type="checkbox" data-bind="checked: shadows"/></td>
</tr>
<tr>
<td>Terrain Cast</td>
<td><input type="checkbox" data-bind="checked: terrainCast"/></td>
</tr>
<tr>
<td>Show debug</td>
<td><input type="checkbox" data-bind="checked: debug"/></td>
Expand All @@ -78,6 +92,10 @@
<td>Cascade colors</td>
<td><input type="checkbox" data-bind="checked: cascadeColors"/></td>
</tr>
<tr>
<td>Fit near/far</td>
<td><input type="checkbox" data-bind="checked: fitNearFar"/></td>
</tr>
</tbody></table>
</div>
<script id="cesium_sandcastle_script">
Expand All @@ -88,15 +106,18 @@
var viewModel = {
lightAngle : 0.0,
lightHorizon : 0.0,
shadowFar : 1000.0,
distance : 1000.0,
radius : 200.0,
shadows : true,
terrainCast : false,
debug : true,
freeze : false,
cascadeColors : false,
shadowModeOptions : ['Cascades', 'Single'],
shadowMode : 'Cascades',
lightSourceOptions : ['Freeform', 'Sun', 'Fixed'],
lightSource : 'Freeform',
fitNearFar : true,
cascadeOptions : [1, 4],
cascades : 4,
lightSourceOptions : ['Freeform', 'Sun', 'Fixed', 'Point'],
lightSource : 'Point',
sizeOptions : [256, 512, 1024, 2048],
size : 1024
};
Expand All @@ -106,12 +127,15 @@
Cesium.knockout.applyBindings(viewModel, toolbar);
Cesium.knockout.getObservable(viewModel, 'lightAngle').subscribe(updateLightDirection);
Cesium.knockout.getObservable(viewModel, 'lightHorizon').subscribe(updateLightDirection);
Cesium.knockout.getObservable(viewModel, 'shadowFar').subscribe(updateSettings);
Cesium.knockout.getObservable(viewModel, 'distance').subscribe(updateSettings);
Cesium.knockout.getObservable(viewModel, 'radius').subscribe(updateSettings);
Cesium.knockout.getObservable(viewModel, 'debug').subscribe(updateSettings);
Cesium.knockout.getObservable(viewModel, 'freeze').subscribe(updateSettings);
Cesium.knockout.getObservable(viewModel, 'shadows').subscribe(updateSettings);
Cesium.knockout.getObservable(viewModel, 'terrainCast').subscribe(updateSettings);
Cesium.knockout.getObservable(viewModel, 'fitNearFar').subscribe(updateSettings);
Cesium.knockout.getObservable(viewModel, 'cascadeColors').subscribe(updateShadows);
Cesium.knockout.getObservable(viewModel, 'shadowMode').subscribe(updateShadows);
Cesium.knockout.getObservable(viewModel, 'cascades').subscribe(updateShadows);
Cesium.knockout.getObservable(viewModel, 'lightSource').subscribe(updateShadows);
Cesium.knockout.getObservable(viewModel, 'size').subscribe(updateSettings);

Expand All @@ -128,15 +152,21 @@
}

function updateSettings() {
shadowMap._farPlane = Number(viewModel.shadowFar);
shadowMap._distance = Number(viewModel.distance);
shadowMap._radius = Number(viewModel.radius);
shadowMap._fitNearFar = viewModel.fitNearFar;
shadowMap.debugShow = viewModel.debug;
shadowMap.debugFreezeFrame = viewModel.freeze;
shadowMap.enabled = viewModel.shadows;
shadowMap.setSize(viewModel.size);

if (globeVisible) {
globe.castShadows = viewModel.terrainCast;
}
}

function updateShadows() {
var shadowMode = viewModel.shadowMode;
var cascades = viewModel.cascades;
var lightSource = viewModel.lightSource;
var cascadeColors = viewModel.cascadeColors;

Expand All @@ -151,15 +181,21 @@
resetShadows({
context : context,
lightCamera : fixedLightCamera,
fitToScene : false
cascadesEnabled : false
});
} else if (shadowMode === 'Cascades') {
} else if (lightSource === 'Point') {
resetShadows({
context : context,
lightCamera : pointLightCamera,
isPointLight : true
});
} else if (cascades === 4) {
resetShadows({
context : context,
lightCamera : lightCamera
});
shadowMap.debugVisualizeCascades = cascadeColors;
} else if (shadowMode === 'Single') {
} else if (cascades === 1) {
resetShadows({
context : context,
lightCamera : lightCamera,
Expand All @@ -171,7 +207,7 @@
}

var globeVisible = true;
var terrainEnabled = false;
var terrainEnabled = true;

var viewer = new Cesium.Viewer('cesiumContainer', {
scene3DOnly : true,
Expand Down Expand Up @@ -218,13 +254,15 @@
var scene = viewer.scene;
var context = scene.context;
var camera = scene.camera;
var globe = scene.globe;
var shadowMap;
var center;
var height;

var fixedLightCamera = new Cesium.Camera(scene);
var freeformLightCamera = new Cesium.Camera(scene);
var sunCamera = scene._sunCamera;
var pointLightCamera = new Cesium.Camera(scene);

// Get the height of the terrain at the given longitude/latitude, then create the scene.
var positions = [new Cesium.Cartographic(centerLongitude, centerLatitude)];
Expand All @@ -248,6 +286,8 @@
fixedLightCamera.frustum = frustum;
fixedLightCamera.lookAt(center, new Cesium.Cartesian3(tilt, tilt, offsetZ));

pointLightCamera.position = center;

camera.lookAt(center, new Cesium.Cartesian3(25.0, 25.0, 30.0));

updateLightDirection();
Expand All @@ -274,8 +314,8 @@
var position3 = Cesium.Cartesian3.fromRadians(centerLongitude, centerLatitude, height + 15.0);

//createModel('../../SampleData/models/CesiumAir/Cesium_Air.glb', position3);
createModel('../../SampleData/models/ShadowTester/Shadow_Tester.gltf', center);
createModel('../../SampleData/models/WoodTower/Wood_Tower.gltf', ground);
createModel('../../SampleData/models/ShadowTester/Shadow_Tester_Point.gltf', center);
//createModel('../../SampleData/models/WoodTower/Wood_Tower.gltf', ground);
createBox(position3);
createBoxRTC(position2);
createSphere(position1);
Expand Down
30 changes: 29 additions & 1 deletion Source/Renderer/AutomaticUniforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -1551,7 +1551,7 @@ define([
/**
* An automatic GLSL uniform representing the sun's shadow map light direction in eye coordinates.
*
* @alias czm_sunShadowMapLightDirection
* @alias czm_sunShadowMapLightDirectionEC
* @glslUniform
*/
czm_sunShadowMapLightDirectionEC : new AutomaticUniform({
Expand All @@ -1560,6 +1560,34 @@ define([
getValue : function(uniformState) {
return uniformState.shadowMap.lightDirectionEC;
}
}),

/**
* An automatic GLSL uniform representing the sun's shadow map light position in eye coordinates.
*
* @alias czm_sunShadowMapLightPositionEC
* @glslUniform
*/
czm_sunShadowMapLightPositionEC : new AutomaticUniform({
size : 1,
datatype : WebGLConstants.FLOAT_VEC3,
getValue : function(uniformState) {
return uniformState.shadowMap.lightPositionEC;
}
}),

/**
* An automatic GLSL uniform representing the sun's shadow map radius.
*
* @alias czm_sunShadowMapRadius
* @glslUniform
*/
czm_sunShadowMapRadius : new AutomaticUniform({
Copy link
Contributor

Choose a reason for hiding this comment

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

Combine this with the above uniform to make a vec4?

Also, what is the radius? Attenuation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Radius is just how far the point light reaches.

size : 1,
datatype : WebGLConstants.FLOAT,
getValue : function(uniformState) {
return uniformState.shadowMap.radius;
}
})
};

Expand Down
8 changes: 8 additions & 0 deletions Source/Renderer/DrawCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ define([
*/
this.castShadows = defaultValue(options.castShadows, false);

/**
* Whether this command should receive shadows when shadowing is enabled.
*
* @type {Boolean}
* @default false
*/
this.receiveShadows = defaultValue(options.receiveShadows, false);

/**
* An object with functions whose names match the uniforms in the shader program
* and return values to set those uniforms.
Expand Down
12 changes: 12 additions & 0 deletions Source/Scene/FrameState.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,18 @@ define([
* @type {ShadowMap}
*/
this.shadowMap = undefined;

/**
* The near plane of the scene's frustum commands. Used for fitting the shadow map.
* @type {Number}
*/
this.shadowNear = 1.0;

/**
* The far plane of the scene's frustum commands. Used for fitting the shadow map.
* @type {Number}
*/
this.shadowFar = 100.0;
}

/**
Expand Down
14 changes: 12 additions & 2 deletions Source/Scene/GlobeSurfaceShaderSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,15 @@ define([
fs.defines.push('FOG');
}

if (receiveShadows) {
// Output v_positionEC, and v_normalEC if it has vertex normals
if (hasVertexNormals) {
vs.defines.push('ENABLE_VERTEX_LIGHTING');
} else {
vs.defines.push('ENABLE_DAYNIGHT_SHADING');
}
}

var computeDayColor = '\
vec4 computeDayColor(vec4 initialColor, vec2 textureCoordinates)\n\
{\n\
Expand Down Expand Up @@ -192,8 +201,9 @@ define([
vs.sources.push(get2DYPositionFraction(useWebMercatorProjection));

if (receiveShadows) {
vs.sources[1] = ShadowMapShader.createShadowReceiveVertexShader(vs.sources[1]);
fs.sources[0] = ShadowMapShader.createShadowReceiveFragmentShader(fs.sources[0], frameState, '-v_normalEC', 'v_positionEC');
var normalVarying = hasVertexNormals ? 'v_normalEC' : undefined;
vs.sources[1] = ShadowMapShader.createShadowReceiveVertexShader(vs.sources[1], frameState);
fs.sources[0] = ShadowMapShader.createShadowReceiveFragmentShader(fs.sources[0], frameState, normalVarying, 'v_positionEC');
}

var shader = ShaderProgram.fromCache({
Expand Down
1 change: 1 addition & 0 deletions Source/Scene/GlobeSurfaceTileProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,7 @@ define([
command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog, receiveShadows);
command.shadowCastProgram = tileProvider._surfaceShaderSet.getShadowCastProgram(frameState, surfaceTile, useWebMercatorProjection, castShadows);
command.castShadows = castShadows;
command.receiveShadows = receiveShadows;
command.renderState = renderState;
command.primitiveType = PrimitiveType.TRIANGLES;
command.vertexArray = surfaceTile.vertexArray;
Expand Down
5 changes: 3 additions & 2 deletions Source/Scene/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -1503,7 +1503,7 @@ define([
var shadowsEnabled = defined(frameState.shadowMap) && frameState.shadowMap.enabled;
if (shadowsEnabled && model.castShadows) {
var shadowCastVS = ShadowMapShader.createShadowCastVertexShader(drawVS);
var shadowCastFS = ShadowMapShader.createShadowCastFragmentShader(drawFS, frameState);
var shadowCastFS = ShadowMapShader.createShadowCastFragmentShader(drawFS, frameState, false);
model._rendererResources.shadowCastPrograms[id] = ShaderProgram.fromCache({
context : context,
vertexShaderSource : shadowCastVS,
Expand All @@ -1514,7 +1514,7 @@ define([

// Modify draw program to receive shadows
if (shadowsEnabled && model.receiveShadows) {
drawVS = ShadowMapShader.createShadowReceiveVertexShader(drawVS);
drawVS = ShadowMapShader.createShadowReceiveVertexShader(drawVS, frameState);
// TODO : assumes the shader has these varyings, which may not be true for some models
drawFS = ShadowMapShader.createShadowReceiveFragmentShader(drawFS, frameState, 'v_normal', 'v_positionEC');
}
Expand Down Expand Up @@ -2615,6 +2615,7 @@ define([
shaderProgram : rendererPrograms[technique.program],
shadowCastProgram : rendererShadowCastPrograms[technique.program],
castShadows : model.castShadows,
receiveShadows : model.receiveShadows,
uniformMap : uniformMap,
renderState : rs,
owner : owner,
Expand Down
6 changes: 4 additions & 2 deletions Source/Scene/Primitive.js
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,7 @@ define([
var shadowsEnabled = defined(frameState.shadowMap) && frameState.shadowMap.enabled;
if (!defined(primitive._shadowCastSP) && shadowsEnabled && primitive._castShadows) {
var shadowCastVS = ShadowMapShader.createShadowCastVertexShader(vs);
var shadowCastFS = ShadowMapShader.createShadowCastFragmentShader(fs, frameState);
var shadowCastFS = ShadowMapShader.createShadowCastFragmentShader(fs, frameState, false);
primitive._shadowCastSP = ShaderProgram.fromCache({
context : context,
vertexShaderSource : shadowCastVS,
Expand Down Expand Up @@ -1144,7 +1144,7 @@ define([

// Modify program to receive shadows
if (shadowsEnabled && primitive._receiveShadows) {
vs = ShadowMapShader.createShadowReceiveVertexShader(vs);
vs = ShadowMapShader.createShadowReceiveVertexShader(vs, frameState);
fs = ShadowMapShader.createShadowReceiveFragmentShader(fs, frameState, 'v_normalEC', 'v_positionEC');
}

Expand Down Expand Up @@ -1215,6 +1215,7 @@ define([
colorCommand.shaderProgram = primitive._sp;
colorCommand.shadowCastProgram = primitive._shadowCastSP;
colorCommand.castShadows = primitive._castShadows;
colorCommand.receiveShadows = primitive._receiveShadows;
colorCommand.uniformMap = uniforms;
colorCommand.pass = pass;

Expand All @@ -1233,6 +1234,7 @@ define([
colorCommand.shaderProgram = primitive._sp;
colorCommand.shadowCastProgram = primitive._shadowCastSP;
colorCommand.castShadows = primitive._castShadows;
colorCommand.receiveShadows = primitive._receiveShadows;
colorCommand.uniformMap = uniforms;
colorCommand.pass = pass;

Expand Down
Loading