[CPP] 소프트웨어 렌더링(크자이공부)

라멘커비·2024년 3월 19일
0

DirectX 2D

목록 보기
2/24

std::weak_ptr

언리얼은 자동으로 shared_ptr
서로가 서로를 알아야하는 순환 참조가 필요한 경우에 쓰는 ptr이 또 있음 std::weak_ptr
어제 코드에서 클래스 내부 shared_ptr을 weak_ptr로 바꾸면 이제 leak 안 남음
weak_ptr은 레퍼런스 카운팅에 영향 안 준다고 함.

일반 포인터는 스레드(thread)에 안전하지 않음.

소프트웨어 렌더링

화면에 무언가를 그린다고 생각할 때 그려지는 것들은 픽셀 덩어리임. 삼각형을 그린다고 하면 삼각형에 건져지는(?) 픽셀들의 색을 바꾸는 것.
모니터 화면 안에 도형을 표현하기 위한 점을 버텍스Vertex라고 부른다.
초기에 있는 점들의 집합?을 Mesh라고 부름.
최초의 메쉬를 만들 때는 원점을 기준으로 만들어져야 한다. 원본 메쉬를 회전하고 싶거나 할 때 원본을 수정하면 안 된다. 렌더링메쉬를 따로 두고 거기서 함.
메쉬 변환 순서는 회전 -> 이동이 되어야 특정 자리에서 회전하는 도형을 그릴 수 있음. 반대로하면 원점 기준으로 뺑뺑이 돌게 된다.

  • 삼각형 그려서 회전시키고 이동시키는 코드
FTransform Transform;
float Speed = 100.0f;
float RotSpeed = 360.0f;
void USoftRenderingLevel::Render(float _DeltaTime)
{
	ULevel::Render(_DeltaTime);

	std::shared_ptr<UWindowImage> Image = GEngine->MainWindow.GetBackBufferImage();
	HDC DC = Image->GetImageDC();


	// 최초의 도형을 만들때는 언제나 원점을 기준으로 만들어야 한다.
	// 기본적으로 이녀석은 FBX파일이나 매쉬파일
	std::vector<std::vector<FVector>> Mesh =
	{
		{ {0.0, -50.0f}, {-50.0f, 50.0f}, {50.0f, 50.0f} },
		{ { 0.0, -45.0f }, { 0.0, -55.0f }, { 0.0, -45.0f } },
	};


	if (UEngineInput::IsPress('Q'))
	{
		Transform.AddRotation(FVector(0.0f, 0.0f, 1.0f) *RotSpeed* _DeltaTime);
	}

	if (UEngineInput::IsPress('E'))
	{
		Transform.AddRotation(FVector(0.0f, 0.0f, -1.0f) * RotSpeed * _DeltaTime);
	}

	if (UEngineInput::IsPress('W'))
	{
		Transform.AddPosition(FVector::Up *RotSpeed * _DeltaTime);
	}

	if (UEngineInput::IsPress('S'))
	{
		Transform.AddPosition(FVector::Down * Speed * _DeltaTime);
	}

	if (UEngineInput::IsPress('A'))
	{
		Transform.AddPosition(FVector::Left * Speed * _DeltaTime);
	}


	if (UEngineInput::IsPress('D'))
	{
		Transform.AddPosition(FVector::Right * Speed * _DeltaTime);
	}

	std::vector<std::vector<FVector>> RenderingMesh = Mesh;

	// 변환의 순서는 먼저 회전
	for (size_t TriCount = 0; TriCount < RenderingMesh.size(); TriCount++)
	{
		for (size_t VertexCount = 0; VertexCount < RenderingMesh[TriCount].size(); VertexCount++)
		{
			RenderingMesh[TriCount][VertexCount].RotationZToDeg(Transform.GetRotation().Z);
		}
	}

	// 그리고 이동
	for (size_t TriCount = 0; TriCount < RenderingMesh.size(); TriCount++)
	{
		for (size_t VertexCount = 0; VertexCount < RenderingMesh[TriCount].size(); VertexCount++)
		{
			RenderingMesh[TriCount][VertexCount] += Transform.GetPosition();
		}
	}
	

	std::vector < std::vector<POINT>> WinApiPoints;
	WinApiPoints.resize(RenderingMesh.size());
	for (size_t TriCount = 0; TriCount < RenderingMesh.size(); TriCount++)
	{
		WinApiPoints[TriCount].resize(RenderingMesh[TriCount].size());
		for (size_t VertexCount = 0; VertexCount < RenderingMesh[TriCount].size(); VertexCount++)
		{
			WinApiPoints[TriCount][VertexCount] = RenderingMesh[TriCount][VertexCount].ConvertToWinApiPOINT();
		}
	}

	for (size_t TriCount = 0; TriCount < WinApiPoints.size(); TriCount++)
	{
		POINT& StartPoint = WinApiPoints[TriCount][0];
		Polygon(DC, &StartPoint, 3);
	}
}
  • 실행 모습
    이동, 회전 잘 됨

크자이공부 => 월드 변환

크기, 자전, 이동, 공전, 부모 순서로 변환시켜야 한다.

Scale 곱하는 걸 행렬로 바꾸면

근데 지금은 1x4 * 4x1 행렬 곱하기처럼 계산하기 때문에 직관적임. 나중에는 곱하기를 행렬로 하는 게 편하다.

	Scale.Scale(Transform.GetScale());
	
	// 크기변환
	// RenderingMesh[0][0].x == -0.5 * 100
	for (size_t TriCount = 0; TriCount < RenderingMesh.size(); TriCount++)
	{
		for (size_t VertexCount = 0; VertexCount < RenderingMesh[TriCount].size(); VertexCount++)
		{
			// 완전한 3차원 변환이 되려면
			RenderingMesh[TriCount][VertexCount] *= Scale;
		}
	}
float4 float4::operator*(const float4x4& _Other) const
{
	float4 Result;
	Result.X = (Arr2D[0][0] * _Other.Arr2D[0][0]) + (Arr2D[0][1] * _Other.Arr2D[1][0]) + (Arr2D[0][2] * _Other.Arr2D[2][0]) + (Arr2D[0][3] * _Other.Arr2D[3][0]);
	Result.Y = (Arr2D[0][0] * _Other.Arr2D[0][1]) + (Arr2D[0][1] * _Other.Arr2D[1][1]) + (Arr2D[0][2] * _Other.Arr2D[2][1]) + (Arr2D[0][3] * _Other.Arr2D[3][1]);
	Result.Z = (Arr2D[0][0] * _Other.Arr2D[0][2]) + (Arr2D[0][1] * _Other.Arr2D[1][2]) + (Arr2D[0][2] * _Other.Arr2D[2][2]) + (Arr2D[0][3] * _Other.Arr2D[3][2]);
	Result.W = (Arr2D[0][0] * _Other.Arr2D[0][3]) + (Arr2D[0][1] * _Other.Arr2D[1][3]) + (Arr2D[0][2] * _Other.Arr2D[2][3]) + (Arr2D[0][3] * _Other.Arr2D[3][3]);
	return Result;
}

float4& float4::operator*=(const class float4x4& _Other) 
{
	float4 Result;
	Result.X = (Arr2D[0][0] * _Other.Arr2D[0][0]) + (Arr2D[0][1] * _Other.Arr2D[1][0]) + (Arr2D[0][2] * _Other.Arr2D[2][0]) + (Arr2D[0][3] * _Other.Arr2D[3][0]);
	Result.Y = (Arr2D[0][0] * _Other.Arr2D[0][1]) + (Arr2D[0][1] * _Other.Arr2D[1][1]) + (Arr2D[0][2] * _Other.Arr2D[2][1]) + (Arr2D[0][3] * _Other.Arr2D[3][1]);
	Result.Z = (Arr2D[0][0] * _Other.Arr2D[0][2]) + (Arr2D[0][1] * _Other.Arr2D[1][2]) + (Arr2D[0][2] * _Other.Arr2D[2][2]) + (Arr2D[0][3] * _Other.Arr2D[3][2]);
	Result.W = (Arr2D[0][0] * _Other.Arr2D[0][3]) + (Arr2D[0][1] * _Other.Arr2D[1][3]) + (Arr2D[0][2] * _Other.Arr2D[2][3]) + (Arr2D[0][3] * _Other.Arr2D[3][3]);
	*this = Result;
	return *this;
}
profile
일단 시작해보자

0개의 댓글