-
-
Notifications
You must be signed in to change notification settings - Fork 4
v5 Creating filters
V5 过滤器很棒。
坐标有3个单位量度:
- 归一化(Normalized) (0,0) 是左上角, (1,1) 是右下角。
- 虚拟单元(Virtual units) (CSS), 用于容器、显示对象等的单位。(0,0) 是左上角, (1,1) 是右下角。
- 物理像素(Physical pixels) (像素), 基本上是一个屏幕单位。 差异出现在视网膜屏幕上。 例如,如果您想知道当前像素的右/左/上/下的物理像素,它会很有帮助。
在这里和所有文档中,我们将归一化
一词用于第一种类型,将像素
用于第三种类型。 默认情况下,我们谈论的是虚拟单元(CSS)。
pixi滤镜中有5个坐标系。每种都可以使用三种类型中的任何一种。
-
输入坐标 - FilterSystem从池中获取的临时pow2纹理。 用于
texture2D
采样。 - 屏幕坐标 - 不取决于输出是临时纹理还是屏幕,是否有10个滤镜离开屏幕,那就是屏幕坐标。
- 滤镜坐标 - (0,0)映射到滤镜覆盖的屏幕部分的左上角。 对于CSS或物理单位,其比例与屏幕相同,但偏移量不同。
-
精灵纹理坐标 - 有时在滤镜中会有额外的精灵输入。精灵位于pixi阶段树中,其面积不等于滤镜面积。这就是我们在
texture2D()
中传递的额外采样器。示例是DisplacementFilter -
精灵图集坐标 - 精灵可以使用来自图集的纹理,仅 精灵纹理坐标 不足以从
texture2D
获取正确的值。 示例:SpriteMaskFilter
过滤器构造函数参数包括顶点和片段着色器。如果我们在其中指定 null
或 undefined
会怎样?
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 :
- 我不知道为什么会有
max
- 我建议把它放在
vFilterCoord
中
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void){
gl_FragColor = texture2D(uSampler, vTextureCoord);
}
如上所述,vTextureCoord
是我们传递给默认采样器的 归一化输入坐标。
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移植东西,并且使用了默认的片段着色器,则可能会注意到您的滤镜在v5中看起来有所不同。这是因为默认的v4片段代码存在一个严重的问题,即有关alpha的二重乘法。
在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
字段。 要修复崩溃,您必须:
- 将
input.sourceFrame
替换为input.filterFrame
。 - 在滤镜构造函数参数或body中添加
dimensions
uniform:this.uniforms.dimensions = new Float32Array(2);
但是,我建议您完全删除它,以支持内置的inputSize
uniform,inputSize.xy
是滤镜区域的大小(以像素为单位),与dimensions
完全相同。在这种情况下,您可以从构造函数和apply
函数中删除多余的代码。
v5中的填充在autoFit之前应用,v4中的填充在之后应用。 这就导致了问题blurFilter和其他带有填充的滤镜被不同地对待:https://github.com/pixijs/pixi.js/issues/5969
滤镜可以使用临时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 // 滤镜像素(物理)
Version 5
Version 4