본문 바로가기
Graphic/ThreeJS

28 Shader patterns

by curious week 2025. 8. 4.

✨ Shader Patterns with GLSL

GLSL을 사용하여 정해진 텍스처 없이 수학적으로 패턴을 생성하고, 다양한 형태의 그림, 변형, 왜곡, 그리고 애니메이션 가능한 모양을 만들어내는 기법들을 소개합니다.


🎯 목표

  • GLSL(Fragment Shader)에서 다양한 패턴을 그리는 수학적 기법 학습
  • vUv 좌표를 중심으로 값을 계산하고 시각화
  • 텍스처 없이도 정확한 제어가 가능한 셰이더 패턴 구현
  • mod, step, length, distance, mix, abs, sin, atan, cnoise, clamp 등의 함수 활용법 숙지

📦 기본 셋업

  • ShaderMaterial을 사용한 PlaneGeometry 기반 장면 구성
  • vUv 변수를 통해 vertex shader로부터 UV 좌표 전달
// vertex.glsl
varying vec2 vUv;

void main() {
  // ...
  vUv = uv;
}

// fragment.glsl
varying vec2 vUv;

void main() {
  // vUv 접근 가능
}

🎨 패턴

1) Geometry의 attributes에서 uv 값을 이용하여 색상 패턴 만들기

// vertex.glsl
varying vec2 vUv;

void main()
{
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

    vUv = uv; // 보통 texture를 vertex에 맞게 mapping하기 위해 사용
}
// fragment.glsl
varying vec2 vUv;

void main()
{
    gl_FragColor = vec4(vUv.r, vUv.g, 1.0, 1.0);
}

2)  blue 값만 변경

// fragment.glsl
varying vec2 vUv;

void main()
{
    gl_FragColor = vec4(vUv, 0.0, 1.0);
}

3) (x 축으로 이동할 수록 전체 색상이 1에 가까워지므로) 흑백 패턴 형성

// fragment.glsl
varying vec2 vUv;

void main()
{
    gl_FragColor = vec4(vUv.x, vUv.x, vUv.x, 1.0);
}

또는

varying vec2 vUv;

void main()
{
    float strength = vUv.x;

    gl_FragColor = vec4(strength, strength, strength, 1.0);
}

4) y축으로

// fragment.glsl
varying vec2 vUv;

void main()
{
    float strength = vUv.y;

    gl_FragColor = vec4(strength, strength, strength, 1.0);
}

5)

// fragment.glsl
varying vec2 vUv;

void main()
{
    float strength = 1.0 - vUv.y;

    gl_FragColor = vec4(strength, strength, strength, 1.0);
}

6)

// fragment.glsl
varying vec2 vUv;

void main()
{
    float strength = vUv.y * 10.0;

    gl_FragColor = vec4(strength, strength, strength, 1.0);
}

7) mod(a, b)는 a를 b로 나눈 나머지 === a % b

// fragment.glsl
varying vec2 vUv;

void main()
{
    float strength = mod(vUv.y * 10.0, 1.0);

    gl_FragColor = vec4(strength, strength, strength, 1.0);
}

8) float step(float edge, float x) edge 기준값, x 비교값

// step 함수
if (x < edge)
    return 0.0;
else
    return 1.0;

// fragment.glsl
varying vec2 vUv;

void main()
{
    float strength = mod(vUv.y * 10.0, 1.0);
    
    // {} 중괄호 없어도 동작함.
    if(strength < 0.5) {
        strength = 0.0;
    } else {
        strength = 1.0;
    }
    // or
    strength = strength <= 0.5 ? 0.0 : 1.0;
    // or
    strength = step(0.5, strength);

    gl_FragColor = vec4(strength, strength, strength, 1.0);
}

9) step 기준값 조정

  // Pattern 9
    float strength = mod(vUv.y * 10.0, 1.0);
    strength = step(0.8, strength);

10) vUv x 값으로 변경

    // Pattern 10
	float strength = mod(vUv.x * 10.0, 1.0);
    strength = step(0.8, strength);

11)

    // Pattern 11
    float strength = step(0.8, mod(vUv.x * 10.0, 1.0));
    strength += step(0.8, mod(vUv.y * 10.0, 1.0));

12) *= 으로 교차하는 곳(step이 0.8이므로 나머지 20%)만 값이 1.0이 되도록

    // Pattern 12
    float strength = step(0.8, mod(vUv.x * 10.0, 1.0));
    strength *= step(0.8, mod(vUv.y * 10.0, 1.0));

13) x축 step 조절

    // Pattern 13
    float strength = step(0.4, mod(vUv.x * 10.0, 1.0));
    strength *= step(0.8, mod(vUv.y * 10.0, 1.0));

14) 각각 생성 후 합치기

    // Pattern 14
    float barX = step(0.4, mod(vUv.x * 10.0, 1.0));
    barX *= step(0.8, mod(vUv.y * 10.0, 1.0));

    float barY = step(0.8, mod(vUv.x * 10.0, 1.0));
    barY *= step(0.4, mod(vUv.y * 10.0, 1.0));

    float strength = barX + barY;

    gl_FragColor = vec4(strength, strength, strength, 1.0);

15) 위치 조정

    // Pattern 15
    float barX = step(0.4, mod(vUv.x * 10.0 , 1.0));
    barX *= step(0.8, mod(vUv.y * 10.0 + 0.2, 1.0));

    float barY = step(0.8, mod(vUv.x * 10.0 + 0.2, 1.0));
    barY *= step(0.4, mod(vUv.y * 10.0, 1.0));

    float strength = barX + barY;

    gl_FragColor = vec4(strength, strength, strength, 1.0);

16)

    // Pattern 16
    float strength = abs(vUv.x - 0.5);

    gl_FragColor = vec4(strength, strength, strength, 1.0);

17) min (abs로 x, y축 모두 대칭 구조로 만들고, min으로 두 값 중 작은 값을 출력한다.)

    // Pattern 17
    float strength = min(abs(vUv.x - 0.5), abs(vUv.y - 0.5));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

18) max

    // Pattern 18
    float strength = max(abs(vUv.x - 0.5), abs(vUv.y - 0.5));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

19)

    // Pattern 19
    float strength = step(0.2 ,max(abs(vUv.x - 0.5), abs(vUv.y - 0.5)));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

20)

    // Pattern 20
    float square1 = step(0.2 ,max(abs(vUv.x - 0.5), abs(vUv.y - 0.5)));
    float square2 = 1.0 - step(0.25 ,max(abs(vUv.x - 0.5), abs(vUv.y - 0.5)));
    float strength = square1 * square2;

    gl_FragColor = vec4(strength, strength, strength, 1.0);

21)

    // Pattern 21
    float strength = round(vUv.x * 10.0) / 10.0;
    // or
    float strength = floor(vUv.x * 10.0) / 10.0;

    gl_FragColor = vec4(strength, strength, strength, 1.0);

22)

    // Pattern 22
    float strength = floor(vUv.x * 10.0) / 10.0;
    strength *= floor(vUv.y * 10.0) / 10.0;

    gl_FragColor = vec4(strength, strength, strength, 1.0);

23) 난수 생성

// fragment.glsl
varying vec2 vUv;

// Pattern 23
float random(vec2 st){
    return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
}

void main()
{   
    // Pattern 23
    float strength = random(vUv);

    gl_FragColor = vec4(strength, strength, strength, 1.0);
}
  • dot(st.xy, vec2(12.9898, 78.233))
    • dot product (내적) → st.x * 12.9898 + st.y * 78.233
  • sin(...)
    • 사인 함수 → 이걸 쓰면 출력값이 -1.0 ~ +1.0 사이의 복잡한 곡선형 값이 됩니다. → 주기적이면서 예측이 어려운 패턴
  • * 43758.5453123
    • 큰 수를 곱해 소수점 아래에 많은 변화를 유도 → 사인 결과는 -1 ~ 1 이므로, 곱셈을 통해 값 분산을 넓힘
  • fract(...)
    • 소수점 이하만 추출 (0.0 ~ 1.0 사이로 잘라냄)→ 결과는 항상 [0.0, 1.0) 범위의 float
    • ex) fract(3.1415) == 0.1415, fract(-1.7) == 0.3

24)

// fragment.glsl
varying vec2 vUv;

// Pattern 23
float random(vec2 st){
    return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
}

void main()
{
	// Pattern 24
    vec2 gridUv = vec2(
        floor(vUv.x * 10.0) / 10.0, floor(vUv.y * 10.0) / 10.0
    );
    float strength = random(gridUv);

    gl_FragColor = vec4(strength, strength, strength, 1.0);
}

정해진 난수이기 때문에 항상 동일한 패턴이 발생

25) vUv.y + vUv.x * 0.5, vUv.y * 10.0 + vUv.x * 5.0 부분이 기울기를 만듦.

// fragment.glsl
varying vec2 vUv;

// Pattern 23
float random(vec2 st){
    return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
}

void main()
{
    // Pattern 25
    // vec2 gridUv = vec2(
    //   floor(vUv.x * 10.0) / 10.0, floor((vUv.y + vUv.x * 0.5) * 10.0) / 10.0
    // );
    vec2 gridUv = vec2(
    	floor(vUv.x * 10.0) / 10.0, floor(vUv.y * 10.0 + vUv.x * 5.0) / 10.0
    );
    float strength = random(gridUv);

    gl_FragColor = vec4(strength, strength, strength, 1.0);
}

26) length: 길이 계산

    // Pattern 26
    float strength = length(vUv);

    gl_FragColor = vec4(strength, strength, strength, 1.0);

27) distance(거리, 중앙): 거리 계산

    // Pattern 27
    float strength = distance(vUv, vec2(0.5, 0.5));
    // or
    float strength = length(vUv - 0.5);

    gl_FragColor = vec4(strength, strength, strength, 1.0);

28)

    // Pattern 28
    float strength = 1.0 - distance(vUv, vec2(0.5));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

29)

    // Pattern 29
    float strength = 0.01 / distance(vUv, vec2(0.5));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

30)

    // Pattern 30
    vec2 lightUv = vec2(vUv.x * 0.1 + 0.45, vUv.y * 0.5 + 0.25);
    float strength = 0.015 / distance(lightUv, vec2(0.5, 0.5));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

31)

    // Pattern 31
    vec2 lightUvX = vec2(vUv.x * 0.1 + 0.45, vUv.y * 0.5 + 0.25);
    float lightX = 0.015 / distance(lightUvX, vec2(0.5, 0.5));

    vec2 lightUvY = vec2(vUv.y * 0.1 + 0.45, vUv.x * 0.5 + 0.25);
    float lightY = 0.015 / distance(lightUvY, vec2(0.5, 0.5));

    float strength = lightX * lightY;

    gl_FragColor = vec4(strength, strength, strength, 1.0);

32)

// fragment.glsl
#define PI 3.1415926535897932384626433832795

varying vec2 vUv;

// Pattern 32
vec2 rotate(vec2 uv, float rotation, vec2 mid)
{
    return vec2(
      cos(rotation) * (uv.x - mid.x) + sin(rotation) * (uv.y - mid.y) + mid.x,
      cos(rotation) * (uv.y - mid.y) - sin(rotation) * (uv.x - mid.x) + mid.y
    );
}

void main()
{
     // Pattern 32
    // vec2 rotatedUv = rotate(vUv, 0.5, vec2(0.5)); 
    // or
    vec2 rotatedUv = rotate(vUv, PI * 0.25, vec2(0.5));

    vec2 lightUvX = vec2(rotatedUv.x * 0.1 + 0.45, rotatedUv.y * 0.5 + 0.25);
    float lightX = 0.015 / distance(lightUvX, vec2(0.5, 0.5));

    vec2 lightUvY = vec2(rotatedUv.y * 0.1 + 0.45, rotatedUv.x * 0.5 + 0.25);
    float lightY = 0.015 / distance(lightUvY, vec2(0.5, 0.5));

    float strength = lightX * lightY;

    gl_FragColor = vec4(strength, strength, strength, 1.0);
}

33)

    // Pattern 33
    float strength = step(0.25, distance(vUv, vec2(0.5)));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

34)

    // Pattern 34
    float strength = abs(distance(vUv, vec2(0.5)) - 0.25);

    gl_FragColor = vec4(strength, strength, strength, 1.0);

35)

   // Pattern 35
    float strength = step(0.01, abs(distance(vUv, vec2(0.5)) - 0.25));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

36)

    // Pattern 36
    float strength = 1.0 - step(0.01, abs(distance(vUv, vec2(0.5)) - 0.25));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

37)

   // Pattern 37
    vec2 wavedUv = vec2(vUv.x, vUv.y + sin(vUv.x * 30.0) * 0.1);
    float strength = 1.0 - step(0.01, abs(distance(wavedUv, vec2(0.5)) - 0.25));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

38)

    // Pattern 38
    vec2 wavedUv = vec2(vUv.x + sin(vUv.y * 30.0) * 0.1, vUv.y + sin(vUv.x * 30.0) * 0.1);
    float strength = 1.0 - step(0.01, abs(distance(wavedUv, vec2(0.5)) - 0.25));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

39)

    // Pattern 39
    vec2 wavedUv = vec2(vUv.x + sin(vUv.y * 100.0) * 0.1, vUv.y + sin(vUv.x * 100.0) * 0.1);
    float strength = 1.0 - step(0.01, abs(distance(wavedUv, vec2(0.5)) - 0.25));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

40) atan 각도

   // Pattern 40
    float angle = atan(vUv.x, vUv.y);
    float strength = angle;

    gl_FragColor = vec4(strength, strength, strength, 1.0);

41) - 0.5 씩이므로 중앙을 기준으로 40과 같은 형태를 띈다.

    // Pattern 41
    float angle = atan(vUv.x - 0.5, vUv.y - 0.5);
    float strength = angle;

    gl_FragColor = vec4(strength, strength, strength, 1.0);

42)

    // Pattern 42
    float angle = atan(vUv.x - 0.5, vUv.y - 0.5) / (PI * 2.0) + 0.5;
    float strength = angle;
    
    gl_FragColor = vec4(strength, strength, strength, 1.0);
  • vUv.x - 0.5, vUv.y - 0.5
    • UV 좌표계를 (0,0) ~ (1,1) 범위에서 **중심 기준인 (-0.5, -0.5) ~ (+0.5, +0.5)**로 이동
    • 즉, vec2(0.5, 0.5)를 원점(0,0)처럼 생각하고 회전 기준점으로 만듦
  • atan(x, y) → 각도 계산
    • atan(y, x)는 2D 좌표에서 (0,0)을 기준으로 한 벡터의 방향(각도)을 반환
    • 출력 범위는 -π ~ +π 라디안
    • 360도 회전하는 값을 -180° ~ +180° 식으로 표현한 셈
  • angle / (PI * 2.0) + 0.5
    • -π ~ +π를 0.0 ~ 1.0 범위로 정규화 (normalize)
    • angle / (2π) → -0.5 ~ +0.5
    • + 0.5 → 0.0 ~ 1.0
    • 이렇게 하면 한 바퀴 회전하는 값UV 색상이나 강도로 표현 가능

43)

    // Pattern 43
    float angle = atan(vUv.x - 0.5, vUv.y - 0.5) / (PI * 2.0) + 0.5;
    float strength = mod(angle * 20.0, 1.0);

    gl_FragColor = vec4(strength, strength, strength, 1.0);

44)

    // Pattern 44
    float angle = atan(vUv.x - 0.5, vUv.y - 0.5) / (PI * 2.0) + 0.5;
    float strength = sin(angle * 100.0);

    gl_FragColor = vec4(strength, strength, strength, 1.0);

45)

    // Pattern 45
    float angle = atan(vUv.x - 0.5, vUv.y - 0.5) / (PI * 2.0) + 0.5;
    float sinusoid = sin(angle * 100.0);
    float radius = 0.25 + sinusoid * 0.02;
    float strength = 1.0 - step(0.01, abs(distance(vUv, vec2(0.5)) - radius));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

46)

Perlin Noise

// fragment.glsl
#define PI 3.1415926535897932384626433832795

varying vec2 vUv;

// Pattern 46
//	Classic Perlin 2D Noise 
//	by Stefan Gustavson (https://github.com/stegu/webgl-noise)
//
vec4 permute(vec4 x)
{
  return mod(((x*34.0)+1.0)*x, 289.0);
}

vec2 fade(vec2 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);}

float cnoise(vec2 P){
  vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0);
  vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0);
  Pi = mod(Pi, 289.0); // To avoid truncation effects in permutation
  vec4 ix = Pi.xzxz;
  vec4 iy = Pi.yyww;
  vec4 fx = Pf.xzxz;
  vec4 fy = Pf.yyww;
  vec4 i = permute(permute(ix) + iy);
  vec4 gx = 2.0 * fract(i * 0.0243902439) - 1.0; // 1/41 = 0.024...
  vec4 gy = abs(gx) - 0.5;
  vec4 tx = floor(gx + 0.5);
  gx = gx - tx;
  vec2 g00 = vec2(gx.x,gy.x);
  vec2 g10 = vec2(gx.y,gy.y);
  vec2 g01 = vec2(gx.z,gy.z);
  vec2 g11 = vec2(gx.w,gy.w);
  vec4 norm = 1.79284291400159 - 0.85373472095314 * 
    vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11));
  g00 *= norm.x;
  g01 *= norm.y;
  g10 *= norm.z;
  g11 *= norm.w;
  float n00 = dot(g00, vec2(fx.x, fy.x));
  float n10 = dot(g10, vec2(fx.y, fy.y));
  float n01 = dot(g01, vec2(fx.z, fy.z));
  float n11 = dot(g11, vec2(fx.w, fy.w));
  vec2 fade_xy = fade(Pf.xy);
  vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
  float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
  return 2.3 * n_xy;
}

void main()
{
    // Pattern 46
    float strength = cnoise(vUv * 10.0);

    gl_FragColor = vec4(strength, strength, strength, 1.0);
}

47)

    // Pattern 47
    float strength = step(0.0, cnoise(vUv * 10.0));
    
    gl_FragColor = vec4(strength, strength, strength, 1.0);

48)

    // Pattern 48
    float strength = 1.0 - abs(cnoise(vUv * 10.0));
    
    gl_FragColor = vec4(strength, strength, strength, 1.0);

49)

    // Pattern 49
    float strength = sin(cnoise(vUv * 10.0) * 20.0);

    gl_FragColor = vec4(strength, strength, strength, 1.0);

50)

    // Pattern 50
    float strength = step(0.9, sin(cnoise(vUv * 10.0) * 20.0));

    gl_FragColor = vec4(strength, strength, strength, 1.0);

번호 | 설명 | 핵심 | 개념

1 RGB = (x, y, 1.0) gl_FragColor = vec4(vUv, 1.0, 1.0)
2 RGB = (x, y, 0.0) Blue 제거
3 Grayscale X축 strength = vUv.x
4 Grayscale Y축 strength = vUv.y
5 Y축 반전 strength = 1.0 - vUv.y
6 Gradient 확대 strength = vUv.y * 10.0
7 반복되는 gradient mod(...) 활용
8~9 Step 함수를 이용한 흑백 스트라이프 step(edge, value)
10~15 X, Y축 조합, offset 조절 step, mod, +=, *=, clamp
16~20 대칭, 중심 거리, 박스/라이트 abs, length, distance
21~25 격자화, tilt, 의사 랜덤 floor, random, vec2(floor(...))
26~31 거리 기반 밝기, 중앙 집중 distance, 0.15 / distance(...)
32 UV 회전 사용자 정의 rotate() 함수
33~36 원, 도넛, 링 만들기 distance, abs, step 조합
37~39 웨이브 왜곡 sin(...)으로 UV 조작
40~45 각도 기반 패턴 atan, mod, sin
46~50 Perlin Noise 및 조합 cnoise, sin(cnoise(...)), step(...)

🎛️ 색상 혼합

mix로 왼쪽 두 개를 더해 색상과 연습한 패턴을 혼합할 수 있다.

단색 대신 색상 보간을 위해 mix(...) 함수 사용:

vec3 blackColor = vec3(0.0);
vec3 uvColor = vec3(vUv, 1.0);
vec3 mixedColor = mix(blackColor, uvColor, strength);
gl_FragColor = vec4(mixedColor, 1.0);

⚠️ 일부 패턴에서는 strength가 1.0을 초과할 수 있으므로 clamp(strength, 0.0, 1.0) 처리 필요


GLSL 함수 모음

mod(a, b) a를 b로 나눈 나머지
step(edge, x) x < edge: 0.0, x >= edge: 1.0
length(vec) 벡터의 길이 계산
distance(a, b) 두 벡터 사이 거리
abs(x) 절대값
sin(x) 사인 곡선 (웨이브 표현 등)
atan(y, x) y/x의 아크탄젠트 (각도)
floor(x) 내림
mix(a, b, t) 보간 (0: a, 1: b)
clamp(x, min, max) 범위 제한

🌀 Perlin Noise

  • Classic Perlin Noise 함수 정의 필요
  • cnoise(vec2) 사용 전 permute, fade 함수 포함 필요
float strength = cnoise(vUv * 10.0);

활용 예시 효과

step(0.0, cnoise(...)) 젖소 무늬 스타일 패턴
1.0 - abs(...) 밝은 중심, 어두운 테두리
sin(cnoise(...) * 20.0) 전기, 불꽃 같은 패턴

🔗 참고: Book of Shaders - Noise


🧪 연습 팁

  • 각 패턴을 주석 처리하면서 실험할 것
  • uTime 같은 uniform을 추가해 움직이는 패턴을 만들어 볼 것
  • getCircle(), getSquare() 같은 재사용 함수로 추출하는 연습하기

// fragment.glsl
#define PI 3.1415926535897932384626433832795

varying vec2 vUv;

// Pattern 23
float random(vec2 st){
    return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
}

// Pattern 32
vec2 rotate(vec2 uv, float rotation, vec2 mid)
{
    return vec2(
      cos(rotation) * (uv.x - mid.x) + sin(rotation) * (uv.y - mid.y) + mid.x,
      cos(rotation) * (uv.y - mid.y) - sin(rotation) * (uv.x - mid.x) + mid.y
    );
}

// Pattern 46
//	Classic Perlin 2D Noise 
//	by Stefan Gustavson (https://github.com/stegu/webgl-noise)
//
vec4 permute(vec4 x)
{
  return mod(((x*34.0)+1.0)*x, 289.0);
}

vec2 fade(vec2 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);}

float cnoise(vec2 P){
  vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0);
  vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0);
  Pi = mod(Pi, 289.0); // To avoid truncation effects in permutation
  vec4 ix = Pi.xzxz;
  vec4 iy = Pi.yyww;
  vec4 fx = Pf.xzxz;
  vec4 fy = Pf.yyww;
  vec4 i = permute(permute(ix) + iy);
  vec4 gx = 2.0 * fract(i * 0.0243902439) - 1.0; // 1/41 = 0.024...
  vec4 gy = abs(gx) - 0.5;
  vec4 tx = floor(gx + 0.5);
  gx = gx - tx;
  vec2 g00 = vec2(gx.x,gy.x);
  vec2 g10 = vec2(gx.y,gy.y);
  vec2 g01 = vec2(gx.z,gy.z);
  vec2 g11 = vec2(gx.w,gy.w);
  vec4 norm = 1.79284291400159 - 0.85373472095314 * 
    vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11));
  g00 *= norm.x;
  g01 *= norm.y;
  g10 *= norm.z;
  g11 *= norm.w;
  float n00 = dot(g00, vec2(fx.x, fy.x));
  float n10 = dot(g10, vec2(fx.y, fy.y));
  float n01 = dot(g01, vec2(fx.z, fy.z));
  float n11 = dot(g11, vec2(fx.w, fy.w));
  vec2 fade_xy = fade(Pf.xy);
  vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
  float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
  return 2.3 * n_xy;
}


void main()
{
    // Pattern 3
    // float strength = vUv.x;
    
    // Pattern 4
    // float strength = vUv.y;
    
    // Pattern 5
    // float strength = 1.0 - vUv.y;

    // Pattern 6
    // float strength = vUv.y * 10.0;
    
    // Pattern 7
    // float strength = mod(vUv.y * 10.0, 1.0);
    
    // Pattern 8
    // float strength = mod(vUv.y * 10.0, 1.0);
    // strength = strength <= 0.5 ? 0.0 : 1.0;
    // strength = step(0.5, strength);

    // Pattern 9
    // float strength = mod(vUv.y * 10.0, 1.0);
    // strength = step(0.8, strength);

    // Pattern 10
    // float strength = mod(vUv.x * 10.0, 1.0);
    // strength = step(0.8, strength);

    // Pattern 11
    // float strength = step(0.8, mod(vUv.x * 10.0, 1.0));
    // strength += step(0.8, mod(vUv.y * 10.0, 1.0));

    // Pattern 12
    // float strength = step(0.8, mod(vUv.x * 10.0, 1.0));
    // strength *= step(0.8, mod(vUv.y * 10.0, 1.0));

    // Pattern 13
    // float strength = step(0.4, mod(vUv.x * 10.0, 1.0));
    // strength *= step(0.8, mod(vUv.y * 10.0, 1.0));

    // Pattern 14
    // float barX = step(0.4, mod(vUv.x * 10.0, 1.0));
    // barX *= step(0.8, mod(vUv.y * 10.0, 1.0));

    // float barY = step(0.8, mod(vUv.x * 10.0, 1.0));
    // barY *= step(0.4, mod(vUv.y * 10.0, 1.0));

    // float strength = barX + barY;

    // Pattern 15
    // float barX = step(0.4, mod(vUv.x * 10.0 , 1.0));
    // barX *= step(0.8, mod(vUv.y * 10.0 + 0.2, 1.0));

    // float barY = step(0.8, mod(vUv.x * 10.0 + 0.2, 1.0));
    // barY *= step(0.4, mod(vUv.y * 10.0, 1.0));

    // float strength = barX + barY;

    // Pattern 16
    // float strength = abs(vUv.x - 0.5);

    // Pattern 17
    // float strength = min(abs(vUv.x - 0.5), abs(vUv.y - 0.5));

    // Pattern 18
    // float strength = max(abs(vUv.x - 0.5), abs(vUv.y - 0.5));

    // Pattern 19
    // float strength = step(0.2 ,max(abs(vUv.x - 0.5), abs(vUv.y - 0.5)));

    // Pattern 20
    // float square1 = step(0.2 ,max(abs(vUv.x - 0.5), abs(vUv.y - 0.5)));
    // float square2 = 1.0 - step(0.25 ,max(abs(vUv.x - 0.5), abs(vUv.y - 0.5)));
    // float strength = square1 * square2;

    // Pattern 21
    // float strength = round(vUv.x * 10.0) / 10.0;

    // Pattern 22
    // float strength = floor(vUv.x * 10.0) / 10.0;
    // strength *= floor(vUv.y * 10.0) / 10.0;
    
    // Pattern 23
    // float strength = random(vUv);

    // Pattern 24
    // vec2 gridUv = vec2(
    //     floor(vUv.x * 10.0) / 10.0, floor(vUv.y * 10.0) / 10.0
    // );
    // float strength = random(gridUv);

    // Pattern 25
    // vec2 gridUv = vec2(
    //     floor(vUv.x * 10.0) / 10.0, floor(vUv.y * 10.0 + vUv.x * 5.0) / 10.0
    // );
    // float strength = random(gridUv);

    // Pattern 26
    // float strength = length(vUv);

    // Pattern 27
    // float strength = distance(vUv, vec2(0.5, 0.5));
    // float strength = length(vUv - 0.5);

    // Pattern 28
    // float strength = 1.0 - distance(vUv, vec2(0.5));

    // Pattern 29
    // float strength = 0.01 / distance(vUv, vec2(0.5));

    // Pattern 30
    // vec2 lightUv = vec2(vUv.x * 0.1 + 0.45, vUv.y * 0.5 + 0.25);
    // float strength = 0.015 / distance(lightUv, vec2(0.5, 0.5));

    // Pattern 31
    // vec2 lightUvX = vec2(vUv.x * 0.1 + 0.45, vUv.y * 0.5 + 0.25);
    // float lightX = 0.015 / distance(lightUvX, vec2(0.5, 0.5));

    // vec2 lightUvY = vec2(vUv.y * 0.1 + 0.45, vUv.x * 0.5 + 0.25);
    // float lightY = 0.015 / distance(lightUvY, vec2(0.5, 0.5));

    // float strength = lightX * lightY;

    // Pattern 32
    // vec2 rotatedUv = rotate(vUv, PI * 0.25, vec2(0.5));

    // vec2 lightUvX = vec2(rotatedUv.x * 0.1 + 0.45, rotatedUv.y * 0.5 + 0.25);
    // float lightX = 0.015 / distance(lightUvX, vec2(0.5, 0.5));

    // vec2 lightUvY = vec2(rotatedUv.y * 0.1 + 0.45, rotatedUv.x * 0.5 + 0.25);
    // float lightY = 0.015 / distance(lightUvY, vec2(0.5, 0.5));

    // float strength = lightX * lightY;

    // Pattern 33
    // float strength = step(0.25, distance(vUv, vec2(0.5)));

    // Pattern 34
    // float strength = abs(distance(vUv, vec2(0.5)) - 0.25);

    // Pattern 35
    // float strength = step(0.01, abs(distance(vUv, vec2(0.5)) - 0.25));

    // Pattern 36
    // float strength = 1.0 - step(0.01, abs(distance(vUv, vec2(0.5)) - 0.25));

    // Pattern 37
    // vec2 wavedUv = vec2(vUv.x, vUv.y + sin(vUv.x * 30.0) * 0.1);
    // float strength = 1.0 - step(0.01, abs(distance(wavedUv, vec2(0.5)) - 0.25));

    // Pattern 38
    // vec2 wavedUv = vec2(vUv.x + sin(vUv.y * 30.0) * 0.1, vUv.y + sin(vUv.x * 30.0) * 0.1);
    // float strength = 1.0 - step(0.01, abs(distance(wavedUv, vec2(0.5)) - 0.25));

    // Pattern 39
    // vec2 wavedUv = vec2(vUv.x + sin(vUv.y * 30.0) * 0.1, vUv.y + sin(vUv.x * 30.0) * 0.1);
    // float strength = 1.0 - step(0.01, abs(distance(wavedUv, vec2(0.5)) - 0.25));

    // Pattern 40
    // float angle = atan(vUv.x, vUv.y);
    // float strength = angle;

    // Pattern 41
    // float angle = atan(vUv.x - 0.5, vUv.y - 0.5);
    // float strength = angle;

    // Pattern 42
    // float angle = atan(vUv.x - 0.5, vUv.y - 0.5) / (PI * 2.0) + 0.5;
    // float strength = angle;

    // Pattern 43
    // float angle = atan(vUv.x - 0.5, vUv.y - 0.5) / (PI * 2.0) + 0.5;
    // float strength = mod(angle * 20.0, 1.0);

    // Pattern 44
    // float angle = atan(vUv.x - 0.5, vUv.y - 0.5) / (PI * 2.0) + 0.5;
    // float strength = sin(angle * 100.0);

    // Pattern 45
    // float angle = atan(vUv.x - 0.5, vUv.y - 0.5) / (PI * 2.0) + 0.5;
    // float sinusoid = sin(angle * 100.0);
    // float radius = 0.25 + sinusoid * 0.02;
    // float strength = 1.0 - step(0.01, abs(distance(vUv, vec2(0.5)) - radius));

    // Pattern 46
    // float strength = cnoise(vUv * 10.0);

    // Pattern 47
    // float strength = step(0.0, cnoise(vUv * 10.0));

    // Pattern 48
    // float strength = 1.0 - abs(cnoise(vUv * 10.0));

    // Pattern 49
    // float strength = sin(cnoise(vUv * 10.0) * 20.0);

    // Pattern 50
    // float strength = step(0.9, sin(cnoise(vUv * 10.0) * 20.0));

    // Black and white version
    // gl_FragColor = vec4(strength, strength, strength, 1.0);
    
    // Colored version
    // Pattern 11
    float strength = step(0.8, mod(vUv.x * 10.0, 1.0));
    strength += step(0.8, mod(vUv.y * 10.0, 1.0));
    strength = clamp(strength, 0.0, 1.0); // 범위 제한

    vec3 blackColor = vec3(0.0);
    vec3 uvColor = vec3(vUv, 1.0);
    vec3 mixedColor = mix(blackColor, uvColor, strength);
    gl_FragColor = vec4(mixedColor, 1.0);
  
}
// vertex.glsl
varying vec2 vUv;

void main()
{
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

    vUv = uv; // 보통 texture를 vertex에 맞게 mapping하기 위해 사용
}

'Graphic > ThreeJS' 카테고리의 다른 글

30 Animated galaxy  (5) 2025.08.05
29 Animated Water Shader  (2) 2025.08.04
27 Shaders  (5) 2025.08.02
26. 프로젝트 구조화(Code structuring for bigger projects)  (4) 2025.08.02
25 Realistic render  (2) 2025.07.31