Files
2nd/10_Wiki/Topic_Programming/Programming & Language/Edge Bleeding.md
T
Antigravity Agent 9148c358d0 docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
2026-07-05 00:33:48 +09:00

4.9 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-edge-bleeding Edge Bleeding 10_Wiki/Topics verified self
Texture Bleeding
Atlas Bleeding
none A 0.9 applied
graphics
texture
rendering
2026-05-10 pending
language framework
GLSL/HLSL WebGL/Three.js/Unity/Unreal

Edge Bleeding

매 한 줄

"매 texture sampling 의 인접 texel이 unintended 하게 leak — atlas seam의 colored line으로 manifest.". 매 mipmap downsample / bilinear interpolation 매 texel boundary를 cross 하면서 발생. 매 sprite atlas, texture array, lightmap에서 매 visible artifact.

매 핵심

매 원인

  • 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.

매 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.

매 응용 (해결책)

  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).

💻 패턴

Half-texel inset (GLSL)

uniform vec2 atlasSize;  // e.g. (2048, 2048)
uniform vec4 spriteRect; // x, y, w, h in pixels

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);
}

Atlas packer with padding (TS)

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 };
}

Three.js NearestFilter (no bleed, no smooth)

texture.minFilter = THREE.NearestFilter;
texture.magFilter = THREE.NearestFilter;
texture.generateMipmaps = false;
texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;

Mipmap-aware padding count

function paddingForMipLevels(levels: number): number {
    return Math.pow(2, levels - 1); // 4 levels → 8px padding
}

Conservative cubemap seam fix (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;
}

매 결정 기준

상황 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

기본값: 매 padding 2px + half-texel inset, 매 mipmap 매 사용 시 2 * (mip levels) px.

🔗 Graph

  • 변형: Atlas Bleeding
  • 응용: Texture Array
  • Adjacent: Mipmap

🤖 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