在片段着色器中画圆

问题描述 投票:0回答:2

在创建着色器方面我完全是个菜鸟。或者更好地说,我昨天才知道。

我正在尝试创建一个非常简单的圆圈。我以为我终于明白了,但事实证明它太大了。它应该与应用滤镜的 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>

filter webgl pixi.js
2个回答
2
投票

Pixi.js 的

vTextureCoord
不会从 0 到 1。

来自文档

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

...

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

如果要获取像素坐标,请使用统一的filterArea,它会自动传递给过滤器。

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");
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];
body { margin: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.2/pixi.js"></script>


1
投票

您似乎偶然发现了奇怪的浮点精度问题:片段着色器中的纹理坐标 (

vTextureCoord
) 并不严格在 (0, 1) 范围内。这是我添加行
gl_FragColor = vec4(vTextureCoord, 0, 1)
:

后得到的结果

UV debug shader output

看起来不错,但如果我们仔细观察,右下像素应该是 (1, 1, 0),但事实并非如此:

Lower right pixel

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

Lower right pixel is (1, 1)

Circle fits!

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

© www.soinside.com 2019 - 2024. All rights reserved.