[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
---
|
||||
id: game-shader-patterns
|
||||
title: Shader 패턴 — Vertex / Fragment / WGSL
|
||||
category: Coding
|
||||
status: draft
|
||||
source_trust_level: B
|
||||
verification_status: conceptual
|
||||
created_at: 2026-05-09
|
||||
updated_at: 2026-05-09
|
||||
tags: [game, shader, glsl, wgsl, vibe-coding]
|
||||
tech_stack: { language: "GLSL / WGSL", applicable_to: ["Game", "Frontend"] }
|
||||
applied_in: []
|
||||
aliases: [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)
|
||||
```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
|
||||
```ts
|
||||
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)
|
||||
```wgsl
|
||||
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)
|
||||
```glsl
|
||||
// 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: 원
|
||||
```glsl
|
||||
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
|
||||
```glsl
|
||||
gl_FragColor = vec4(mix(vec3(1, 0, 0), vec3(0, 0, 1), vUv.y), 1.0);
|
||||
```
|
||||
|
||||
### Pattern: noise
|
||||
```glsl
|
||||
// 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)
|
||||
```ts
|
||||
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)
|
||||
```glsl
|
||||
// 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
|
||||
```glsl
|
||||
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
|
||||
```tsx
|
||||
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)
|
||||
```wgsl
|
||||
@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 가 디버그.
|
||||
|
||||
## 🔗 관련 문서
|
||||
- [[Frontend_Three_R3F]]
|
||||
- [[Frontend_WebGPU_Patterns]]
|
||||
- [[Game_Loop_ECS]]
|
||||
Reference in New Issue
Block a user