SkyBox

스카이박스의 기본 원리

// SkyBox.hlsl 중요 부분
float4 viewPos = mul(float4(input.position.xyz, 0), viewMatrix);
output.position.z = output.position.w * 0.999999f;
  1. 큐브 메시 사용: 플레이어를 감싸는 큰 정육면체 메시를 생성

  2. 큐브맵 텍스처: 6개 방향(+X, -X, +Y, -Y, +Z, -Z)의 이미지로 구성된 특수 텍스처 사용

  3. 카메라 중심 배치: 스카이박스는 항상 카메라를 중심으로 이동

  4. 깊이 값 최대화: 다른 모든 객체 뒤에 그려지도록 깊이 값을 최대치(0.999999)로 설정

쉐이더 구현

// SkyBox.hlsl
VS_OUTPUT VS(VS_INPUT input)
{
    VS_OUTPUT output;

    // 위치를 뷰 행렬로 변환하되, w=0으로 설정하여 이동 성분 제거
    float4 viewPos = mul(float4(input.position.xyz, 0), viewMatrix);
    float4 clipSpacePos = mul(viewPos, projectionMatrix);
    output.position = clipSpacePos.xyzw;
    
    // 깊이 값을 최대치로 설정 (항상 가장 뒤에 그려지도록)
    output.position.z = output.position.w * 0.999999f;

    // 로컬 위치를 텍스처 좌표로 사용
    output.PosL = input.position.xyz;
    return output;
}

float4 PS(VS_OUTPUT input) : SV_Target
{
    // 입력된 방향으로 큐브맵 샘플링
    float4 textureColor = texture0.Sample(sampler0, input.PosL);
    return textureColor;
}

  • 핵심 기술 설명:

    • 이동 성분 제거 (w=0 기법):

      • float4 viewPos = mul(float4(input.position.xyz, 0), viewMatrix);

        • 위치 벡터의 w 성분을 0으로 설정하면 변환 행렬의 translation 성분이 영향을 주지 않음

        • 결과적으로 카메라가 이동해도 스카이박스는 상대적 거리 변화 없이 항상 배경으로 남음

        • 회전 성분만 적용되어 카메라 방향에 따라 적절한 배경이 보임

    • 깊이 값 조정

      • output.position.z = output.position.w * 0.999999f;

        • Z 값을 w와 거의 같게 설정하여 정규화된 깊이 값이 1에 매우 가까워짐

        • 이는 스카이박스가 항상 다른 객체보다 뒤에 그려지도록 함

        • 0.999999를 곱하는 이유는 정확히 1.0이 되면 일부 그래픽 하드웨어에서 깊이 버퍼 정밀도 문제가 발생할 수 있기 때문

    • 큐브맵 샘플링

      • float4 textureColor = texture0.Sample(sampler0, input.PosL);

        • 큐브 정점의 로컬 위치(input.PosL)를 직접 텍스처 좌표로 사용

        • 이 벡터는 중심에서 큐브의 각 정점으로 향하는 방향 벡터가 됨

        • 큐브맵 텍스처는 이 방향 벡터를 기반으로 적절한 텍셀 값을 반환

Last updated