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 - reorganize shaders #3749

Merged
merged 3 commits into from
Mar 22, 2016
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion Apps/Sandcastle/gallery/development/Shadows.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
freeze : false,
cascadeColors : false,
fitNearFar : true,
softShadows : true,
softShadows : false,
cascadeOptions : [1, 4],
cascades : 4,
lightSourceOptions : ['Freeform', 'Sun', 'Fixed', 'Point'],
Expand Down
24 changes: 5 additions & 19 deletions Source/Renderer/AutomaticUniforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -1535,30 +1535,16 @@ define([
}),

/**
* An automatic GLSL uniform representing the shadow map cascade offsets.
* An automatic GLSL uniform representing the shadow map cascade matrices.
*
* @alias czm_shadowMapCascadeOffsets
* @alias czm_shadowMapCascadeMatrices
* @glslUniform
*/
czm_shadowMapCascadeOffsets : new AutomaticUniform({
czm_shadowMapCascadeMatrices : new AutomaticUniform({
size : 4,
datatype : WebGLConstants.FLOAT_VEC3,
getValue : function(uniformState) {
return uniformState.shadowMap.cascadeOffsets;
}
}),

/**
* An automatic GLSL uniform representing the shadow map cascade scales.
*
* @alias czm_shadowMapCascadeScales
* @glslUniform
*/
czm_shadowMapCascadeScales : new AutomaticUniform({
size : 4,
datatype : WebGLConstants.FLOAT_VEC3,
datatype : WebGLConstants.FLOAT_MAT4,
getValue : function(uniformState) {
return uniformState.shadowMap.cascadeScales;
return uniformState.shadowMap.cascadeMatrices;
}
}),

Expand Down
8 changes: 0 additions & 8 deletions Source/Scene/Scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -1583,10 +1583,6 @@ define([

us.updateFrustum(frustum);

if (scene.shadowMap.enabled) {
scene.shadowMap.updateShadowMapMatrix(us);
}

clearDepth.execute(context, passState);

us.updatePass(Pass.GLOBE);
Expand Down Expand Up @@ -1636,10 +1632,6 @@ define([
// Do not overlap frustums in the translucent pass to avoid blending artifacts
frustum.near = frustumCommands.near;
us.updateFrustum(frustum);

if (scene.shadowMap.enabled) {
scene.shadowMap.updateShadowMapMatrix(us);
}
}

us.updatePass(Pass.TRANSLUCENT);
Expand Down
81 changes: 38 additions & 43 deletions Source/Scene/ShadowMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,7 @@ define([

// Uniforms
this._cascadeSplits = [new Cartesian4(), new Cartesian4()];
this._cascadeOffsets = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()];
this._cascadeScales = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()];
this._cascadeMatrices = [new Matrix4(), new Matrix4(), new Matrix4(), new Matrix4()];

var numberOfPasses;
if (this._isPointLight) {
Expand All @@ -182,6 +181,7 @@ define([
this._passCameras = new Array(numberOfPasses);
this._passStates = new Array(numberOfPasses);
this._passFramebuffers = new Array(numberOfPasses);
this._passTextureOffsets = new Array(numberOfPasses);

for (var i = 0; i < numberOfPasses; ++i) {
this._passCameras[i] = new ShadowMapCamera();
Expand Down Expand Up @@ -259,9 +259,10 @@ define([
return this._shadowMapTexture;
}
},

/**
* The shadow map matrix used in shadow receive programs.
* It converts gl_Position to shadow map texture space.
* Transforms from eye space to shadow texture space.
*
* @memberof ShadowMap.prototype
* @type {Matrix4}
Expand Down Expand Up @@ -334,16 +335,13 @@ define([
return this._cascadeSplits;
}
},
cascadeOffsets : {
get : function() {
return this._cascadeOffsets;
}
},
cascadeScales : {

cascadeMatrices : {
get : function() {
return this._cascadeScales;
return this._cascadeMatrices;
}
},

lightDirectionEC : {
get : function() {
return this._lightDirectionEC;
Expand Down Expand Up @@ -531,13 +529,13 @@ define([
if (this._isPointLight && this._usesCubeMap) {
textureSize.x = size;
textureSize.y = size;
var viewport = new BoundingRectangle(0, 0, size, size);
this._passStates[0].viewport = viewport;
this._passStates[1].viewport = viewport;
this._passStates[2].viewport = viewport;
this._passStates[3].viewport = viewport;
this._passStates[4].viewport = viewport;
this._passStates[5].viewport = viewport;
var faceViewport = new BoundingRectangle(0, 0, size, size);
this._passStates[0].viewport = faceViewport;
this._passStates[1].viewport = faceViewport;
this._passStates[2].viewport = faceViewport;
this._passStates[3].viewport = faceViewport;
this._passStates[4].viewport = faceViewport;
this._passStates[5].viewport = faceViewport;
} else if (numberOfPasses === 1) {
// +----+
// | 1 |
Expand Down Expand Up @@ -575,6 +573,16 @@ define([

// Update clear pass state
this._clearPassState.viewport = new BoundingRectangle(0, 0, textureSize.x, textureSize.y);

// Transforms shadow coordinates [0, 1] into the pass's region of the texture
for (var i = 0; i < numberOfPasses; ++i) {
var viewport = this._passStates[i].viewport;
var biasX = viewport.x / textureSize.x;
var biasY = viewport.y / textureSize.y;
var scaleX = viewport.width / textureSize.x;
var scaleY = viewport.height / textureSize.y;
this._passTextureOffsets[i] = new Matrix4(scaleX, 0.0, 0.0, biasX, 0.0, scaleY, 0.0, biasY, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
}
};

var scratchViewport = new BoundingRectangle();
Expand Down Expand Up @@ -848,22 +856,23 @@ define([
var far = shadowMapCamera.frustum.far;

var cascadeSubFrustum = sceneCamera.frustum.clone(scratchFrustum);
var shadowViewProjection = shadowMapCamera.getViewProjection();

for (var j = 0; j < numberOfCascades; ++j) {
// Find the bounding box of the camera sub-frustum in shadow map texture space
cascadeSubFrustum.near = splitsNear[j];
cascadeSubFrustum.far = splitsFar[j];
var viewProjection = Matrix4.multiply(cascadeSubFrustum.projectionMatrix, sceneCamera.viewMatrix, scratchMatrix);
var inverseViewProjection = Matrix4.inverse(viewProjection, scratchMatrix);
var cascadeMatrix = Matrix4.multiply(shadowMapCamera.getViewProjection(), inverseViewProjection, scratchMatrix);
var shadowMapMatrix = Matrix4.multiply(shadowViewProjection, inverseViewProjection, scratchMatrix);

// Project each corner from camera NDC space to shadow map texture space. Min and max will be from 0 to 1.
var min = Cartesian3.fromElements(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, scratchMin);
var max = Cartesian3.fromElements(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE, scratchMax);

for (var k = 0; k < 8; ++k) {
var corner = Cartesian4.clone(frustumCornersNDC[k], scratchFrustumCorners[k]);
Matrix4.multiplyByVector(cascadeMatrix, corner, corner);
Matrix4.multiplyByVector(shadowMapMatrix, corner, corner);
Cartesian3.divideByScalar(corner, corner.w, corner); // Handle the perspective divide
Cartesian3.minimumByComponent(corner, min, min);
Cartesian3.maximumByComponent(corner, max, max);
Expand All @@ -885,16 +894,10 @@ define([
cascadeCamera.frustum.near = near + min.z * (far - near);
cascadeCamera.frustum.far = near + max.z * (far - near);

// Scale and offset are used to transform shadowPosition to the proper cascade in the shader
var cascadeScale = shadowMap._cascadeScales[j];
cascadeScale.x = 1.0 / (max.x - min.x);
cascadeScale.y = 1.0 / (max.y - min.y);
cascadeScale.z = 1.0 / (max.z - min.z);

var cascadeOffset = shadowMap._cascadeOffsets[j];
cascadeOffset.x = -min.x;
cascadeOffset.y = -min.y;
cascadeOffset.z = -min.z;
// Transforms from eye space to the cascade's texture space
var cascadeMatrix = shadowMap._cascadeMatrices[j];
Matrix4.multiply(cascadeCamera.getViewProjection(), sceneCamera.inverseViewMatrix, cascadeMatrix);
Matrix4.multiply(shadowMap._passTextureOffsets[j], cascadeMatrix, cascadeMatrix);
}
}

Expand Down Expand Up @@ -1004,9 +1007,6 @@ define([
frustum.far = shadowMap._radius;
frustum.aspectRatio = 1.0;

// Re-purpose the shadow map matrix
Matrix4.inverse(frustum.projectionMatrix, shadowMap._shadowMapMatrix);

for (var i = 0; i < 6; ++i) {
var camera = shadowMap._passCameras[i];
camera.positionWC = shadowMap._shadowMapCamera.positionWC;
Expand Down Expand Up @@ -1081,6 +1081,12 @@ define([
this._passCameras[0].clone(this._shadowMapCamera);
}

// Transforms from eye space to shadow texture space
if (!this._isPointLight && this._numberOfCascades <= 1) {
var inverseView = this._sceneCamera.inverseViewMatrix;
Matrix4.multiply(this._shadowMapCamera.getViewProjection(), inverseView, this._shadowMapMatrix);
}

if (this.debugShow) {
applyDebugSettings(this, frameState);
}
Expand All @@ -1093,17 +1099,6 @@ define([
}
};

ShadowMap.prototype.updateShadowMapMatrix = function(uniformState) {
if (this._isPointLight) {
// Point light shadows do not project into light space
return;
}
// Calculate shadow map matrix. It converts gl_Position to shadow map texture space.
// Needs to be updated for each frustum in multi-frustum rendering because the projection matrix changes.
var shadowViewProjection = this._shadowMapCamera.getViewProjection();
Matrix4.multiply(shadowViewProjection, uniformState.inverseViewProjection, this._shadowMapMatrix);
};

ShadowMap.prototype.isDestroyed = function() {
return false;
};
Expand Down
Loading