v5 Creating filters - zlq4863947/pixi.js-cn GitHub Wiki

概览

V5 过滤器很棒。

坐标系

坐标有3个单位量度:

  1. 归一化(Normalized) (0,0) 是左上角, (1,1) 是右下角。
  2. 虚拟单元(Virtual units) (CSS), 用于容器、显示对象等的单位。(0,0) 是左上角, (1,1) 是右下角。
  3. 物理像素(Physical pixels) (像素), 基本上是一个屏幕单位。 差异出现在视网膜屏幕上。 例如,如果您想知道当前像素的右/左/上/下的物理像素,它会很有帮助。

在这里和所有文档中,我们将归一化一词用于第一种类型,将像素用于第三种类型。 默认情况下,我们谈论的是虚拟单元(CSS)。

pixi滤镜中有5个坐标系。每种都可以使用三种类型中的任何一种。

  1. 输入坐标 - FilterSystem从池中获取的临时pow2纹理。 用于texture2D 采样。
  2. 屏幕坐标 - 不取决于输出是临时纹理还是屏幕,是否有10个滤镜离开屏幕,那就是屏幕坐标。
  3. 滤镜坐标 - (0,0)映射到滤镜覆盖的屏幕部分的左上角。 对于CSS或物理单位,其比例与屏幕相同,但偏移量不同。
  4. 精灵纹理坐标 - 有时在滤镜中会有额外的精灵输入。精灵位于pixi阶段树中,其面积不等于滤镜面积。这就是我们在texture2D()中传递的额外采样器。示例是DisplacementFilter
  5. 精灵图集坐标 - 精灵可以使用来自图集的纹理,仅 精灵纹理坐标 不足以从texture2D获取正确的值。 示例:SpriteMaskFilter

默认滤镜代码

过滤器构造函数参数包括顶点和片段着色器。如果我们在其中指定 nullundefined 会怎样?

new Filter(undefined, fragShader, myUniforms); // 默认的顶点着色器
new Filter(vertShader, undefined, myUniforms); // 默认片段着色器
new Filter(undefined, undefined, myUniforms);  // 全部默认

默认的顶点着色器

attribute vec2 aVertexPosition;

uniform mat3 projectionMatrix;

varying vec2 vTextureCoord;

uniform vec4 inputSize;
uniform vec4 outputFrame;

vec4 filterVertexPosition( void )
{
    vec2 position = aVertexPosition * max(outputFrame.zw, vec2(0.)) + outputFrame.xy;

    return vec4((projectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0);
}

vec2 filterTextureCoord( void )
{
    return aVertexPosition * (outputFrame.zw * inputSize.zw);
}

void main(void)
{
    gl_Position = filterVertexPosition();
    vTextureCoord = filterTextureCoord();
}
  • aVertexPosition归一化滤镜坐标

  • vTextureCoord归一化输入坐标

  • aVertexPosition * outputFrame.zw滤镜坐标

  • vec2 position = aVertexPosition * max(outputFrame.zw, vec2(0.)) + outputFrame.xy 为屏幕坐标

@ivanpopelyshev :

  1. 我不知道为什么会有max
  2. 我建议把它放在vFilterCoord

默认片段代码

varying vec2 vTextureCoord;

uniform sampler2D uSampler;

void main(void){
   gl_FragColor = texture2D(uSampler, vTextureCoord);
}

如上所述,vTextureCoord是我们传递给默认采样器的 归一化输入坐标

v4中的默认着色器

v4顶点着色器

PixiJS v4中的默认着色器与v5中的默认着色器不同。 如果要从v4移植滤镜,请对顶点着色器使用以下代码:

attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;

uniform mat3 projectionMatrix;

varying vec2 vTextureCoord;

void main(void) {
    gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
    vTextureCoord = aTextureCoord;
}

aTextureCoord 是通过的归一化输入坐标。如果PixiJS v5检测到该属性,它将切换到v4兼容模式,以添加旧的滤镜uniforms。

v4默认片段着色器

如果您要从v4移植东西,并且使用了默认的片段着色器,则可能会注意到您的滤镜在v5中看起来有所不同。这是因为默认的v4片段代码存在一个严重的问题,即有关alpha的二重乘法。

v4 dimensions uniform

在v4中有一个非常流行的dimensions统一的解决方法,它看起来像这样:

apply (filterManager, input, output, clear)
{
    this.uniforms.dimensions[0] = input.sourceFrame.width;
    this.uniforms.dimensions[1] = input.sourceFrame.height;
    filterManager.applyFilter(this, input, output, clear);
}

不幸的是,在v5中它崩溃了,因为input不是RenderTarget而是RenderTexture,它没有sourceFrame字段。 要修复崩溃,您必须:

  1. input.sourceFrame替换为input.filterFrame
  2. 在滤镜构造函数参数或body中添加dimensions uniform: this.uniforms.dimensions = new Float32Array(2);

但是,我建议您完全删除它,以支持内置的inputSize uniform,inputSize.xy 是滤镜区域的大小(以像素为单位),与dimensions完全相同。在这种情况下,您可以从构造函数和apply函数中删除多余的代码。

v4填充差异

v5中的填充在autoFit之前应用,v4中的填充在之后应用。 这就导致了问题blurFilter和其他带有填充的滤镜被不同地对待:https://github.com/pixijs/pixi.js/issues/5969

Multi-pass filters

滤镜可以使用临时renderTextures两次应用着色器,或应用内部滤镜

apply(filterManager, input, output, clear) {
    let rt = filterManager.getFilterTexture();
    filterManager.applyFilter(this, input, rt, true);
    filterManager.applyFilter(this, rt, output, clear);
}

在v4中,该函数是getRenderTarget(clear, resolution)。 在v5中,您可以使用getFilterTexture(resolution)

getFilterTexture()返回与输入大小相同的纹理。 如果使用resolution,则新纹理中的滤镜区域可以具有不同的归一化坐标系! 很好,除非您开始将其用作额外的采样器。

而且,由于全屏滤镜逻辑的存在,不能保证getFilterTexture(0.5 * input.resolution)返回的纹理恰好是输入的两倍。

如果要将其作为额外的采样器,则必须使用转换方法。

假设我们有一个内部滤镜,该滤镜会产生分辨率较低的临时纹理。

apply(filterManager, input, output, clear) {
    let rt = filterManager.getFilterTexture(0.5 * input.baseTexture.resolution);
    this._innerFilter.apply(filterManager, input, rt, true);
    this.uniforms.innerSampler = rt;
    this.uniforms.inputToTex = [input.width / rt.width, input.height / rt.height];
    filterManager.applyFilter(this, input, output, clear);
}
uniform sampler2D innerSampler;
uniform vec2 inputToTex;

{
    ...
    vec2 texCoord = vTextureCoord * inputToTex;
    vec4 inputColor = texture2D(uSampler, vTextureCoord);
    vec4 rtColor = texture2D(innerSampler, texCoord);
}

全屏滤镜

此行强制pixi使用与屏幕相同大小的临时renderTexture:

filter.filterArea = renderer.screen; //与app.screen相同

也称为pixi-v3仿真模式。

在这种情况下,输入,输出和屏幕坐标是相同的,并且您不必使用转换方法。

转换方法

vTextureCoord // 归一化滤镜
vTextureCoord * inputSize.xy // 滤镜像素(css)
vTextureCoord * inputSize.xy + outputFrame.xy // 屏幕像素(css) coord
vTextureCoord * inputSize.xy / outputFrame.zw // 滤镜 (归一化)
vTextureCoord * inputPixel.xy // 滤镜像素(物理)