使用SKShader片段着色器的SKSpriteNode最近邻居

时间:2017-10-16 01:25:17

标签: ios opengl-es sprite-kit

我试图在我的spritekit 2d像素艺术游戏中应用调色板交换功能,并且在应用SKShader时,似乎忽略了SKSpriteNode纹理上的filteringMode。

因此,我认为我需要首先应用最近邻居着色,然后再进行调色板交换逻辑。

基于在着色器玩具上找到的一些代码我已经做了这个尝试,这看起来像是正确的方向,如果坐标被标准化并且(0.0,0.0)是左下角(&( 1.0,1.0)右上角,但结果太明显了。

https://www.shadertoy.com/view/MllSzX

我对shader.fsh文件的改编:

void main() {

    float texSize = 48.0;
    vec2 pixel = v_tex_coord * texSize;
    float c_onePixel = 1.0 / texSize;
    pixel = (floor(pixel) / texSize);
    gl_FragColor = texture2D(u_texture, pixel + vec2(c_onePixel/2.0));
}

在进行调色板交换之前,如何让最近邻居在我的SKShader上工作?

2 个答案:

答案 0 :(得分:0)

不是我自己的完美答案,但我设法通过在我的info.plist中将PrefersOpenGL添加到YES来防止此问题,但我知道在ios上尽可能使用Metal < / p>

答案 1 :(得分:0)

我遇到了类似的问题。我想在像素周围创建轮廓,同时保持其像素化,但是它模糊了现有像素,使其看起来很糟糕。我最终实现了最近的邻居,然后在计算了最近的邻居位置之后检查了邻居像素,以查看该像素的alpha是否大于0。如果是,我将填写该像素。这是我的操作方式:

Outline.fsh:

vec2 nearestNeighbor(vec2 loc, vec2 size) {
    vec2 onePixel = vec2(1.0, 1.0) / size;
    vec2 coordinate = floor(loc * size) / size;
    return coordinate + onePixel / 2.0;
}

void main() {
    vec2 onePixel = vec2(1.0, 1.0) / a_sprite_size;
    vec4 texture = texture2D(u_texture, nearestNeighbor(v_tex_coord, a_sprite_size)); // Nearest neighbor for the current pixel
    if (texture.a == 0.0) {
        // Pixel has no alpha, check if any neighboring pixels have a non 0 alpha
        vec4 outlineColor = vec4(0.9, 0.9, 0.0, 1.0);
        if (texture2D(u_texture, nearestNeighbor(v_tex_coord + vec2(onePixel.x, 0), a_sprite_size)).a > 0.0) {
            // Right neighbor has an alpha > 0
            gl_FragColor = outlineColor;
        } else if (texture2D(u_texture, nearestNeighbor(v_tex_coord + vec2(-onePixel.x, 0), a_sprite_size)).a > 0.0) {
            // Left neighbor has an alpha > 0
            gl_FragColor = outlineColor;
        } else if (texture2D(u_texture, nearestNeighbor(v_tex_coord + vec2(0, onePixel.y), a_sprite_size)).a > 0.0) {
            // Top neighbor has an alpha > 0
            gl_FragColor = outlineColor;
        } else if (texture2D(u_texture, nearestNeighbor(v_tex_coord + vec2(0, -onePixel.y), a_sprite_size)).a > 0.0) {
            // Bottom neighbor has an alpha > 0
            gl_FragColor = outlineColor;
        } else {
            // No neighbors with an alpha > 0, don't change the color
            gl_FragColor = texture;
        }
    } else {
        // Pixel has an alpha > 0
        gl_FragColor = texture;
    }
}

然后,您需要将着色器添加到精灵中,并在精灵和着色器上设置已定义的属性,以便可以使用着色器中定义的值。

        spriteNode.setValue(SKAttributeValue(vectorFloat2: vector_float2(Float(spriteNode.size.width), Float(spriteNode.size.height))), forAttribute: "a_sprite_size")
        let shader = SKShader(fileNamed: "Outline.fsh")
        shader.attributes = [
            SKAttribute(name: "a_sprite_size", type: .vectorFloat2)
        ]
        spriteNode.shader = shader

希望这对其他遇到类似问题的人有所帮助!