Files
game_engine/docs/superpowers/specs/2026-03-26-transparent-objects-design.md
tolelom ef8c39b5ae docs: add transparent objects design spec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 14:49:44 +09:00

3.4 KiB

Transparent Objects Design

Overview

디퍼드 라이팅 후 HDR 타겟에 알파 블렌딩으로 투명 오브젝트를 포워드 렌더링한다.

Scope

  • ForwardPass 구조체 + 파이프라인 (알파 블렌딩, HDR 타겟)
  • 포워드 셰이더 (Blinn-Phong + alpha)
  • 카메라 거리 기준 back-to-front 정렬
  • deferred_demo에 반투명 큐브 추가

Render Pass Order

G-Buffer → SSGI → RT Shadow → Lighting → [Forward Transparency] → Bloom → Tonemap

ForwardPass

pub struct ForwardPass {
    pipeline: wgpu::RenderPipeline,
}

파이프라인 설정

  • target: Rgba16Float (HDR_FORMAT) — LoadOp::Load
  • depth: Depth32Float (G-Buffer depth) — LoadOp::Load, depth_write: false, compare: LessEqual
  • blend: SrcAlpha / OneMinusSrcAlpha (standard alpha blending)
  • vertex: MeshVertex layout (기존 동일)
  • bind groups: group(0) camera+light, group(1) texture — 기존 레이아웃 재사용
  • immediate_size: 0 (wgpu 28.0)

생성

impl ForwardPass {
    pub fn new(
        device: &wgpu::Device,
        camera_light_layout: &wgpu::BindGroupLayout,
        texture_layout: &wgpu::BindGroupLayout,
    ) -> Self;
}

렌더

pub fn render(
    &self,
    encoder: &mut wgpu::CommandEncoder,
    hdr_view: &wgpu::TextureView,
    depth_view: &wgpu::TextureView,
    camera_light_bg: &wgpu::BindGroup,
    texture_bg: &wgpu::BindGroup,
    meshes: &[(Mesh, f32)],  // (mesh, alpha) — back-to-front 정렬 완료 상태
);

Forward Shader (forward_shader.wgsl)

기존 mesh_shader.wgsl과 거의 동일하나:

  • CameraUniform에 alpha uniform 추가, 또는 별도 uniform
  • fragment output에서 color.a = alpha

가장 간단한 방법: CameraUniform의 _padding 필드를 alpha로 재활용:

struct CameraUniform {
    view_proj: mat4x4<f32>,
    model: mat4x4<f32>,
    camera_pos: vec3<f32>,
    alpha: f32,  // 기존 _padding → alpha로 사용
};

Fragment shader:

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    // Blinn-Phong lighting calculation (동일)
    let lit_color = ambient + diffuse + specular;
    return vec4<f32>(lit_color, camera.alpha);
}

투명 메시 정렬

pub fn sort_transparent_back_to_front(
    meshes: &mut Vec<(usize, Vec3)>,  // (mesh_index, center_position)
    camera_pos: Vec3,
) {
    meshes.sort_by(|a, b| {
        let da = (a.1 - camera_pos).length();
        let db = (b.1 - camera_pos).length();
        db.partial_cmp(&da).unwrap_or(std::cmp::Ordering::Equal)
    });
}

이 함수는 순수 수학이므로 단위 테스트 가능.

deferred_demo 통합

  1. ForwardPass 생성 (기존 camera_light_layout, texture_layout 재사용)
  2. 반투명 큐브 2개 생성 (alpha=0.4, alpha=0.6)
  3. 매 프레임: 투명 메시를 카메라 거리로 정렬
  4. Lighting pass 후, Bloom 전에 forward_pass.render() 호출

File Structure

  • crates/voltex_renderer/src/forward_pass.rs — ForwardPass
  • crates/voltex_renderer/src/forward_shader.wgsl — 포워드 셰이더
  • crates/voltex_renderer/src/lib.rs — 모듈 추가
  • examples/deferred_demo/src/main.rs — 투명 메시 + 포워드 패스 통합

Testing

sort_transparent_back_to_front (순수 수학)

  • 3개 위치를 카메라 기준 정렬 → 먼 것부터 순서 검증
  • 동일 거리 → 크래시 없음

ForwardPass (GPU 의존 → 빌드 검증)

  • 컴파일 성공 확인