Pixi-shadows allows you to add shadows and lights to your pixi stage. The lights themselves are very simple, and this plugin purely focuses on the shadows. If you are interested in high quality lighting, you can easily combine this plugin with the pixi-lights plugin. Check out the main demo here.
This plugin was made by a very inexperienced developer in the field. I made it for usage in a personal project, and had to learn how to work with glsl to achieve this. I don't even have any real experience with opengl/webgl, so things are most likely not optimised. Any feedback is appreciated!
When using this plugin, you have to make sure the following dependencies are present:
Next your can either perform an npm install, or manually import the source file.
npm install pixi-shadows
or, clone and build this repository, then copy the pixi-shadows commonjs script or umd scriptmanually for usage without npm.
All pixiJS v6 plugins has special umd
build suited for vanilla.
Navigate pixi-shadows
npm package, take dist/pixi-shadows.umd.js
file.
Also, you can access CDN link, something like https://cdn.jsdelivr.net/npm/pixi-shadows@latest/dist/pixi-shadows.umd.js
.
<script src="https://github.com/TarVK/pixi-shadows/raw/master/lib/pixi.js"></script>
<script src="https://github.com/TarVK/pixi-shadows/raw/master/lib/pixi-shadows.umd.js"></script>
All classes can then be accessed through PIXI.shadows
package.
To quickly get going, check out this example:
import { AppLoaderPlugin, Shadow } from 'pixi-shadows';
import { Application, Container, InteractionEvent, SCALE_MODES, Sprite, Texture } from 'pixi.js';
// Initialise the shadows plugin
Application.registerPlugin(AppLoaderPlugin);
/* The actual demo code: */
// Create your application
const width = 800;
const height = 500;
const app = new Application({ width, height, autoStart: true });
document.body.appendChild(app.view);
// AppLoaderPlugin.init.apply(app);
// Create a world container
const world = app.shadows.container;
// A function to combine different assets of your world object, but give them a common transform by using pixi-layers
// It is of course recommended to create a custom class for this, but this demo just shows the minimal steps required
function createShadowSprite(texture: Texture, shadowTexture: Texture) {
const container = new Container(); // This represents your final 'sprite'
// Things that create shadows
if (shadowTexture) {
const shadowCastingSprite = new Sprite(shadowTexture);
shadowCastingSprite.parentGroup = app.shadows.casterGroup;
container.addChild(shadowCastingSprite);
}
// The things themselves (their texture)
const sprite = new Sprite(texture);
container.addChild(sprite);
return container;
}
// Can set ambientLight for the shadow filter, making the shadow less dark:
// shadows.filter.ambientLight = 0.4;
// Create a light that casts shadows
const shadow = new Shadow(700, 1);
shadow.position.set(450, 150);
world.addChild(shadow);
// Create a background (that doesn't cast shadows)
const bgTexture = Texture.from('../../assets/background.jpg');
const background = new Sprite(bgTexture);
world.addChild(background);
// Create some shadow casting demons
const demonTexture = Texture.from('../../assets/flameDemon.png');
demonTexture.baseTexture.scaleMode = SCALE_MODES.NEAREST; // For pixelated scaling
const demon1 = createShadowSprite(demonTexture, demonTexture);
demon1.position.set(100, 100);
demon1.scale.set(3);
world.addChild(demon1);
const demon2 = createShadowSprite(demonTexture, demonTexture);
demon2.position.set(500, 100);
demon2.scale.set(3);
world.addChild(demon2);
const demon3 = createShadowSprite(demonTexture, demonTexture);
demon3.position.set(300, 200);
demon3.scale.set(3);
world.addChild(demon3);
// Make the light track your mouse
world.interactive = true;
world.on('mousemove', (event: InteractionEvent) => {
shadow.position.copyFrom(event.data.global);
});
// Create a light point on click
world.on('pointerdown', (event: InteractionEvent) => {
const shadow2 = new Shadow(700, 0.7);
shadow2.position.copyFrom(event.data.global);
world.addChild(shadow);
});
Main steps:
Application.registerPlugin(AppLoaderPlugin);
line will register this plugin to set up your app properly. This does some fairly specific things however, which might not be correct in your usage case. So you can also decide to ignore the step and manually set up your application. Please check out what the init method does in this file.app.shadows.casterGroup
. Similarly, you can assign a sprite the group app.shadows.overlayGroup
making it render on top of shadows. By default shadow casters are also used as overlays.Shadow
object.var shadow = new Shadow(radius);
world.addChild(shadow);
Parameters:
Attributes:
var filter = app.shadows.filter;
Attributes:
This plugin can easily be used together with pixi-lights. Even more so, some structural choices were specifically made to support pixi-lights as this was the end goal. Here you can find a demo with its corresponding source code.
In order to see all things that can be done with pixi-shadows, please have a look at the following demo with its corresponding source code. This demo can also be used to test performance (which is rather poor), and test how high numbers have to be crancked to achieve a desired effeect.
As mentioned before, pixi-shadows can most likely be improved in terms of performance. For that reason I think it is important to explain how it currently works, such that more experienced people might be able to give feedback. It might also be handy for people that need to customise the plugin if it doesn't fit their needs exactly.
A demo with its corresponding source code is provided to show various components of the process. I attempted to comment pixi-shadows' source code a little bit as well, so hopefully this in combination with the explanation below should be enough to understand how it operates. Additionally you can check this detailed article I found (but didn't use directly) that seems to have a very similar approach.
Step by step description of what happens for each rendered frame:
npm install
npm run dev
This will start a development server that will live update as you save changes to the source code. you can choose which example to work on in the main page.
npm run build