WWolves Den

DirectX 11 · 약 4분

Direct2D로 사각형 그리기: 좌표, 브러시, 변환

격자와 사각형 예제를 작은 렌더링 단계로 나누고, 2D에서 3×2 행렬이 필요한 이유를 정리합니다.

Wolfgadeok · 업데이트

도형과 그리는 도구를 구분하기

격자 배경 위에 크기가 다른 두 사각형을 그리는 화면을 예로 들어 봅시다. 사각형 좌표는 무엇을 어디에 그릴지 나타내는 데이터이고, 브러시는 어떤 색과 불투명도로 그릴지 정하는 자원입니다. FillRectangle은 내부를 채우고 DrawRectangle은 외곽선을 그립니다. 같은 사각형을 사용해도 도구와 함수에 따라 결과가 달라집니다.

렌더 타깃은 그릴 대상과 관련된 상태를 가지고 있습니다. Direct2D의 ID2D1Factory가 도형 관련 객체와 렌더 타깃 생성에 사용되는 것과, 렌더 타깃이 실제 그리기 명령을 받는 것은 구분합니다. 팩토리와 렌더 타깃의 역할을 나누어 읽으면 초기화와 화면 출력 코드를 분리하기 쉽습니다. Direct3D의 디바이스·컨텍스트·렌더 타깃 뷰와 이름만 보고 같은 객체로 취급하지 않습니다.

크기가 다른 두 사각형을 정의하고 FillRectangle과 DrawRectangle으로 각각 그리는 C++ 코드
작은 사각형의 내부를 채우고 큰 사각형의 외곽선을 그리는 코드입니다. 서로 다른 브러시를 전달하며, 그리기를 마친 뒤에는 EndDraw의 결과를 확인합니다. 이전 버전의 에디터 화면으로, 현재 버전과 메뉴 배치가 다를 수 있습니다. 이미지를 누르면 크게 볼 수 있습니다.

2D에도 이동과 회전 행렬이 필요하다

3×2 변환 행렬은 3D 기능을 끄기 위해 넣는 설정이 아닙니다. 2차원 이동, 회전, 크기 조절과 기울이기 같은 아핀 변환을 표현합니다. 항등 행렬은 좌표를 바꾸지 않는 기준 상태입니다. 예를 들어 캐릭터의 로컬 사각형은 원점 근처에 두고 그릴 때 이동 변환을 적용하면, 매번 네 모서리 좌표를 직접 고치는 대신 같은 도형을 재사용할 수 있습니다.

변환은 렌더 타깃의 상태로 남을 수 있으므로 월드 오브젝트를 그린 다음 UI까지 같은 변환이 적용되지 않도록 복원해야 합니다. 아래는 렌더 타깃과 브러시가 정상 생성되어 있다는 가정의 부분 예제입니다. Clear는 이번 예제에서 배경을 매번 다시 그리기 위해 사용하며, 모든 종류의 누적 그림 프로그램이 매 프레임 지워야 한다는 뜻은 아닙니다.

예제 · cpp

target->BeginDraw();
target->SetTransform(D2D1::Matrix3x2F::Identity());
target->Clear(D2D1::ColorF(D2D1::ColorF::White));

target->SetTransform(D2D1::Matrix3x2F::Translation(playerX, playerY));
target->FillRectangle(D2D1::RectF(-25.f, -25.f, 25.f, 25.f), brush);

target->SetTransform(D2D1::Matrix3x2F::Identity());
const HRESULT drawResult = target->EndDraw();
// drawResult의 실패와 D2DERR_RECREATE_TARGET을 호출자가 처리합니다.

픽셀과 논리 좌표를 섞지 않기

창의 바깥 크기에는 제목 표시줄과 테두리가 포함됩니다. 게임 화면의 크기는 클라이언트 영역을 기준으로 읽어야 합니다. Direct2D의 논리 좌표(DIP)와 실제 픽셀도 DPI 설정에 따라 달라질 수 있습니다. 예를 들어 화면 크기를 1024×768로 설정해도 확대 배율이 다른 모니터에서 정확히 같은 픽셀 크기로 보인다고 가정하면 안 됩니다.

검증할 때는 사각형이 중앙에 오는지뿐 아니라 창을 크게 줄였을 때 잘리는 위치, 화면 배율을 바꿨을 때의 크기, UI와 월드 변환의 분리를 확인합니다. 격자를 그리는 반복문의 간격 역시 화면 좌표 단위인지 월드 단위인지 이름으로 드러내면 이후 카메라 이동을 추가할 때 혼란이 줄어듭니다.

참고 자료

예제는 학습용이며, 모든 환경에서 실행 검증된 완성 프로젝트는 아닙니다. 적용 전 사용 중인 버전과 프로젝트 환경에서 동작을 확인하세요.