오늘은 3D에 들어가기에 앞서 기존에 했던 것을 복습해보자.

 

1.사각형그리기

먼저 사각형을 그려볼 것이다. 사각형은 삼각형을 그렸던 코드와 쉐이더 fx 파일을 바탕으로 구현해보자.

일단 사각형을 만들 때 삼각형 2개를 결합해서 사용할 수도 있고 인덱스버퍼를 활용하여 순서를 맞춰줘서 사각형을

완성하는 방식도 있다. 

지금은 이전에 했던 방식처럼 4개의 점과 인덱스를 통해 사각형을 만들어보자 

GeometryHelper 클래스를 만들어서 사각형의 정점정보와 인덱스 정보를 생성해주는 함수를 만들어주자 

어떤방식으로 사각형을 만들어줄지 VertexData에서 구조체를 선택해줘야하는데

지금은 정점과 Color를 가지고 있는 VertexColor 구조체를 통해 사각형을 만들어주자

GeometryHelper

#pragma once
#include "Geometry.h"
#include "VertexData.h"

class GeometryHelper
{
public:
	static void CreateQuad(shared_ptr<Geometry<VertexColorData>> geometry, Color color);
};

 

GeometryHelper

#include "pch.h"
#include "GeometryHelper.h"

void GeometryHelper::CreateQuad(shared_ptr<Geometry<VertexColorData>> geometry, Color color)
{
	vector<VertexColorData> vtx;
	//인덱스버퍼포함
	vtx.resize(4);

	
	vtx[0].position = Vec3(-0.5f, -0.5f, 0.f);
	vtx[0].color = color;
	vtx[1].position = Vec3(-0.5f, 0.5f, 0.f);
	vtx[1].color = color;
	vtx[2].position = Vec3(0.5f, -0.5f, 0.f);
	vtx[2].color = color;
	vtx[3].position = Vec3(0.5f, 0.5f, 0.f);
	vtx[3].color = color;
	geometry->SetVertices(vtx);

	//1 3	보통 시계방향
	//0 2
	vector<uint32> idx = { 0,1,2,2,1,3 };
	geometry->SetIndices(idx);
}

 

만들어준 GeometryHelper를 QuadDemo 클래스에서 호출해서 사각형을 그려줄 수 있도록하자

이때 geometry가 정점의 위치와 색깔을 가진 VertexColorData 구조체를 통해 선언해주고

정점버퍼와 인덱스버퍼를 만들어주고 복사 및 설정을 해주어야한다.

그리고 VertexColorData에 맞게 쉐이더도 새로 만들어주자 

Quad.fx

struct VertexInput
{
	float4 position : POSITION;
    float4 color : COLOR;
};

struct VertexOutput
{
	float4 position : SV_POSITION;
    float4 color : COLOR;
};

VertexOutput VS(VertexInput input)
{
	VertexOutput output;
	output.position = input.position;
    output.color = input.color;

	return output;
}

float4 PS(VertexOutput input) : SV_TARGET
{
    return input.color;
}

//와이어프레임모드
RasterizerState FillModeWireFrame
{
    FillMode = Wireframe;
};

technique11 T0
{
	//하나의 통로
	pass P0
	{
		SetVertexShader(CompileShader(vs_5_0, VS()));
		SetPixelShader(CompileShader(ps_5_0, PS()));
	}

	pass P1
	{
        SetRasterizerState(FillModeWireFrame); 
		SetVertexShader(CompileShader(vs_5_0, VS()));
		SetPixelShader(CompileShader(ps_5_0, PS()));
	}
};

QuadDemo.h

#pragma once
#include "IExecute.h"
#include "Geometry.h"

class QuadDemo : public IExecute
{
public:
	void Init() override;
	void Update() override;
	void Render() override;


	shared_ptr<Shader> _shader;
	
	shared_ptr<Geometry<VertexColorData>> _geometry;

	shared_ptr<VertexBuffer> _vertexBuffer;
	shared_ptr<IndexBuffer> _indexBuffer;
};

QuadDemo.cpp

#include "pch.h"
#include "02. QuadDemo.h"
#include "GeometryHelper.h"

void QuadDemo::Init()
{
	_shader = make_shared<Shader>(L"02. Quad.fx");

	_geometry = make_shared<Geometry<VertexColorData>>();
	GeometryHelper::CreateQuad(_geometry, Color(1.f, 0.f, 0.f, 1.f));

	//고속복사
	_vertexBuffer = make_shared<VertexBuffer>();
	_vertexBuffer->Create(_geometry->GetVertices());

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

void QuadDemo::Update()
{

}

void QuadDemo::Render()
{
	uint32 stride = _vertexBuffer->GetStride();
	uint32 offset = _vertexBuffer->GetOffset();

	DC->IASetVertexBuffers(0, 1, _vertexBuffer->GetComPtr().GetAddressOf(), &stride, &offset);
	DC->IASetIndexBuffer(_indexBuffer->GetComPtr().Get(), DXGI_FORMAT_R32_UINT, 0);
	
	//_buffer->GetCount()
	_shader->DrawIndexed(0, 0, _indexBuffer->GetCount(), 0, 0);
}

 

마지막으로 Main 클래스에서 QuadDemo의 단계가 실행되도록 코드를 수정해주자

Main.cpp

#include "pch.h"
#include "Main.h"
#include "Engine/Game.h"
#include "01. TriangleDemo.h"
#include "02. QuadDemo.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	GameDesc desc;
	desc.appName = L"GameCoding";
	desc.hInstance = hInstance;
	desc.vsync = false;
	desc.hWnd = NULL;
	desc.width = 800;
	desc.height = 600;
	desc.clearColor = Color(0.5f, 0.5f, 0.5f, 0.5f);
	//실행단위
	desc.app = make_shared<QuadDemo>();

	GAME->Run(desc);

	return 0;
}

 

이렇게 해주면 사각형이 나오게 된다.

 

이때 Draw 함수에서 두번째 매개변수를 1으로 바꿔주면 1번 pass가 실행되며 사각형의 와이어프레임 즉 선만 보이게 된다.

 

2.Constant Buffer

이제 Constant Buffer을 통해 움직이는 사각형을 만들어보자 

이때 shader를 받아주는 fx에서 Matrix를 선언해주고 이를 곱해주는 방식으로 해주면 된다.

그리고 Update를 통해 받는 키에 따라 delta time과 스피드를 통해 움직이도록 해주고 이를 translation matrix를 통해

World 행렬에 적용해주고 이를 shader 변수의 GetMatrix로 shader쪽의 Matrix를 가져오고 이 Matrix를 Set해주면 된다.

ConstBuffer.fx

matrix World;
matrix View;
matrix Projection;

struct VertexInput
{
	float4 position : POSITION;
    float4 color : COLOR;
};

struct VertexOutput
{
	float4 position : SV_POSITION;
    float4 color : COLOR;
};

VertexOutput VS(VertexInput input)
{
	VertexOutput output;
    output.position = mul(input.position,World);
    output.position = mul(output.position, View);
    output.position = mul(output.position, Projection);
	

    output.color = input.color;

	return output;
}

float4 PS(VertexOutput input) : SV_TARGET
{
    return input.color;
}

//와이어프레임모드
RasterizerState FillModeWireFrame
{
    FillMode = Wireframe;
};

technique11 T0
{
	//하나의 통로
	pass P0
	{
		SetVertexShader(CompileShader(vs_5_0, VS()));
		SetPixelShader(CompileShader(ps_5_0, PS()));
	}

	pass P1
	{
        SetRasterizerState(FillModeWireFrame); 
		SetVertexShader(CompileShader(vs_5_0, VS()));
		SetPixelShader(CompileShader(ps_5_0, PS()));
	}
};

ConstBufferDemo.h

#pragma once
#include "IExecute.h"
#include "Geometry.h"

class ConstBufferDemo : public IExecute
{
public:
	void Init() override;
	void Update() override;
	void Render() override;


	shared_ptr<Shader> _shader;
	
	shared_ptr<Geometry<VertexColorData>> _geometry;

	shared_ptr<VertexBuffer> _vertexBuffer;
	shared_ptr<IndexBuffer> _indexBuffer;

	Vec3 _translation = Vec3(0.f, 0.f, 0.f);

	Matrix _world=Matrix::Identity;
	Matrix _view = Matrix::Identity;
	Matrix _projection = Matrix::Identity;
};

 

ConstBufferDemo.cpp

#include "pch.h"
#include "03. ConstBufferDemo.h"
#include "GeometryHelper.h"

void ConstBufferDemo::Init()
{
	_shader = make_shared<Shader>(L"03. ConstBuffer.fx");

	_geometry = make_shared<Geometry<VertexColorData>>();
	GeometryHelper::CreateQuad(_geometry, Color(1.f, 0.f, 0.f, 1.f));

	//고속복사
	_vertexBuffer = make_shared<VertexBuffer>();
	_vertexBuffer->Create(_geometry->GetVertices());

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

void ConstBufferDemo::Update()
{
	float dt = TIME->GetDeltaTime();

	if (INPUT->GetButton(KEY_TYPE::A)) 
	{
		_translation.x -= 3.f * dt;
	}
	else if (INPUT->GetButton(KEY_TYPE::D))
	{
		_translation.x += 3.f * dt;
	}
	else if (INPUT->GetButton(KEY_TYPE::W))
	{
		_translation.y += 3.f * dt;
	}
	else if (INPUT->GetButton(KEY_TYPE::S))
	{
		_translation.y -= 3.f * dt;
	}

	//SRT
	_world = Matrix::CreateTranslation(_translation);
}

void ConstBufferDemo::Render()
{

	_shader->GetMatrix("World")->SetMatrix((float*)&_world);
	_shader->GetMatrix("View")->SetMatrix((float*)&_view);
	_shader->GetMatrix("Projection")->SetMatrix((float*)&_projection);

	uint32 stride = _vertexBuffer->GetStride();
	uint32 offset = _vertexBuffer->GetOffset();

	DC->IASetVertexBuffers(0, 1, _vertexBuffer->GetComPtr().GetAddressOf(), &stride, &offset);
	DC->IASetIndexBuffer(_indexBuffer->GetComPtr().Get(), DXGI_FORMAT_R32_UINT, 0);
	
	//_buffer->GetCount()
	_shader->DrawIndexed(0, 0, _indexBuffer->GetCount(), 0, 0);
}

 

Main.cpp

#include "pch.h"
#include "Main.h"
#include "Engine/Game.h"
#include "01. TriangleDemo.h"
#include "02. QuadDemo.h"
#include "03. ConstBufferDemo.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	GameDesc desc;
	desc.appName = L"GameCoding";
	desc.hInstance = hInstance;
	desc.vsync = false;
	desc.hWnd = NULL;
	desc.width = 800;
	desc.height = 600;
	desc.clearColor = Color(0.5f, 0.5f, 0.5f, 0.5f);
	//실행단위
	desc.app = make_shared<ConstBufferDemo>();

	GAME->Run(desc);

	return 0;
}

 

이렇게 해주면 사각형이 움직인다.

 

3.Camera

카메라를 구현하기 위한 기본 코드는 이전 2D에서 했던 코드를 가져오지만 Camera부분에서 3D에기 때문에원근투영만 되는 카메라로 바꿔주도록하자 

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 UpdateMatrix();

	void SetNear(float value) { _near = value; }
	void SetFar(float value) { _far = value; }
	void SetFOV(float value) { _fov = value; }
	void SetWidth(float value) { _width = value; }
	void SetHeight(float value) { _height = value; }

	Matrix& GetViewMatrix() { return _matview; }
	Matrix& GetProjectionMatrix() { return _matProjection; }
	

private:
	Matrix _matview = Matrix::Identity;
	Matrix _matProjection = Matrix::Identity;

	float _near = 1.f;
	float _far = 1000.f;
	float _fov = XM_PI / 4.f;
	float _width = 0.f;
	float _height = 0.f;
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)
{
	_width = static_cast<float>(GAME->GetGameDesc().width);
	_height = static_cast<float>(GAME->GetGameDesc().height);
}

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);

	//월드의 역행렬
	//S_MatView = GetTransform()->GetWorldMatrix().Invert();
	
	//필드오브 뷰,비율,니어,파
	S_MatProjection = ::XMMatrixPerspectiveFovLH(_fov, _width / _height, _near, _far);
}

 

그리고 카메라를 움직일때 바로 CameraDemo의 Update에서 작동시키는 것이아닌 Camera라는 오브젝트 하나를 만든다음 거기에 스크립트를 붙여서 작동하게 만들어주자 

CameraScript.h

#pragma once
#include "MonoBehaviour.h"

class CameraScript : public MonoBehaviour
{
public:
	virtual void Start() override;
	virtual void Update() override;

	float _speed = 10.f;
};

CameraScript.cpp

#include "pch.h"
#include "CameraScript.h"
#include "Transform.h"

void CameraScript::Start()
{

}

void CameraScript::Update()
{
	float dt = TIME->GetDeltaTime();

	Vec3 pos = GetTransform()->GetPosition();

	if (INPUT->GetButton(KEY_TYPE::W))
		pos += GetTransform()->GetLook() * _speed * dt;
	
	if (INPUT->GetButton(KEY_TYPE::S))
		pos -= GetTransform()->GetLook() * _speed * dt;

	if (INPUT->GetButton(KEY_TYPE::A))
		pos -= GetTransform()->GetRight() * _speed * dt;

	if (INPUT->GetButton(KEY_TYPE::D))
		pos += GetTransform()->GetLook() * _speed * dt;

	GetTransform()->SetPosition(pos);

	if (INPUT->GetButton(KEY_TYPE::Q))
	{
		Vec3 rotation = GetTransform()->GetLocalRotation();
		rotation.x -= dt * 0.5f;
		GetTransform()->SetLocalRotation(rotation);
	}

	if (INPUT->GetButton(KEY_TYPE::E))
	{
		Vec3 rotation = GetTransform()->GetLocalRotation();
		rotation.x += dt * 0.5f;
		GetTransform()->SetLocalRotation(rotation);
	}

	if (INPUT->GetButton(KEY_TYPE::Z))
	{
		Vec3 rotation = GetTransform()->GetLocalRotation();
		rotation.y -= dt * 0.5f;
		GetTransform()->SetLocalRotation(rotation);
	}

	if (INPUT->GetButton(KEY_TYPE::C))
	{
		Vec3 rotation = GetTransform()->GetLocalRotation();
		rotation.y += dt * 0.5f;
		GetTransform()->SetLocalRotation(rotation);
	}


}

 

이제 메인코드와 CameraDemo 코드를 수정해주자

카메라라는 이름의 게임오브젝트에 만들어준 CameraScript를 붙여주고 Update에서는 카메라 오브젝트의 Update가 작동

하도록 하면 된다.

CameraDemo.h

#pragma once

#include "IExecute.h"
#include "Geometry.h"

class CameraDemo : public IExecute
{
public:
	void Init() override;
	void Update() override;
	void Render() override;


	shared_ptr<Shader> _shader;
	
	// Object
	shared_ptr<Geometry<VertexColorData>> _geometry;
	shared_ptr<VertexBuffer> _vertexBuffer;
	shared_ptr<IndexBuffer> _indexBuffer;


	Matrix _world=Matrix::Identity;
	Matrix _view = Matrix::Identity;
	Matrix _projection = Matrix::Identity;

	//Camera
	shared_ptr<GameObject> _camera;
};

CameraDemo.cpp

#include "pch.h"
#include "04. CameraDemo.h"
#include "GeometryHelper.h"
#include "Camera.h"
#include "CameraScript.h"

void CameraDemo::Init()
{
	_shader = make_shared<Shader>(L"03. ConstBuffer.fx");

	_geometry = make_shared<Geometry<VertexColorData>>();
	GeometryHelper::CreateQuad(_geometry, Color(1.f, 0.f, 0.f, 1.f));

	//고속복사
	_vertexBuffer = make_shared<VertexBuffer>();
	_vertexBuffer->Create(_geometry->GetVertices());

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

	// Camera
	_camera = make_shared<GameObject>();
	_camera->GetOrAddTransform();
	_camera->AddComponent(make_shared<Camera>());
	_camera->AddComponent(make_shared<CameraScript>());
}

void CameraDemo::Update()
{
	_camera->Update();
}

void CameraDemo::Render()
{
	_shader->GetMatrix("World")->SetMatrix((float*)&_world);
	_shader->GetMatrix("View")->SetMatrix((float*)&Camera::S_MatView);
	_shader->GetMatrix("Projection")->SetMatrix((float*)&Camera::S_MatProjection);

	uint32 stride = _vertexBuffer->GetStride();
	uint32 offset = _vertexBuffer->GetOffset();

	DC->IASetVertexBuffers(0, 1, _vertexBuffer->GetComPtr().GetAddressOf(), &stride, &offset);
	DC->IASetIndexBuffer(_indexBuffer->GetComPtr().Get(), DXGI_FORMAT_R32_UINT, 0);
	
	//_buffer->GetCount()
	_shader->DrawIndexed(0, 0, _indexBuffer->GetCount(), 0, 0);
}

 

Main.cpp

#include "pch.h"
#include "Main.h"
#include "Engine/Game.h"
#include "01. TriangleDemo.h"
#include "02. QuadDemo.h"
#include "03. ConstBufferDemo.h"
#include "04. CameraDemo.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	GameDesc desc;
	desc.appName = L"GameCoding";
	desc.hInstance = hInstance;
	desc.vsync = false;
	desc.hWnd = NULL;
	desc.width = 800;
	desc.height = 600;
	desc.clearColor = Color(0.5f, 0.5f, 0.5f, 0.5f);
	//실행단위
	desc.app = make_shared<CameraDemo>();

	GAME->Run(desc);

	return 0;
}

 

이렇게 해주면 이제 카메라가 움직일 수 있게 된다.

+ Recent posts