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

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

我正在尝试在我的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上工作?

ios opengl-es sprite-kit
2个回答
0
投票

不是我自己的完美答案,但我设法通过在我的info.plist中添加PrefersOpenGLYES来防止这个问题但是我知道在ios上尽可能使用Metal是首选


0
投票

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

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

希望这可以帮助其他有类似问题的人!

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