https://thebookofshaders.com/08/
※ 다음 페이지를 참고하여 공부한 게시물입니다.
https://www.opentutorials.org/module/3659/24584
Rotate
// Author @patriciogv ( patriciogonzalezvivo.com ) - 2015
#ifdef GL_ES
precision mediump float;
#endif
#define PI 3.14159265359
uniform vec2 u_resolution;
uniform float u_time;
mat2 rotate2d(float _angle){
return mat2(cos(_angle),-sin(_angle),
sin(_angle),cos(_angle));
}
float box(in vec2 _st, in vec2 _size){
_size = vec2(0.5) - _size*0.5;
vec2 uv = smoothstep(_size,
_size+vec2(0.001),
_st);
uv *= smoothstep(_size,
_size+vec2(0.001),
vec2(1.0)-_st);
return uv.x*uv.y;
}
float cross(in vec2 _st, float _size){
return box(_st, vec2(_size,_size/4.)) +
box(_st, vec2(_size/4.,_size));
}
void main(){
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(0.0);
// move space from the center to the vec2(0.0)
st -= vec2(0.5);
// rotate the space
st = rotate2d( sin(u_time)*PI ) * st;
// move it back to the original place
st += vec2(0.5);
// Show the coordinates of the space on the background
// color = vec3(st.x,st.y,0.0);
// Add the shape on the foreground
color += vec3(cross(st,0.4));
gl_FragColor = vec4(color,1.0);
}
십자가 모양이 회전하는 쉐이더 코드를 작성해보자.
#ifdef GL_ES
precision mediump float;
#endif
#define PI 3.14159265359
uniform vec2 u_resolution;
uniform float u_mouse;
uniform float u_time;
float rect(vec2 loc, vec2 size, vec2 coord){
vec2 sw = loc - size/2.;
vec2 ne = loc + size/2.;
float pad = 0.001;
vec2 ret = smoothstep(sw - pad, sw, coord);
ret -= smoothstep(ne, ne + pad, coord);
return ret.x * ret.y;
}
float cross(vec2 loc, vec2 size, vec2 coord){
float r1 = rect(loc, size, coord);
float r2 = rect(loc, size.yx, coord);
return max(r1, r2);
}
void main(){
vec2 coord = gl_FragCoord.xy/u_resolution;
coord.x *= u_resolution.x/u_resolution.y;
vec3 col = vec3(cross(vec2(.5), vec2(0.550, 0.070), coord));
gl_FragColor = vec4(col, 1.);
}
먼저 십자가를 그리기 위해 사각형 함수 rect()를 cross안에서 max()로 합쳐서 표현한다.
이전과 다른 점은 rect() 안에서 smoothstep에 pad를 이용해서 흐릿하게 보이는 구간을 설정하였다.
sw(south west) 에서는 왼쪽 아래 부분이므로 pad를 빼고, ne(north east)는 오른쪽 상단 부분으로 pad만큼을 더함으로써 smooth한 padding 간격을 만들어낸다.
여기서 회전하는 법은 어떻게 넣을까?
#ifdef GL_ES
precision mediump float;
#endif
#define PI 3.14159265359
uniform vec2 u_resolution;
uniform float u_mouse;
uniform float u_time;
float rect(vec2 loc, vec2 size, vec2 coord){
vec2 sw = loc - size/2.;
vec2 ne = loc + size/2.;
float pad = 0.001;
vec2 ret = smoothstep(sw - pad, sw, coord);
ret -= smoothstep(ne, ne + pad, coord);
return ret.x * ret.y;
}
float cross(vec2 loc, vec2 size, vec2 coord){
float r1 = rect(loc, size, coord);
float r2 = rect(loc, size.yx, coord);
return max(r1, r2);
}
mat2 rotate2d(float _angle){
return mat2(cos(_angle), -sin(_angle),
sin(_angle), cos(_angle));
}
void main(){
vec2 coord = gl_FragCoord.xy/u_resolution;
coord.x *= u_resolution.x/u_resolution.y;
coord = coord * rotate2d(0.000);
vec3 col = vec3(cross(vec2(.5), vec2(0.550, 0.070), coord));
gl_FragColor = vec4(col, 1.);
}
중간에 rotate2d() 라는 함수를 추가하고, 이를 coord좌표에 곱해주었다. rotate2d는 input 각도만큼 회전행렬 연산을 처리해주는 것이다.
그랬더니 십자가가 이렇게 움직인다. 헉...
사실 coord에 rotate 회전행렬 연산을 곱했다는 것은 원점을 중심으로 회전시킨 것이다. 현재 원점은 (0,0) 위치 왼쪽 하단에 위치하기 때문에 이렇게 회전하는 것이다.
따라서 원점을 십자가의 중심으로 옮겨주고, 원점이 화면에 중앙에 나오도록 변경하자.
#ifdef GL_ES
precision mediump float;
#endif
#define PI 3.14159265359
uniform vec2 u_resolution;
uniform float u_mouse;
uniform float u_time;
float rect(vec2 loc, vec2 size, vec2 coord){
vec2 sw = loc - size/2.;
vec2 ne = loc + size/2.;
float pad = 0.001;
vec2 ret = smoothstep(sw - pad, sw, coord);
ret -= smoothstep(ne, ne + pad, coord);
return ret.x * ret.y;
}
float cross(vec2 loc, vec2 size, vec2 coord){
float r1 = rect(loc, size, coord);
float r2 = rect(loc, size.yx, coord);
return max(r1, r2);
}
mat2 rotate2d(float _angle){
return mat2(cos(_angle), -sin(_angle),
sin(_angle), cos(_angle));
}
void main(){
vec2 coord = gl_FragCoord.xy/u_resolution;
coord = coord*2. -1.;
coord.x *= u_resolution.x/u_resolution.y;
coord = coord * rotate2d(0.);
vec3 col = vec3(cross(vec2(0.), vec2(0.550, 0.070), coord));
gl_FragColor = vec4(col, 1.);
}
십자가를 원점으로 이동시켜 회전할 수 있도록 수정하였다.
coord = coord*2. -1.;
좌표를 두 배 늘렸다가 절반만큼 뺌으로써 원점을 화면의 중앙으로 옮기고
vec3 col = vec3(cross(vec2(0.), vec2(0.550, 0.070), coord));
이렇게 원점의 위치에 십자가를 생성시킨다.
coord = coord * rotate2d(sin(u_time));
시간에 따라 왔다 갔다 회전시키고 싶은 경우 rotate2d 값에 시간에 따른 sin()값을 넣으면 된다.
Scale
void main(){
vec2 coord = gl_FragCoord.xy/u_resolution;
coord = coord*2. - 1.;
coord.x *= u_resolution.x/u_resolution.y;
coord = coord * 1.; // <--
coord = coord * rotate2d(sin(u_time));
vec3 col = vec3(cross(vec2(0.), vec2(0.550, 0.070), coord));
gl_FragColor = vec4(col, 1.);
}
coord에 특정 배수만큼 값을 곱하면 값이 커질수록 십자가가 작아져보인다. 이는 곱하는 배수가 커질수록 좌표가 화면에 보여줄 수 있는 범위가 넓어지므로 십자가가 작아 보이는 것이다.
#ifdef GL_ES
precision mediump float;
#endif
#define PI 3.14159265359
uniform vec2 u_resolution;
uniform float u_mouse;
uniform float u_time;
float rect(vec2 loc, vec2 size, vec2 coord){
vec2 sw = loc - size/2.;
vec2 ne = loc + size/2.;
float pad = 0.001;
vec2 ret = smoothstep(sw - pad, sw, coord);
ret -= smoothstep(ne, ne + pad, coord);
return ret.x * ret.y;
}
float cross(vec2 loc, vec2 size, vec2 coord){
float r1 = rect(loc, size, coord);
float r2 = rect(loc, size.yx, coord);
return max(r1, r2);
}
mat2 rotate2d(float _angle){
return mat2(cos(_angle), -sin(_angle),
sin(_angle), cos(_angle));
}
void main(){
vec2 coord = gl_FragCoord.xy/u_resolution;
coord = coord*2. - 1.;
coord.x *= u_resolution.x/u_resolution.y;
coord = coord * sin(u_time);
coord = coord * rotate2d(sin(u_time));
vec3 col = vec3(cross(vec2(0.), vec2(0.550, 0.070), coord));
gl_FragColor = vec4(col, 1.);
}
이를 이용해서 coord 좌표에 sin으로 시간에 따라 커졌다 작아졌다 scale을 조정할 수 있다.
'개발 · 컴퓨터공학' 카테고리의 다른 글
[Capstone Project] issue : cannot assign to readonly property 참고 사이트 (0) | 2023.03.08 |
---|---|
GLSL - Making Patterns Circle and Diamond 원 및 다이아몬트 패턴 만들기 (0) | 2023.03.07 |
[Capstone Project] 망가지는 texture mapping 해결방안 (0) | 2023.03.03 |
[Capstone Project] 길이 조정 환경 만들기 - 1, 2 (0) | 2023.03.02 |
GLSL - cross translate 십자가 위치 변환 (1) | 2023.03.01 |