프로그래밍 공부
작성일
2024. 5. 13. 20:16
작성자
WDmil
728x90

 

 

 


선형보간 작업부

	struct Frame
	{
		int clip = 0;        // 현재 재생 중인 클립의 인덱스
		int nextclip = 0;	// 다음 클립의 인덱스
		int curFrame = 0;    // 현재 프레임 인덱스
		int nextcurFrame = 0;    // 다음 프레임 인덱스
		float time = 0;      // 현재 프레임에서의 경과 시간
		float scale = 1.0f;   // 애니메이션 재생 속도 조절용 스케일
		float transtime = 0; // 애니메이션 전환속도 조절용 스케일
		float transtimemax = 0.5; // 애니메이션 전환속도를 버퍼로 전달함.
	};

	// FrameBuffer 클래스: 상속된 ConstBuffer를 사용하여 프레임 데이터를 GPU에 전달하는 클래스
	class FrameBuffer : public ConstBuffer
	{
	public:
		FrameBuffer() : ConstBuffer(&frame, sizeof(Frame)) {}; // 프레임 데이터를 상속된 ConstBuffer에 전달

		Frame* GetData() { return &frame; } // 프레임 데이터에 대한 포인터 반환

	private:
		Frame frame; // 프레임 데이터를 저장하는 구조체 인스턴스
	};
 

FrameBuffer입니다.

 

Buffer로 전달해야하는값은 위와 같습니다.

 

현재 프레임 인덱스, 다음 프레임 인덱스는. 현 모션과 다음 모션의 선형보간 작업를 위해 들어가야합니다.

 

현재 프레임에서의 경과 시간은, 현재 프레임 인덱스가 진행되는 float값을 int로 형변환 하기 전에,

 

다음 인덱스와 현재 인덱스를 0과 1로 두고, 백분율로, 얼마나 갔는지 확인하는 값 입니다.

 

해당 값을 통해. 현재 애니메이션의 프레임의 선형보간이 어느정도로 진행되었는지 확인할 수 있습니다.

 

애니메이션 전환속도 조절용 스케일과 전환속도는, 현재 진행된 전환값과 최대 전환값을 확인하여 애니메이션의 전환이 얼마나 진행되었는지 확인하여 선형보간 하기위해 필요합니다.

 

cbuffer FrameBuffer : register(b3)
{
	int clip;
	int nextclip;
	int curFrame;
	int nextcurFrame;
	float time;
	float scale; // 애니메이션 재생 속도 조절용 스케일
	float transtime; // 애니메이션 전환속도 조절용 스케일
	float transtimemax; // 교환비 최대값

}

Texture2DArray transformMap : register(t0);

matrix SkinWorld(float4 indices, float4 weights)
{
	matrix resulttransform = 0;
	
	matrix transform = 0;
	matrix nexttransform = 0;
	matrix cur;
	matrix nextcur;
	
	matrix curanim;
	
	float4 c0, c1, c2, c3;
	float4 n0, n1, n2, n3;
	
	// 매트릭스 뽑는것.
	[unroll(4)] // 제한하는 구문. 4개이상 절때 돌아갈 수 없게 제한한다.
	for (int i = 0; i < 4; i++)
	{
		c0 = transformMap.Load(int4(indices[i] * 4 + 0, curFrame, clip, 0));
		c1 = transformMap.Load(int4(indices[i] * 4 + 1, curFrame, clip, 0));
		c2 = transformMap.Load(int4(indices[i] * 4 + 2, curFrame, clip, 0));
		c3 = transformMap.Load(int4(indices[i] * 4 + 3, curFrame, clip, 0));
		
		cur = matrix(c0, c1, c2, c3);
		
		n0 = transformMap.Load(int4(indices[i] * 4 + 0, nextcurFrame, clip, 0));
		n1 = transformMap.Load(int4(indices[i] * 4 + 1, nextcurFrame, clip, 0));
		n2 = transformMap.Load(int4(indices[i] * 4 + 2, nextcurFrame, clip, 0));
		n3 = transformMap.Load(int4(indices[i] * 4 + 3, nextcurFrame, clip, 0));
		
		nextcur = matrix(n0, n1, n2, n3);
	
		curanim = lerp(cur, nextcur, time);
		transform += mul(weights[i], curanim);
	}
	// transtime이 0이라면, 현재 transform을 할 필요가 없기 때문,
	if (transtime <= 0.00001)
		return transform;

	// 바뀔시 다음 모션의 선형보간을 진행
	// nextFrmae
	[unroll(4)]
	for (int i = 0; i < 4; i++)
	{
		c0 = transformMap.Load(int4(indices[i] * 4 + 0, curFrame, nextclip, 0));
		c1 = transformMap.Load(int4(indices[i] * 4 + 1, curFrame, nextclip, 0));
		c2 = transformMap.Load(int4(indices[i] * 4 + 2, curFrame, nextclip, 0));
		c3 = transformMap.Load(int4(indices[i] * 4 + 3, curFrame, nextclip, 0));
		
		cur = matrix(c0, c1, c2, c3);
		
		n0 = transformMap.Load(int4(indices[i] * 4 + 0, nextcurFrame, nextclip, 0));
		n1 = transformMap.Load(int4(indices[i] * 4 + 1, nextcurFrame, nextclip, 0));
		n2 = transformMap.Load(int4(indices[i] * 4 + 2, nextcurFrame, nextclip, 0));
		n3 = transformMap.Load(int4(indices[i] * 4 + 3, nextcurFrame, nextclip, 0));
		
		nextcur = matrix(n0, n1, n2, n3);

		curanim = lerp(cur, nextcur, time);
		nexttransform += mul(weights[i], curanim);
	}
	
	resulttransform = lerp(transform, nexttransform, transtime / transtimemax);
	return resulttransform;
}
 

hlsl입니다. 첫번째 함수부를 살펴보면, c0 ~ c3까지, n0 ~ n3까지 두개를 확인하는데,

 

이 값을 두번 사용하는 이유는, 현재 프레임과 다음 프레임의 애니메이션간 보간작업을 위해 사용합니다.

 

받아온 time값에 보간값을 대입하여. 현재 애니메이션이 다음프래임까지 얼마나 진행되었는지, 비율을 계산하여.

 

그 비율값만큼씩 만 곱해줍니다.

 

그렇게 하여, 데이터의 연산시 뚝뚝 끊기는 상황을 예방합니다.

 

https://tv.kakao.com/v/442529210

 

위 영상은 선형보간 이전 영상입니다.

 

https://tv.kakao.com/v/442529283

 

위 영상은 선형보간 이후 영상입니다.

 

위 와 같은 차이점을 발견할 수 있습니다.

 

 

이러한 프레임간 선형보간을 하였다면, 그 이후 애니메이션간 선형보간 작업도 가능합니다.

 

애니메이션이 다음 애니메이션으로 이동하였을 때, 각 Vertex가 프레임마다 이동비율을 계산하듯,

다음 애니메이션으로 이동하였을 때 그 애니메이션과 현재 애니메이션의 이동속도를 정하고, DELTA TIME만큼 갱신될 때,

 

그 갱신된 값을 사용해서, 현재 애니메이션의 진행이. 최대 전환속도에 얼마나 진행되었는지를 확인하여. 선형보간 작업을 하면 됩니다.

 

단, 애니메이션간 보간작업 시, 프레임 최소값을 확인하고, 그 최소값을 기준으로 보간작업을 하지 않으면

 

애니메이션이 깨지는 현상이 발생함으로,

 

전환전 애니메이션과 전환후 애니메이션을 확인하고, 두개의 프레임 최대값중, 가장 적은 최대값을 기준으로

 

프레임 갱신을 하지 않으면 애니메이션이 깨집니다.

 

 

 

애니매이션간 보간작업을 진행하였을 때의 결과작업입니다.

 

만약, 애니메이션 전환시간이 0일경우, 보간작업을 하지 않은것과 같은 결과가 나타납니다.

 

728x90

'작업사항 정리 > DIrectX3D' 카테고리의 다른 글

DirectX3D 작업물 몰아넣은 Git  (0) 2024.05.13
Collision & 회전  (0) 2024.05.12
인스턴싱 & 무한  (0) 2024.05.12
상점기능 구현  (0) 2024.05.12
간단 PacMan  (0) 2024.05.12