Skip to content

Commit

Permalink
Add shadow effect to LightingEffect class
Browse files Browse the repository at this point in the history
  • Loading branch information
jianhuang01 committed Jul 29, 2019
1 parent 231960f commit 0ff1e52
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 218 deletions.
6 changes: 6 additions & 0 deletions docs/api-reference/layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,12 @@ Notes:
- `toValue` (TypedArray) - the new value to transition to, for the current vertex
- `fromChunk` (Array | TypedArray) - the existing value to transition from, for the chunk that the current vertex belongs to. A "chunk" is a group of vertices that help the callback determine the context of this transition. For most layers, all objects are in one chunk. For PathLayer and PolygonLayer, each path/polygon is a chunk.

##### `enableShadow` (Boolean, optional) **Experimental**

* Default: `true`

Experimental shadow effect can be toggled on and off for a layer by setting `enableShadow` prop. In order to render shadow, a [DirectionalLight](/docs/api-reference/lights/directional-light.md) with `castShadow` set to `true` must be created and passed to [LightingEffect](/docs/effects/lighting-effect.md).


## Members

Expand Down
1 change: 1 addition & 0 deletions docs/api-reference/lights/directional-light.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const directionalLight = new DirectionalLight({color, intensity, direction});
* `color` - (*array*,) RGB color of directional light source, default value is `[255, 255, 255]`.
* `intensity` - (*number*) Strength of directional light source, default value is `1.0`.
* `direction` - (*array*,) 3D vector specifies the direction the light comes from, default value is `[0, 0, -1]`.
* `castShadow` - (*boolean*, optional) Enable experimental shadow effect, default value is `false`.

## Source

Expand Down
10 changes: 6 additions & 4 deletions examples/experimental/sun/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {Component} from 'react';
import {render} from 'react-dom';
import {StaticMap} from 'react-map-gl';
import DeckGL from 'deck.gl';
import {AmbientLight, DirectionalLight, _LightWithShadowEffect} from '@deck.gl/core';
import {AmbientLight, DirectionalLight, LightingEffect} from '@deck.gl/core';
import {SolidPolygonLayer} from '@deck.gl/layers';
import {PhongMaterial} from '@luma.gl/core';

Expand All @@ -21,16 +21,18 @@ const ambientLight = new AmbientLight({
const dirLight0 = new DirectionalLight({
color: [255, 255, 255],
intensity: 1.0,
direction: [10, -20, -30]
direction: [10, -20, -30],
castShadow: true
});

const dirLight1 = new DirectionalLight({
color: [255, 255, 255],
intensity: 1.0,
direction: [-10, -20, -30]
direction: [-10, -20, -30],
castShadow: true
});

const lightingEffect = new _LightWithShadowEffect({ambientLight, dirLight0, dirLight1});
const lightingEffect = new LightingEffect({ambientLight, dirLight0, dirLight1});

const material = new PhongMaterial({
ambient: 0.1,
Expand Down
136 changes: 0 additions & 136 deletions modules/core/src/effects/lighting/light-with-shadow-effect.js

This file was deleted.

154 changes: 146 additions & 8 deletions modules/core/src/effects/lighting/lighting-effect.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import {AmbientLight} from '@luma.gl/core';
import {
AmbientLight,
Texture2D,
setDefaultShaderModules,
getDefaultShaderModules
} from '@luma.gl/core';
import DirectionalLight from './directional-light';
import Effect from '../../lib/effect';
import {Matrix4, Vector3} from 'math.gl';
import ShadowPass from '../../passes/shadow-pass';
import {default as shadow} from '../../shaderlib/shadow/shadow';

const DefaultAmbientLightProps = {color: [255, 255, 255], intensity: 1.0};
const DefaultDirectionalLightProps = [
Expand All @@ -15,6 +23,7 @@ const DefaultDirectionalLightProps = [
direction: [1, 8, -2.5]
}
];
const DefaultShadowColor = [0, 0, 0, 200 / 255];

// Class to manage ambient, point and directional light sources in deck
export default class LightingEffect extends Effect {
Expand All @@ -24,6 +33,12 @@ export default class LightingEffect extends Effect {
this.directionalLights = [];
this.pointLights = [];

this.shadowColor = DefaultShadowColor;
this.shadowPasses = [];
this.lightMatrices = [];
this.dummyShadowMaps = [];
this.castShadow = false;

for (const key in props) {
const lightSource = props[key];

Expand All @@ -42,20 +57,143 @@ export default class LightingEffect extends Effect {
default:
}
}
this.applyDefaultLights();
this._applyDefaultLights();

if (this.directionalLights.some(light => light.castShadow)) {
this.castShadow = true;
this._addShadowModule();
}
}

prepare(gl, {layers, viewports, onViewportActive, views, pixelRatio}) {
if (!this.castShadow) return {};

this._createLightMatrix();

if (this.shadowPasses.length === 0) {
this._createShadowPasses(gl, pixelRatio);
}

if (this.dummyShadowMaps.length === 0) {
this._createDummyShadowMaps(gl);
}

const shadowMaps = [];

for (let i = 0; i < this.shadowPasses.length; i++) {
const shadowPass = this.shadowPasses[i];
shadowPass.render({
layers,
viewports,
onViewportActive,
views,
effectProps: {
shadow_lightId: i,
dummyShadowMaps: this.dummyShadowMaps,
shadow_viewProjectionMatrices: this.lightMatrices
}
});
shadowMaps.push(shadowPass.shadowMap);
}

return {
shadowMaps,
dummyShadowMaps: this.dummyShadowMaps,
shadow_lightId: 0,
shadowColor: this.shadowColor,
shadow_viewProjectionMatrices: this.lightMatrices
};
}

getParameters(layer) {
const {ambientLight} = this;
const pointLights = this.getProjectedPointLights(layer);
const directionalLights = this.getProjectedDirectionalLights(layer);
const pointLights = this._getProjectedPointLights(layer);
const directionalLights = this._getProjectedDirectionalLights(layer);
return {
lightSources: {ambientLight, directionalLights, pointLights}
};
}

// Private
applyDefaultLights() {
cleanup() {
for (const shadowPass of this.shadowPasses) {
shadowPass.delete();
}
this.shadowPasses.length = 0;

for (const dummyShadowMap of this.dummyShadowMaps) {
dummyShadowMap.delete();
}
this.dummyShadowMaps.length = 0;

this._removeShadowModule();
}

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

this.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);
}
}

_createShadowPasses(gl, pixelRatio) {
for (let i = 0; i < this.directionalLights.length; i++) {
this.shadowPasses.push(new ShadowPass(gl, {pixelRatio}));
}
}
_createDummyShadowMaps(gl) {
for (let i = 0; i < this.directionalLights.length; i++) {
this.dummyShadowMaps.push(
new Texture2D(gl, {
width: 1,
height: 1
})
);
}
}

_addShadowModule() {
const defaultShaderModules = getDefaultShaderModules();
let hasShadowModule = false;
for (const module of defaultShaderModules) {
if (module.name === `shadow`) {
hasShadowModule = true;
break;
}
}
if (!hasShadowModule) {
defaultShaderModules.push(shadow);
setDefaultShaderModules(defaultShaderModules);
}
}

_removeShadowModule() {
const defaultShaderModules = getDefaultShaderModules();
for (let i = 0; i < defaultShaderModules.length; i++) {
if (defaultShaderModules[i].name === `shadow`) {
defaultShaderModules.splice(i, 1);
setDefaultShaderModules(defaultShaderModules);
break;
}
}
}

_applyDefaultLights() {
const {ambientLight, pointLights, directionalLights} = this;
if (!ambientLight && pointLights.length === 0 && directionalLights.length === 0) {
this.ambientLight = new AmbientLight(DefaultAmbientLightProps);
Expand All @@ -64,7 +202,7 @@ export default class LightingEffect extends Effect {
}
}

getProjectedPointLights(layer) {
_getProjectedPointLights(layer) {
const projectedPointLights = [];

for (let i = 0; i < this.pointLights.length; i++) {
Expand All @@ -74,7 +212,7 @@ export default class LightingEffect extends Effect {
return projectedPointLights;
}

getProjectedDirectionalLights(layer) {
_getProjectedDirectionalLights(layer) {
const projectedDirectionalLights = [];

for (let i = 0; i < this.directionalLights.length; i++) {
Expand Down

0 comments on commit 0ff1e52

Please sign in to comment.