Filter 在片段着色器中绘制圆

Filter 在片段着色器中绘制圆,filter,webgl,pixi.js,Filter,Webgl,Pixi.js,当涉及到创建着色器时,我是一个彻头彻尾的noob。或者更好地说,我昨天才知道 我试图创建一个非常简单的圆。我想我终于弄明白了,但结果是太大了。它应该与应用过滤器的DisplayObject大小相匹配 片段着色器: precision mediump float; varying vec2 vTextureCoord; vec2 resolution = vec2(1.0, 1.0); void main() { vec2 uv = vTextureCoord.xy / resolut

当涉及到创建着色器时,我是一个彻头彻尾的noob。或者更好地说,我昨天才知道

我试图创建一个非常简单的圆。我想我终于弄明白了,但结果是太大了。它应该与应用过滤器的DisplayObject大小相匹配

片段着色器:

precision mediump float;

varying vec2 vTextureCoord;
vec2 resolution = vec2(1.0, 1.0);

void main() {
    vec2 uv = vTextureCoord.xy / resolution.xy;
    uv -= 0.5;
    uv.x *= resolution.x / resolution.y;
    float r = 0.5;
    float d = length(uv);
    float c = smoothstep(d,d+0.003,r);
    gl_FragColor = vec4(vec3(c,0.5,0.0),1.0);
}
使用Pixi.js的示例:

var-app=new PIXI.Application();
document.body.appendChild(app.view);
var background=PIXI.Sprite.fromImage(“required/assets/bkg grass.jpg”);
背景宽度=200;
背景高度=200;
app.stage.addChild(后台);
变量vertexShader=`
属性向量2;
属性向量2编码;
均匀mat3投影矩阵;
可变向量2 vTextureCoord;
真空总管(真空)
{
gl_位置=vec4((投影矩阵*vec3(1.0)).xy,0.0,1.0);
vTextureCoord=ATextureCord;
}
`;
var fragShader=`
精密中泵浮子;
可变向量2 vTextureCoord;
vec2分辨率=vec2(1.0,1.0);
void main(){
vec2 uv=vTextureCoord.xy/resolution.xy;
uv-=0.5;
uv.x*=分辨率.x/分辨率.y;
浮点数r=0.5;
浮动d=长度(uv);
浮点数c=平滑步长(d,d+0.003,r);
gl_FragColor=vec4(vec3(c,0.5,0.),1.0);
}
`;
var filter=new PIXI.filter(顶点着色器、fragShader);
filter.padding=0;
background.filters=[filter]
body{margin:0;}

您似乎偶然发现了奇怪的浮点精度问题:片段着色器中的纹理坐标(
vTextureCoord
)不严格在(0,1)范围内。下面是我添加line
gl_FragColor=vec4(vTextureCoord,0,1)
时得到的结果:

看起来不错,但如果我们仔细检查,右下角的像素应该是(1,1,0),但不是:

如果我们使用两个大小的幂(例如512 x 512),而不是将大小设置为500 x 500,那么问题就会消失:


另一种可能的缓解问题的方法是尝试绕过Pixi计算投影矩阵的代码,并提供自己的代码,将较小的四边形转换为所需的屏幕位置

Pixi.js的
vtexturecord
不会从0变为1

V4过滤器与V3不同。不能只添加着色器并假设纹理坐标在[0,1]范围内

注意:vTextureCoord乘以filterArea.xy是边界框的实际大小

如果要获取像素坐标,请使用统一过滤器区域,它将自动传递到过滤器

uniform vec4 filterArea;
...
vec2 pixelCoord = vTextureCoord * filterArea.xy;
它们以像素为单位。如果我们想要像“将椭圆填充到边界框中”这样的东西,那么这是行不通的。所以,让我们也传递维度!PIXI不是自动完成的,我们需要手动修复:

filter.apply = function(filterManager, input, output)
{
  this.uniforms.dimensions[0] = input.sourceFrame.width
  this.uniforms.dimensions[1] = input.sourceFrame.height

  // draw the filter...
 filterManager.applyFilter(this, input, output);
}
让我们在着色器中组合它

uniform vec4 filterArea;
uniform vec2 dimensions;
...
vec2 pixelCoord = vTextureCoord * filterArea.xy;
vec2 normalizedCoord = pixelCoord / dimensions;
这是更新的代码片段

var-app=new PIXI.Application();
document.body.appendChild(app.view);
var background=PIXI.Sprite.fromImage(“required/assets/bkg grass.jpg”);
背景宽度=200;
背景高度=200;
app.stage.addChild(后台);
变量vertexShader=`
属性向量2;
属性向量2编码;
均匀mat3投影矩阵;
可变向量2 vTextureCoord;
真空总管(真空)
{
gl_位置=vec4((投影矩阵*vec3(1.0)).xy,0.0,1.0);
vTextureCoord=ATextureCord;
}
`;
var fragShader=`
精密中泵浮子;
可变向量2 vTextureCoord;
二维均匀矢量;
均匀vec4过滤区;
void main(){
vec2 pixelCoord=vTextureCoord*filterArea.xy;
vec2 uv=像素坐标/尺寸;
uv-=0.5;
浮点数r=0.5;
浮动d=长度(uv);
浮点数c=平滑步长(d,d+0.003,r);
gl_FragColor=vec4(vec3(c,0.5,0.),1.0);
}
`;
var filter=new PIXI.filter(顶点着色器、fragShader);
filter.apply=函数(filterManager、输入、输出)
{
this.uniforms.dimensions[0]=input.sourceFrame.width
this.uniforms.dimensions[1]=input.sourceFrame.height
//绘制过滤器。。。
applyFilter(这个、输入、输出);
}
filter.padding=0;
background.filters=[filter]
body{margin:0;}

谢谢!你让我意识到我忘了什么。我已经更新了小提琴@gman好吧,问题仍然是一样的:片段着色器依赖于(依赖于?)在图像上从0变为1,以适应圆,而不是。