개발/Shader / / 2023. 3. 7. 20:36

GLSL - Making Patterns Circle and Diamond 원 및 다이아몬트 패턴 만들기

반응형

https://thebookofshaders.com/09/

 

The Book of Shaders

Gentle step-by-step guide through the abstract and complex universe of Fragment Shaders.

thebookofshaders.com

※ 다음 페이지를 참고하여 공부한 게시물입니다.

https://www.opentutorials.org/module/3659/24643

 

17. Patterns - GLSL / Shader

17. Patterns 2019-04-14 23:57:50

www.opentutorials.org

 

Patterns - Circle

// Author @patriciogv - 2015

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform float u_time;

float circle(in vec2 _st, in float _radius){
    vec2 l = _st-vec2(0.5);
    return 1.-smoothstep(_radius-(_radius*0.01),
                         _radius+(_radius*0.01),
                         dot(l,l)*4.0);
}

void main() {
	vec2 st = gl_FragCoord.xy/u_resolution;
    vec3 color = vec3(0.0);

    st *= 3.0;      // Scale up the space by 3
    st = fract(st); // Wrap around 1.0

    // Now we have 9 spaces that go from 0-1

    color = vec3(st,0.0);
    // color = vec3(circle(st,0.5));

	gl_FragColor = vec4(color,1.0);
}

격자 모양의 색 무늬와 격자 모양 안에 원이 들어있는 흑백 무늬가 있다. 위 코드에서 vec3(circle())에 대한 주석을 지우면 원 무늬로 변경할 수 있다. 

위 무늬를 직접 작성해보자.

 

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

void main() {
    vec2 coord = gl_FragCoord.xy/u_resolution;
    coord.x *= u_resolution.x/u_resolution.y;
    
    coord *= 3.;
    coord = fract(coord);
    
    vec3 col = vec3(1. - step(.3, distance(coord, vec2(.5))));
    gl_FragColor = vec4(col, 1.);
}

 

 

코드의 단계를 동그라미 하나를 그리는 것부터 하나씩 보자.

 

먼저 distance와 step을 이용하여 반지름 0.3의 동그라미를 그리고, step값을 1에서 뺌으로써 0.3보다 작으면 0(검정)이고 크면 1(흰색)인 것을 반전시켜 검은 바탕에 흰색으로 만든다.

이후 좌표 크기를 3배로 늘리고 fract를 이용해서 1을 넘어가는 각 좌표들에서 fract로 인해 소수점 단위로 계산되어 step으로 동그라미를 그릴 수 있도록 하여 1x1 좌표범위마다 무늬가 나오도록 한다.

 

 

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

void main() {
    vec2 coord = gl_FragCoord.xy/u_resolution;
    coord.x *= u_resolution.x/u_resolution.y;
    
    coord *= 3.;
    coord = fract(coord);
    
    vec3 col = vec3(coord, 0.1);
    gl_FragColor = vec4(col, 1.);
}

vec3한테 coord에 따른 color값만을 주고 fract로 1x1 box 패턴을 줄 수 있다.

 

Patterns - Diamond

// Author @patriciogv ( patriciogonzalezvivo.com ) - 2015

#ifdef GL_ES
precision mediump float;
#endif

// Copyright (c) Patricio Gonzalez Vivo, 2015 - http://patriciogonzalezvivo.com/
// I am the sole copyright owner of this Work.
//
// You cannot host, display, distribute or share this Work in any form,
// including physical and digital. You cannot use this Work in any
// commercial or non-commercial product, website or project. You cannot
// sell this Work and you cannot mint an NFTs of it.
// I share this Work for educational purposes, and you can link to it,
// through an URL, proper attribution and unmodified screenshot, as part
// of your educational material. If these conditions are too restrictive
// please contact me and we'll definitely work it out.

uniform vec2 u_resolution;
uniform float u_time;

#define PI 3.14159265358979323846

vec2 rotate2D(vec2 _st, float _angle){
    _st -= 0.5;
    _st =  mat2(cos(_angle),-sin(_angle),
                sin(_angle),cos(_angle)) * _st;
    _st += 0.5;
    return _st;
}

vec2 tile(vec2 _st, float _zoom){
    _st *= _zoom;
    return fract(_st);
}

float box(vec2 _st, vec2 _size, float _smoothEdges){
    _size = vec2(0.5)-_size*0.5;
    vec2 aa = vec2(_smoothEdges*0.5);
    vec2 uv = smoothstep(_size,_size+aa,_st);
    uv *= smoothstep(_size,_size+aa,vec2(1.0)-_st);
    return uv.x*uv.y;
}

void main(void){
    vec2 st = gl_FragCoord.xy/u_resolution.xy;
    vec3 color = vec3(0.0);

    // Divide the space in 4
    st = tile(st,4.);

    // Use a matrix to rotate the space 45 degrees
    st = rotate2D(st,PI*0.25);

    // Draw a square
    color = vec3(box(st,vec2(0.7),0.01));
    // color = vec3(st,0.0);

    gl_FragColor = vec4(color,1.0);
}

이러한 다이아몬드 모양을 만들어보자.

 

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

float rect(vec2 coord, vec2 size){
    vec2 center = vec2(.5);
    float hor = step(center.x - size.x, coord.x) - step(center.x + size.x, coord.x);
    float ver = step(center.y - size.y, coord.y) - step(center.y + size.y, coord.y);
    
    return hor * ver;
}

void main() {
    vec2 coord = gl_FragCoord.xy/u_resolution;
    coord.x *= u_resolution.x/u_resolution.y;
    
    coord *= 4.;
    coord = fract(coord);
    
    vec3 col = vec3(rect(coord, vec2(0.290,0.290)));
    
    gl_FragColor = vec4(col, 1.);
}

이번에는 원이 아니라 직사각형을 만든다는 점 이외에는 로직이 동일하다.

 

직사각형의 로직이 간혹 헷갈려서 다시 정리해보았다.

step을 이용해서 x좌표에 따라 y좌표에 따라 1로 설정되는 범위를 구해서 서로 곱하면 x,y가 (1,1)인 구간만이 남아 사각형이 생성된다. 이러한 방식으로 사각형을 생성한다는 것을 기억하자.

 

이렇게 사각형으로 패턴을 만들고 나서 다이아몬드 형태를 만들기 위해서는 회전시켜야한다.

 

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

mat2 rotate2d(float _angle){
    return mat2(cos(_angle), -sin(_angle),
               sin(_angle), cos(_angle));
}

float rect(vec2 coord, vec2 size){
    vec2 center = vec2(.5);
    float hor = step(center.x - size.x, coord.x) - step(center.x + size.x, coord.x);
    float ver = step(center.y - size.y, coord.y) - step(center.y + size.y, coord.y);
    
    return hor * ver;
}

void main() {
    vec2 coord = gl_FragCoord.xy/u_resolution;
    coord.x *= u_resolution.x/u_resolution.y;
    
    coord *= 4.;
    coord = fract(coord);
    coord *= rotate2d(0.208);
    
    vec3 col = vec3(rect(coord, vec2(0.290,0.290)));
    
    gl_FragColor = vec4(col, 1.);
}

rotate2d() 함수를 통해 회전해보았지만, 원점을 중심으로 회전하게 되는데, 사각형의 중심을 기준으로 회전하도록 바꾸자.

 

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

mat2 rotate2d(float _angle){
    return mat2(cos(_angle), -sin(_angle),
               sin(_angle), cos(_angle));
}

float rect(vec2 coord, vec2 size){
    vec2 center = vec2(0.);
    float hor = step(center.x - size.x, coord.x) - step(center.x + size.x, coord.x);
    float ver = step(center.y - size.y, coord.y) - step(center.y + size.y, coord.y);
    
    return hor * ver;
}

void main() {
    vec2 coord = gl_FragCoord.xy/u_resolution;
    coord.x *= u_resolution.x/u_resolution.y;
    
    coord *= 4.;
    coord = fract(coord);
    coord -= .5;
    coord *= rotate2d(u_time * 2.);
    
    vec3 col = vec3(rect(coord, vec2(0.290,0.290)));
    
    gl_FragColor = vec4(col, 1.);
}

사각형을 원점에 생성하고, 원점을 옮기는 방법으로 사각형이 중심을 기준으로 회전하도록 만들었다.

 

이를 구현할 때 주의할 점이 있는데,

사각형을 먼저 fract()로 나누고 나서 coord로 원점을 이동시켜야한다.

 

    coord -= .5;
    coord = fract(coord);

반대로 원점을 먼저 이동시킨 후에 fract()를 하게 되면 그림에서 coord로 인해 잘린 사각형의 오른쪽 위 부분만 보이게 된다.

 

#ifdef GL_ES
precision mediump float;
#endif

#define QUAR_PI .785

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

mat2 rotate2d(float _angle){
    return mat2(cos(_angle), -sin(_angle),
               sin(_angle), cos(_angle));
}

float rect(vec2 coord, vec2 size){
    vec2 center = vec2(0.);
    float hor = step(center.x - size.x, coord.x) - step(center.x + size.x, coord.x);
    float ver = step(center.y - size.y, coord.y) - step(center.y + size.y, coord.y);
    
    return hor * ver;
}

void main() {
    vec2 coord = gl_FragCoord.xy/u_resolution;
    coord.x *= u_resolution.x/u_resolution.y;
    
    coord *= 4.;
    coord = fract(coord);
    coord -= .5;
    coord *= rotate2d(QUAR_PI);
    
    vec3 col = vec3(rect(coord, vec2(0.3,0.3)));
    
    gl_FragColor = vec4(col, 1.);
}

사각형을 1/4 PI 만큼 회전시켜서 다이아몬트 형태로 만들었다. 

 

 

#ifdef GL_ES
precision mediump float;
#endif

#define QUAR_PI .785

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

mat2 rotate2d(float _angle){
    return mat2(cos(_angle), -sin(_angle),
               sin(_angle), cos(_angle));
}

float rect(vec2 coord, vec2 size){
    vec2 center = vec2(0.);
    float hor = step(center.x - size.x, coord.x) - step(center.x + size.x, coord.x);
    float ver = step(center.y - size.y, coord.y) - step(center.y + size.y, coord.y);
    
    return hor * ver;
}

void main() {
    vec2 coord = gl_FragCoord.xy/u_resolution;
    coord.x *= u_resolution.x/u_resolution.y;
    
    coord *= 4.;
    coord = fract(coord);
    coord -= .5;
    coord *= rotate2d(QUAR_PI);
    
    vec3 col = vec3(rect(coord, vec2(0.25 * sqrt(2.))));
    
    gl_FragColor = vec4(col, 1.);
}

모서리와 모서리를 맞닿게 하려면 계산이 좀 필요하다.

대각선의 길이가 0.5가 되게 하려면 0.25에 root(2)를 곱한 값을 반지름으로 하면 딱 대각선이 0.5가 된다.

 

https://thebookofshaders.com/09/

 

The Book of Shaders

Gentle step-by-step guide through the abstract and complex universe of Fragment Shaders.

thebookofshaders.com

위에서 또 다른 신기한 문양을 공부할 수 있다.

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유