Skip to content

Commit

Permalink
Merge 6e72bb7 into 7e18584
Browse files Browse the repository at this point in the history
  • Loading branch information
jianhuang01 committed Aug 6, 2019
2 parents 7e18584 + 6e72bb7 commit 1671a2d
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 98 deletions.
40 changes: 16 additions & 24 deletions modules/core/src/effects/lighting/lighting-effect.js
Expand Up @@ -35,7 +35,6 @@ export default class LightingEffect extends Effect {

this.shadowColor = DEFAULT_SHADOW_COLOR;
this.shadowPasses = [];
this.lightMatrices = [];
this.dummyShadowMaps = [];
this.shadow = false;

Expand Down Expand Up @@ -68,7 +67,8 @@ export default class LightingEffect extends Effect {
prepare(gl, {layers, viewports, onViewportActive, views, pixelRatio}) {
if (!this.shadow) return {};

this._createLightMatrix();
// create light matrix every frame to make sure always updated from light source
const shadowMatrices = this._createLightMatrix();

if (this.shadowPasses.length === 0) {
this._createShadowPasses(gl, pixelRatio);
Expand All @@ -88,9 +88,9 @@ export default class LightingEffect extends Effect {
onViewportActive,
views,
effectProps: {
shadow_lightId: i,
shadowLightId: i,
dummyShadowMaps: this.dummyShadowMaps,
shadow_viewProjectionMatrices: this.lightMatrices
shadowMatrices
}
});
shadowMaps.push(shadowPass.shadowMap);
Expand All @@ -99,9 +99,8 @@ export default class LightingEffect extends Effect {
return {
shadowMaps,
dummyShadowMaps: this.dummyShadowMaps,
shadow_lightId: 0,
shadowColor: this.shadowColor,
shadow_viewProjectionMatrices: this.lightMatrices
shadowMatrices
};
}

Expand All @@ -124,29 +123,22 @@ export default class LightingEffect extends Effect {
dummyShadowMap.delete();
}
this.dummyShadowMaps.length = 0;

if (this.shadow) {
this._removeShadowModule();
}
}

_createLightMatrix() {
const projectionMatrix = new Matrix4().ortho({
left: -1,
right: 1,
bottom: -1,
top: 1,
near: 0,
far: 2
});

this.lightMatrices = [];
const lightMatrices = [];
for (const light of this.directionalLights) {
const viewMatrix = new Matrix4()
.lookAt({
eye: new Vector3(light.direction).negate()
})
// arbitrary number that covers enough grounds
.scale(1e-3);
const viewProjectionMatrix = projectionMatrix.clone().multiplyRight(viewMatrix);
this.lightMatrices.push(viewProjectionMatrix);
const viewMatrix = new Matrix4().lookAt({
eye: new Vector3(light.direction).negate()
});

lightMatrices.push(viewMatrix);
}
return lightMatrices;
}

_createShadowPasses(gl, pixelRatio) {
Expand Down
79 changes: 62 additions & 17 deletions modules/core/src/shaderlib/shadow/shadow.js
Expand Up @@ -21,6 +21,7 @@ import {createModuleInjection} from '@luma.gl/core';
import {PROJECT_COORDINATE_SYSTEM} from '../project/constants';
import {Vector3, Matrix4} from 'math.gl';
import memoize from '../../utils/memoize';
import {pixelsToWorld} from 'viewport-mercator-project';

const vs = `
const int max_lights = 2;
Expand Down Expand Up @@ -95,7 +96,8 @@ vec4 shadow_filterShadowColor(vec4 color) {
`;

const moduleName = 'shadow';
const _getMemoizedViewportCenterPosition = memoize(_getViewportCenterPosition);
const getMemoizedViewportCenterPosition = memoize(getViewportCenterPosition);
const getMemoizedViewProjectionMatrices = memoize(getViewProjectionMatrices);

createModuleInjection(moduleName, {
hook: 'vs:DECKGL_FILTER_GL_POSITION',
Expand All @@ -114,40 +116,87 @@ color = shadow_filterShadowColor(color);
const DEFAULT_SHADOW_COLOR = [0, 0, 0, 1.0];
const VECTOR_TO_POINT_MATRIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0];

function _getViewportCenterPosition({viewport, center}) {
function screenToCommonSpace(xyz, pixelUnprojectionMatrix) {
const [x, y, z] = xyz;
const coord = pixelsToWorld([x, y, z], pixelUnprojectionMatrix);

if (Number.isFinite(z)) {
return coord;
}
return [coord[0], coord[1], 0];
}

function getViewportCenterPosition({viewport, center}) {
return new Matrix4(viewport.viewProjectionMatrix).invert().transformVector4(center);
}

function getViewProjectionMatrices({viewport, shadowMatrices}) {
const projectionMatrices = [];
const pixelUnprojectionMatrix = viewport.pixelUnprojectionMatrix;
const corners = [];

corners[0] = screenToCommonSpace([0, 0], pixelUnprojectionMatrix);
corners[1] = screenToCommonSpace([viewport.width, 0], pixelUnprojectionMatrix);
corners[2] = screenToCommonSpace([0, viewport.height], pixelUnprojectionMatrix);
corners[3] = screenToCommonSpace([viewport.width, viewport.height], pixelUnprojectionMatrix);
corners[4] = screenToCommonSpace([0, 0, -1.0], pixelUnprojectionMatrix);
corners[5] = screenToCommonSpace([viewport.width, 0, -1.0], pixelUnprojectionMatrix);
corners[6] = screenToCommonSpace([0, viewport.height, -1.0], pixelUnprojectionMatrix);
corners[7] = screenToCommonSpace(
[viewport.width, viewport.height, -1.0],
pixelUnprojectionMatrix
);

for (const shadowMatrix of shadowMatrices) {
const viewMatrix = shadowMatrix.clone().translate(new Vector3(viewport.center).negate());
const positions = corners.map(corner => viewMatrix.transformVector3(corner));
const projectionMatrix = new Matrix4().ortho({
left: Math.min(...positions.map(position => position[0])),
right: Math.max(...positions.map(position => position[0])),
bottom: Math.min(...positions.map(position => position[1])),
top: Math.max(...positions.map(position => position[1])),
near: Math.min(...positions.map(position => -position[2])),
far: Math.max(...positions.map(position => -position[2]))
});
projectionMatrices.push(projectionMatrix.multiplyRight(shadowMatrix));
}
return projectionMatrices;
}

function createShadowUniforms(opts = {}, context = {}) {
const uniforms = {
shadow_uDrawShadowMap: Boolean(opts.drawToShadowMap),
shadow_uUseShadowMap: opts.shadowMaps ? opts.shadowMaps.length > 0 : false,
shadow_uColor: opts.shadowColor || DEFAULT_SHADOW_COLOR,
shadow_uLightId: opts.shadow_lightId,
shadow_uLightCount: opts.shadow_viewProjectionMatrices.length
shadow_uLightId: opts.shadowLightId || 0,
shadow_uLightCount: opts.shadowMatrices.length
};

const center = _getMemoizedViewportCenterPosition({
const center = getMemoizedViewportCenterPosition({
viewport: opts.viewport,
center: context.project_uCenter
});

const viewProjectionMatrices = [];
const projectCenters = [];

for (let i = 0; i < opts.shadow_viewProjectionMatrices.length; i++) {
const viewProjectionMatrix = opts.shadow_viewProjectionMatrices[i]
const viewProjectionMatrices = getMemoizedViewProjectionMatrices({
shadowMatrices: opts.shadowMatrices,
viewport: opts.viewport
}).slice();

for (let i = 0; i < opts.shadowMatrices.length; i++) {
const viewProjectionMatrix = viewProjectionMatrices[i];
const viewProjectionMatrixCentered = viewProjectionMatrix
.clone()
.translate(new Vector3(opts.viewport.center).negate());

if (context.project_uCoordinateSystem === PROJECT_COORDINATE_SYSTEM.LNG_LAT) {
viewProjectionMatrices[i] = viewProjectionMatrix;
viewProjectionMatrices[i] = viewProjectionMatrixCentered;
projectCenters[i] = [0, 0, 0, 0];
} else {
viewProjectionMatrices[i] = opts.shadow_viewProjectionMatrices[i]
viewProjectionMatrices[i] = viewProjectionMatrix
.clone()
.multiplyRight(VECTOR_TO_POINT_MATRIX);
projectCenters[i] = viewProjectionMatrix.transformVector4(center);
projectCenters[i] = viewProjectionMatrixCentered.transformVector4(center);
}
}

Expand All @@ -173,11 +222,7 @@ export default {
if (opts.drawToShadowMap || (opts.shadowMaps && opts.shadowMaps.length > 0)) {
const shadowUniforms = {};
const {shadowEnabled = true} = opts;
if (
shadowEnabled &&
opts.shadow_viewProjectionMatrices &&
opts.shadow_viewProjectionMatrices.length > 0
) {
if (shadowEnabled && opts.shadowMatrices && opts.shadowMatrices.length > 0) {
Object.assign(shadowUniforms, createShadowUniforms(opts, context));
} else {
Object.assign(shadowUniforms, {
Expand Down
3 changes: 1 addition & 2 deletions test/modules/core/effects/lighting-effect.spec.js
Expand Up @@ -116,7 +116,6 @@ test('LightingEffect#prepare and cleanup', t => {
pixelRatio: 1
});

t.equal(lightingEffect.lightMatrices.length, 2, 'LightingEffect prepares light matrices');
t.equal(lightingEffect.shadowPasses.length, 2, 'LightingEffect prepares shadow passes');
t.equal(lightingEffect.dummyShadowMaps.length, 2, 'LightingEffect prepares dummy shadow maps');

Expand All @@ -139,7 +138,7 @@ test('LightingEffect#shadow module', t => {
let hasShadow = defaultModules.some(m => m.name === 'shadow');
t.equal(hasShadow, true, 'LightingEffect adds shadow module to default correctly');

lightingEffect._removeShadowModule();
lightingEffect.cleanup();
hasShadow = defaultModules.some(m => m.name === 'shadow');
t.equal(hasShadow, false, 'LightingEffect removes shadow module to default correctly');
t.end();
Expand Down

0 comments on commit 1671a2d

Please sign in to comment.