ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [week2] Texture Rendering
    UE5 2025. 3. 20. 23:31

    # DirectX 11 렌더링 파이프라인 (함수 호출 기반 정리)

    ## CPU 준비 단계 (함수 단위)
    1. **디바이스 및 스왑 체인 생성**
       - `D3D11CreateDeviceAndSwapChain()`

    2. **렌더 타겟 및 뎁스 스텐실 준비**
       - `SwapChain->GetBuffer()`
       - `Device->CreateRenderTargetView()`
       - `Device->CreateDepthStencilView()`

    3. **자원(Resource) 준비**
       - 정점 버퍼: `Device->CreateBuffer()`
       - 인덱스 버퍼: `Device->CreateBuffer()`
       - 셰이더 컴파일: `D3DCompileFromFile()`
       - 셰이더 생성: `Device->CreateVertexShader()`, `Device->CreatePixelShader()`
       - 인풋 레이아웃 생성: `Device->CreateInputLayout()`
       - 상수 버퍼 생성: `Device->CreateBuffer()` (D3D11_BIND_CONSTANT_BUFFER)
       - 텍스처 및 샘플러: `Device->CreateTexture2D()`, `Device->CreateSamplerState()`


    ## 한 프레임 렌더링 함수 호출 순서
    1. Context->ClearRenderTargetView()
    2. Context->ClearDepthStencilView()
    3. Context->OMSetRenderTargets()
    4. Context->IASetVertexBuffers()
    5. Context->IASetIndexBuffer()
    6. Context->IASetInputLayout()
    7. Context->VSSetShader(), PSSetShader(), (필요 시 GS/HS/DS)
    8. Context->VSSetConstantBuffers(), PSSetConstantBuffers()
    9. Context->RSSetViewports()
    10. Context->PSSetSamplers(), PSSetShaderResources()
    11. Context->Draw() 또는 DrawIndexed()
    12. SwapChain->Present()

     

     

    자원(메모리/성능) 소모가 큰 순서

    1️⃣ 텍스처 생성 / 로드 고해상도 텍스처는 VRAM 메모리를 대량 사용하며 압축 및 비압축 처리 비용도 큼
    2️⃣ 셰이더 컴파일 (D3DCompileFromFile) 실시간 컴파일은 CPU 부하가 매우 큼 (실제 게임은 보통 미리 컴파일한 *.cso 파일 사용)
    3️⃣ 버퍼 생성 (CreateBuffer) 대규모 Vertex / Index / ConstantBuffer 생성 시 메모리 할당 비용 발생
    4️⃣ InputLayout 생성 내부 구조 분석과 파싱으로 약간의 자원 소비 (한 번만 생성 후 캐싱 가능)
    5️⃣ PSSetShaderResources (텍스처 바인딩) 너무 자주 바인딩하면 드라이버 state change 비용 발생
    6️⃣ Draw() / DrawIndexed() 호출 GPU 실행 명령이긴 하지만, 이미 준비된 자원 위에서 실행되므로 상대적으로 비용은 낮음
    7️⃣ OMSetRenderTargets / Clear 호출 렌더타겟 & 뎁스 초기화는 GPU 메모리 클리어 작업, 비용 있지만 짧은 편
    8️⃣ VSSetShader / PSSetShader 호출 상태 설정 변경 정도이므로 자원 소모는 낮음

     

     

    자원 소모 최적화 팁

    ✅ 1️⃣ 텍스처 최적화

    DDS(DXT 압축) 텍스처 사용 압축된 텍스처 포맷으로 VRAM 사용량 최소화, 로딩 속도 증가, GPU-Friendly
    Mipmap 포함 저장 멀리 있는 물체는 낮은 해상도로 자동 렌더링 → 성능 최적화
    필요한 해상도만 사용 8K 텍스처 불필요하면 4K / 2K 로 줄여서 메모리 절약
    다중 텍스처 통합(Atlas) 여러 작은 텍스처를 한 장으로 묶어 Draw Call & state change 최소화

    ✅ 2️⃣ 셰이더 최적화

    런타임 컴파일 금지 D3DCompileFromFile() 대신 미리 컴파일된 cso 파일 로드 사용
    셰이더 캐싱 시스템 구축 동일한 셰이더 재사용 시 재컴파일/재로드 하지 않음, 메모리 절약
    불필요한 if / 분기 최소화 GPU 분기 처리는 비싼 연산 → 브랜치 대신 조건 mask 처리 추천

    ✅ 3️⃣ 버퍼 관리 최적화

    큰 정적 버퍼는 한 번 생성 후 재사용 매 프레임 CreateBuffer() 호출하지 말고 초기화 시 생성해서 계속 유지
    동적 버퍼는 D3D11_USAGE_DYNAMIC + Map() 사용 CPU 가 자주 업데이트하는 경우 Map/Unmap 으로 효율적 쓰기 가능
    Stream Output 또는 Instancing 사용 반복되는 데이터 전송을 줄이고 GPU 내부 인스턴싱으로 성능 향상

    ✅ 4️⃣ 상태 변화(State Change) 최적화

    PSSetShaderResources / VSSetShader / Sampler 최소 변경 매 Draw Call 마다 텍스처, 쉐이더 바꾸면 드라이버 오버헤드 증가 — 유사 상태 묶어 그리기 (Batch) 추천
    DrawCall 정리 (Batching) 유사한 메터리얼, 동일 텍스처를 사용하는 객체들을 한 번에 처리해서 상태 전환 비용 최소화
    렌더링 순서 정리 (Material sorting) 텍스처나 셰이더 교체가 적은 순서대로 렌더링을 정리하면 GPU 스테이트 변경 비용 절약

    ✅ 5️⃣ Present & VSync 주의

    VSync 끄기(개발 중) 성능 측정 시 GPU 제한 없이 성능 체크 가능
    VSync 켜기(출시) 화면 찢어짐 방지, 그러나 GPU 대기 시간이 추가되므로 FPS 제한 확인 필요

    ✅ 전체 최적화 흐름 추천

    1. 초기화 시 정적 리소스 전부 로드 & 캐싱
    2. 렌더링 시 텍스처 & 셰이더 상태 변경 최소화 → 비슷한 메터리얼끼리 묶어서 그리기
    3. 자주 변경되는 정점 데이터는 동적 버퍼 사용 (Map/Unmap)
    4. draw 호출 개수 최소화 (인스턴싱 또는 배치)
    5. 텍스처는 압축 포맷과 mipmap 필수 적용
    6. Shader 컴파일은 무조건 사전 컴파일 후 cso 파일 로딩

     

    ✅ 3️⃣ 정적 버퍼 vs 동적 버퍼 비교 정리

    항목 정적 버퍼 (D3D11_USAGE_DEFAULT) 동적 버퍼 (D3D11_USAGE_DYNAMIC)
    용도 변경 거의 없는 데이터 (지형, 모델 메쉬 등) 프레임마다 업데이트되는 데이터 (UI, 파티클, 애니메이션 변형 등)
    CPU 접근 ❌ 없음 (GPU 전용) ✅ CPU 쓰기 가능 (Map/Unmap 사용)
    업데이트 방법 변경 시 리소스를 다시 생성해야 함 Map(DISCARD) & memcpy & Unmap
    장점 GPU 최적화 / 빠른 렌더링 CPU가 자주 바꾸는 데이터 처리에 최적화
    단점 변경 어려움 (매번 리소스 새로 생성 필요) 잘못 설계하면 빈번한 복사 및 GPU Sync 문제가 발생할 수 있음

     

    ✅ 배치 렌더링(Batching) vs 인스턴싱(Instancing) 비교

    항목 배치 렌더링 (Batching) 인스턴싱 (Instancing)
    방식 CPU 에서 여러 오브젝트 정점 데이터를 월드 변환 후 큰 버퍼로 묶어서 전송 정점 버퍼는 1개, 인스턴스 데이터(월드행렬 등)를 추가로 보내 GPU에서 변환 처리
    움직임/변화 불가능 또는 버퍼 재생성 필요 실시간 가능 (인스턴스 버퍼만 매 프레임 업데이트)
    DrawCall 개수 1회 Draw() 호출 (묶어서 처리) 1회 DrawIndexedInstanced() 호출로 여러 인스턴스 렌더링
    CPU 부하 큼 (큰 정점 버퍼 합치고 계산 필요) 적음 (인스턴스 버퍼 갱신만 하면 됨)
    GPU 효율 중간 (큰 정점량이면 오히려 부담) 높음 (병렬 처리 최적화 가능)
    주로 사용하는 상황 고정 지형, 타일맵, 변경 안 되는 배경 나무, 풀, 파티클, 반복되는 작은 오브젝트 대량 렌더링

     

    2주차 배운 것

     

    1. Actor와 ActorComponent

    2. 대략적인 생명주기

    3. 텍스쳐 렌더링

    4. 인덱스 버퍼 사용방법

    5. SubUV

Designed by Tistory.