[SoftRenderer 구현 및 검토]
현재 프로젝트에서 여러 게임 오브젝트를 구현하십시오.
GameObject2D.h
#pragma once
class GameObject2D {
public:
GameObject2D() = default;
GameObject2D(const Mesh* InMeshPtr) : _MeshPtr(InMeshPtr) { }
GameObject2D(std::string name, const Mesh* InMeshPtr) : _name(name), _MeshPtr(InMeshPtr) {}
Transform2D& GetTransform() { return _Transform; }
const Mesh* GetMesh() { return _MeshPtr; }
FORCEINLINE bool HasMesh() const { return (_MeshPtr != nullptr); }
std::string GetName() { return _name; };
protected:
Transform2D _Transform;
const Mesh* _MeshPtr = nullptr;
std::string _name;
};
GameEngine.h
#pragma once
class GameEngine
{
public:
GameEngine() = default;
public:
bool Init();
bool LoadScene();
bool LoadResource();
public:
InputManager& GetInputManager() { return _InputManager; }
GameObject2D* GetPlayer() { return _Player.get(); }
Camera2D* GetCamera() { return _Camera.get(); }
std::vector<std::unique_ptr<GameObject2D>>& GetObject() { return _Object; }
GameObject2D* FindGameObject(std::string name);
private:
std::unique_ptr<GameObject2D> _Player;
std::unique_ptr<Mesh> _QuadMesh;
std::unique_ptr<Camera2D> _Camera;
std::unordered_map<std::string, std::unique_ptr<Mesh>> _Mesh;
std::vector<std::unique_ptr<GameObject2D>> _Object;
InputManager _InputManager;
};
GameEngine.cpp
#include "Precompiled.h"
#include "InputManager.h"
#include "Mesh.h"
#include "Transform2D.h"
#include "GameObject2D.h"
#include"Camera2D.h"
#include "GameEngine.h"
bool GameEngine::Init()
{
if (!_InputManager.GetXAxis || !_InputManager.GetYAxis || !_InputManager.SpacePressed)
{
return false;
}
if (!LoadResource())
{
return false;
}
if (!LoadScene())
{
return false;
}
return true;
}
bool GameEngine::LoadScene()
{
const float initScale = 100.0f;
_Player = std::make_unique<GameObject2D>(_QuadMesh.get());
_Player->GetTransform().SetScale(Vector2::One * initScale);
for (int i = 0; i < 5; i++)
{
_Object.push_back(std::make_unique<GameObject2D>("Object", _Mesh["QuadMesh"].get()));
_Object[_Object.size() - 1]->GetTransform().SetScale(Vector2::One * initScale);
_Object[_Object.size() - 1]->GetTransform().SetPosition(Vector2(initScale * i, initScale * i));
}
for (int i = 0; i < 5; i++)
{
_Object.push_back(std::make_unique<GameObject2D>("Object", _Mesh["QuadMesh"].get()));
_Object[_Object.size() - 1]->GetTransform().SetScale(Vector2::One * initScale);
_Object[_Object.size() - 1]->GetTransform().SetPosition(Vector2(initScale * i, -initScale * i));
}
for (int i = 0; i < 5; i++)
{
_Object.push_back(std::make_unique<GameObject2D>("Object", _Mesh["QuadMesh"].get()));
_Object[_Object.size() - 1]->GetTransform().SetScale(Vector2::One * initScale);
_Object[_Object.size() - 1]->GetTransform().SetPosition(Vector2(-initScale * i, initScale * i));
}
for (int i = 0; i < 5; i++)
{
_Object.push_back(std::make_unique<GameObject2D>("Object", _Mesh["QuadMesh"].get()));
_Object[_Object.size() - 1]->GetTransform().SetScale(Vector2::One * initScale);
_Object[_Object.size() - 1]->GetTransform().SetPosition(Vector2(-initScale * i, -initScale * i));
}
_Camera = std::make_unique<Camera2D>();
return true;
}
bool GameEngine::LoadResource()
{
_QuadMesh = std::make_unique<Mesh>();
_Mesh["QuadMesh"] = std::make_unique<Mesh>();
static float squareHalfSize = 0.5f;
static int vertexCount = 4;
static int triangleCount = 2;
static int indexCount = triangleCount * 3;
_QuadMesh->_Vertices = {
Vector2(-squareHalfSize, -squareHalfSize),
Vector2(-squareHalfSize, squareHalfSize),
Vector2(squareHalfSize, squareHalfSize),
Vector2(squareHalfSize, -squareHalfSize)
};
_QuadMesh->_Indices = {
0, 2, 1,
0, 3, 2
};
_Mesh["QuadMesh"]->_Vertices = {
Vector2(-squareHalfSize, -squareHalfSize),
Vector2(-squareHalfSize, squareHalfSize),
Vector2(squareHalfSize, squareHalfSize),
Vector2(squareHalfSize, -squareHalfSize)
};
_Mesh["QuadMesh"]->_Indices = {
0, 2, 1,
0, 3, 2
};
return true;
}
GameObject2D* GameEngine::FindGameObject(std::string name)
{
for (int i = 0; i < _Object.size(); i++)
{
if(name == _Object[i].get()->GetName())
{
return _Object[i].get();
}
}
return nullptr;
}
SoftRenderer2D.cpp 의 Render2D
// 렌더링 로직
void SoftRenderer::Render2D()
{
// 격자 그리기
DrawGrid2D();
////////////////////// 월드 공간 //////////////////////
Matrix3x3 viewMat = _GameEngine.GetCamera()->GetViewMatrix();
Transform2D& playerTransform = _GameEngine.GetPlayer()->GetTransform();
Matrix3x3 finalMat = playerTransform.GetModelingMatrix();
// 게임 로직에서 변경한 피벗 위치의 출력
_RSI->PushStatisticText(playerTransform.GetPosition().ToString());
const Mesh* mesh = _GameEngine.GetPlayer()->GetMesh();
size_t vertexCount = mesh->_Vertices.size();
size_t indexCount = mesh->_Indices.size();
size_t triangleCount = indexCount / 3;
auto& object = _GameEngine.GetObject();
for (int i = 0; i < object.size(); i++)
{
const Mesh* mesh = object[i]->GetMesh();
size_t vertexCount = mesh->_Vertices.size();
size_t indexCount = mesh->_Indices.size();
size_t triangleCount = indexCount / 3;
Vector2* vertices = new Vector2[vertexCount];
std::memcpy(vertices, &mesh->_Vertices[0], sizeof(Vector2) * vertexCount);
int* indices = new int[indexCount];
std::memcpy(indices, &mesh->_Indices[0], sizeof(int) * indexCount);
Matrix3x3 final = viewMat * object[i]->GetTransform().GetModelingMatrix();
for (int vi = 0; vi < vertexCount; ++vi)
{
vertices[vi] = final * vertices[vi];
}
for (int ti = 0; ti < triangleCount; ++ti)
{
int bi = ti * 3;
_RSI->DrawLine(vertices[indices[bi]], vertices[indices[bi + 1]], _CurrentColor);
_RSI->DrawLine(vertices[indices[bi]], vertices[indices[bi + 2]], _CurrentColor);
_RSI->DrawLine(vertices[indices[bi + 1]], vertices[indices[bi + 2]], _CurrentColor);
}
}
// 렌더러가 사용할 정점 버퍼와 인덱스 버퍼 생성
Vector2* vertices = new Vector2[vertexCount];
std::memcpy(vertices, &mesh->_Vertices[0], sizeof(Vector2) * vertexCount);
int* indices = new int[indexCount];
std::memcpy(indices, &mesh->_Indices[0], sizeof(int) * indexCount);
// 각 정점에 행렬을 적용
for (int vi = 0; vi < vertexCount; ++vi)
{
vertices[vi] = finalMat * vertices[vi];
vertices[vi] = viewMat * vertices[vi];
}
// 변환된 정점을 잇는 선 그리기
for (int ti = 0; ti < triangleCount; ++ti)
{
int bi = ti * 3;
_RSI->DrawLine(vertices[indices[bi]], vertices[indices[bi + 1]], _CurrentColor);
_RSI->DrawLine(vertices[indices[bi]], vertices[indices[bi + 2]], _CurrentColor);
_RSI->DrawLine(vertices[indices[bi + 1]], vertices[indices[bi + 2]], _CurrentColor);
}
delete[] vertices;
delete[] indices;
}
현재 프로젝트에서 카메라를 따르는 플레이어를 구현하십시오.
// 게임 로직
void SoftRenderer::Update2D(float InDeltaSeconds)
{
InputManager input = _GameEngine.GetInputManager();
Transform2D& playerTransform = _GameEngine.GetPlayer()->GetTransform();
Transform2D& cameraTransform = _GameEngine.GetCamera()->GetTransform();
Vector2 deltaPosition = Vector2(input.GetXAxis(), input.GetYAxis()) * _MoveSpeed * InDeltaSeconds;
playerTransform.AddPosition(deltaPosition);
cameraTransform.SetPosition(playerTransform.GetPosition() * InDeltaSeconds + cameraTransform.GetPosition() * (1.0f - InDeltaSeconds));
_CurrentColor = input.SpacePressed() ? LinearColor::Red : LinearColor::Blue;
}
코드를 공유하고 GIF 애니메이션 결과를 첨부하십시오.
다이어그램, 핸드 드로잉 등을 사용하여 전체 softrenderer 프로세스, 파이프 라인, 아키텍처를 요약하십시오.
우선 SoftRenderer는 아래 3가지의 모듈과 1개의 플레이어로 구성 돼 있으며, 3가지의 모듈을 합쳐서 작동이 됩니다.
소프트렌더러의 파이프 라인은 아래와 같이 구성 돼 있습니다.(개인적인 생각입니다.)
GameEngine, GameObject2D 클래스의 각 멤버 변수 유형에 대한 적절한 이유를 제공하십시오.
게임오브젝트 같은 경우에는 처음부터 끝까지 다 검색해야 하기 떄문에 시간복잡도가 O(n) 인 Vector를 선택하였습니다.
'게임제작기법연구' 카테고리의 다른 글
게임제작기법연구 10주차 (0) | 2020.06.16 |
---|---|
게임제작기법연구 8주차 (0) | 2020.06.02 |
게임제작기법연구 6주차 (0) | 2020.05.19 |
게임제작기법연구 5주차 (0) | 2020.05.12 |
게임제작기법연구 4주차 (0) | 2020.05.05 |