GLSL ES检查片段是否在纹理边界

时间:2016-05-03 00:59:30

标签: glsl glsles gml

我正在尝试为2d精灵制作轮廓着色器,基本上它需要精灵并检查颜色,如果片段有那种颜色它被认为是轮廓,它然后检查它周围的纹素,如果没有它们是透明的,其alpha设置为0.

基本上我需要做的是让着色器忽略纹理的边框,因为如果片段在边框上,它将始终被视为轮廓。

我将包含绝对uv坐标的custom_FragCoord变量从顶点着色器发送到片段着色器,然后我说,例如,如果“custom_FragCoord.x> 1.进行轮廓检查”,则将所有内容都绘制在第一栏被视为大纲。

问题是当精灵有一个没有绘制任何东西的边框时,然后着色器似乎不会开始在精灵的边框处绘制,所以例如如果精灵的左边框没有任何东西,那么它将开始绘制custom_FragCoord.x = 1.,而不是0.,因此它不会自动将其视为轮廓,而是检查相邻的纹素,当它检查左纹素时,它将找不到透明纹理,因为它尝试过从纹理的边界检查左纹理元素。

如果有人能够对可以做的事情有所了解,这将是一个巨大的帮助。

如果链接不起作用,这是代码:

//////////////////////// Vertex shader ////////////////////////

attribute vec3 in_Position;                  // (x,y,z)
//attribute vec3 in_Normal;                  // (x,y,z)     unused in this shader.
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

varying vec2 custom_FragCoord;

void main()
{
    vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;

    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;

    //Send absolute fragment coordinate to fragment shader, maybe there's a different coordinate that should be sent instead since checks using this one only work when the sprite's texture touches all borders of the sprite size
    custom_FragCoord = (gm_Matrices[MATRIX_WORLD] * object_space_pos).xy;
}

//////////////////////// Fragment shader ////////////////////////
///Outlines shader

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform vec3 sl_v3_ColorTo; //What color should the outline be
uniform vec2 sl_v2_PixelSize; //Distance to next fragment's x/y, for size of step calculation
uniform vec2 sl_v2_SpriteSize; //Size of current drawn sprite (Not used currently, but could be relevant idk)

varying vec2 custom_FragCoord; //Absolute fragment coordinate

void main()
{
    vec3 v3_colorToTest = vec3(1.,1.,1.); //White outline color, for testing
    vec3 v3_outLineColor = vec3(0.149, 0.149, 0.149); //Color of outline to look for, if fragment is not this color just ignore

    //Check difference between fragment color and acceptable outline color
    vec3 v3_colDiff = vec3 (    texture2D(gm_BaseTexture, v_vTexcoord).r - v3_outLineColor.r,
                                texture2D(gm_BaseTexture, v_vTexcoord).g - v3_outLineColor.g,
                                texture2D(gm_BaseTexture, v_vTexcoord).b - v3_outLineColor.b);

    //How much does the fragment's color differ from the outline color it seeks
    float f_colDiff = (v3_colDiff.x+v3_colDiff.y+v3_colDiff.z)/3.;

    //If fragment color varies by more than 0.001 set alpha to 0, otherwise set it to 8
    float alpha = 8.*floor(texture2D(gm_BaseTexture, v_vTexcoord).a + 0.001 -abs(f_colDiff));

    //Bunch of conditionals, just to test, I'll take them off once stuff works
    /*Here lies the problem: If the sprite is, for instance, 32x32, but only the bottom-half of it has stuff to draw, the "custom_FragCoord.y > 1" check will be useless,
    since it will start drawing at custom_FragCoord.y = 15, not custom_FragCoord.y = 0*/

    if (custom_FragCoord.x > 1. && custom_FragCoord.y > 1. && custom_FragCoord.x < sl_v2_SpriteSize.x-1. && custom_FragCoord.y < sl_v2_SpriteSize.y-1.)
    {      
        //Check all around for transparency, if none is found it is not an outline
        for (float i = 0.; i <= 315.; i+= 45.)
        {
            alpha -= ceil(texture2D(gm_BaseTexture, v_vTexcoord +vec2(sign(cos(i))*sl_v2_PixelSize.x,sign(sin(i))*sl_v2_PixelSize.y)).a);
        }
    }

    //Paint result, with a white color to test out
    vec4 col = vec4(v3_colorToTest, alpha);

    gl_FragColor = col;
}

1 个答案:

答案 0 :(得分:0)

想出来,必须通过sprite_get_uvs()手动将精灵的纹理UV边框传递给着色器。

如果有人有兴趣,可以使用着色器:

//////////////////////// Vertex shader ////////////////////////
attribute vec3 in_Position;                  // (x,y,z)
//attribute vec3 in_Normal;                  // (x,y,z)     unused in this shader.
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;

    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;
}

//////////////////////// Fragment shader ////////////////////////
//Outlines shader
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform vec3 sl_v3_ColorTo; //What color should the outline be
uniform vec2 sl_v2_PixelSize; //Size of display, for size of step calculation
uniform vec4 sl_v2_TextureUV; //Texture's UV coordinates

void main()
{
    vec3 v3_colorToTest = vec3(1.,1.,1.);
    vec3 v3_outLineColor = vec3(0.149, 0.149, 0.149);

    vec3 v3_colDiff = vec3 (    texture2D(gm_BaseTexture, v_vTexcoord).r - v3_outLineColor.r,
                                texture2D(gm_BaseTexture, v_vTexcoord).g - v3_outLineColor.g,
                                texture2D(gm_BaseTexture, v_vTexcoord).b - v3_outLineColor.b);

    float f_colDiff = (v3_colDiff.x+v3_colDiff.y+v3_colDiff.z)/3.;

    float alpha = 8.*floor(texture2D(gm_BaseTexture, v_vTexcoord).a + 0.001 -abs(f_colDiff));

    vec4 v3_borderCheck = vec4 (    v_vTexcoord.x - sl_v2_TextureUV.x,
                                    v_vTexcoord.y - sl_v2_TextureUV.y,
                                    sl_v2_TextureUV.z - v_vTexcoord.x,
                                    sl_v2_TextureUV.w - v_vTexcoord.y);

    //Checks the borders, if on border is always outline
    alpha += floor(1.-v3_borderCheck.x +sl_v2_PixelSize.x);
    alpha += floor(1.-v3_borderCheck.y +sl_v2_PixelSize.y);
    alpha += floor(1.-v3_borderCheck.z +sl_v2_PixelSize.x);
    alpha += floor(1.-v3_borderCheck.w +sl_v2_PixelSize.x);

    //Check neighbors
    alpha -= ceil(texture2D(gm_BaseTexture, v_vTexcoord + vec2(sl_v2_PixelSize.x, 0.)).a);
    alpha -= ceil(texture2D(gm_BaseTexture, v_vTexcoord + vec2(-sl_v2_PixelSize.x, 0.)).a);
    alpha -= ceil(texture2D(gm_BaseTexture, v_vTexcoord + vec2(0., sl_v2_PixelSize.y)).a);
    alpha -= ceil(texture2D(gm_BaseTexture, v_vTexcoord + vec2(0., -sl_v2_PixelSize.y)).a);
    //Check diagonal neighbors
    alpha -= ceil(texture2D(gm_BaseTexture, v_vTexcoord + vec2(sl_v2_PixelSize.x, sl_v2_PixelSize.y)).a);
    alpha -= ceil(texture2D(gm_BaseTexture, v_vTexcoord + vec2(-sl_v2_PixelSize.x, sl_v2_PixelSize.y)).a);
    alpha -= ceil(texture2D(gm_BaseTexture, v_vTexcoord + vec2(sl_v2_PixelSize.x, -sl_v2_PixelSize.y)).a);
    alpha -= ceil(texture2D(gm_BaseTexture, v_vTexcoord + vec2(-sl_v2_PixelSize.x, -sl_v2_PixelSize.y)).a);

    vec4 col = vec4(v3_colorToTest, alpha); //alpha * sl_f_OutlineAlpha here later, sl_OutlineAlpha being a variable changeable in object (not dependent on object's image_alpha, set it to object_alpha inside object when appropriate)

    gl_FragColor = col;
}

它以非常具体的方式运作,因此我不知道它是否对其他人有用。

我确定有些地方可以优化,如果有人有建议请告诉我。