在片段着色器中绘制一个圆圈

时间:2017-05-28 20:56:50

标签: filter webgl pixi.js

在创建着色器时,我是一个完整的菜鸟。或者更好的说,我昨天刚刚了解了它。

我正在尝试创建一个非常简单的圈子。我终于弄明白了,但事实证明它很大。它应该与应用过滤器的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");
background.width = 200;
background.height = 200;
app.stage.addChild(background);

var vertexShader = `
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;
}
`;

var fragShader = `
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.),1.0);
}
`;
var filter = new PIXI.Filter(vertexShader, fragShader);
filter.padding = 0;
background.filters = [filter];

body { margin: 0; }

<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.2/pixi.js"></script>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

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

UV debug shader output

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

Lower right pixel

问题消失了,如果不是将尺寸设置为500乘500,我们使用2的幂大小(比如512乘512),问题就会消失:

Lower right pixel is (1, 1)

Circle fits!

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

答案 1 :(得分:1)

Pixi.js的vTextureCoord不会从0变为1。

来自the docs

  

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

     

...

     

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

     

如果要获取像素坐标,请使用均匀filterArea,它将自动传递给过滤器。

uniform vec4 filterArea;
...
vec2 pixelCoord = vTextureCoord * filterArea.xy;
     

它们以像素为单位。如果我们想要像#34这样的东西,将椭圆填充到边界框中,那就不会起作用了。所以,让我们传递尺寸! 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;

您的代码段已更新。

&#13;
&#13;
var app = new PIXI.Application();
document.body.appendChild(app.view);

var background = PIXI.Sprite.fromImage("required/assets/bkg-grass.jpg");
background.width = 200;
background.height = 200;
app.stage.addChild(background);

var vertexShader = `
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;
}
`;

var fragShader = `
precision mediump float;

varying vec2 vTextureCoord;
uniform vec2 dimensions;
uniform vec4 filterArea;

void main() {
    vec2 pixelCoord = vTextureCoord * filterArea.xy;
    vec2 uv = pixelCoord / dimensions;
    uv -= 0.5;
    float r = 0.5;
    float d = length(uv);
    float c = smoothstep(d,d+0.003,r);
    gl_FragColor = vec4(vec3(c,0.5,0.),1.0);
}
`;
var filter = new PIXI.Filter(vertexShader, fragShader);
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);
}

filter.padding = 0;
background.filters = [filter];
&#13;
body { margin: 0; }
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.2/pixi.js"></script>
&#13;
&#13;
&#13;