25
그래픽스 특강 1
그래픽스 프로그래밍이란?
'창(window)'을 생성하고, API를 활용해 '창'에 그림을 그리는 프로그램
Win32 API
깊게 파고들 필요가 없음 https://learn.microsoft.com/ko-kr/windows/win32/learnwin32/creating-a-window
CALLBACK WindowProc()
: 창 메시지 처리할 때 사용
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ switch (uMsg) { case WM_DESTROY: // 창 끄기 이벤트 PostQuitMessage(0); return 0; case WM_PAINT: // 창 그리기 이벤트 { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); // All painting occurs here, between BeginPaint and EndPaint. FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1)); EndPaint(hwnd, &ps); } return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); // 윈도우 내장 기본 처리}lp = long pointer 줄임말
핸들은 void 포인터임.
#ifdef STRICTtypedef void *HANDLE;#if 0 && (_MSC_VER > 1000)#define DECLARE_HANDLE(name) struct name##__; typedef struct name##__ *name#else#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name#endif.c_str()
메세지 루프
창에서 메세지 이벤트를 가져오는 메소드는 2가지가 있다
GetMessage: 동기 방식(blocking)PeekMessage: 비동기 방식(non-blocking)
/* * Message structure */typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt;#ifdef _MAC DWORD lPrivate;#endif} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;오 신기

WINMAIN과 main의 차이
- main()은 디버그 환경에서 창과 콘솔을 동시에 띄워줌
- WinMain은 창만 띄워줌
창의 클라이언트 영역 크기
// 창 전체 크기를 1280x780 으로 설정했을 때RECT rect;GetClientRect(hwnd, &rect); // 1280x780 -> left 0, top 0, right 1264, bottom 761// 클라이언트 영역을 온전히 1280x780으로 보장해주고 싶을 때RECT rect = {};rect.left = 0;rect.top = 0;rect.right = width;rect.bottom = height;AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); // left -8 top -31 right 1288 bottom 808GraphicsContext/RenderContext?
장치초기화
장치(그래픽카드) 초기화. Direct3D에서 "장치"로 다루는 객체는 3개(하드웨어: 그래픽카드 1개)인데
- Device: 리소스(텍스쳐, 이미지 등) 생성 전담
- DeviceContext: 생성된 리소스 그래픽카드에 연결(binding)/draw call
- SwapChain: 백버퍼 프론트버퍼 교환 → 기능 변화가 적음(dxgi.h 라이브러리로 분리)
장치초기화는 GraphicsContext에서 관리함. Direct3D 리소스는 포인터로만 다룰 수 있음
d3d_driver_type
typedef enum D3D_DRIVER_TYPE { D3D_DRIVER_TYPE_UNKNOWN = 0, D3D_DRIVER_TYPE_HARDWARE = ( D3D_DRIVER_TYPE_UNKNOWN + 1 ) , D3D_DRIVER_TYPE_REFERENCE = ( D3D_DRIVER_TYPE_HARDWARE + 1 ) , // 진짜 글카 쓰기 D3D_DRIVER_TYPE_NULL = ( D3D_DRIVER_TYPE_REFERENCE + 1 ) , // 글카 지정 x 계산만 D3D_DRIVER_TYPE_SOFTWARE = ( D3D_DRIVER_TYPE_NULL + 1 ) , // 다렉으로 렌더 D3D_DRIVER_TYPE_WARP = ( D3D_DRIVER_TYPE_SOFTWARE + 1 ) } D3D_DRIVER_TYPE;라이브러리 추가
링커>입력>추가 종속성에서 d3d11.lib, dxgi.lib 추가(vs 설치 때 게임 킷 추가하면 설치됨)
테셀레이션?

물체의 표면을 더 작은 타일(폴리곤)으로 잘게 쪼개는 기법. 보통 테셀레이션과 함께 3D 텍스쳐 매핑 기법을 사용함
Bump, Normal, Displacement

Normal Mapping
노멀 매핑(Normal Mapping)은 폴리곤의 법선 벡터(Normal Vector)의 값을 사용하여 로우 폴리곤의 그래픽 환경에서 하이 폴리곤의 입체감 및 질감을 구현하는 방법이다. 물체의 질감을 있는 그대로 폴리곤으로 표현하면 삼각형의 양이 많아지고 결국 연산이 많이 필요하게 되는데 폴리곤을 무척 적게 사용하고도 비슷한 효과를 낼 수 있는 기술이다. 1990년대까지는 논문에서나 존재하던 기술이었으나 하드웨어의 속도가 빨라지고 프로그래머블 셰이더가 일반화되는 2000년대 중반부터 널리 사용되기 시작하였다.


| 표면 변화 | 표현 방식 | 특징 | |
|---|---|---|---|
| Bump | X | 흑백 밝기 값 | 수직 높이정보만 가지고 있다 (그레이스케일 수치값을 이용) |
| Normal | X | RGB 방향 정보 | 이름의 Normal은 노멀벡터를 칭하는 것. x,y,z 공간 상의 방향에 대한 정보를 가지고 있다 (R,G,B 값을 이용) |
| Displacement | O | 실제 지오메트리 변형 | 보통 노멀맵까지 같이 써야 그림자 표현이 됨 |
테셀레이션과 디스플레이스먼트 매핑같은 고급 매핑을 활용할 자원의 성능이 충분해졌다 하더라도 2010년대 초반까지만 해도 이를 많이 활용하기엔 여전히 버거운 기능이었다. 그러다가 2013년에 AMD에서 개발한 새로운 API인 Mantle을 도입하여 기존의 API로 구현하면서 발생한 오버헤드를 줄이고 콘솔 게임기에서나 활용했던 하드웨어 직접 접근, 이기종 컴퓨팅, 비동기 셰이딩, 개선된 메모리 공유 기능을 통해 성능 효율이 대폭 상승하게 되어 테셀레이션과 고급 매핑의 제약이 줄어들었고 2015년부터 게임사들에게 본격적으로 사용되기 시작했다.
2014년에 MS에서도 Mantle의 특성을 반영하고 대응하기 위해 DirectX 12를 발표하였고, 2015년에 크로노스 그룹에서도 역시 Mantle과 DirectX 12에 대응하기 위해 기존의 OpenGL 네이밍이 아닌 Vulkan "Vulkan(API)")이라는 새로운 이름의 API를 발표하였으며, 언리얼 엔진, 유니티 엔진, 크라이엔진, 프로스트바이트 엔진 등의 유명 게임 엔진 쪽에서도 이러한 새로운 API를 실험적으로 도입하여 테셀레이션과 고급 매핑 기능을 많이 활용한 게임이 증가했다.