공용으로 관리될 부분은 Manager로 빼서 관리를 해보자.SceneManager지금까지 짠 코드를 보면 GameObject들을 그냥 Main 프로그램이 전부 다 가지고 있고 Update를 요청했다.우리가 생각해보면 유니티에서는 Scene이라고 하는 객체가 모든 GameObject를 가지고 있고 이를 관리하고 있다.그렇기에 SceneManager를 만들어서 관리해보자.여기서 Scene은 위에서 말한 대로 각종 오브젝트들을 보관하고 있는 클래스이다.SceneManager는 이러한 여러개의 Scene들을 하나로 묶어서 관리하기 위한 클래스이다.#pragma onceclass GameObject;class Scene{public: void Awake(); void Start(); void Update(); v..
C++
엔진 구조를 완벽히 분석하는 것은 실제 상용 엔진을 이해하는데 매우 큰 도움이 된다.Component유니티에서는 어떤 오브젝트에 Component를 여러개를 조립해서 하나의 생명을 불어넣을 수 있다.이전 포스팅에서 다뤘던 Transform도 하나의 Component라고 할 수 있다. 각 Component는 하나의 특정 역할을 하는 것이 대부분이다. 그래서 지금 작업중인 GameObject를 수정해보자. 현재 GameObject는 Mesh에 대한 정보, 즉 한번만 로드하면 될 정보들도 같이 들고 있다. 이는 고블린의 쉐이더나 정점정보를 각 고블린 당 하나씩 들고 있다는 점이 문제인 것이다. 이는 나중에 MeshRenderer로 수정할 것이다. enum class ComponentType : uint8{ T..
마지막으로 엔진을 만드는 초석이 되는 프레임워크 중 GameObjcet 마다 개별로 가지고 있는(공용으로 사용되는 쉐이더나 Vertex 정보들이 아닌) 것들을 따로 분리해보자.유니티에서 부모와 자식 계층을 잘 생각해보자.자식의 좌표는 부모의 좌표계에 종속된다. 만약 B 가 10,0,0 좌표에 있다고 하고 A는 5,0,0에 있다고 해보자. B가 A의 자식이 되었을 때, B에 표시되는 좌표는 5,0,0으로 바뀐다. 그 이윤 부모의 좌표계를 기준으로 5,0,0에 있기 때문이다.그럼 B의 월드 좌표를 얻기 위해서는 어떻게 해야할까? 먼저 부모를 기준으로 하는 변환 행렬을 구한 뒤(SRT) 다시 그 위치를 기준으로 한번 더 SRT를 하면 구할 수 있을 것이다. 이런 것처럼 Transform에는 많은 정보가 있고 ..
지난 포스팅에 이어서 프레임워크를 제작해보자.Shader쉐이더는 vertexShader와 vsBlob, pixelShader와 psBlob을 묶어줘야한다.#pragma onceenum ShaderScope{ SS_None = 0, SS_VertexShader = (1 device); virtual ~Shader(); virtual void Create(const wstring& path, const string& name, const string& version) abstract; ComPtr GetBlob() { return _blob; }protected: void LoadShaderFromFile(const wstring& path, const string& name, const string& v..
지금까지 짠 코드는 하나의 클래스와 헤더파일에 전부 몰려있기 때문에 이를 분리해서 프레임워크를 제작해보자.이것만 해도 2D 게임을 만드는 주축이 된다고 해도 무방하다.파일 구조는 다음과 같다. GraphicsGraphics 라는 클래스는 그래픽스와 관련된 모든 디바이스 를 관리하는 클래스가 될 것이다. 가장 공통적인 내용을 가지고 있을 것이다.#pragma onceclass Graphics{public: Graphics(HWND hwnd); ~Graphics(); void RenderBegin(); void RenderEnd(); ComPtr GetDevice() { return _device; } ComPtr GetDeviceContext() { return _deviceContext; }private..
행렬 기초행렬을 처음 이해할 때, 하나의 포탈이라고 이해하면 편하다. 만약 어떤 물체가 Scale이라는 행렬 포탈안에 들어가게 된다면 물체의 Scale이 조정이 되는 것이다. 만약 Rotation에 들어가게 된다면 회전을 하게되는 것이다.즉, 하나의 변화를 나타낸다 라는 개념으로 이해하면 된다.(게임에서) 행렬은 말 그대로 행(Row)과 열(Col)로 이루어진 수식을 의미한다.3개의 행이 있고 2개의 열이 있다면 3x2 행렬이라고 말한다.그리고 1행 1열 1행 2열 순으로 번호를 매긴다. 행렬에 대한 특징으로 행렬 M에 k를 곱하면 각 요소에 전부 다 k를 곱하는 특성을 가지고 있다.행렬의 덧셈 뺄셈은 각 위치끼리 더하고 빼기를 하게된다. 하지만 유의해야할 점은 행렬의 사이즈가 동일해야한다는 점이다.가장..
Constant Buffer상수 버퍼는 Vertex Shader 단계에서 변수를 사용하고 싶을 때 이용할 수 있는 녀석이다.그 전 포스팅에서 CreateGeometry 함수에서 도형에 대한 기하학정보를 하드코딩으로 정했다.근데 만약 우리가 진지한 게임을 만든다고 했을 때, 플레이어가 일일이 움직이는 것을 보정할 순 없는 노릇이다.왜냐하면 CPU에서 우리가 게임을 만든다고 하면 Update 문에서 1틱당 얼만큼의 위치 벡터를 곱해주는 형식으로 플레이어를 이동할 수 있겠지만 우리가 GPU에서 지금까지 작업하면서 했던 것중 하나는 바로 CPU의 정보를 GPU로 넘겨주는 것이었다. 그리고 우리가 작업할 때 Usage를 D3D11_USAGE_IMMUTABLE로 설정했다.이말은 즉슨, 1회성으로 CPU가 작업을 한..
이전 포스팅에서 VertexBuffer를 만들어서 건네줬는데 그 이외에 IndexBuffer도 있다.IndexBuffer에 대해 알아보자.IndexBuffer만약 우리가 사각형을 화면에 띄운다고 해보자.그러면 정점이 몇개가 필요할까? 4개가 아닌 6개가 필요하다. 그 이유는 삼각형 단위로 이루어져있기 때문이다. 그런데 지금 당장만 생각해도 되게 비 효율적일것 같다는 생각이 든다. 아무리 삼각형 단위로 계산한다고 해도 정말 큰 에셋이라면 정점이 수만가지가 될텐데 그걸 다 계산하기 쉽지않을 것이다.그래서 이럴경우를 대비해 정점마다 넘버링(인덱스)를 추가해서 관리하는 것이 IndexBuffer이다.사각형을 한번 만들어보자.필드에 정점을 아래와 같이 인덱스를 매기자. 1 3 0 2즉 012 / 123 두 개의 ..
더보기DirectX가 중요하다는 사실을 누구나 알고 있다. 어디서 중요하다고 해서 그렇든 학원에서 가르쳐주니까 그렇든 중요한 건 누구나 알고 있지만 스스로 혼자 독학하긴 쉽지 않다.그러니 나무를 보지 말고 숲을 봐야한다. DX의 경우 함수가 정말 많이 나오는데 함수가 어떤 역할을 하는지만 알고 인자 하나하나가 무엇인지 너무 고민하지 말아야 한다. 큰 틀을 공부하면 자연스레 깨달을 것이다.장치 초기화Direct3D 초기화의 시작은 Direct3D 11 장치(ID3D11Device)와 그 문백(ID3D11Device Context)를 생성하는 것이다.ID3D11Device 인터페이스는 기능 지원 점검과 자원 할당에 쓰인다.ID3D11DeviceContext 인터페이스는 렌더 대상을 설정하고, 자원을 그래픽..
랜더링에 대해 - GPU컴퓨터는 여러 부품을 가지고 있지만 그 중 3대 부품을 꼽자면 CPU, 메모리, 보조기억장치(SSD) 일 것이다. 우리가 맨 처음 운영체제를 설치하고나면 보조기억장치에 저장이 될 것이다. 그리고 컴퓨터를 실행하면 그 것을 메모리에 옮겨서 차지하게 된다. 우리가 본격적으로 프로그래밍을 통해 프로그램을 실행하면 로직은 CPU가 처리하고 그 안에 데이터를 보관 있는 것은 메모리이다. 이런 식으로 기본적으로 뭔가 진행하는데 있어서 중요한 3대 부품은 위와 같지만, 게임을 좋아하는 사람이라면 당연히 알 수 있듯이 GPU 역시 매우 중요하다.그림을 한번 바꿔서 CPU랑 GPU랑 무엇이 다르고 어떤 역할을 하는지 알아보자.근본적으로 CPU는 무언가를 "연산" 하기 위함이고 메모리는 "저장"하..