그래픽스
드로우콜 (Draw Call)
CPU는 현재 프레임에 어떤 것을 그려야 할지 정하고, GPU에 오브젝트를 그리라고 명령을 호출하는 명령이다. 게임의 오브젝트를 화면에 렌더링하려면 우선 오브젝트가 렌더링 대상인지를 판단한다. 이러한 과정을 컬링이라고 한다. 컬링을 거친 오브젝트가 렌더링 되기 위해선 CPU에서 GPU에 다음의 정보를 줘야 한다. 메시 정보 텍스처 정보 쉐이더 정보 트랜스폼 정보 알파 블렌딩 여부 기타 등등 메시 텍스쳐 쉐이더등의 정보는 스토리지에 보관되어 있다가 CPU가 이를 읽어들여 CPU 메모리에 데이터를 올린다. 그 후 CPU메모리에 있는 정보들을 GPU 메모리로 복사한다. 정보들은 GPU 메모리에 있어야 GPU가 사용할 수 있다. 만약 위 복사과정이 매 프레임마다 일어난다면 성능을 많이 잡아먹을 것이다. 따라서 ..
배칭 (Batching)
배칭은 여러 배치를 묶어 하나의 배치를 만드는 것이다. 드로우콜 횟수를 줄이는 가장 효과적인 방법 중 하나이기도 하다. 배칭을 위해서는 오브젝트들이 동일한 머티리얼을 사용해야 하는데, 이때 머티리얼이 동일하다는 것은 동일한 머티리얼 인스턴스가 같다는 것을 의미한다. 스태틱 배칭 스태틱 배칭은 정적인 오브젝트를 대상으로 하는 배칭 기법이다. 따라서 런타임에서 버텍스 연산을 하지 않아도 되기 때문에 매우 효율적이다. 스태틱 배칭은 메시의 폴리곤 수에 상관 없이 같은 머티리얼을 사용하는 오브젝트들을 하나의 메시로 묶어준다. 단, 머티리얼이 1개라고 해서 무조건 1개의 배치로 합쳐지는 것은 아니며 라이트와 같은 요소들로 인해 배칭이 나뉠 수 있다. 합쳐진 메시를 생성해야 하기 때문에 추가적인 메모리가 필요하다...
병목 (Bottleneck)
최적화 게임의 성능 최적화를 위해서는 다음의 작업들을 고려할 수 있다. 메시의 버텍스 줄이기 텍스처 크기 줄이기 가벼운 쉐이더 사용 드로우콜 줄이기 게임 로직 최적화 물리 연산 줄이기 기타 등등 그러나 위 작업들을 수행하기 전에 어디서 병목이 일어나는지를 알아야 한다. 왜냐면 병목이 일어나는 곳 외에서 최적화를 해봤자 전반적인 수행 속도는 크게 바뀌지 않기 때문이다. 목표 설정 게임의 최적화 목표를 설정할 때 60FPS냐 30FPS냐를 정하는 것을 목표로 삼을 수 있다. 그러나 먼저 기준이 되는 하드웨어 스펙을 정해야 한다. 예를 들어 만드는 게임이 퍼즐게임이라면 가능한 다양한 기기에서 이용 가능하도록 해야 할 것이다. 또한 더 좋은 디바이스라고 해서 병목이 덜 발생할 것이라고 생각할 수 있지만 사실은 ..
곡선 (Curve) & 스플라인 (Spline)
곡선을 표현하기에 앞서, 두 정점 (A, B) 사이에 있는 점 P를 다음과 같이 표현할 수 있다. 또한 곡선은 t에 대한 방정식(P(t))으로 표현할 수 있다. 베지에 곡선(Bézier Curves) n차 베지에 곡선은 n+1개의 점으로 얻을 수 있는 베지에 곡선이다. 1차(Linear) 베지에 곡선은 앞서 말한 점 A,B 사이에 있는 점 P의 집합으로 표현할 수 있다. 말이 곡선이지, 사실상 A-B를 잇는 선분이다. 2차(Quadratic) 베지에 곡선은 아래와 같다. 2차 베지에 곡선은 A와 B를 잇는 1차 베지에 곡선 위에 있는 한 점 AB(t)와 B와 C를 잇는 1차 베지에 곡선 위의 한 점 BC(t)사이에 있는 한 점 P(t)의 집합으로 볼 수 있다. 식으로 표현하면 다음과 같다 이때 두 선분 ..
2D AABB OBB 충돌
충돌 * Bounding Box * 충돌을 검사하기 위해 단순한 박스 모양으로 충돌을 검사하는 것. - 메쉬의 폴리곤 하나하나 검사하기엔 연산이 너무 많아 단순한 박스 모양이나 구, 캡슐 형태를 주로 사용한다. AABB와 OBB의 차이 * AABB (Axis Aligned Bounding Box) : 정렬된 축의 박스끼리의 충돌이다. * OBB (Oriented Bounding Box) : 박스와 함께 축 같이 회전한다. AABB (Axis Aligned Bounding Box) * 2D AABB 충돌은 두 가지를 체크하여 두 가지 모두 true여야 충돌이다. 1. 가로 체크 : 두 사각형의 중점 가로 사이의 거리 < 두 사각형의 밑변 절반의 크기 합 2. 세로 체크 : 두 사각형의 중점 세로 사이의 거..
두 점 사이의 거리 구하기
플레이어 사이의 거리 혹은 충돌하려는 두 물체 사이의 거리, 더 나아가서는 사정 거리 안에 들어왔는지 아닌지를 알고 싶을 때가 생기면 어떻게 해야 할까? 가장 간단한 방법은 피타고라스의 정리를 이용하는 것이다. A와 B를 잇는 선분을 하나 그린 후 이를 빗변으로 하는 직각 삼각형을 하나 그린다. A(x1, y1), B(x2, y2)라 할 때 나머지 하나의 꼭짓점의 좌표는 C(x2, y1)이 된다. 여기서 피타고라스의 정리를 사용하면 A와 B를 잇는 빗변의 거리를 구할 수 있다. 제곱근은 직접 연산을 통해 계산해도 되지만 헤더를 추가해 sqrt 와 pow를 이용해도 된다. sqrt(값) 제곱근을 구하는 함수로 제곱근을 반환 pow(값, 지수) 제곱을 구하는 함수. 3차원으로 확장 위의 거리의 공식은 xy축..
DirectX 12 멀티 스레드 렌더링 (Multi-Thread Rendering)
현재 프로젝트에서 사용 중인 스레드의 개수는 4개이다. 싱글 스레드 렌더링과 멀티스레드 렌더링의 성능을 비교해보겠다. 우선 사용하고 있는 메쉬 모델 데이터의 정보이다. 애니메이션 정보가 없는 스태틱 메쉬의 경우 vertex 정점 11,400개 / index 3,800개이다. 애니메이션 스키닝을 해야 하는 다이나믹 메쉬의 경우 vertex 정점 51,294개 / index 17,096개이다. 모든 오브젝트에 대해서 인스턴싱은 적용 X. 모든 오브젝트는 vertex 셰이더와 pixel 셰이더를 통해 렌더링 한다. 1. StaticMesh x1000 한 번 장면을 그릴 때마다 그리는 vertex의 개수는 11,400 * 1,000 = 11,400,000개. 그림자 깊이까지 총 2번을 그리므로 11,400,00..
[Direct X] Constant Buffer(상수 버퍼) 란?
상수 버퍼(Constant buffer)는 정점 및 픽셀 셰이더에서 사용될 상수를 모아 놓은 버퍼이다. 상수 버퍼 사용을 위해 cpp 코드 영역에 상수 버퍼 타입의 구조체를 정의하고 셰이더에도 동일한 포맷으로 상수 버퍼 구조체를 정의. 그리고 시스템 메모리에서 구조체 변수 생성 및 값 설정 후 정점 혹은 픽셀 셰이더에 Set 시킨다. 값 설정 및 set은 보통 매 프레임 실행되는 Render() 함수에 적용한다. 그러면 이 Set 시킨 데이터를 설정한 셰이더에서 사용할 수 있다. 상수 버퍼를 사용하는 이유? 셰이더에서 매번 사용되는 상수, 하지만 cpp 파일에서 전달해주어야 한다고 가정할 때, 개별적으로 하나하나 값을 전달해 주는 것은 대역폭(bandwidth)이 크고 부담이 많이 된다고 한다. 따라서 ..
[DX11] 튜토리얼 4 - 3D 공간
메커니즘은 매 프레임마다 Y값을 회전하고 이를 상수버퍼에다 실은 후 셰이더 파일에 1:1 매핑 시킴으로써 큐브의 버텍스가 매 프레임마다 위치를 변경하는데 마치 회전하는 효과를 준다. // 행렬의 전이를 계산 ConstantBuffer cb; cb.mWorld = XMMatrixTranspose( g_World ); cb.mView = XMMatrixTranspose( g_View ); cb.mProjection = XMMatrixTranspose( g_Projection ); g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb, 0, 0 ); g_pImmediateContext->VSSetShader( g_pVertexShade..
DirectX와 HLSL간의 행렬 순서와 연산
예제 프로그램의 셰이더 코드에서는 'World * View * Projection' 순으로 행렬연산을 수행하는게, 내 프로그램에서는 'Project * View * World' 순으로 연산해야 정상적인 결과가 나왔기 때문이다. 컴퓨터에서 다차원 배열로 행렬을 구성할 때, 행렬을 어떤 순서로 접근할 것인지에 대한 순서가 있다. DirectX에서는 행렬 순서가 row-major(행우선)이고, HLSL에서는 column-major(열우선)이다. 위와 같이 행렬을 접근하는 순서가 다르기 때문에, 사용하는 라이브러리에 명시된 순서를 확인하고 그에 맞게 연산을 하지 않으면 제대로 된 결과가 나오지 않는다. 서로간의 행렬 순서가 달랐기 때문에, DirectX에서는 'World * View * Projection' 순..