유튜브 kishimisu의 An introduction to Shader Art Coding 영상을 정리한 내용입니다.
중간에 등장하는 자료들은 영상을 캡처한 것입니다.
이번 포스팅의 예제는 Shadertoy 에서 GLSL로 진행했습니다.
🐥 UV 좌표계 수정
origin resolution |
downsampled resolution |
![1](https://github.com/inhopp/inhopp/assets/96368476/c6a73e00-20ca-424f-a1ce-45c8ef70ce1a) |
![2](https://github.com/inhopp/inhopp/assets/96368476/26edeeca-4db0-412d-80e4-fb79dd9f59ec) |
void main(out vec4 fragColor, in vec2 fragCoord)
{
vec2 uv = fragCoord / iResolution.xy; // 0 ~ 1
uv = uv - 0.5; // align center
uv = uv * 2.0; // -1 ~ 1
fragColor = vec4(uv, 0.0, 1.0);
}
- 스크린의 중앙을 기준으로 작업을 하기 때문에 uv 좌표계를 center 중심으로 바꿔주기
🐥 Fix Aspect Ratio
Before Fix |
After Fix |
![4](https://github.com/inhopp/inhopp/assets/96368476/def2911a-e9fa-42b4-8197-af5e1c411427) |
![3](https://github.com/inhopp/inhopp/assets/96368476/62da4e64-583d-48a8-83d4-64bb74ea118e) |
void main(out vec4 fragColor, in vec2 fragCoord)
{
vec2 uv = fragCoord / iResolution.xy; // 0 ~ 1
uv = uv - 0.5; // align center
uv = uv * 2.0; // -1 ~ 1
fragColor = vec4(uv, 0.0, 1.0);
}
- 일반적으로 모니터의 가로x세로 해상도가 다르기 때문에 정사각형 모양의 스크린을 원한다면 aspect ratio를 보정해야 한다.
🐥 2D Signed Distance Function
![5](https://github.com/inhopp/inhopp/assets/96368476/2f73f64f-6396-4a95-8300-2a1c1c687ca8)
void main(out vec4 fragColor, in vec2 fragCoord)
{
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
float d = length(uv);
d -= 0.5;
d = abs(d);
fragColor = vec4(d, d, d, 1.0);
}
- 물체의 표면을 표현하고 싶을 때 사용하는 SDF
- Signed Distance Function : 물체의 형태를 유지하는 level set
- negative : 물체 내부
- zero : 물체 표면
- positive : 물체 외부
- absolute value, abs()를 이용하여 내부, 외부 모두 흰색으로 만들어주기
- Q ) 경계면 좀 더 깔끔하게 만들 수는 없나..??
Step Function
Graph |
Result |
![5](https://github.com/inhopp/inhopp/assets/96368476/79c1fa16-86d2-484e-a083-f511a7bc0433) |
![6](https://github.com/inhopp/inhopp/assets/96368476/850744b6-be35-4f93-8d47-e9cff7c7775f) |
- step function을 이용하면 칼 같은 경계 표현 가능
Smoothstep Function
Graph |
Result |
![7](https://github.com/inhopp/inhopp/assets/96368476/dc521cbd-ca65-4629-a9fb-a96c530e2ef4) |
![8](https://github.com/inhopp/inhopp/assets/96368476/eb751f6f-c968-4459-9574-e6c02db7efcd) |
- smoothstep으로는 원하는 두께로 부드럽게 표현 가능
🐥 Sine 함수로 주기 만들기
![9](https://github.com/inhopp/inhopp/assets/96368476/5ffd8860-ba0a-4cb4-8337-d90f27d14516)
void main(out vec4 fragColor, in vec2 fragCoord)
{
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
float d = length(uv);
d = sin(d * 8.0 + iTime) / (8.0);
d = abs(d);
d = smoothstep(0.0, 0.1, d);
fragColor = vec4(d, d, d, 1.0);
}
- sine function을 이용하여 주기를 주고
- iTime을 더해주며 움직임 표현
🐥 1/x 함수로 색 반전시키기
Graph |
Result |
![10](https://github.com/inhopp/inhopp/assets/96368476/87879abe-aa21-4b8f-95f2-feb7da10bb67) |
![11](https://github.com/inhopp/inhopp/assets/96368476/1c201e83-fcea-4114-9e0d-13b39859e723) |
void main(out vec4 fragColor, in vec2 fragCoord)
{
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
float d = length(uv);
d = sin(d * 8.0 + iTime) / (8.0);
d = abs(d);
d = 0.01 / d;
fragColor = vec4(d, d, d, 1.0);
}
- 색을 반전시키기 위해서는 0 -> 1, 1 -> 0 으로 부드럽게 변경해야 함
- 1/x 함수를 이용하면 원하는 강도로 부드럽게 반전시킬 수 있다.
- color 곱해주면 알록달록 표현 가능
Example1 |
Example2 |
![12](https://github.com/inhopp/inhopp/assets/96368476/01276e56-d7fa-4892-82f7-1cdbf9f8ef42) |
![13](https://github.com/inhopp/inhopp/assets/96368476/a9b62aee-a309-458f-801d-c853a70befd5) |
🐥 Palette 만들기
vec3 palette(float t)
{
vec3 a = vec3(0.5, 0.5, 0.5);
vec3 a = vec3(0.5, 0.5, 0.5);
vec3 a = vec3(1.0, 1.0, 1.0);
vec3 a = vec3(0.263, 0.416, 0.557);
vec3 a + b*cos(6.28318 * (c*t + d));
}
void main(out vec4 fragColor, in vec2 fragCoord)
{
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
float d = length(uv);
vec3 col = palette(d + iTime);
d = sin(d * 8.0 + iTime) / (8.0);
d = abs(d);
d = 0.02 / d;
col *= d;
fragColor = vec4(col, 1.0);
}
![16](https://github.com/inhopp/inhopp/assets/96368476/0da80753-3052-44cb-9b09-97e5c3d2fcba)
Inigo Quilez website
- 위 사이트에 들어가면 원하는 팔레트의 변수 값들을 찾을 수 있음
- 연속적으로 색이 변하는 팔레트이기 때문에 시간에 따른 주기함수에 쓰기 좋다.
- palette 변수로 time을 더해주면 같은 원 내에서도 알록달록 변함
Example1 |
Example2 |
![15](https://github.com/inhopp/inhopp/assets/96368476/299808ec-3a19-4f53-88e8-efda52a8a12a) |
![14](https://github.com/inhopp/inhopp/assets/96368476/c5d67b6e-49fd-4f0f-bdb9-29db1c78f6d0) |
🐥 Fraction 함수로 스크린 분할
Graph |
Result |
![17](https://github.com/inhopp/inhopp/assets/96368476/9125573d-327a-4a55-b605-a59058bde443) |
![18](https://github.com/inhopp/inhopp/assets/96368476/8172e7d3-cab0-4986-b2a4-728619164d24) |
void main(out vec4 fragColor, in vec2 fragCoord)
{
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y; // -1 ~ 1
uv = fract(uv * 2.0) - 0.5; // -2 ~ 2 : 가로세로 4등분 & center 보정
float d = length(uv);
vec3 col = palette(d + iTime);
d = sin(d * 8.0 + iTime) / (8.0);
d = abs(d);
d = 0.02 / d;
col *= d;
fragColor = vec4(col, 1.0);
}
- fraction : 정수 부분을 뺀 소수 부분
- uv의 범위를 늘려주고 fraction을 이용하면 스크린을 반복할 수 있음
Global Effect 추가하기
![ezgif com-video-to-gif (6)](https://github.com/inhopp/inhopp/assets/96368476/f476164d-57fa-463d-8ac5-605420de8091)
void main(out vec4 fragColor, in vec2 fragCoord)
{
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y; // -1 ~ 1
vec2 uv0 = uv; // glbal coordinate
uv = fract(uv * 2.0) - 0.5; // -2 ~ 2 : 가로세로 4등분 & center 보정
float d = length(uv);
vec3 col = palette(length(uv0) + iTime); // global effect
d = sin(d * 8.0 + iTime) / (8.0);
d = abs(d);
d = 0.02 / d;
col *= d;
fragColor = vec4(col, 1.0);
}
- fraction 적용 전 global coordinate(?)을 저장해두고, 이를 이용하여 global effect를 만들어 줄 수 있다.
🐥 Iteration으로 Fractal 구조 만들기
![ezgif com-video-to-gif (7)](https://github.com/inhopp/inhopp/assets/96368476/7eaf0aec-e6a2-4bbe-b6d7-1964d1830831)
void main( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
vec2 uv0 = uv;
vec3 finalColor = vec3(0.0);
for(float i=0.0; i<2.0; i++)
{
uv = fract(uv * 2.0) - 0.5;
float d = length(uv);
vec3 col = palette(length(uv0) + iTime);
d = sin(d*8. + iTime) / 8. ;
d = abs(d);
d = 0.02 / d;
finalColor += col * d;
}
fragColor = vec4(finalColor, 1.0);
}
- fraction으로 쪼갠 영역 안에서 또 fraction으로 쪼개버리기
- i를 늘려주면서 fractal 구조 만들 수 있음
🐥 Final Results
void main( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
vec2 uv0 = uv;
vec3 finalColor = vec3(0.0);
for(float i=0.0; i<4.0; i++)
{
uv = fract(uv * 1.5) - 0.5;
float d = length(uv) * exp(-length(uv0));
vec3 col = palette(length(uv0) + i*0.4 + iTime*0.4);
d = sin(d*8. + iTime) / 8. ;
d = abs(d);
d = pow(0.01 / d, 1.2);
finalColor += col * d;
}
fragColor = vec4(finalColor, 1.0);
}
- 규칙성을 흩트려 뜰이기 위해 몇 가지 작업 수행
- for문 안에서 2.0이 아닌 1.5배로 애매하게 쪼개기
- d = x * exp(-x), 부드러운 형태로 변형
- 0~1 사이에 pow 함수를 적용해 어두운 부분은 더 어둡게 표현
![ezgif com-crop (4)](https://github.com/inhopp/inhopp/assets/96368476/bcc16fc7-9456-4fd7-a4f6-ba3fe01875ba)
맨 위로 이동하기
Mini_Project 카테고리 내 다른 글 보러가기
댓글 남기기