오늘부터는 유니티 엔진을 모작한다는 느낌으로 어떤 하나의 엔진을 천천히 만들어간다는 느낌으로 기존 코드를 정리하고 새로운 클래스를 추가해보자 

처음으로 지금은 게임오브젝트 코드자체에 렌더링관련 부분이 구현되어있는데 나중에 완성된 엔진에서 게임오브젝트는 보여주는 기능뿐만 아니라 다양한 기능을 가지게 된다.

그렇기 때문에 렌더링부분을  게임오브젝트 자체 코드에서 다루는 것이 아닌 그려지는 역활을 하게 될 Component로 옮겨줄 것이다.

1.Component  코드 정리

처음으로 할 것은 Component 코드에 유니티 엔진의 방식대로 Awake Start Update등의 기본 함수를 추가해주고

이를 상속 받는 모든 클래스에서 이 함수를 사용할 수 있도록 하자.

또한 오브젝트당 하나씩만 추가할 수 있는 즉 고정적인 개수의 Component를 Enum Class로 선언해주고 이 개수를 enum으로 저장해주자 

 Monobehaviour라는 클래스를 추가해 Script가 생성될 때는 이 클래스를 상속받아서 생성되도록 해주자

 

Component.h

#pragma once

class GameObject;
class Transform;

enum class ComponentType :uint8
{
	Transform,		//고정개수
	MeshRenderer,
	Camera,
	Animator,
	//Todo..
	Script,		//동적개수

	End,
};

enum
{
	//개수가 고정인 컴포넌트 개수
	FIXED_COMPONENT_COUNT = static_cast<uint8>(ComponentType::End)-1;
};

class Component
{
public:
	Component(ComponentType type);
	virtual ~Component();

	//생성될때 호출
	virtual void Awake() {}
	virtual void Start() {}
	virtual void Update() {}
	virtual void LateUpdate(){}
	virtual void FixedUpdate(){}

	shared_ptr<GameObject> GetGameObject();
	shared_ptr<Transform> GetTransform();

private:
	friend class GameObject;
	void SetGameObject(shared_ptr<GameObject> gameObject) { _gameObject = gameObject; }


protected:
	ComponentType _type;
	weak_ptr<GameObject> _gameObject;
};

 

Component.cpp

#include "pch.h"
#include "Component.h"

Component::Component(ComponentType type)
	:_type(type)
{
}

Component::~Component()
{
}


std::shared_ptr<GameObject> Component::GetGameObject()
{
	return _gameObject.lock();
}

std::shared_ptr<Transform> Component::GetTransform()
{
	return _gameObject.lock()->GetTransform();
}

 

2.GameObject 코드 정리

다음엔 GameObject에도 Awake Update 등의 기본함수를 추가해준다.

 

그리고 중요한 부분을 요약해보자면 

1.GameObject에서 고정적인 개수의 컴포넌트는 std::array 를 통해 관리하여 만약 배열의 길이를 넘어서는 값을 호출하면 크러쉬가 발생하게 하여 좀 더 안전하게 관리할 수 있도록 하자.

2.개수가 여러개 추가될 수 있는 Script는 배열의 크기가 동적으로 바뀔 수 있는 Vector를 통해 관리해주자

3.각 기본 함수에서 자신이 가지고 Component의 기본함수가 호출 되도록 구현하자. 

즉 GameObject의 Update가 수행되면 각 Component의 Update도 수행되는 식으로 말이다.

4.GameObject에서 Transform과 같은 가장 핵심적인 부품을 가지고 올 수 있고 없는 경우에 생성하는 헬퍼함수를 만들어주자.

5.GameObject에서 Component가 추가될 수 있도록 함수를 만들어주자 이때 스마트포인터를 넘겨주어야하는 데 자기자신의 값인 this 포인터를 넘겨주는 것이 아니라 shared_from_this 를 사용하여 메모리 오염을 방지하도록 하자.

이 때 Shared_from_this 방식은 weak_ptr을 가지고 있다가 자체적으로 생성시에 자신의 스마트 포인터를 채워주는 방식으로 작동한다.

-생성자에서 사용 시에는 크러쉬가 발생할 수 있다.

 

 

GameObject.h

#pragma once

class MonoBehaviour;

class GameObject : public enable_shared_from_this<GameObject>
{
public:
	GameObject(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext);
	~GameObject();

	void Awake();
	void Start();
	void Update();
	void LateUpdate();
	void FixedUpdate();

	//헬퍼함수
	shared_ptr<Component> GetFixedComponent(ComponentType type);
	shared_ptr<Transform> GetTransform();

	shared_ptr<Transform> GetOrAddTransform();
	void AddComponent(shared_ptr<Component> component);

	//..

	void Render(shared_ptr<Pipeline> pipeline);
private:
	ComPtr<ID3D11Device> _device;

	//기하학적 도형 - cpu
	//vector<Vertex> _vertices;
	//vector<uint32> _indices;

	shared_ptr<Geometry<VertexTextureData>> _geometry;

	shared_ptr<VertexBuffer> _vertexBuffer;

	//인덱스버퍼 - 이거도 Geometry에 포함
	shared_ptr<IndexBuffer> _indexBuffer;
	shared_ptr<InputLayout> _inputLayout;

	//VS
	shared_ptr<VertexShader> _vertexShader;

	//RS
	shared_ptr<RasterizerState> _rasterizerState;

	//PS
	shared_ptr<PixelShader> _pixelShader;

	//SRV - 이미지를 어떻게 쓸것인가 - 텍스처
	shared_ptr<Texture> _texture1;

	shared_ptr<SamplerState> _samplerState;
	shared_ptr<BlendState> _blendState;
private:
	//SRT scale, rotate translate
	//쉐이더단계에서 더해줄 수 있는 인자같은 존재
	TransformData _transformData;
	shared_ptr<ConstantBuffer<TransformData>> _constantBuffer;


protected:
	//개수가 고정인 
	std::array<shared_ptr<Component>, FIXED_COMPONENT_COUNT> _components;
	//개수가 동적인
	vector<shared_ptr<MonoBehaviour>> _scripts;
};

 

GameObject.cpp

#include "pch.h"
#include "GameObject.h"
#include "MonoBehaviour.h"
#include "Transform.h"

GameObject::GameObject(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext)
	:_device(device)
{
	//정점정보 - 사각형 만들기
	_geometry = make_shared<Geometry<VertexTextureData>>();
	GeometryHelper::CreateRectangle(_geometry);

	//정점버퍼
	_vertexBuffer = make_shared<VertexBuffer>(device);
	_vertexBuffer->Create(_geometry->GetVertices());

	//IndexBuffer
	_indexBuffer = make_shared<IndexBuffer>(device);
	_indexBuffer->Create(_geometry->GetIndices());

	_vertexShader = make_shared<VertexShader>(device);
	_vertexShader->Create(L"Default.hlsl", "VS", "vs_5_0");

	//인풋레이아웃
	/// <summary>
	/// 입력이 어떻게 이뤄져있는지
	/// </summary>
	_inputLayout = make_shared<InputLayout>(device);
	_inputLayout->Create(VertexTextureData::descs, _vertexShader->GetBlob());

	_pixelShader = make_shared<PixelShader>(device);
	_pixelShader->Create(L"Default.hlsl", "PS", "ps_5_0");

	_rasterizerState = make_shared<RasterizerState>(device);
	_rasterizerState->Create();

	_blendState = make_shared<BlendState>(device);
	_blendState->Create();

	_constantBuffer = make_shared<ConstantBuffer<TransformData>>(device, deviceContext);
	_constantBuffer->Create();

	_texture1 = make_shared<Texture>(device);
	_texture1->Create(L"cat.png");

	_samplerState = make_shared<SamplerState>(device);
	_samplerState->Create();

}

GameObject::~GameObject()
{
}

void GameObject::Awake()
{

}

void GameObject::Start()
{
	for (shared_ptr<Component>& component : _components)
	{
		if (component)
			component->Start();
	}

	for (shared_ptr<MonoBehaviour>& script : _scripts)
	{
		script->Start();
	}
}

void GameObject::Update()
{
	for (shared_ptr<Component>& component : _components)
	{
		if(component)
			component->Update();
	}

	for (shared_ptr<MonoBehaviour>& script : _scripts)
	{

		script->Update();
	}

	_transformData.matWorld = GetOrAddTransform()->GetWorldMatrix();
	_constantBuffer->CopyData(_transformData);
}

void GameObject::LateUpdate()
{
	for (shared_ptr<Component>& component : _components)
	{
		if (component)
			component->LateUpdate();
	}

	for (shared_ptr<MonoBehaviour>& script : _scripts)
	{
		script->LateUpdate();
	}
}

void GameObject::FixedUpdate()
{
	for (shared_ptr<Component>& component : _components)
	{
		if (component)
			component->FixedUpdate();
	}

	for (shared_ptr<MonoBehaviour>& script : _scripts)
	{
		script->FixedUpdate();
	}
}

shared_ptr<Component> GameObject::GetFixedComponent(ComponentType type)
{
	uint8 index = static_cast<uint8>(type);
	assert(index < FIXED_COMPONENT_COUNT);
	return _components[index];
}

shared_ptr<Transform> GameObject::GetTransform()
{
	shared_ptr<Component> component = GetFixedComponent(ComponentType::Transform);
	return static_pointer_cast<Transform>(component);
}

shared_ptr<Transform> GameObject::GetOrAddTransform()
{
	if (GetTransform() == nullptr)
	{
		shared_ptr<Transform> transform = make_shared<Transform>();
		AddComponent(transform);
	}

	return GetTransform();
}

void GameObject::AddComponent(shared_ptr<Component> component)
{
	component->SetGameObject(shared_from_this());
	//this를 넘겨주면 레퍼런스를 이중으로 관리하기 때문에 메모리 오염발생 가능성
	uint8 index = static_cast<uint8>(component->GetType());
	if (index < FIXED_COMPONENT_COUNT)
	{
		_components[index] = component;
	}
	else
	{
		_scripts.push_back(dynamic_pointer_cast<MonoBehaviour>(component));
	}
}

void GameObject::Render(shared_ptr<Pipeline> pipeline)
{
	PipelineInfo info;
	info.inputLayout = _inputLayout;
	info.vertexShader = _vertexShader;
	info.pixelShader = _pixelShader;
	info.rasterizerState = _rasterizerState;
	info.blendState = _blendState;
	pipeline->UpdatePipeline(info);

	pipeline->SetVertexBuffer(_vertexBuffer);
	pipeline->SetIndexBuffer(_indexBuffer);
	pipeline->SetConstantBuffer(0, SS_VertexShader, _constantBuffer);
	pipeline->SetTexture(0, SS_PixelShader, _texture1);
	pipeline->SetSamplerState(0, SS_PixelShader, _samplerState);
	pipeline->DrawIndexed(_geometry->GetIndexCount(), 0, 0);
}

 

 

이렇게 해주게 되면 이전처럼 화면이 나오게 된다.

 

3.카메라 추가

이제 카메라 컴포넌트를 추가해보자

 

카메라의 가지게 될 주요기능을 적어보자

1.카메라가 원근 투영을 하는지 직교투영을 하는지 알고 있어야한다. 

2.원근투영인지 직교투영인지에 따라 Update할 때 Matrix 또한 Update해주어야한다.

이때 카메라 변환 행렬을 계산할 때 XMMatrixLookAtLH 함수를 사용하는 방법이 있고 

월드 행렬의 역행렬을 구하는 방법도 있다. 이게 가능한 이유는 원래는 카메라를 기준으로 하는 좌표에서 월드를 기준으로

하는 좌표로 넘어가는 것이 월드 변환 행렬이었는데 거꾸로 카메라를 기준으로 하고 싶으면 역행렬을 곱해줘도 된다는 것이다.

일단은 카메라가 한개라고 가정하고 static을 통해 카메라와 관련된 행렬을 선언해주자

 

Camera.h

#pragma once
#include "Component.h"

enum class ProjectType
{
	Persperctive,		//원근투영
	Orthographic,		//직교투영
};

class Camera : public Component
{
	using Super = Component;
public:
	Camera();
	virtual ~Camera();

	virtual void Update() override;

	void SetProjectionType(ProjectType type) { _type = type; }
	ProjectType GetProjectionType() { return _type; }

	void UpdateMatrix();

private:
	ProjectType _type = ProjectType::Orthographic;

public:
	//일단 카메라가 한개라고 가정
	static Matrix S_MatView;
	static Matrix S_MatProjection;
};

 

Camera.cpp

#include "pch.h"
#include "Camera.h"

Matrix Camera::S_MatView = Matrix::Identity;
Matrix Camera::S_MatProjection = Matrix::Identity;

Camera::Camera() : Super(ComponentType::Camera)
{

}

Camera::~Camera()
{

}

void Camera::Update()
{
	UpdateMatrix();
}

void Camera::UpdateMatrix()
{
	//카메라좌표
	Vec3 eyePosition = GetTransform()->GetPosition();
	//바라보는 방향
	Vec3 focusPosition = eyePosition + GetTransform()->GetLook(); 
	//위쪽방향 - 임의로 정해줘도 된다.
	Vec3 upDirection = GetTransform()->GetUp();
	//카메라 변환행렬 계산 - 월드의 역행렬
	S_MatView = ::XMMatrixLookAtLH(eyePosition, focusPosition, upDirection);

	//방법2 - 월드의 역행렬
	//S_MatView = GetTransform()->GetWorldMatrix().Invert();

	if (_type == ProjectType::Persperctive)
	{
		//필드오브 뷰,비율,니어,파
		S_MatProjection = ::XMMatrixPerspectiveFovLH(XM_PI / 4.f, 800.f / 600.f, 1.f, 100.f);
	}
	else
	{
		//화면의 크기, 니어,파
		S_MatProjection = ::XMMatrixOrthographicLH(800, 600, 0.f, 1.f);
	}
}

 

카메라 컴포넌트가 추가되었으니 이에 맞게 기본 쉐이더 코드도 수정해주자 이때 카메라는 하나이고 물체는 여러개가 

있을 수 있으니 업데이트되는 버퍼를 따로 지정해주자

//카메라와 물체 따로 -> 카메라는 하나 물체는 계속 바꾸면서 사용
cbuffer CameraData : register(b0)
{
    row_major matrix matView;
    row_major matrix matProjection;
}

cbuffer TransformData : register(b1)
{
    row_major matrix matWorld;
}

 

이에 맞게 카메라 데이터와 TransformData를 받아주는 구조체도 수정해주자

Struct.h

#pragma once
#include "Types.h"

//
//struct Vertex
//{
//	Vec3 position;		//12바이트 0부터시작
//	//Color color;		//12부터시작
//	Vec2 uv;
//};

struct CameraData
{
	Matrix matView = Matrix::Identity;
	Matrix matProjection= Matrix::Identity;
};

struct TransformData
{
	Matrix matWorld = Matrix::Identity;
};

 

GameObject 에서도 동일하게 수정해주자 

 

GameObject.h

#pragma once

class MonoBehaviour;
class Transform;
class Camera;

class GameObject : public enable_shared_from_this<GameObject>
{
public:
	GameObject(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext);
	~GameObject();

	void Awake();
	void Start();
	void Update();
	void LateUpdate();
	void FixedUpdate();

	//헬퍼함수
	shared_ptr<Component> GetFixedComponent(ComponentType type);
	shared_ptr<Transform> GetTransform();
	shared_ptr<Camera> GetCamera();

	shared_ptr<Transform> GetOrAddTransform();
	void AddComponent(shared_ptr<Component> component);

	//..

	void Render(shared_ptr<Pipeline> pipeline);
private:
	ComPtr<ID3D11Device> _device;

	//기하학적 도형 - cpu
	//vector<Vertex> _vertices;
	//vector<uint32> _indices;

	shared_ptr<Geometry<VertexTextureData>> _geometry;

	shared_ptr<VertexBuffer> _vertexBuffer;

	//인덱스버퍼 - 이거도 Geometry에 포함
	shared_ptr<IndexBuffer> _indexBuffer;
	shared_ptr<InputLayout> _inputLayout;

	//VS
	shared_ptr<VertexShader> _vertexShader;

	//RS
	shared_ptr<RasterizerState> _rasterizerState;

	//PS
	shared_ptr<PixelShader> _pixelShader;

	//SRV - 이미지를 어떻게 쓸것인가 - 텍스처
	shared_ptr<Texture> _texture1;

	shared_ptr<SamplerState> _samplerState;
	shared_ptr<BlendState> _blendState;
private:
	//Camera
	//쉐이더단계에서 더해줄 수 있는 인자같은 존재
	CameraData _cameraData;
	shared_ptr<ConstantBuffer<CameraData>> _cameraBuffer;

	//SRT scale, rotate translate
	TransformData _transformData;
	shared_ptr<ConstantBuffer<TransformData>> _transformBuffer;

protected:
	//개수가 고정인 
	std::array<shared_ptr<Component>, FIXED_COMPONENT_COUNT> _components;
	//개수가 동적인
	vector<shared_ptr<MonoBehaviour>> _scripts;
};

 

GameObject.cpp

#include "pch.h"
#include "GameObject.h"
#include "MonoBehaviour.h"
#include "Transform.h"
#include "Camera.h"

GameObject::GameObject(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext)
	:_device(device)
{
	//정점정보 - 사각형 만들기
	_geometry = make_shared<Geometry<VertexTextureData>>();
	GeometryHelper::CreateRectangle(_geometry);

	//정점버퍼
	_vertexBuffer = make_shared<VertexBuffer>(device);
	_vertexBuffer->Create(_geometry->GetVertices());

	//IndexBuffer
	_indexBuffer = make_shared<IndexBuffer>(device);
	_indexBuffer->Create(_geometry->GetIndices());

	_vertexShader = make_shared<VertexShader>(device);
	_vertexShader->Create(L"Default.hlsl", "VS", "vs_5_0");

	//인풋레이아웃
	/// <summary>
	/// 입력이 어떻게 이뤄져있는지
	/// </summary>
	_inputLayout = make_shared<InputLayout>(device);
	_inputLayout->Create(VertexTextureData::descs, _vertexShader->GetBlob());

	_pixelShader = make_shared<PixelShader>(device);
	_pixelShader->Create(L"Default.hlsl", "PS", "ps_5_0");

	_rasterizerState = make_shared<RasterizerState>(device);
	_rasterizerState->Create();

	_blendState = make_shared<BlendState>(device);
	_blendState->Create();

	_transformBuffer = make_shared<ConstantBuffer<TransformData>>(device, deviceContext);
	_transformBuffer->Create();

	_cameraBuffer = make_shared<ConstantBuffer<CameraData>>(device, deviceContext);
	_cameraBuffer->Create();

	_texture1 = make_shared<Texture>(device);
	_texture1->Create(L"cat.png");

	_samplerState = make_shared<SamplerState>(device);
	_samplerState->Create();

}

GameObject::~GameObject()
{
}

void GameObject::Awake()
{

}

void GameObject::Start()
{
	for (shared_ptr<Component>& component : _components)
	{
		if (component)
			component->Start();
	}

	for (shared_ptr<MonoBehaviour>& script : _scripts)
	{
		script->Start();
	}
}

void GameObject::Update()
{
	for (shared_ptr<Component>& component : _components)
	{
		if (component)
			component->Update();
	}

	for (shared_ptr<MonoBehaviour>& script : _scripts)
	{

		script->Update();
	}

	//TMP
	if (GetCamera())
		return;

	_cameraData.matView = Camera::S_MatView;
	_cameraData.matProjection = Camera::S_MatProjection;
	_cameraBuffer->CopyData(_cameraData);

	_transformData.matWorld = GetOrAddTransform()->GetWorldMatrix();
	_transformBuffer->CopyData(_transformData);
}

void GameObject::LateUpdate()
{
	for (shared_ptr<Component>& component : _components)
	{
		if (component)
			component->LateUpdate();
	}

	for (shared_ptr<MonoBehaviour>& script : _scripts)
	{
		script->LateUpdate();
	}
}

void GameObject::FixedUpdate()
{
	for (shared_ptr<Component>& component : _components)
	{
		if (component)
			component->FixedUpdate();
	}

	for (shared_ptr<MonoBehaviour>& script : _scripts)
	{
		script->FixedUpdate();
	}
}

shared_ptr<Component> GameObject::GetFixedComponent(ComponentType type)
{
	uint8 index = static_cast<uint8>(type);
	assert(index < FIXED_COMPONENT_COUNT);
	return _components[index];
}

shared_ptr<Transform> GameObject::GetTransform()
{
	shared_ptr<Component> component = GetFixedComponent(ComponentType::Transform);
	return static_pointer_cast<Transform>(component);
}

shared_ptr<Camera> GameObject::GetCamera()
{
	shared_ptr<Component> component = GetFixedComponent(ComponentType::Camera);
	return static_pointer_cast<Camera>(component);
}

shared_ptr<Transform> GameObject::GetOrAddTransform()
{
	if (GetTransform() == nullptr)
	{
		shared_ptr<Transform> transform = make_shared<Transform>();
		AddComponent(transform);
	}

	return GetTransform();
}

void GameObject::AddComponent(shared_ptr<Component> component)
{
	component->SetGameObject(shared_from_this());
	//this를 넘겨주면 레퍼런스를 이중으로 관리하기 때문에 메모리 오염발생 가능성
	uint8 index = static_cast<uint8>(component->GetType());
	if (index < FIXED_COMPONENT_COUNT)
	{
		_components[index] = component;
	}
	else
	{
		_scripts.push_back(dynamic_pointer_cast<MonoBehaviour>(component));
	}
}

void GameObject::Render(shared_ptr<Pipeline> pipeline)
{
	PipelineInfo info;
	info.inputLayout = _inputLayout;
	info.vertexShader = _vertexShader;
	info.pixelShader = _pixelShader;
	info.rasterizerState = _rasterizerState;
	info.blendState = _blendState;
	pipeline->UpdatePipeline(info);

	pipeline->SetVertexBuffer(_vertexBuffer);
	pipeline->SetIndexBuffer(_indexBuffer);

	pipeline->SetConstantBuffer(0, SS_VertexShader, _cameraBuffer);
	pipeline->SetConstantBuffer(1, SS_VertexShader, _transformBuffer);

	pipeline->SetTexture(0, SS_PixelShader, _texture1);
	pipeline->SetSamplerState(0, SS_PixelShader, _samplerState);

	pipeline->DrawIndexed(_geometry->GetIndexCount(), 0, 0);
}

이렇게 해주게 되면 아직은 아무것도 안보이게 된다. 왜냐하면 지금 설정해둔 카메라의 윈도우 크기가 너무 크게 설정되어 있어서 물체가 거의 안보이는 것이다.
물체가 보이게 되려면 물체자체의 크기를 키우거나 윈도우사이즈를 작게 조정하면 된다.

지금은 Camera 코드에서 카메라 뷰포트의 크기를 조절해보자

Camera.cpp


	if (_type == ProjectType::Persperctive)
	{
		//필드오브 뷰,비율,니어,파
		S_MatProjection = ::XMMatrixPerspectiveFovLH(XM_PI / 4.f, 800.f / 600.f, 1.f, 100.f);
	}
	else
	{
		//화면의 크기, 니어,파
		S_MatProjection = ::XMMatrixOrthographicLH(8, 6, 0.f, 1.f);
	}

 

이렇게 해주게되면 작지만 고양이가 보이게 된다.

 

이제 GameObject에서 가지고 있던 렌더링부분을 따로 빼주도록 하자

MeshRenderer라는 클래스로 따로 만들어 줄텐데 이 컴포넌트를 가지고있는 GameObject만이 렌더링 파이프라인을 거쳐

보일 수 있도록하자.

GameObjct의 렌더부분을 모두 MeshRenderer로 가져온 뒤 코드를 정리해주자

지금은 렌더링부분을 모두가 넣어줄 것이지만 나중에 물체에 종속적인 부분과 공통적인 부분을 나눠볼 것이다. 

MeshRenderer.h

#pragma once
#include "Component.h"
class MeshRenderer : public Component
{
	using Super = Component;
public:
	MeshRenderer(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext);
	virtual ~MeshRenderer();

	virtual void Update() override;
	void Render(shared_ptr<Pipeline> pipeline);
private:
	ComPtr<ID3D11Device> _device;

	shared_ptr<Geometry<VertexTextureData>> _geometry;

	shared_ptr<VertexBuffer> _vertexBuffer;

	//인덱스버퍼 - 이거도 Geometry에 포함
	shared_ptr<IndexBuffer> _indexBuffer;
	shared_ptr<InputLayout> _inputLayout;

	//VS
	shared_ptr<VertexShader> _vertexShader;

	//RS
	shared_ptr<RasterizerState> _rasterizerState;

	//PS
	shared_ptr<PixelShader> _pixelShader;

	//SRV - 이미지를 어떻게 쓸것인가 - 텍스처
	shared_ptr<Texture> _texture1;

	shared_ptr<SamplerState> _samplerState;
	shared_ptr<BlendState> _blendState;

private:
	//Camera
	//쉐이더단계에서 더해줄 수 있는 인자같은 존재
	CameraData _cameraData;
	shared_ptr<ConstantBuffer<CameraData>> _cameraBuffer;

	//SRT scale, rotate translate
	TransformData _transformData;
	shared_ptr<ConstantBuffer<TransformData>> _transformBuffer;
};

 

MeshRenderer.cpp

#include "pch.h"
#include "MeshRenderer.h"
#include "Camera.h"

MeshRenderer::MeshRenderer(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext) 
	: Super(ComponentType::MeshRenderer), _device(device)
{
	//정점정보 - 사각형 만들기
	_geometry = make_shared<Geometry<VertexTextureData>>();
	GeometryHelper::CreateRectangle(_geometry);

	//정점버퍼
	_vertexBuffer = make_shared<VertexBuffer>(device);
	_vertexBuffer->Create(_geometry->GetVertices());

	//IndexBuffer
	_indexBuffer = make_shared<IndexBuffer>(device);
	_indexBuffer->Create(_geometry->GetIndices());

	_vertexShader = make_shared<VertexShader>(device);
	_vertexShader->Create(L"Default.hlsl", "VS", "vs_5_0");

	//인풋레이아웃
	/// <summary>
	/// 입력이 어떻게 이뤄져있는지
	/// </summary>
	_inputLayout = make_shared<InputLayout>(device);
	_inputLayout->Create(VertexTextureData::descs, _vertexShader->GetBlob());

	_pixelShader = make_shared<PixelShader>(device);
	_pixelShader->Create(L"Default.hlsl", "PS", "ps_5_0");

	_rasterizerState = make_shared<RasterizerState>(device);
	_rasterizerState->Create();

	_blendState = make_shared<BlendState>(device);
	_blendState->Create();

	_transformBuffer = make_shared<ConstantBuffer<TransformData>>(device, deviceContext);
	_transformBuffer->Create();

	_cameraBuffer = make_shared<ConstantBuffer<CameraData>>(device, deviceContext);
	_cameraBuffer->Create();

	_texture1 = make_shared<Texture>(device);
	_texture1->Create(L"cat.png");

	_samplerState = make_shared<SamplerState>(device);
	_samplerState->Create();
}

MeshRenderer::~MeshRenderer()
{

}

void MeshRenderer::Update()
{
	_cameraData.matView = Camera::S_MatView;
	//_cameraData.matView = Matrix::Identity;
	_cameraData.matProjection = Camera::S_MatProjection;
	//_cameraData.matProjection = Matrix::Identity;
	_cameraBuffer->CopyData(_cameraData);

	_transformData.matWorld = GetTransform()->GetWorldMatrix();
	_transformBuffer->CopyData(_transformData);


	//Render
}

void MeshRenderer::Render(shared_ptr<Pipeline> pipeline)
{
	PipelineInfo info;
	info.inputLayout = _inputLayout;
	info.vertexShader = _vertexShader;
	info.pixelShader = _pixelShader;
	info.rasterizerState = _rasterizerState;
	info.blendState = _blendState;
	pipeline->UpdatePipeline(info);

	pipeline->SetVertexBuffer(_vertexBuffer);
	pipeline->SetIndexBuffer(_indexBuffer);

	pipeline->SetConstantBuffer(0, SS_VertexShader, _cameraBuffer);
	pipeline->SetConstantBuffer(1, SS_VertexShader, _transformBuffer);

	pipeline->SetTexture(0, SS_PixelShader, _texture1);
	pipeline->SetSamplerState(0, SS_PixelShader, _samplerState);

	pipeline->DrawIndexed(_geometry->GetIndexCount(), 0, 0);
}

 

이렇게 하고 GameObject에서 MeshRenderer를 가져올 수 있게 헬퍼함수를 추가해주자

GameObject.cpp

shared_ptr<MeshRenderer> GameObject::GetMeshRenderer()
{
	shared_ptr<Component> component = GetFixedComponent(ComponentType::MeshRenderer);
	return static_pointer_cast<MeshRenderer>(component);
}

 

마지막으로 정상적으로 작동할 수 있도록 Game 즉 메인 코드에서 cat부분에 Renderer component를 추가해주고 Render부분 코드도 수정해주자 

Game.cpp

#include "pch.h"
#include "Game.h"
#include "Camera.h"
#include "MeshRenderer.h"

Game::Game()
{
}

Game::~Game()
{
}

void Game::Init(HWND hwnd)
{
	_hwnd = hwnd;

	_graphics = make_shared<Graphics>(hwnd);
	_pipeline = make_shared<Pipeline>(_graphics->GetDeviceContext());

	//GO
	_cat = make_shared<GameObject>(_graphics->GetDevice(), _graphics->GetDeviceContext());
	{
		_cat->GetOrAddTransform();
		_cat->AddComponent(make_shared<MeshRenderer>(_graphics->GetDevice(), _graphics->GetDeviceContext()));
		//_cat->GetTransform()->GetScale(Vec3(100.f,100.f,100.f));
		//...
	}
	_camera = make_shared<GameObject>(_graphics->GetDevice(), _graphics->GetDeviceContext());
	{
		_camera->GetOrAddTransform();
		_camera->AddComponent(make_shared<Camera>());
	}
}

void Game::Update()
{
	_cat->Update();



	_camera->Update();
}

void Game::Render()
{
	_graphics->RenderBegin();			//초기화

	auto _deviceContext = _graphics->GetDeviceContext();
	// IA - VS - RS - PS -OM
	//TODO : 그리기
	{
		//TMP
		_cat->GetMeshRenderer()->Render(_pipeline);
	}

	_graphics->RenderEnd();			//제출
}

 

이렇게 하면 고양이가 출력된다.

+ Recent posts