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 12 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.

84 changes: 63 additions & 21 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,30 +106,36 @@
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
};

Cesium.knockout.track(viewModel);
var toolbar = document.getElementById('toolbar');
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 (lightSource === 'Point') {
resetShadows({
context : context,
lightCamera : pointLightCamera,
isPointLight : true
});
} else if (shadowMode === 'Cascades') {
} 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,17 @@
var scene = viewer.scene;
var context = scene.context;
var camera = scene.camera;
var globe = scene.globe;
var shadowMap;
var center;
var height;

scene.debugShowFramesPerSecond = true;

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 +288,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 +316,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 @@ -1492,6 +1492,20 @@ define([
}
}),

/**
* An automatic GLSL uniform representing the sun's shadow map texture as a cube map.
*
* @alias czm_sunShadowMapTextureCube
* @glslUniform
*/
czm_sunShadowMapTextureCube : new AutomaticUniform({
size : 1,
datatype : WebGLConstants.SAMPLER_CUBE,
getValue : function(uniformState) {
return uniformState.shadowMap.shadowMapTexture;
}
}),

/**
* An automatic GLSL uniform representing the sun's shadow map matrix.
*
Expand Down Expand Up @@ -1551,7 +1565,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 +1574,20 @@ define([
getValue : function(uniformState) {
return uniformState.shadowMap.lightDirectionEC;
}
}),

/**
* An automatic GLSL uniform that stores the point light's eye space position and radius.
*
* @alias czm_sunShadowMapLightPositionEC
* @glslUniform
*/
czm_sunShadowMapLightPositionEC : new AutomaticUniform({
size : 1,
datatype : WebGLConstants.FLOAT_VEC4,
getValue : function(uniformState) {
return uniformState.shadowMap.lightPositionEC;
}
})
};

Expand Down
4 changes: 4 additions & 0 deletions Source/Renderer/Context.js
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,10 @@ define([
}
};

Context.prototype.bindFramebuffer = function(framebuffer) {
bindFramebuffer(this, framebuffer);
};

Context.prototype.readPixels = function(readState) {
var gl = this._gl;

Expand Down
2 changes: 1 addition & 1 deletion Source/Renderer/CubeMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ define([
this._positiveZ = new CubeMapFace(gl, texture, textureTarget, gl.TEXTURE_CUBE_MAP_POSITIVE_Z, pixelFormat, pixelDatatype, size, preMultiplyAlpha, flipY);
this._negativeZ = new CubeMapFace(gl, texture, textureTarget, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, pixelFormat, pixelDatatype, size, preMultiplyAlpha, flipY);

this.sampler = new Sampler();
this.sampler = defined(options.sampler) ? options.sampler : new Sampler();
}

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

/**
* Whether this command should receive shadows when shadowing is enabled.
*
* @type {Boolean}
* @default false
*/
// TODO : not used right now, but keep if it proves useful
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
7 changes: 6 additions & 1 deletion Source/Renderer/Framebuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ define([

defineProperties(Framebuffer.prototype, {
/**
* The status of the framebuffer. If the status is not WebGLConstants.COMPLETE,
* The status of the framebuffer. If the status is not WebGLConstants.FRAMEBUFFER_COMPLETE,
* a {@link DeveloperError} will be thrown when attempting to render to the framebuffer.
* @memberof Framebuffer.prototype
* @type {Number}
Expand Down Expand Up @@ -308,6 +308,11 @@ define([
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
};

Framebuffer.prototype._attachTexture = function(context, attachment, texture) {
context.bindFramebuffer(this);
attachTexture(this, attachment, texture);
};

Framebuffer.prototype._getActiveColorAttachments = function() {
return this._activeColorAttachments;
};
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 = 10000.0;
}

/**
Expand Down
18 changes: 14 additions & 4 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 Expand Up @@ -276,8 +286,8 @@ define([
vs.sources.push(getPositionMode(sceneMode));
vs.sources.push(get2DYPositionFraction(useWebMercatorProjection));

vs.sources[1] = ShadowMapShader.createShadowCastVertexShader(vs.sources[1]);
fs.sources[0] = ShadowMapShader.createShadowCastFragmentShader(fs.sources[0], frameState, true);
vs.sources[1] = ShadowMapShader.createShadowCastVertexShader(vs.sources[1], frameState, 'v_positionEC');
fs.sources[0] = ShadowMapShader.createShadowCastFragmentShader(fs.sources[0], frameState, true, 'v_positionEC');

shadowCastShader = this._shadowCastPrograms[flags] = ShaderProgram.fromCache({
context : frameState.context,
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
Loading