[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -2,91 +2,140 @@
|
||||
id: wiki-2026-0508-edge-bleeding
|
||||
title: Edge Bleeding
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AUTO-2BC744]
|
||||
aliases: [Texture Bleeding, Atlas Bleeding]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
tags: [auto-reinforced]
|
||||
verification_status: applied
|
||||
tags: [graphics, texture, rendering]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
github_commit: "[P-Reinforce] Continuous Worker - Edge Bleeding"
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: GLSL/HLSL
|
||||
framework: WebGL/Three.js/Unity/Unreal
|
||||
---
|
||||
|
||||
# [[Edge Bleeding]]
|
||||
# Edge Bleeding
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> Edge Bleeding(경계선 블리딩)은 여러 이미지를 하나로 합친 텍스처 아틀라스([[Texture Atlas]])를 사용할 때 주로 발생하는 시각적 결함입니다 [1]. 특히 낮은 밉맵([[Mipmap]]) 레벨에서 텍스처 필터링이 일어날 때, 아틀라스 내에 인접해 있는 텍스처들의 색상이 서로 섞이거나 번지는 현상을 의미합니다 [1, 2]. 이를 방지하기 위해서는 텍스처 간에 여백을 두어 메모리를 희생하거나, 최신 텍스처 배열([[Data Array Textures]]) 기술을 활용해야 합니다 [2, 3].
|
||||
## 매 한 줄
|
||||
> **"매 texture sampling 의 인접 texel이 unintended 하게 leak — atlas seam의 colored line으로 manifest."**. 매 mipmap downsample / bilinear interpolation 매 texel boundary를 cross 하면서 발생. 매 sprite atlas, texture array, lightmap에서 매 visible artifact.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **발생 원인:** 동일한 재질을 공유하여 드로우 콜([[Draw Call]])을 최적화하기 위해 여러 텍스처를 하나의 큰 이미지로 병합하는 텍스처 아틀라스 방식을 사용할 때 발생합니다 [1, 2]. GPU가 거리에 따라 해상도를 낮춘 밉맵을 생성하고 필터링하는 과정에서 인접한 텍스처 영역의 픽셀이 침범하여 색상이 섞이게 됩니다 [1, 2].
|
||||
- **기존의 해결 방식과 한계:** 이 현상을 방지하기 위해 텍스처 아틀라스 내부의 개별 텍스처들 사이에 물리적인 여백(Padding)을 추가하는 우회 기법이 사용됩니다 [2]. 하지만 이 방식은 텍스처 공간을 낭비하게 만들어 메모리 비효율성을 초래합니다 [2].
|
||||
- **현대적인 해결책 (Data Array Textures):** [[WebGL]] 2.0에서 지원하는 데이터 배열 텍스처(Data Array Textures)를 사용하면 Edge Bleeding을 완벽히 제거할 수 있습니다 [3, 4]. 이 방식은 텍스처를 평면에 병합하는 대신 레이어(Layer) 구조의 스택으로 쌓아 인덱스로 접근하므로, 밉맵 생성 시 인접 텍스처 간의 교차 오염(Cross-contamination)이 발생하지 않습니다 [1, 3].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
### 매 원인
|
||||
- **Bilinear filter**: 매 sample point 매 texel center 사이 → 인접 texel weighted.
|
||||
- **Mipmap downsample**: 매 box filter 매 atlas neighbor를 average.
|
||||
- **UV precision**: float precision 매 정확한 boundary 매 hit 못 함.
|
||||
- **Anisotropic filtering**: 매 large footprint → 매 더 많은 neighbor sampling.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Texture Atlas]], [[Mipmap]], [[Data Array Textures]]
|
||||
- **Projects/Contexts:** [[InstancedMesh 최적화]], WebGL 2.0
|
||||
- **Contradictions/Notes:** 소스에 관련 정보가 부족합니다. (소스 내에서 명시적인 의견 대립은 발견되지 않으며, Edge Bleeding은 텍스처 아틀라스의 명확한 단점[1, 2]이자 WebGL 2.0의 텍스처 배열 도입으로 쉽게 극복 가능한 문제[3, 4]로 일관되게 설명됩니다.)
|
||||
### 매 manifestation
|
||||
- Sprite atlas: 매 sprite edge 매 인접 sprite color line.
|
||||
- Tilemap: 매 tile seam 매 dark/bright line.
|
||||
- Skybox cubemap: 매 face boundary 매 visible seam.
|
||||
- Lightmap: 매 chart boundary 매 dark crack.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
### 매 응용 (해결책)
|
||||
1. **Padding (gutter)**: 매 sprite 사이 1-2px transparent / replicated edge.
|
||||
2. **Half-texel UV inset**: UV 매 `(0.5/W, 0.5/H)` ~ `(1 - 0.5/W, 1 - 0.5/H)` 의 clamp.
|
||||
3. **CLAMP_TO_EDGE**: wrap mode 매 repeat → clamp.
|
||||
4. **Conservative UV**: 매 mesh UV 매 atlas region 의 inside 의 inset.
|
||||
5. **Mipmap-aware padding**: 매 mip level 별 padding (1px → 2px → 4px).
|
||||
|
||||
---
|
||||
## 💻 패턴
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### Half-texel inset (GLSL)
|
||||
```glsl
|
||||
uniform vec2 atlasSize; // e.g. (2048, 2048)
|
||||
uniform vec4 spriteRect; // x, y, w, h in pixels
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
vec2 sampleUV(vec2 localUV) {
|
||||
vec2 halfTexel = 0.5 / atlasSize;
|
||||
vec2 minUV = spriteRect.xy / atlasSize + halfTexel;
|
||||
vec2 maxUV = (spriteRect.xy + spriteRect.zw) / atlasSize - halfTexel;
|
||||
return mix(minUV, maxUV, localUV);
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Atlas packer with padding (TS)
|
||||
```typescript
|
||||
function packSprite(sprite: ImageData, padding = 2): PackedSprite {
|
||||
const w = sprite.width + padding * 2;
|
||||
const h = sprite.height + padding * 2;
|
||||
const padded = new ImageData(w, h);
|
||||
// edge replicate (not transparent) for bilinear safety
|
||||
for (let y = 0; y < h; y++) {
|
||||
for (let x = 0; x < w; x++) {
|
||||
const sx = clamp(x - padding, 0, sprite.width - 1);
|
||||
const sy = clamp(y - padding, 0, sprite.height - 1);
|
||||
copyPixel(sprite, sx, sy, padded, x, y);
|
||||
}
|
||||
}
|
||||
return { data: padded, padding };
|
||||
}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Three.js NearestFilter (no bleed, no smooth)
|
||||
```javascript
|
||||
texture.minFilter = THREE.NearestFilter;
|
||||
texture.magFilter = THREE.NearestFilter;
|
||||
texture.generateMipmaps = false;
|
||||
texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Mipmap-aware padding count
|
||||
```typescript
|
||||
function paddingForMipLevels(levels: number): number {
|
||||
return Math.pow(2, levels - 1); // 4 levels → 8px padding
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Conservative cubemap seam fix (HLSL)
|
||||
```hlsl
|
||||
float3 SampleCubeSeamless(TextureCube tex, SamplerState s, float3 dir, float roughness) {
|
||||
float mip = roughness * 8.0;
|
||||
float texSize = 512.0 / pow(2, mip);
|
||||
float scale = 1.0 - 1.0 / texSize;
|
||||
return tex.SampleLevel(s, dir * scale, mip).rgb;
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Pixel art sprite | NearestFilter + padding 1px |
|
||||
| 3D texture atlas (smooth) | Half-texel inset + padding (2 * mip levels) |
|
||||
| Tilemap | Padding + clamp + per-tile texture array (best) |
|
||||
| Cubemap | GL_TEXTURE_CUBE_MAP_SEAMLESS (GL 3.2+) |
|
||||
| Lightmap | Chart padding 4px + dilation |
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
**기본값**: 매 padding 2px + half-texel inset, 매 mipmap 매 사용 시 2 * (mip levels) px.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Texture Mapping]] · [[Texture Filtering]]
|
||||
- 변형: [[Atlas Bleeding]] · [[Cubemap Seam]]
|
||||
- 응용: [[Sprite Atlas]] · [[Lightmap]] · [[Texture Array]]
|
||||
- Adjacent: [[Mipmap]] · [[Bilinear Filtering]] · [[UV Mapping]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: sprite atlas / tilemap / lightmap 매 visible seam, 매 mipmap 매 사용한 atlas, 매 cubemap face 경계 artifact.
|
||||
**언제 X**: single texture (no atlas), 매 NEAREST filter 매 사용 + no mipmap, fully procedural texture.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Transparent padding alone**: 매 bilinear가 transparent와 mix → 매 dark fringe.
|
||||
- **Padding 너무 small**: mip level 3+ 매 도달 시 여전히 leak.
|
||||
- **Repeat wrap on atlas**: 매 opposite edge 매 sample → 완전한 wrong color.
|
||||
- **UV exactly at texel boundary**: 매 float precision 의해 random side 매 sample.
|
||||
- **Generate mipmap on packed atlas**: 매 mip downsample 매 인접 sprite를 average → mid-mip levels artifact.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Real-Time Rendering 4ed, Unity / Unreal docs, OpenGL spec).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Edge bleeding 원인 / padding 전략 / mip-aware solution |
|
||||
|
||||
Reference in New Issue
Block a user