이웃 격자 밖으로 출력된 결과에 대한 자연스러운 처리
.. float n = Hash21(id); col += Star(gv - vec2(n, fract(n * 34.)) + .5, 1.); ..

위의 결과를 보면 격자 하나에 대해 어떤 형상 하나가 표시되어 있다. 문제는 형상 하나가 외부 격자 밖에서는 짤려나간다는 것인데, 이를 해결하기 위한 코드가 아래와 같다.
..
for(int y=-1; y<=1; y++) {
for(int x=-1; x<=1; x++) {
vec2 offs = vec2(x, y);
float n = Hash21(id + offs);
col += Star(gv - offs - vec2(n, fract(n * 34.)) + .5, 1.);
}
}
..

위의 코드에서 유의해야할 점은 형상 하나가 바로 인접한 이웃의 이웃 밖으로 나갈 경우 처리되지 않는다. 이럴때는 밖으로 나간 것까지 포함되도록 for 문의 반복 범위를 확장해야 한다.
전체 코드는 다음과 같다.
uniform vec3 uResolution;
uniform float uTime;
uniform vec4 uMouse;
mat2 Rot(float a) {
float s = sin(a);
float c = cos(a);
return mat2(c, -s, s, c);
}
float Star(vec2 uv, float flare) {
float d = length(uv);
float m = .05 / d;
float rays = max(0., 1. - abs(uv.x * uv.y * 1000.));
m += rays * flare;
uv *= Rot(3.1415 / 4.);
rays = max(0., 1. - abs(uv.x * uv.y * 1000.));
m += rays * .3 * flare;
m *= smoothstep(1., .0, d); // 형상 하나가 바로 인접한 이웃 밖으로 나가지 않도록 해주는 코드
return m;
}
float Hash21(vec2 p) {
p = fract(p * vec2(123.34, 456.21));
p += dot(p, p + 45.32);
return fract(p.x * p.y);
}
void main() {
vec2 uv = (gl_FragCoord.xy - .5 * uResolution.xy) / uResolution.y;
uv *= 3.;
vec3 col = vec3(0);
vec2 gv = fract(uv) - .5;
vec2 id = floor(uv);
for(int y=-1; y<=1; y++) {
for(int x=-1; x<=1; x++) {
vec2 offs = vec2(x, y);
float n = Hash21(id + offs);
col += Star(gv - offs - vec2(n, fract(n * 34.)) + .5, 1.);
}
}
if(gv.x > .48 || gv.y > .48) col.r = 1.;
gl_FragColor = vec4(col, 1.0);
}
Mandelbrot Fractal
x축은 실수부, y축을 허수로 생각하는 공간(복소수평면)에서의 원점에서 일정한 offset 값만큼 이동하여 제곱한 값에 대한 실수부와 허수를 각각 x, y축으로 삼아 픽셀값으로 시각화한 결과가 Mandelbrot Fractal이며 구현 코드와 그에 대한 결과는 아래와 같다.
uniform vec3 uResolution;
uniform float uTime;
uniform vec4 uMouse;
void main() {
vec2 uv = (gl_FragCoord.xy - .5 * uResolution.xy) / uResolution.y;
uv += vec2(0.08, 0.15);
vec2 c = uv * 2.5 + vec2(-.69955, -.37999); // Offset
vec2 z = vec2(0.);
float iter = 0.;
float max_iter = 60.;
float h = 2. + sin(uTime);
for(float i=0.; i<max_iter; i++) {
z = vec2(
z.x * z.x - z.y * z.y, // 실수부
2. * z.x * z.y // 허수부
) + c;
if(length(z) > 2.) break;
iter++;
}
float f = iter / max_iter;
f = pow(f, .75);
vec3 col = vec3(f);
gl_FragColor = vec4(col, 1.0);
}

GLSL 퀵 레퍼런스
어떤 지점(p)에서 Ray(r)에 가장 가까운 r 위의 좌표 얻기
struct ray {
vec3 o, d;
};
vec3 ClosestPoint(ray r, vec3 p) {
return r.o + max(0., dot(p-r.o, r.d)) * r.d;
}
위의 ClosePoint를 이용하면 ray와 어떤 지점에 대한 최단 거리를 아래 함수를 이용해 구할 수 있다.
float DistRay(ray r, vec3 p) {
return length(p - ClosestPoint(r, p));
}
선 그리기 함수
float line(vec2 p, vec2 a, vec2 b) {
vec2 pa = p - a, ba = b - a;
float t = clamp(dot(pa, ba)/dot(ba, ba), 0., 1.);
vec2 c = a + ba * t;
float d = length(c - p);
return smoothstep(fwidth(d), 0., d - .001);
}
0 ~ 1 사이의 값을 갖는 간단한 노이즈 함수
float random (in vec2 st) {
return fract(sin(dot(st.xy,
vec2(12.9898,78.233)))*
43758.5453123);
}
// Based on Morgan McGuire @morgan3d
// https://www.shadertoy.com/view/4dS3Wd
float noise (in vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
// Four corners in 2D of a tile
float a = random(i);
float b = random(i + vec2(1.0, 0.0));
float c = random(i + vec2(0.0, 1.0));
float d = random(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(a, b, u.x) +
(c - a)* u.y * (1.0 - u.x) +
(d - b) * u.x * u.y;
}
-1 ~ 1 사이의 값을 갖는 Simplex 노이즈 함수
// Some useful functions
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }
//
// Description : GLSL 2D simplex noise function
// Author : Ian McEwan, Ashima Arts
// Maintainer : ijm
// Lastmod : 20110822 (ijm)
// License :
// Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
//
float snoise(vec2 v) {
// Precompute values for skewed triangular grid
const vec4 C = vec4(0.211324865405187,
// (3.0-sqrt(3.0))/6.0
0.366025403784439,
// 0.5*(sqrt(3.0)-1.0)
-0.577350269189626,
// -1.0 + 2.0 * C.x
0.024390243902439);
// 1.0 / 41.0
// First corner (x0)
vec2 i = floor(v + dot(v, C.yy));
vec2 x0 = v - i + dot(i, C.xx);
// Other two corners (x1, x2)
vec2 i1 = vec2(0.0);
i1 = (x0.x > x0.y)? vec2(1.0, 0.0):vec2(0.0, 1.0);
vec2 x1 = x0.xy + C.xx - i1;
vec2 x2 = x0.xy + C.zz;
// Do some permutations to avoid
// truncation effects in permutation
i = mod289(i);
vec3 p = permute(
permute( i.y + vec3(0.0, i1.y, 1.0))
+ i.x + vec3(0.0, i1.x, 1.0 ));
vec3 m = max(0.5 - vec3(
dot(x0,x0),
dot(x1,x1),
dot(x2,x2)
), 0.0);
m = m*m ;
m = m*m ;
// Gradients:
// 41 pts uniformly over a line, mapped onto a diamond
// The ring size 17*17 = 289 is close to a multiple
// of 41 (41*7 = 287)
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt(a0*a0 + h*h);
m *= 1.79284291400159 - 0.85373472095314 * (a0*a0+h*h);
// Compute final noise value at P
vec3 g = vec3(0.0);
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * vec2(x1.x,x2.x) + h.yz * vec2(x1.y,x2.y);
return 130.0 * dot(m, g);
}
좀더 고른 분포의 랜던 hash
uvec2 murmurHash21(uint src) {
const uint M = 0x5bd1e995u;
uvec2 h = uvec2(1190494759u, 2147483647u);
src *= M;
src ^= src>>24u;
src *= M;
h *= M;
h ^= src;
h ^= h>>13u;
h *= M;
h ^= h>>15u;
return h;
}
// 2 outputs, 1 input
vec2 hash21(float src) {
uvec2 h = murmurHash21(floatBitsToUint(src));
return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
}
smoothstep의 보간식
아래의 a와 b는 동일한 값이다.
float f = uv.x; float a = smoothstep(0., 1., f); float b = f * f * (3. - 2. * f);
위의 보간식을 cubic Hermite curve(큐빅 헤르미트 곡선)라고 한다. 0~1 사이의 영역에서 시작과 끝을 좀더 편평하게 만들어주는 quintic interpolation cuver(퀸틱 보간 곡선)에 대한 코드는 다음과 같다.
float f = uv.x; float b = f * f * f * (6. * f * f - 15. * f + 10.);

modelMatrix로 변환된 normal 얻기
varying vec3 vNormal; ... vNormal = mat3(transpose(inverse(modelMatrix))) * normal;
프레그먼트 쉐이더에서는 받은 vNormal을 반드시 정규화(normalize)해야 한다.
3초 주기로 0 ~ 1 사이의 연속된 값 얻기
uniform float u_time; // 0, 1, 2, ...의 값이며 각각 0초, 1초, 2초, ...를 나타냄 ... float period = 3.; // 3초 주기 float t = mod(u_time, period) / period; // 0 ~ 1 사이의 연속된 값 // sin 함수에 3.1415를 곱하는 이유는 sin 함수의 한 주기가 360도이기 때문임 vec3 color = mix(vec3(0), vec3(1), abs(sin(3.1415 * t))); // or vec3 color = mix(vec3(0), vec3(1), sin(3.1415 * t) * .5 + .5);
원하는 각도를 이루는 선
아래의 이미지는 45도를 이루는 선인데, 이처럼 원하는 각도를 이루는 선을 만들기 위한 코드이다.

uniform vec3 uResolution;
uniform float uTime;
uniform vec4 uMouse;
#define PI (3.141592)
void main() {
vec2 st = gl_FragCoord.xy / uResolution.xy;
st = (gl_FragCoord.xy - .5 * uResolution.xy) / uResolution.y;
float w = fwidth(st.y);
float a = (45.) * PI / 180.0;
float d = dot(st, vec2(cos(a), sin(a)));
d = smoothstep(-w, w, abs(d));
gl_FragColor = vec4(vec3(1. - d), 1.);
}
다각형 그리기
uniform vec3 uResolution;
uniform float uTime;
uniform vec4 uMouse;
#define PI 3.14159265359
#define TWO_PI 6.28318530718
void main(){
vec2 st = gl_FragCoord.xy/uResolution.xy * 2. - 1.; //-1-1
st.x *= uResolution.x/uResolution.y;
vec3 color = vec3(0.0);
float d = 0.0;
// Number of sides of your shape
int N = 6;
// int N = int(floor(mod(uTime * 10., 20.))) + 3;
// Angle and radius from the current pixel
float a = atan(st.x,st.y)+PI;
float r = TWO_PI/float(N);
// Shaping function that modulate the distance
d = cos(floor(.5+a/r)*r-a)*length(st);
// color = vec3(d); // Distance Field
color = vec3(1.0-step(.5, d)); // Fill
// color = vec3(step(.5,d) * step(d,.51)); // Only outline
gl_FragColor = vec4(color,1.0);
}

GLSL 코드
다음과 같은 결과를 프레그먼트 쉐이더로 작성한다면 … ? 즉, 화면의 반을 가르고 가른 영역의 중심을 원점으로 삼으며 원점을 기준으로 gl_FragCoord 지점에 대한 좌표(x,y)에 대한 각도(atan(y,x))에 대해 왼쪽 영역은 cos 값으로, 오른쪽 영역은 sin 값으로 채움.

방식은 여러가지겠지만 여기서는 2가지 구현 코드를 언급함. 첫번째는 제시된 문제를 그대로 해석해 풀이한 것.
uniform vec2 iResolution;
void main2() {
vec2 uv = gl_FragCoord.xy / iResolution;
vec2 origin = uv.x < 0.5 ? vec2(0.25, 0.5) : vec2(0.75, 0.5);
vec2 v = uv - origin;
float angle = atan(v.y, v.x);
float c = cos(angle);
float s = sin(angle);
vec3 color = uv.x < 0.5 ? vec3(c) : vec3(s);
gl_FragColor = vec4(color, 1.0);
}
두번째는 삼각함수의 원리를 이해하고 상황에 맞게 최적화해 구현한 것.
uniform vec2 iResolution;
void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
vec2 normal = uv.x > .5 ?
normalize(uv - vec2(0.75, 0.5)) :
normalize(uv - vec2(0.25, 0.5));
float t = uv.x > .5 ? normal.y : normal.x;
gl_FragColor = vec4(vec3(t), 1.0);
}
