카테고리 없음

게임제작기법연구 9주차

ckhyeok 2020. 6. 9. 15:27


WorldTransform에서 지정한 부모에 상대적인 LocalTransform으로 변환하는 과정을 정리하기.

변환에는 Scale, Rotation, Position 가 존재합니다..

 

Scale은 자신의 World Scale 값을 부모의 World Scale 값에 나누면 됩니다.

Rotation은 자신의 World Rotation에서 부모의 World Rotation 값을 빼주면 됩니다.

Position은 자신의 World Position에 부모의 World Matrix의 역함수를 곱하면 됩니다.

 

예를들어 위치값(1,1,1)에 Rotation(20, 0, 0)에 Scale값이 4인 Parent란 객체와

             위치값(5,5,5)에 Rotation(10, 0, 0)에 Scale값이 1인 Child란 객체가 있습니다.

아직 이 둘은 부모자녀 관계가 아닌 상태입니다.

그리고 이제 Child 객체를 Parent의 자녀로 옮겨보았습니다. 

Scale은 부모의 값/자신의 값이 됐으며, Rotation은 자신-부모가 됐습니다.

Position 같은 경우에는 자녀의 Position 값이 부모의 크기, 회전, 위치 값에 영향을 받기 때문에 

부모로부터의 상대적인 형태를 얻고 싶다면 부모의 TRS를 기본 상태로 바꾼 뒤(0도, Scale=1, (0,0,0)) 

내가 얼마나 떨어졌는지를 측정하는 것이 맞습니다. 그래야 정확한 상대좌표를 구할 수 있기 때문이다.

왜 부모 GameObject에 WorldTransform을 저장하는지 이유를 정리하기.

만약 부모가 WorldTransform을 갖고 있지 않는다 가정하면, 자녀가 WorldTrnasform이 필요할 때 마다 매번 부모까지 계산을 해줘야 하기 때문입니다. 또한, 메모리 적인 부분에 있어서는 손해를 볼 수 있겠지만 결과적으로 보면 부모가 갖고 있는 것이 자녀가 갖고 있는 것 보다 더 효율이 좋다고 생각합니다.

트랜스폼 부모 자식 관계 설정하는 코드를 생성.

SetParent

SetParent 함수 // 계산 및 적용 후 Update 함수를 실행함.

bool Transform2D::SetParent(Transform2D* InTransformPtr)
{
	if (InTransformPtr == nullptr)
		return false;

	// 계층 구조에 이미 설정되어 있는지 체크
	for (Transform2D* current = InTransformPtr; current != nullptr; current = current->GetParent())
	{
		if (this == current)
			return false;
	}
	// 이미 부모가 있는 경우 해당 부모의 자식 목록에서 자신을 제거.
	if (_ParentPtr != nullptr)
	{
		auto it = std::find(_Children.begin(), _Children.end(), this);
		assert(it != _ParentPtr->_Children.end());
		_ParentPtr->_Children.erase(it);
		_ParentPtr = nullptr;
	}

	// 새로운 부모에 자신을 등록하고 부모로 등록
	InTransformPtr->_Children.push_back(this);
	_ParentPtr = InTransformPtr;
	
	// 부모로부터 로컬 정보를 재계산
	Vector2 invScale = Vector2(1.f / _ParentPtr->WorldScale.X, 1.f / _ParentPtr->WorldScale.Y);
	Scale = Vector2(Scale.X * invScale.X, Scale.Y * invScale.Y);
	Rotation -= _ParentPtr->WorldRotation;
	
	
	// 회전한 이동 벡터에 Inv스케일 적용  ( 최종 로컬 위치 )
	Position = _ParentPtr->GetInvWorldModelingMatrix() * Position;
	Update();

	return true;
}

Update

Update 함수 // 축 재정비 및 미리 행렬을 곱해둔 후 반영시킴.

void Transform2D::Update()
{
	CalculateLocalAxis(); // 자신의 로컬 축 방향을 재정비
	CalculateMatrices(); // 행렬을 미리 곱해두기

	for (auto&& i : _Children) // 자식들도 모두 영향을 받으므로 재귀적으로 모두 갱신
	{
		i->Update(); // World 정보만 갱신
	}
}

 

CalculateMatrics

CalculateMatrices 함수 // 부모의 유무에 따라 로컬이 월드가 될 수도 있고, 부모의 월드에 곱해야 할 수도 있음.

void Transform2D::CalculateMatrices()
{
	_LocalTRS = GetModelingMatrix();
	if (_ParentPtr == nullptr)
	{
		WorldScale = Scale;
		WorldRotation = Rotation;
		WorldPosition = Position;
		_WorldTRS = _LocalTRS; // 루트인 경우 로컬 TRS는 월드 TRS와 동일 
	}
	else
	{
		WorldScale = Vector2(_ParentPtr->WorldScale.X * Scale.X, _ParentPtr->WorldScale.Y * Scale.Y);
		WorldRotation = _ParentPtr->WorldRotation + Rotation;
		WorldPosition = _ParentPtr->_WorldTRS * Position;
		_WorldTRS = _ParentPtr->_WorldTRS * _LocalTRS;  // 부모의 월드 TRS에 로컬 TRS를 곱하여 월드 TRS 행렬을 저장
	}
}

 


위의 Hierarchy System을 사용해 태양, 지구, 달의 최소 세 개로 구성된 태양계 시스템을 구현하기.