ModelAnimator (인스턴싱)

Jaemyeong Lee·2025년 4월 2일

✅ 1. AnimInstancingDemo 클래스 구성

  • ModelInstancingDemo를 복사해서 AnimInstancingDemo로 이름을 바꾼다.
  • Init, Update, Render 함수는 뼈대는 동일하되, ModelRendererModelAnimator로 교체한다.
  • 애니메이션 데이터를 가진 모델 Kachujin을 로드하고, ModelAnimator에 세팅한다.
obj->AddComponent(make_shared<ModelAnimator>(_shader));
obj->GetModelAnimator()->SetModel(m1);

ModelAnimator는 애니메이션이 적용되는 모델 전용 렌더러이다. 움직이지 않는 모델은 ModelRenderer로 처리한다.


✅ 2. Shader 파일 생성 및 설정

  • 21. ModelInstancingDemo.fx를 복사해 22. AnimInstancingDemo.fx로 만들고, Client/Shaders/Week3 폴더에 넣는다.
  • AnimInstancingDemo.fx애니메이션 보간트윈 시스템을 처리하는 로직이 들어가야 하므로, 기존 TweenDemo.fx 기반으로 설계한다.

핵심 변경점

cbuffer TweenBuffer
{
    TweenFrameDesc TweenFrames[MAX_MODEL_INSTANCE];
};

matrix GetAnimationMatrix(VS_IN input)
{
    // instanceID를 통해 각 인스턴스의 TweenFrame 정보를 참조
    int animIndex = TweenFrames[input.instanceID].curr.animIndex;
    ...
}

instanceID를 통해 각 인스턴스의 고유한 애니메이션 프레임 데이터를 셰이더에서 받아온다.


✅ 3. InstancingManager 확장 - RenderAnimRenderer 추가

  • 기존에는 RenderModelRenderer까지만 있었는데, ModelAnimator 전용 처리 함수인 RenderAnimRenderer를 추가한다.
  • ModelAnimator 인스턴스를 분류한 후, 월드 행렬과 Tween 정보를 모아서 한 번에 처리한다.

Tween 정보 통합 처리 방식

shared_ptr<InstancedTweenDesc> tweenDesc = make_shared<InstancedTweenDesc>();
tweenDesc->tweens[i] = gameObject->GetModelAnimator()->GetTweenDesc();
RENDER->PushTweenData(*tweenDesc.get());

Tween 데이터를 렌더링 전에 한 번에 모아서 GPU에 밀어 넣는다. 이 방식이 성능 면에서 효율적이며, 관리도 용이하다.


✅ 4. ModelAnimator 구조 변경

  • 애니메이션 프레임 계산은 UpdateTweenData()로 분리
  • RenderInstancing()에서는 실제 GPU에 데이터를 Push하는 역할만 수행

주요 함수 요약

void UpdateTweenData()
{
    // 프레임 전환, 보간 비율 갱신, 트윈 처리 등
}

void RenderInstancing(shared_ptr<InstancingBuffer>& buffer)
{
    // SRV 전달, 본 데이터, 메시 렌더링
}

✅ 5. TweenBuffer 시스템 구축

  • TweenDesc는 애니메이션 정보를 담은 구조체
  • 인스턴싱을 위해 TweenDesc[MAX_MODEL_INSTANCE] 형태로 묶어서 GPU로 전달
  • RenderManager에서 관리하도록 설계
struct InstancedTweenDesc
{
	TweenDesc tweens[MAX_MODEL_INSTANCE];
};

void RenderManager::PushTweenData(const InstancedTweenDesc& desc)
{
	_tweenBuffer->CopyData(desc);
	_tweenEffectBuffer->SetConstantBuffer(_tweenBuffer->GetComPtr().Get());
}

✅ 6. TransformMap 텍스처 생성 (애니메이션 행렬)

  • 애니메이션 프레임마다 본(Bone)마다의 최종 변환 행렬을 텍스처화하여 GPU에 전달
  • CreateTexture()에서 3차원 텍스처 (Texture2DArray)로 만들어 TransformMap으로 셰이더에 연결
_shader->GetSRV("TransformMap")->SetResource(_srv.Get());

정점 셰이더에서는 해당 텍스처를 통해 본 행렬을 읽어오고, 스키닝된 최종 애니메이션 위치를 계산한다.


✅ 7. 인스턴싱 셰이더 동작 원리

  1. instanceID를 통해 해당 인스턴스의 Tween 정보를 가져온다.
  2. TransformMap에서 현재 프레임과 다음 프레임의 본 행렬을 가져온다.
  3. 각 본에 대해 가중치를 곱한 후 합산한다.
  4. 최종 스키닝 매트릭스를 통해 정점 위치를 애니메이션 처리한다.
  5. 마지막으로 인스턴싱된 월드 행렬을 적용하고 렌더링한다.

profile
李家네_공부방

0개의 댓글