2016-05-03 5 views
1

Я пытаюсь создать контурный шейдер для 2d спрайтов, в основном он берет спрайт и проверяет цвет, если фрагмент имеет этот цвет, он считается контуром, тогда проверяет текселей вокруг него, и если ни один из них не являются прозрачными его альфа устанавливается в 0.GLSL ES Проверьте, находится ли фрагмент на границе текстуры

Вот код шейдера, gm_Matrices [MATRIX_WORLD], gm_BaseTexture и т.д. устанавливаются GameMaker, но это все стандартные я предполагаю:

http://paste.ofcode.org/XHJkmxQCVnQWhQJAqkk68D

Релевантные линии - это линия 22 и Line 57.

В принципе, мне нужно сделать, чтобы шейдер игнорировал границы текстуры, так как если фрагмент находится на границе, он всегда будет считаться контуром.

Я отправляю переменную custom_FragCoord, содержащую абсолютные координаты uv из вершинного шейдера в шейдер фрагмента, а затем говорю, например, если «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; 
} 
+0

Ваш код должен быть в самом вопросе, а не в ссылке, так что, если связь умирает, quesiton может оказаться полезным для кого-то другого. – xaxxon

+0

О, простите об этом. –

ответ

0

Фигурного его, пришлось вручную передать текстуры UV границы спрайта затенения, через sprite_get_uvs().

Вот шейдер, если кому-то интересно:

//////////////////////// 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; 
} 

Он работает в очень специфическим образом, так что я не знаю, если это будет полезно для всех остальных.

Я уверен, что есть места, которые можно было бы оптимизировать, если у кого-то есть предложения, скажите мне.