• Home
  • About
    • 게임 개발자 유정룡 photo

      게임 개발자 유정룡

      포트폴리오

    • Learn More
    • Email
    • Github
    • Bitbucket
  • Projects
    • All Projects
    • All Tags

Direct3D11 공부 32일차(MultiBone - Shader)

12 Jul 2021

Reading time ~3 minutes

MultiBone

Shader

#include "00_Global.fx"
#include "00_Render.fx"

struct WorldDesc
{
    matrix Transforms;
};
StructuredBuffer<WorldDesc> InputWorlds;

struct BoneDesc
{
    matrix Transform;
};
StructuredBuffer<BoneDesc> InputBones;

RWTexture2DArray<float4> Output;

이전에 ModelAnimator에서 사용했던 변수 그대로 만들어주고 Input,Output 으로 을 넣어주고 받아온다.

void SetTweenBones(inout matrix world, uint3 id)
{
    int clip[2];
    int currFrame[2];
    int nextFrame[2];
    float time[2];

    clip[0] = Tweenframes[id.y].Curr.Clip;
    currFrame[0] = Tweenframes[id.y].Curr.CurrFrame;
    nextFrame[0] = Tweenframes[id.y].Curr.NextFrame;
    time[0] = Tweenframes[id.y].Curr.Time;
    
    clip[1] = Tweenframes[id.y].Next.Clip;
    currFrame[1] = Tweenframes[id.y].Next.CurrFrame;
    nextFrame[1] = Tweenframes[id.y].Next.NextFrame;
    time[1] = Tweenframes[id.y].Next.Time;
    
    float4 c0, c1, c2, c3;
    float4 n0, n1, n2, n3;
    
    matrix curr = 0, next = 0;
    matrix currAnim = 0, nextAnim = 0;
    
    c0 = TransformsMap.Load(int4(id.x * 4 + 0, currFrame[0], clip[0], 0));
    c1 = TransformsMap.Load(int4(id.x * 4 + 1, currFrame[0], clip[0], 0));
    c2 = TransformsMap.Load(int4(id.x * 4 + 2, currFrame[0], clip[0], 0));
    c3 = TransformsMap.Load(int4(id.x * 4 + 3, currFrame[0], clip[0], 0));
    curr = matrix(c0, c1, c2, c3);
    
    n0 = TransformsMap.Load(int4(id.x * 4 + 0, nextFrame[0], clip[0], 0));
    n1 = TransformsMap.Load(int4(id.x * 4 + 1, nextFrame[0], clip[0], 0));
    n2 = TransformsMap.Load(int4(id.x * 4 + 2, nextFrame[0], clip[0], 0));
    n3 = TransformsMap.Load(int4(id.x * 4 + 3, nextFrame[0], clip[0], 0));
    next = matrix(n0, n1, n2, n3);
    
    currAnim = lerp(curr, next, time[0]);
    
    [flatten]
    if (clip[1] > -1)
    {
        c0 = TransformsMap.Load(int4(id.x * 4 + 0, currFrame[1], clip[1], 0));
        c1 = TransformsMap.Load(int4(id.x * 4 + 1, currFrame[1], clip[1], 0));
        c2 = TransformsMap.Load(int4(id.x * 4 + 2, currFrame[1], clip[1], 0));
        c3 = TransformsMap.Load(int4(id.x * 4 + 3, currFrame[1], clip[1], 0));
        curr = matrix(c0, c1, c2, c3);
    
        n0 = TransformsMap.Load(int4(id.x * 4 + 0, nextFrame[1], clip[1], 0));
        n1 = TransformsMap.Load(int4(id.x * 4 + 1, nextFrame[1], clip[1], 0));
        n2 = TransformsMap.Load(int4(id.x * 4 + 2, nextFrame[1], clip[1], 0));
        n3 = TransformsMap.Load(int4(id.x * 4 + 3, nextFrame[1], clip[1], 0));
        next = matrix(n0, n1, n2, n3);
    
        nextAnim = lerp(curr, next, time[1]);
        
        currAnim = lerp(currAnim, nextAnim, Tweenframes[id.y].TweenTime);
    }
    
    world = mul(currAnim, world);
}

값을 받아온 id대로 업데이트 해준다. 이 전에 본을 업데이트한 방식과 같다.

void SetBlendBones(inout matrix world, uint3 id)
{
    float4 c0, c1, c2, c3;
    float4 n0, n1, n2, n3;
    
    matrix curr = 0, next = 0;
    matrix currAnim[3];
    matrix anim = 0;
    
    BlendFrame frame = BlendFrames[id.y];
    
    [unroll(3)]
    for (int k = 0; k < 3; k++)
    {
        c0 = TransformsMap.Load(int4(id.x * 4 + 0, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0));
        c1 = TransformsMap.Load(int4(id.x * 4 + 1, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0));
        c2 = TransformsMap.Load(int4(id.x * 4 + 2, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0));
        c3 = TransformsMap.Load(int4(id.x * 4 + 3, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0));
        curr = matrix(c0, c1, c2, c3);
    
        n0 = TransformsMap.Load(int4(id.x * 4 + 0, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0));
        n1 = TransformsMap.Load(int4(id.x * 4 + 1, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0));
        n2 = TransformsMap.Load(int4(id.x * 4 + 2, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0));
        n3 = TransformsMap.Load(int4(id.x * 4 + 3, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0));
        next = matrix(n0, n1, n2, n3);
    
        currAnim[k] = lerp(curr, next, frame.Clip[k].Time);
    }
    int clipA = (int) frame.Alpha;
    int clipB = clipA + 1;
    
    float alpha = frame.Alpha;
    if (alpha > 1.0f)
    {
        alpha = frame.Alpha - 1.0f;
        
        if (frame.Alpha >= 2.0f)
        {
            clipA = 1;
            clipB = 2;
        }
    }
    
    anim = lerp(currAnim[clipA], currAnim[clipB], alpha);
    
    world = mul(anim, world);
}

이 것도 이 전에 Blend했던것과 유사하다.

[numthreads(MAX_MODEL_TRANSFORMS, 1, 1)]
void CS(uint3 id : SV_DispatchThreadID)
{
    // 기준 본 * 애니메이션 * 월드
    
    
    // instance id
    matrix world = InputWorlds[id.y].Transforms;
    
    if (BlendFrames[id.y].Mode == 0)
    {
        SetTweenBones(world, id);
    }
    else
    {
        SetBlendBones(world, id);
    }
    
    world = mul(InputBones[id.x].Transform, world);

    
    float4 m0 = world._11_12_13_14;
    float4 m1 = world._21_22_23_24;
    float4 m2 = world._31_32_33_34;
    float4 m3 = world._41_42_43_44;
    
    Output[int3(id.x * 4 + 0, id.y, id.z)] = m0;
    Output[int3(id.x * 4 + 1, id.y, id.z)] = m1;
    Output[int3(id.x * 4 + 2, id.y, id.z)] = m2;
    Output[int3(id.x * 4 + 3, id.y, id.z)] = m3;
}

제일 중요한 부분이다.

현재 원하는 본의 위치를 갖고오고 그 값을 오브젝트의 월드 행렬에 곱해서 값을 전달해준다.

이런 식으로 만들면

각 위치에 오브젝트 잘 들어가고

위치 및 크기 변경 가능해진다.

휴… 버그 정말 많았다… 잘 된다…



DirectX Share Tweet +1