5. 행렬

CJB_ny·2023년 2월 27일
0

이득우 겜수

목록 보기
3/9
post-thumbnail

정리 글

예제 5-1

행렬 곱셈을 활용해 두 선형변환을 한번에 처리하는 로직

// 렌더링 로직을 담당하는 함수
void SoftRenderer::Render2D()
{
	// 렌더링 로직에서 사용하는 모듈 내 주요 레퍼런스
	auto& r = GetRenderer();
	const auto& g = Get2DGameEngine();

	// 배경에 격자 그리기
	DrawGizmo2D();

	// 렌더링 로직의 로컬 변수
	float rad = 0.f;
	static float increment = 0.001f;
	static std::vector<Vector2> hearts;
	HSVColor hsv(0.f, 1.f, 0.85f);

	// 하트를 구성하는 점 생성
	if (hearts.empty())
	{
		for (rad = 0.f; rad < Math::TwoPI; rad += increment)
		{
			float sin = sinf(rad);
			float cos = cosf(rad);
			float cos2 = cosf(2 * rad);
			float cos3 = cosf(3 * rad);
			float cos4 = cosf(4 * rad);
			float x = 16.f * sin * sin * sin;
			float y = 13 * cos - 5 * cos2 - 2 * cos3 - cos4;
			hearts.push_back(Vector2(x, y));
		}
	}

	// 각도에 해당하는 사인과 코사인 값 얻기
	Math::GetSinCos(_sin, _cos, currentDegree);

	// 회전 변환행렬의 기저벡터와 행렬
	Vector2 rBasis1(_cos, _sin);
	Vector2 rBasis2(-_sin, _cos);
	Matrix2x2 rMatrix(rBasis1, rBasis2);	// 2x2 회전행렬 생성

	// 크기 변환향렬의 기적벡터와 행렬
	Vector2 sBasis1 = Vector2::UnitX * currentScale;
	Vector2 sBasis2 = Vector2::UnitY * currentScale;
	Matrix2x2 sMatrix(sBasis1, sBasis2);

	// 크기, 회전 순서로 진행하는 합성 변환행렬의 계산
	Matrix2x2 finalMatrix = rMatrix * sMatrix;

	// 각 값을 초기화한 후 색상을 증가시키면서 점에 대응
	rad = 0.f;
	for (auto const& v : hearts)
	{
		// 1. 점에 행렬을 적용한다.
		Vector2 transformedV = finalMatrix * v;

		// 2. 변환된 점을 이동한다.
		Vector2 translatedV = transformedV + currentPosition;
			
		hsv.H = rad / Math::TwoPI;
		r.DrawPoint(translatedV, hsv.ToLinearColor());
		rad += increment;
	}

	// 현재 위치, 크기, 각도를 화면에 출력
	r.PushStatisticText(std::string("Position : ") + currentPosition.ToString());
	r.PushStatisticText(std::string("Scale : ") + std::to_string(currentScale));
	r.PushStatisticText(std::string("Degree : ") + std::to_string(currentDegree));
}

rMatrix, sMatrix를 만들어서 finalMatrix에 크기 회전 순서로 진행하는 변환 행렬을 계산해서

점에다가 적용시켜준다.

5-2 역행렬을 사용해 원래 형태로 되돌리기

p188

왼쪽에는 사용자의 입력에 따라 크기, 회전, 이동할 수 있도록 하고 오른쪽은 역행렬을 통해 원본을 유지 할 수 있도록 해준다.

// 렌더링 로직을 담당하는 함수
void SoftRenderer::Render2D()
{
	// 렌더링 로직에서 사용하는 모듈 내 주요 레퍼런스
	auto& r = GetRenderer();
	const auto& g = Get2DGameEngine();

	// 배경에 격자 그리기
	DrawGizmo2D();

	// 렌더링 로직의 로컬 변수
	float rad = 0.f;
	static float increment = 0.001f;
	static std::vector<Vector2> hearts;
	HSVColor hsv(0.f, 1.f, 0.85f);
	static Vector2 pivot(200.f, 0.f);	// 하트 두개를 대칭해서 그리기 위한 변수

	// 하트를 구성하는 점 생성
	if (hearts.empty())
	{
		for (rad = 0.f; rad < Math::TwoPI; rad += increment)
		{
			float sin = sinf(rad);
			float cos = cosf(rad);
			float cos2 = cosf(2 * rad);
			float cos3 = cosf(3 * rad);
			float cos4 = cosf(4 * rad);
			float x = 16.f * sin * sin * sin;
			float y = 13 * cos - 5 * cos2 - 2 * cos3 - cos4;
			hearts.push_back(Vector2(x, y));
		}
	}

	// 크기 변환 행렬
	Vector2 sBasis1(currentScale, 0.f);
	Vector2 sBasis2(0.f, currentScale);
	Matrix2x2 sMatrix(sBasis1, sBasis2);

	// 회전 변환 행렬
	float sin, cos;
	Math::GetSinCos(sin, cos, currentDegree);
	Vector2 rBasis1(cos, sin);
	Vector2 rBasis2(-sin, cos);
	Matrix2x2 rMatrix(rBasis1, rBasis2);

	// 전단변환행렬
	Vector2 shBasis1 = Vector2::UnitX;
	Vector2 shBasis2(currentShear, 1.f);
	Matrix2x2 shMatrix(shBasis1, shBasis2);

	// 합성행렬 (전단 * 회전 * 크기)
	Matrix2x2 cMatrix = shMatrix * rMatrix * sMatrix;

	// 크기 변환 행렬의 역행렬
	float invScale = 1.f / currentScale;
	Vector2 isBasis1(invScale, 0.f);
	Vector2 isBasis2(0.f, invScale);
	Matrix2x2 isMatrix(isBasis1, isBasis2);

	// 회전 변환행렬의 역행렬
	Matrix2x2 irMatrix = rMatrix.Transpose();			// 회전 변환행렬의 역행렬은 회전 변환 행렬의 전치행렬과 같다. cos 때문에

	// 전단 변환행렬의 역행렬
	Vector2 ishBasis1 = Vector2::UnitX;
	Vector2 ishBasis2(-currentShear, 1.f);
	Matrix2x2 ishMatrix(ishBasis1, ishBasis2);

	// 역행렬의 합성행렬 (역순으로 결합하기)
	Matrix2x2 icMatrix = isMatrix * irMatrix * ishMatrix; // 합성 변환행렬의 역행렬은 각 역행렬을 역순으로 곱한 행렬이다.
	
	// 각 값을 초기화 한후 동일하게 증가시키면서 색상값을 지정
	rad = 0.f;
	for (auto const& v : hearts)
	{
		// 왼쪽하트 (변환행렬 적용하기)
		Vector2 left = cMatrix * v;						// 합성 변환행렬 cMatrix에 벡터를 곱해 변환 수행하고 이 결과를 변수 left에 저장한다.
		r.DrawPoint(left - pivot, hsv.ToLinearColor()); // 벡터 left를 pivot만큼 빼서 하트를 그린다.
		
		// 오른쪽 하트
		Vector2 right = icMatrix * left;
		r.DrawPoint(right + pivot, hsv.ToLinearColor());

		hsv.H = rad / Math::TwoPI;
		rad += increment;		
	}

	// 현재 밀기, 스케일, 회전각을 화면에 출력
	r.PushStatisticText(std::string("Shear : ") + std::to_string(currentShear));
	r.PushStatisticText(std::string("Scale : ") + std::to_string(currentScale));
	r.PushStatisticText(std::string("Degree : ") + std::to_string(currentDegree));
}

크기 / 회전 / 전단 변환 행렬을 각각 만들어서 크기 / 회전 / 전단 변환행렬의 역행렬도 같이 만들어준다.

회전 변환행렬의 역행렬은 회전 변환행렬의 전치행렬과 같기에 Transpos()로 구해주고

크기 / 전단 변환행렬의 역행렬은 각각의 공식? 규칙대로 만들어주고

auto const& v : hears 에 따라 점 v를 그려 주도록 한다.

5-2 결과

profile
https://cjbworld.tistory.com/ <- 이사중

0개의 댓글