GLSL : 1ピクセルのラインを描く

2018年12月25日

GLSLで一ピクセルのラインを描くフラインです。
(フラインがラインを描く) ← は?

 

今回は水平もしくは垂直にラインを引く話です。

斜めに関しては今回話さないです。

 

GLSLで1ピクセル単位の処理をする際はgl_FragCoordを使用します。

そうです。gl_FragCoordはみなさんがGLSLで正規化されたUV空間を生成するためになんとなくやっている “vec2 p = gl_FragCoord.xy / resolution.xy;”で使われてます。

gl_FragCoordの中身は何かというと処理されるピクセルの位置が入ってます。

なのでgl_FragCoord.xyとresolution.xyを割ることにより画面の横幅が1920だとした時 0.0 = 0.0 / 1919.0となり 1.0 = 1919.0 / 1919.0となります。 (厳密にはこんな計算じゃない)

注意点としては、gl_FragCoordは整数でピクセル位置が来るわけではなく浮動小数でピクセル位置が来るということ、あとは初期のピクセルが0.0にある場合と0.5にある場合があります。 GLSLSandBoxでは0.5にあるので一旦それで行きます。

詳しくは https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/gl_FragCoord.xhtml

 

早速コードです。

// @FL1NE
// single pixel line drawing example
// https://frontl1ne.net

#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

float frag_coord_prefix = 0.5;


vec4 drawLineVertical(float w){
    vec4 ret_color = vec4(0.0);
    float line_position = w + frag_coord_prefix;
    if(gl_FragCoord.x == line_position){
        ret_color = vec4(1.0);
    }
    return ret_color;
}


void main(void) {
    vec2 p = gl_FragCoord.xy / resolution.xy;
    vec4 dest_color = vec4(0.0);
    

    dest_color += drawLineVertical(50.0);

    
    gl_FragColor = dest_color;
}

http://glslsandbox.com/e#51228.0

実行するとこんな感じ

左より0から数えて50ピクセル目の位置にラインが引けました。

 

続いてアイキャッチ画像と同じように縦ラインで埋めてみましょう。

// @FL1NE
// single pixel line drawing example
// https://frontl1ne.net

#ifdef GL_ES
precision mediump float;
#endif

//#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

float frag_coord_prefix = 0.5;


vec4 drawLineVertical(float w){
    vec4 ret_color = vec4(0.0);
    float line_position = w + frag_coord_prefix;
    if(gl_FragCoord.x == line_position){
        ret_color = vec4(1.0);
    }
    return ret_color;
}


void main(void) {
    vec2 p = gl_FragCoord.xy / resolution.xy;
    vec4 dest_color = vec4(0.0);

    for(float i = 0.0; i < 7680.0; i += 2.0){
        dest_color += drawLineVertical(i);
    if(i > resolution.x) break;
    }

    gl_FragColor = dest_color;
}

http://glslsandbox.com/e#51229.0

実行したところ

こんな風になります。

 

このラインで埋める手法の場合以下のような書き方でも再現できます。

// @FL1NE
// single pixel line drawing example
// https://frontl1ne.net

#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

void main(void) {
    vec2 p = gl_FragCoord.xy / resolution.xy;
    vec4 dest_color = vec4(0.0);
    
    dest_color = vec4(floor(mod(gl_FragCoord.x, 2.0)));
    
    gl_FragColor = dest_color;
}

http://glslsandbox.com/e#51230.0

ほぼ同じ見た目

これはgl_FragCoord.xを2.0で割った余りをfloor関数で小数点以下切り捨てをしています。

これによって1ピクセルごとに0,1を繰り返すようになります。

 

これを利用し横方向に行なった結果をgl_FragColorにかけることで古いテレビのようなエフェクトをかけられます。

// @FL1NE
// single pixel line drawing example
// https://frontl1ne.net

#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

void main( void ) {

    vec2 p = gl_FragCoord.xy / resolution.xy;
    gl_FragColor = vec4(p, 0.0, 1.0);
    gl_FragColor *= floor(mod(gl_FragCoord.y, 2.0));
}

http://glslsandbox.com/e#51231.1

 

オールドスクール感

こんな感じです。