- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
import { Filter } from '@pixi/core';
import { Matrix, Point } from '@pixi/math';
import fragment from './displacement.frag';
import vertex from './displacement.vert';
import type { CLEAR_MODES } from '@pixi/constants';
import type { FilterSystem, RenderTexture, Texture, ISpriteMaskTarget } from '@pixi/core';
/**
* The DisplacementFilter class uses the pixel values from the specified texture
* (called the displacement map) to perform a displacement of an object.
*
* You can use this filter to apply all manor of crazy warping effects.
* Currently the `r` property of the texture is used to offset the `x`
* and the `g` property of the texture is used to offset the `y`.
*
* The way it works is it uses the values of the displacement map to look up the
* correct pixels to output. This means it's not technically moving the original.
* Instead, it's starting at the output and asking "which pixel from the original goes here".
* For example, if a displacement map pixel has `red = 1` and the filter scale is `20`,
* this filter will output the pixel approximately 20 pixels to the right of the original.
* @memberof PIXI.filters
*/
export class DisplacementFilter extends Filter
{
public maskSprite: ISpriteMaskTarget;
public maskMatrix: Matrix;
public scale: Point;
/**
* @param {PIXI.Sprite} sprite - The sprite used for the displacement map. (make sure its added to the scene!)
* @param scale - The scale of the displacement
*/
constructor(sprite: ISpriteMaskTarget, scale?: number)
{
const maskMatrix = new Matrix();
sprite.renderable = false;
super(vertex, fragment, {
mapSampler: sprite._texture,
filterMatrix: maskMatrix,
scale: { x: 1, y: 1 },
rotation: new Float32Array([1, 0, 0, 1]),
});
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
if (scale === null || scale === undefined)
{
scale = 20;
}
/**
* scaleX, scaleY for displacements
* @member {PIXI.Point}
*/
this.scale = new Point(scale, scale);
}
/**
* Applies the filter.
* @param filterManager - The manager.
* @param input - The input target.
* @param output - The output target.
* @param clearMode - clearMode.
*/
public apply(
filterManager: FilterSystem, input: RenderTexture, output: RenderTexture, clearMode: CLEAR_MODES
): void
{
// fill maskMatrix with _normalized sprite texture coords_
this.uniforms.filterMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, this.maskSprite);
this.uniforms.scale.x = this.scale.x;
this.uniforms.scale.y = this.scale.y;
// Extract rotation from world transform
const wt = this.maskSprite.worldTransform;
const lenX = Math.sqrt((wt.a * wt.a) + (wt.b * wt.b));
const lenY = Math.sqrt((wt.c * wt.c) + (wt.d * wt.d));
if (lenX !== 0 && lenY !== 0)
{
this.uniforms.rotation[0] = wt.a / lenX;
this.uniforms.rotation[1] = wt.b / lenX;
this.uniforms.rotation[2] = wt.c / lenY;
this.uniforms.rotation[3] = wt.d / lenY;
}
// draw the filter...
filterManager.applyFilter(this, input, output, clearMode);
}
/** The texture used for the displacement map. Must be power of 2 sized texture. */
get map(): Texture
{
return this.uniforms.mapSampler;
}
set map(value: Texture)
{
this.uniforms.mapSampler = value;
}
}