Files
2nd/10_Wiki/Topics/Coding/Game_Shader_Patterns.md
T
2026-05-09 21:08:02 +09:00

7.0 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
game-shader-patterns Shader 패턴 — Vertex / Fragment / WGSL Coding draft B conceptual 2026-05-09 2026-05-09
game
shader
glsl
wgsl
vibe-coding
language applicable_to
GLSL / WGSL
Game
Frontend
shader
GLSL
WGSL
vertex shader
fragment shader
post-processing

Shader Patterns

GPU 의 작은 program. Vertex (위치 변형) + Fragment (색). WebGPU = WGSL, OpenGL/WebGL = GLSL. Effect / 사후 처리 강력.

📖 핵심 개념

  • Vertex shader: 각 vertex 변형.
  • Fragment (pixel) shader: 각 pixel 색 결정.
  • Uniform: CPU → GPU 변수.
  • Attribute: vertex 별 data.

💻 코드 패턴

단순 fragment (GLSL)

// fragment.glsl
precision mediump float;
varying vec2 vUv;
uniform float uTime;

void main() {
  vec3 color = vec3(
    sin(uTime + vUv.x * 6.28) * 0.5 + 0.5,
    sin(uTime + vUv.y * 6.28 + 2.09) * 0.5 + 0.5,
    sin(uTime + vUv.x * 6.28 + 4.18) * 0.5 + 0.5
  );
  gl_FragColor = vec4(color, 1.0);
}

Three.js + GLSL

const material = new THREE.ShaderMaterial({
  vertexShader: `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    varying vec2 vUv;
    uniform float uTime;
    void main() {
      gl_FragColor = vec4(vUv, sin(uTime) * 0.5 + 0.5, 1.0);
    }
  `,
  uniforms: { uTime: { value: 0 } },
});

// 매 frame
material.uniforms.uTime.value = clock.getElapsedTime();

WGSL (WebGPU)

struct VertexInput {
  @location(0) position: vec3f,
  @location(1) uv: vec2f,
}

struct VertexOutput {
  @builtin(position) position: vec4f,
  @location(0) uv: vec2f,
}

struct Uniforms {
  time: f32,
}

@group(0) @binding(0) var<uniform> u: Uniforms;

@vertex
fn vs(input: VertexInput) -> VertexOutput {
  var out: VertexOutput;
  out.position = vec4f(input.position, 1.0);
  out.uv = input.uv;
  return out;
}

@fragment
fn fs(input: VertexOutput) -> @location(0) vec4f {
  let color = vec3f(
    sin(u.time + input.uv.x * 6.28) * 0.5 + 0.5,
    sin(u.time + input.uv.y * 6.28) * 0.5 + 0.5,
    1.0
  );
  return vec4f(color, 1.0);
}

자주 쓰는 함수 (GLSL/WGSL)

// Smoothstep — 부드러운 편향
float t = smoothstep(0.4, 0.6, dist);

// Mix — 보간
vec3 c = mix(red, blue, t);

// Distance
float d = length(uv - vec2(0.5, 0.5));

// Step
float v = step(0.5, x);  // x < 0.5 ? 0 : 1

// Noise (snoise / perlin)
// 라이브러리 또는 직접 구현

Pattern: 원

void main() {
  vec2 uv = vUv - 0.5;
  float d = length(uv);
  float circle = smoothstep(0.3, 0.29, d);
  gl_FragColor = vec4(vec3(circle), 1.0);
}

Pattern: gradient

gl_FragColor = vec4(mix(vec3(1, 0, 0), vec3(0, 0, 1), vUv.y), 1.0);

Pattern: noise

// Simple hash noise
float hash(vec2 p) {
  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}

float noise(vec2 p) {
  vec2 i = floor(p), f = fract(p);
  vec2 u = f * f * (3.0 - 2.0 * f);
  return mix(
    mix(hash(i), hash(i + vec2(1, 0)), u.x),
    mix(hash(i + vec2(0, 1)), hash(i + vec2(1, 1)), u.x),
    u.y
  );
}

void main() {
  float n = noise(vUv * 10.0 + uTime);
  gl_FragColor = vec4(vec3(n), 1.0);
}

Post-processing (Three.js)

import { EffectComposer, RenderPass, ShaderPass } from 'three/examples/jsm/Addons.js';

const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));

const myPass = new ShaderPass({
  uniforms: { tDiffuse: { value: null }, uTime: { value: 0 } },
  vertexShader: ...,
  fragmentShader: `
    uniform sampler2D tDiffuse;
    uniform float uTime;
    varying vec2 vUv;
    void main() {
      vec4 color = texture2D(tDiffuse, vUv);
      // pixelate
      vec2 pixelated = floor(vUv * 100.0) / 100.0;
      color = texture2D(tDiffuse, pixelated);
      gl_FragColor = color;
    }
  `,
});
composer.addPass(myPass);

Vertex displacement (wave)

// vertex
uniform float uTime;
varying vec2 vUv;

void main() {
  vUv = uv;
  vec3 pos = position;
  pos.y += sin(pos.x * 5.0 + uTime) * 0.1;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}

Texture

uniform sampler2D uTexture;
varying vec2 vUv;

void main() {
  vec4 color = texture2D(uTexture, vUv);
  // tint
  color.rgb *= vec3(1.0, 0.5, 0.8);
  gl_FragColor = color;
}

React Three Fiber + custom material

import { extend } from '@react-three/fiber';
import { shaderMaterial } from '@react-three/drei';

const MyMaterial = shaderMaterial(
  { uTime: 0, uColor: new THREE.Color('hotpink') },
  vertexShader,
  fragmentShader
);
extend({ MyMaterial });

function Mesh() {
  const ref = useRef<any>();
  useFrame((_, dt) => { ref.current.uTime += dt; });
  
  return (
    <mesh>
      <boxGeometry />
      <myMaterial ref={ref} />
    </mesh>
  );
}

Compute shader (WebGPU only)

@group(0) @binding(0) var<storage, read> input: array<f32>;
@group(0) @binding(1) var<storage, read_write> output: array<f32>;

@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3u) {
  let i = id.x;
  output[i] = input[i] * 2.0;
}

→ Particle simulation / image processing.

Performance

- Texture lookup 비싸 — minimize.
- Branch (if) 가능한 한 적게 — uniform branch 는 OK, dynamic branch 비싼.
- Precision: highp (vertex) / mediump (fragment) 보통 OK.
- mipmaps 사용 (texture).
- Dependent texture lookup 피하기.
- Discard 비싸 — alpha test 알 됨.

디버그

Spector.js (browser extension): WebGL/WebGPU frame capture.
Renderdoc: native graphics debugger.
GLSL Lint (vscode): syntax 검사.

Print debug:
gl_FragColor = vec4(vec3(myValue), 1.0);
// 색으로 값 시각화.

Shadertoy / The Book of Shaders

  • shadertoy.com — 영감.
  • thebookofshaders.com — 학습.
  • 공유된 shader 가 사실상 라이브러리.

Common shader effects

- Glitch / chromatic aberration
- Bloom
- DOF (depth of field)
- Outline
- Toon / cel shading
- Water / wave
- Fire / smoke
- Motion blur
- Pixelation
- Gaussian blur
- Edge detection

🤔 의사결정 기준

작업 도구
일반 web shader Three.js + GLSL
Modern + WebGPU R3F + WGSL
2D effect PixiJS filter
Image processing WebGPU compute
Native game Unity/Unreal shader graph
Quick prototype Shadertoy

안티패턴

  • Branch heavy 모든 fragment: 느림. lookup texture.
  • Texture 매 frame upload: cache.
  • High precision 모든 곳: mediump 충분.
  • uniform 매 draw 변경: dirty flag.
  • Discard 큰 사용: alpha test 또는 sort.
  • Compile 매 frame: cache.
  • Shader 큰 size: 중복 로직 — function 분리.

🤖 LLM 활용 힌트

  • 공유 shader (Shadertoy) → 자체 변형.
  • WebGPU = WGSL (modern).
  • R3F + drei shaderMaterial 가 가장 단순.
  • Spector.js 가 디버그.

🔗 관련 문서