DirectX 11에서 Multibones는 스켈레탈 애니메이션을 구현하는 데 사용되는 기술이다. 스켈레탈 애니메이션은 3D 모델의 뼈대와 관련된 것으로, 모델이 움직이는 동안 뼈대가 움직이며 모델을 변형시킨다. Multibones는 여러 개의 뼈대를 사용하여 더욱 자연스러운 애니메이션을 만들어낸다. 이를 통해 모델의 각 부분에 대해 다양한 뼈대를 지정할 수 있으며, 더 복잡한 동작을 만들어낼 수 있다.

 

목차

     

     


     

     

     

    Get Multibones

     

    DirectX 11에서 Multibones는 스켈레탈 애니메이션을 구현하는 데 사용되는 기술이다. 스켈레탈 애니메이션은 3D 모델의 뼈대와 관련된 것으로, 모델이 움직이는 동안 뼈대가 움직이며 모델을 변형시킨다.

    Multibones는 여러 개의 뼈대를 사용하여 더욱 자연스러운 애니메이션을 만들어낸다. 이를 통해 모델의 각 부분에 대해 다양한 뼈대를 지정할 수 있으며, 더 복잡한 동작을 만들어낼 수 있다.

    Multibones를 구현하려면 각 뼈대의 정보를 정의하는 뼈대 행렬들을 생성해야 한다. 이 행렬들은 모델의 뼈대들 사이의 계층 구조와 연관되어 있다. 이러한 뼈대 행렬들은 GPU에서 계산되며, 각 프레임마다 각 뼈대의 위치와 회전을 계산하여 모델의 애니메이션을 만든다.

    Multibones를 사용하여 더욱 자연스러운 애니메이션을 만들 수 있지만, 이를 구현하기 위해서는 더 많은 계산이 필요하며, 따라서 프로세서와 그래픽 카드의 성능이 더욱 중요해진다.

     

    Shader
      GetMultiBones.fx
    Framework
      Model
      ModelAnimator.h .cpp
      Renders
      Buffers.h .cpp
    UnitTest
      DirectCompute
      GetMultiBoneDemo

     


     

    GetMultiBones.fx

     

    GetMultiBones.fx

    더보기
    #include "00_Global.fx"
    #include "00_Light.fx"
    #include "00_Render.fx"
    
    struct WorldDesc
    {
        matrix Transform;
    };
    StructuredBuffer<WorldDesc> InputWorlds;//inputWorldBuffer //Model Animator에 있는 Compute Shader
    
    struct BoneDesc
    {
        matrix Transform;
    };
    StructuredBuffer<BoneDesc> InputBones;//inputBoneBuffer
    
    // 한장인데 그냥 2DArray사용
    RWTexture2DArray<float4> 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;
        matrix nextAnim = 0;
        
        // 본은 x에 매핑 
        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);
    }
    
    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);
    }
    
    
    
    [numthreads(MAX_MODEL_TRANSFORMS, 1, 1)]
    void CS(uint3 id : SV_DispatchThreadID)
    {
        //기준본 * 애니메이션 * 월드
        
        // SV_DispatchThreadID을 사용하면 그룹에 상관없이 번호가 이어짐 1대1로
        // y가 트랜스폼 ID와 일치함
        matrix world = InputWorlds[id.y].Transform;
        
        if (BlendFrames[id.y].Mode == 0)
            SetTweenBones(world, id);
        else
            SetBlendBones(world, id);
        
        world = mul(InputBones[id.x].Transform, world);
        
        // desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
        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;
    }
    
    technique11 T0
    {
        pass P0
        {
            SetVertexShader(NULL);
            SetPixelShader(NULL);
    
            SetComputeShader(CompileShader(cs_5_0, CS()));
        }
    }

    Dispatcher Thread ID를 사용하면 그룹에 상관없이  ID와 Texture를 펼친것(=Instance Id)이 1:1로 대응하게 된다.

     


     

    Model Animator

     

    ModelAnimator.h

    더보기
    #pragma once
    
    class ModelAnimator
    {
    public:
    	ModelAnimator(Shader* shader);
    	~ModelAnimator();
    
    	void Update();
    private:
    	void UpdateTweenMode(UINT index);
    	void UpdateBlendMode(UINT index);
    
    public:
    	void Render();
    
    public:
    	void ReadMesh(wstring file);
    	void ReadMaterial(wstring file);
    	void ReadClip(wstring file);
    
    	Model* GetModel() { return model; }
    
    	void Pass(UINT pass);
    
    	Transform* AddTransform();
    	Transform* GetTransform(UINT index) { return transforms[index]; }
    	void UpdateTransforms();
    	UINT GetTransformCount() { return transforms.size(); }
    
    	void PlayTweenMode(UINT index, UINT clip, float speed = 1.0f, float takeTime = 1.0f);
    	void PlayBlendMode(UINT index, UINT clip, UINT clip1, UINT clip2);
    	void SetBlendAlpha(UINT index, float alpha);
    
    	void GetAttachTransform(UINT instance, Matrix* outResult);
    
    private:
    	void CreateTexture();
    	void CreateClipTransform(UINT index);
    
    private:
    	struct ClipTransform
    	{
    		Matrix** Transform;
    
    		ClipTransform()
    		{
    			Transform = new Matrix*[MAX_MODEL_KEYFRAMES];
    
    			for (UINT i = 0; i < MAX_MODEL_KEYFRAMES; i++)
    				Transform[i] = new Matrix[MAX_MODEL_TRANSFORMS];
    		}
    
    		~ClipTransform()
    		{
    			for (UINT i = 0; i < MAX_MODEL_KEYFRAMES; i++)
    				SafeDeleteArray(Transform[i]);
    
    			SafeDeleteArray(Transform);
    		}
    	};
    	ClipTransform* clipTransforms = NULL;
    
    	ID3D11Texture2D* texture = NULL;
    	ID3D11ShaderResourceView* srv = NULL;
    
    private:
    	struct KeyframeDesc
    	{
    		int Clip = 0;
    
    		UINT CurrFrame = 0;
    		UINT NextFrame = 0;
    
    		float Time = 0.0f;
    		float RunningTime = 0.0f;
    
    		float Speed = 1.0f;
    
    		Vector2 Padding;
    	}; // keyframeDesc;
    
    	struct TweenDesc
    	{
    		float TakeTime = 1.0f;
    		float TweenTime = 0.0f;
    		float ChangeTime = 0.0f;
    		float Padding;
    
    		KeyframeDesc Curr;
    		KeyframeDesc Next;
    
    		TweenDesc()
    		{
    			Curr.Clip = 0;
    			Next.Clip = -1;
    		}
    	} tweenDesc[MAX_MODEL_INSTANCE];
    
    	ConstantBuffer* tweenBuffer;
    	ID3DX11EffectConstantBuffer* sTweenBuffer;
    
    private:
    	struct BlendDesc
    	{
    		UINT Mode = 0;
    		float Alpha = 0;
    		Vector2 Padding;
    
    		KeyframeDesc Clip[3];
    	} blendDesc[MAX_MODEL_INSTANCE];
    
    	ConstantBuffer* blendBuffer;
    	ID3DX11EffectConstantBuffer* sBlendBuffer;
    
    private:
    	Shader* shader;
    	Model* model;
    	
    	vector<Transform *> transforms;
    	Matrix worlds[MAX_MODEL_INSTANCE];
    
    	VertexBuffer* instanceBuffer;
    
    private:
    	struct CS_InputDesc
    	{
    		Matrix Bone;
    	};
    
    	struct CS_OutputDesc
    	{
    		Matrix Result;
    	};
    
    private:
    	const float frameRate = 30.0f; //매 프레임 마다 계산하면 계산양이 많아서 30프레임으로 설정.
    	float frameTime = 0.0f;
    
    
    	Shader* computeShader;
    	ID3DX11EffectShaderResourceVariable* sTransformsSRV;
    
    	StructuredBuffer* inputWorldBuffer;
    	ID3DX11EffectShaderResourceVariable* sInputWorldSRV; //입력용 버퍼
    
    	StructuredBuffer* inputBoneBuffer;
    	ID3DX11EffectShaderResourceVariable* sInputBoneSRV; //입력용 버퍼
    
    	TextureBuffer* outputBuffer;
    	ID3DX11EffectUnorderedAccessViewVariable* sOutputUAV;//출력용 버퍼
    
    	
    	ID3DX11EffectConstantBuffer* sComputeTweenBuffer; //Tween 정보
    	ID3DX11EffectConstantBuffer* sComputeBlendBuffer; //Blend 정보
    };

     

     

    ModelAnimator.cpp

    더보기
    #include "Framework.h"
    #include "ModelAnimator.h"
    
    ModelAnimator::ModelAnimator(Shader * shader)
    	: shader(shader)
    {
    	model = new Model();
    
    	tweenBuffer = new ConstantBuffer(&tweenDesc, sizeof(TweenDesc) * MAX_MODEL_INSTANCE);
    	sTweenBuffer = shader->AsConstantBuffer("CB_TweenFrame");
    
    	blendBuffer = new ConstantBuffer(&blendDesc, sizeof(BlendDesc) * MAX_MODEL_INSTANCE);
    	sBlendBuffer = shader->AsConstantBuffer("CB_BlendFrame");
    
    	instanceBuffer = new VertexBuffer(worlds, MAX_MODEL_INSTANCE, sizeof(Matrix), 1, true);
    
    
    	//Create Compute Shader
    	{
    		computeShader = new Shader(L"71_GetMultiBones.fx");
    		
    		inputWorldBuffer = new StructuredBuffer(worlds, sizeof(Matrix), MAX_MODEL_INSTANCE);
    		sInputWorldSRV = computeShader->AsSRV("InputWorlds");
    
    		inputBoneBuffer = new StructuredBuffer(NULL, sizeof(Matrix), MAX_MODEL_TRANSFORMS);
    		sInputBoneSRV = computeShader->AsSRV("InputBones");
    
    
    		ID3D11Texture2D* texture;
    		D3D11_TEXTURE2D_DESC desc;
    		ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
    		desc.Width = MAX_MODEL_TRANSFORMS * 4;
    		desc.Height = MAX_MODEL_INSTANCE;
    		desc.ArraySize = 1;
    		desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
    		desc.MipLevels = 1;
    		desc.SampleDesc.Count = 1;
    		Check(D3D::GetDevice()->CreateTexture2D(&desc, NULL, &texture));
    
    		outputBuffer = new TextureBuffer(texture);
    		SafeRelease(texture);
    
    
    		sOutputUAV = computeShader->AsUAV("Output");
    
    		sTransformsSRV = computeShader->AsSRV("TransformsMap");
    		sComputeTweenBuffer = computeShader->AsConstantBuffer("CB_TweenFrame");
    		sComputeBlendBuffer = computeShader->AsConstantBuffer("CB_BlendFrame");
    
    	}
    }
    
    ModelAnimator::~ModelAnimator()
    {
    	SafeDelete(model);
    
    	SafeDeleteArray(clipTransforms);
    	SafeRelease(texture);
    	SafeRelease(srv);
    
    	SafeDelete(tweenBuffer);
    	SafeDelete(blendBuffer);
    
    	SafeDelete(instanceBuffer);
    
    
    	SafeDelete(computeShader);
    
    	SafeDelete(inputWorldBuffer);
    	SafeDelete(inputBoneBuffer);
    	SafeDelete(outputBuffer);
    }
    
    void ModelAnimator::Update()
    {
    	if (texture == NULL)
    	{
    		for (ModelMesh* mesh : model->Meshes())
    			mesh->SetShader(shader);
    
    		CreateTexture();
    
    
    		Matrix bones[MAX_MODEL_TRANSFORMS];
    		for (UINT i = 0; i < model->BoneCount(); i++)
    			bones[i] = model->BoneByIndex(i)->Transform(); //최초의 기준Bone에서 현재 애니메이션의 행렬을 계산
    
    		inputBoneBuffer->CopyToInput(bones);//계산해서 넣어줌
    	}
    
    	for (UINT i = 0; i < transforms.size(); i++)
    		blendDesc[i].Mode == 0 ? UpdateTweenMode(i) : UpdateBlendMode(i);
    
    	
    	
    	tweenBuffer->Render();
    	blendBuffer->Render();
    
    
    	frameTime += Time::Delta();
    	if (frameTime > (1.0f / frameRate))
    	{
    		sComputeTweenBuffer->SetConstantBuffer(tweenBuffer->Buffer());
    		sComputeBlendBuffer->SetConstantBuffer(blendBuffer->Buffer());
    
    		sTransformsSRV->SetResource(srv); //srv는 ClipTransform의 정보를 가지고 있다.
    		sInputWorldSRV->SetResource(inputWorldBuffer->SRV());
    		sInputBoneSRV->SetResource(inputBoneBuffer->SRV());
    		sOutputUAV->SetUnorderedAccessView(outputBuffer->UAV());
    
    		computeShader->Dispatch(0, 0, 1, MAX_MODEL_INSTANCE, 1);//y를 instance로 사용
    
    		outputBuffer->CopyFromOutput();
    	}
    	frameTime = fmod(frameTime, (1.0f / frameRate));
    
    
    	if (Keyboard::Get()->Down(VK_SPACE))
    	{
    		ID3D11Texture2D* temp = outputBuffer->CopyFromOutput();
    
    		FILE* src;
    		fopen_s(&src, "../src.csv", "w");
    
    		Matrix id[MAX_MODEL_TRANSFORMS];
    
    		for (UINT y = 0; y < MAX_MODEL_INSTANCE; y++)
    		{
    			D3D11_MAPPED_SUBRESOURCE subResource;
    			D3D::GetDC()->Map(temp, 0, D3D11_MAP_READ, 0, &subResource);
    			{
    				void* p = (BYTE *)subResource.pData + y * subResource.RowPitch;
    				memcpy(id, p, MAX_MODEL_TRANSFORMS * sizeof(Matrix));
    			}
    			D3D::GetDC()->Unmap(temp, 0);
    
    
    			for (UINT x = 0; x < MAX_MODEL_TRANSFORMS; x++)
    			{
    				Matrix destMatrix = id[x];
    
    				fprintf(src, "%f,%f,%f,%f,", destMatrix._11, destMatrix._12, destMatrix._13, destMatrix._14);
    				fprintf(src, "%f,%f,%f,%f,", destMatrix._21, destMatrix._22, destMatrix._23, destMatrix._24);
    				fprintf(src, "%f,%f,%f,%f,", destMatrix._31, destMatrix._32, destMatrix._33, destMatrix._34);
    				fprintf(src, "%f,%f,%f,%f\n", destMatrix._41, destMatrix._42, destMatrix._43, destMatrix._44);
    			}
    		}
    
    		fclose(src);
    	}
    
    
    	for (ModelMesh* mesh : model->Meshes())
    		mesh->Update();
    }
    
    void ModelAnimator::UpdateTweenMode(UINT index)
    {
    	TweenDesc& desc = tweenDesc[index];
    
    	//현재 애니메이션
    	{
    		ModelClip* clip = model->ClipByIndex(desc.Curr.Clip);
    
    		desc.Curr.RunningTime += Time::Delta();
    
    		float time = 1.0f / clip->FrameRate() / desc.Curr.Speed;
    		if (desc.Curr.Time >= 1.0f)
    		{
    			desc.Curr.RunningTime = 0;
    
    			desc.Curr.CurrFrame = (desc.Curr.CurrFrame + 1) % clip->FrameCount();
    			desc.Curr.NextFrame = (desc.Curr.CurrFrame + 1) % clip->FrameCount();
    		}
    		desc.Curr.Time = desc.Curr.RunningTime / time;
    	}
    
    	if (desc.Next.Clip > -1)
    	{
    		desc.ChangeTime += Time::Delta();
    		desc.TweenTime = desc.ChangeTime / desc.TakeTime;
    
    		if (desc.TweenTime >= 1.0f)
    		{
    			desc.Curr = desc.Next;
    
    			desc.Next.Clip = -1;
    			desc.Next.CurrFrame = 0;
    			desc.Next.NextFrame = 0;
    			desc.Next.Time = 0;
    			desc.Next.RunningTime = 0.0f;
    
    			desc.ChangeTime = 0.0f;
    			desc.TweenTime = 0.0f;
    		}
    		else
    		{
    			ModelClip* clip = model->ClipByIndex(desc.Next.Clip);
    
    			desc.Next.RunningTime += Time::Delta();
    
    			float time = 1.0f / clip->FrameRate() / desc.Next.Speed;
    			if (desc.Next.Time >= 1.0f)
    			{
    				desc.Next.RunningTime = 0;
    
    				desc.Next.CurrFrame = (desc.Next.CurrFrame + 1) % clip->FrameCount();
    				desc.Next.NextFrame = (desc.Next.CurrFrame + 1) % clip->FrameCount();
    			}
    			desc.Next.Time = desc.Next.RunningTime / time;
    		}
    	}
    }
    
    void ModelAnimator::UpdateBlendMode(UINT index)
    {
    	BlendDesc& desc = blendDesc[index];
    
    	for (UINT i = 0; i < 3; i++)
    	{
    		ModelClip* clip = model->ClipByIndex(desc.Clip[i].Clip);
    
    		desc.Clip[i].RunningTime += Time::Delta();
    
    		float time = 1.0f / clip->FrameRate() / desc.Clip[i].Speed;
    		if (desc.Clip[i].Time >= 1.0f)
    		{
    			desc.Clip[i].RunningTime = 0;
    
    			desc.Clip[i].CurrFrame = (desc.Clip[i].CurrFrame + 1) % clip->FrameCount();
    			desc.Clip[i].NextFrame = (desc.Clip[i].CurrFrame + 1) % clip->FrameCount();
    		}
    		desc.Clip[i].Time = desc.Clip[i].RunningTime / time;
    	}
    }
    
    void ModelAnimator::Render()
    {
    	sTweenBuffer->SetConstantBuffer(tweenBuffer->Buffer());	
    	sBlendBuffer->SetConstantBuffer(blendBuffer->Buffer());
    
    
    	instanceBuffer->Render();
    
    	for (ModelMesh* mesh : model->Meshes())
    		mesh->Render(transforms.size());	
    }
    
    void ModelAnimator::ReadMesh(wstring file)
    {
    	model->ReadMesh(file);
    }
    
    void ModelAnimator::ReadMaterial(wstring file)
    {
    	model->ReadMaterial(file);
    }
    
    void ModelAnimator::ReadClip(wstring file)
    {
    	model->ReadClip(file);
    }
    
    void ModelAnimator::Pass(UINT pass)
    {
    	for (ModelMesh* mesh : model->Meshes())
    		mesh->Pass(pass);
    }
    
    void ModelAnimator::PlayTweenMode(UINT index, UINT clip, float speed, float takeTime)
    {
    	blendDesc[index].Mode = 0;
    
    	tweenDesc[index].TakeTime = takeTime;
    	tweenDesc[index].Next.Clip = clip;
    	tweenDesc[index].Next.Speed = speed;
    }
    
    void ModelAnimator::PlayBlendMode(UINT index, UINT clip, UINT clip1, UINT clip2)
    {
    	blendDesc[index].Mode = 1;
    
    	blendDesc[index].Clip[0].Clip = clip;
    	blendDesc[index].Clip[1].Clip = clip1;
    	blendDesc[index].Clip[2].Clip = clip2;
    }
    
    void ModelAnimator::SetBlendAlpha(UINT index, float alpha)
    {
    	alpha = Math::Clamp(alpha, 0.0f, 2.0f);
    
    	blendDesc[index].Alpha = alpha;
    }
    
    void ModelAnimator::GetAttachTransform(UINT instance, Matrix * outResult)
    {
    	ID3D11Texture2D* texture = outputBuffer->Result();
    
    	D3D11_MAPPED_SUBRESOURCE subResource;
    	D3D::GetDC()->Map(texture, 0, D3D11_MAP_READ, 0, &subResource);
    	{
            //instance 크기 만큼 이동한 후에 한줄의 크기(sizeof(Matrix)*MAX_MODEL_TRANSFORMS) 만큼 가져온다.
    		memcpy(outResult, (BYTE *)subResource.pData + (instance * subResource.RowPitch), sizeof(Matrix) * MAX_MODEL_TRANSFORMS);
    	}
    	D3D::GetDC()->Unmap(texture, 0);
    }
    
    void ModelAnimator::CreateTexture()
    {
    	//Matrix matrix[MAX_MODEL_KEYFRAMES][MAX_MODEL_TRANSFORMS];
    
    	clipTransforms = new ClipTransform[model->ClipCount()];
    	for (UINT i = 0; i < model->ClipCount(); i++)	
    		CreateClipTransform(i);
    	
    
    	//Create Texture
    	{
    		D3D11_TEXTURE2D_DESC desc;
    		ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
    		desc.Width = MAX_MODEL_TRANSFORMS * 4;
    		desc.Height = MAX_MODEL_KEYFRAMES;
    		desc.ArraySize = model->ClipCount();
    		desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; //16Byte * 4 = 64Byte
    		desc.Usage = D3D11_USAGE_IMMUTABLE;
    		desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    		desc.MipLevels = 1;
    		desc.SampleDesc.Count = 1;
    
    		UINT pageSize = MAX_MODEL_TRANSFORMS * 4 * 16 * MAX_MODEL_KEYFRAMES;
    		//void* p = malloc(pageSize * model->ClipCount());
    		void* p = VirtualAlloc(NULL, pageSize * model->ClipCount(), MEM_RESERVE, PAGE_READWRITE);
    
    		//MEMORY_BASIC_INFORMATION, VirtualQuery
    
    		for (UINT c = 0; c < model->ClipCount(); c++)
    		{
    			UINT start = c * pageSize;
    
    			for (UINT k = 0; k < MAX_MODEL_KEYFRAMES; k++)
    			{
    				void* temp = (BYTE *)p + MAX_MODEL_TRANSFORMS * k * sizeof(Matrix) + start;
    
    				VirtualAlloc(temp, MAX_MODEL_TRANSFORMS * sizeof(Matrix), MEM_COMMIT, PAGE_READWRITE);
    				memcpy(temp, clipTransforms[c].Transform[k], MAX_MODEL_TRANSFORMS * sizeof(Matrix));
    			}
    		}//for(c)
    
    
    		D3D11_SUBRESOURCE_DATA* subResources = new D3D11_SUBRESOURCE_DATA[model->ClipCount()];
    		for (UINT c = 0; c < model->ClipCount(); c++)
    		{
    			void* temp = (BYTE *)p + c * pageSize;
    
    			subResources[c].pSysMem = temp;
    			subResources[c].SysMemPitch = MAX_MODEL_TRANSFORMS * sizeof(Matrix);
    			subResources[c].SysMemSlicePitch = pageSize;
    		}
    		Check(D3D::GetDevice()->CreateTexture2D(&desc, subResources, &texture));
    
    		
    		SafeDeleteArray(subResources);
    		VirtualFree(p, 0, MEM_RELEASE);
    	}
    
    
    	//Create SRV
    	{
    		D3D11_SHADER_RESOURCE_VIEW_DESC desc;
    		ZeroMemory(&desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
    		desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
    		desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
    		desc.Texture2DArray.MipLevels = 1;
    		desc.Texture2DArray.ArraySize = model->ClipCount();
    
    		Check(D3D::GetDevice()->CreateShaderResourceView(texture, &desc, &srv));
    	}
    
    	for (ModelMesh* mesh : model->Meshes())
    		mesh->TransformsSRV(srv);
    }
    
    void ModelAnimator::CreateClipTransform(UINT index)
    {
    	Matrix* bones = new Matrix[MAX_MODEL_TRANSFORMS];
    
    	ModelClip* clip = model->ClipByIndex(index);
    	for (UINT f = 0; f < clip->FrameCount(); f++)
    	{
    		for (UINT b = 0; b < model->BoneCount(); b++)
    		{
    			ModelBone* bone = model->BoneByIndex(b);
    
    
    			Matrix parent;
    			Matrix invGlobal = bone->Transform();
    			D3DXMatrixInverse(&invGlobal, NULL, &invGlobal);
    
    			int parentIndex = bone->ParentIndex();
    			if (parentIndex < 0)
    				D3DXMatrixIdentity(&parent);
    			else
    				parent = bones[parentIndex];
    
    
    			Matrix animation;
    			ModelKeyframe* frame = clip->Keyframe(bone->Name());
    
    			if (frame != NULL)
    			{
    				ModelKeyframeData& data = frame->Transforms[f];
    
    				Matrix S, R, T;
    				D3DXMatrixScaling(&S, data.Scale.x, data.Scale.y, data.Scale.z);
    				D3DXMatrixRotationQuaternion(&R, &data.Rotation);
    				D3DXMatrixTranslation(&T, data.Translation.x, data.Translation.y, data.Translation.z);
    
    				animation = S * R * T;
    			}
    			else
    			{
    				D3DXMatrixIdentity(&animation);
    			}
    
    			bones[b] = animation * parent;
    			clipTransforms[index].Transform[f][b] = invGlobal * bones[b];
    		}//for(b)
    	}//for(f)
    }
    
    Transform * ModelAnimator::AddTransform()
    {
    	Transform* transform = new Transform();
    	transforms.push_back(transform);
    
    	return transform;
    }
    
    void ModelAnimator::UpdateTransforms()
    {
    	for (UINT i = 0; i < transforms.size(); i++)
    		memcpy(worlds[i], transforms[i]->World(), sizeof(Matrix));
    
    	D3D11_MAPPED_SUBRESOURCE subResource;
    	D3D::GetDC()->Map(instanceBuffer->Buffer(), 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
    	{
    		memcpy(subResource.pData, worlds, sizeof(Matrix) * MAX_MESH_INSTANCE);
    	}
    	D3D::GetDC()->Unmap(instanceBuffer->Buffer(), 0);
    
    	inputWorldBuffer->CopyToInput(worlds);
    }

     


     

    Buffers

     

    Buffers.h

    더보기
    #pragma once
    
    class VertexBuffer
    {
    public:
    	VertexBuffer(void* data, UINT count, UINT stride, UINT slot = 0, bool bCpuWrite = false, bool bGpuWrite = false);
    	~VertexBuffer();
    
    	UINT Count() { return count; }
    	UINT Stride() { return stride; }
    	ID3D11Buffer* Buffer() { return buffer; }
    
    	void Render();
    
    private:
    	ID3D11Buffer* buffer;
    
    	void* data;
    	UINT count;
    	UINT stride;
    	UINT slot;
    
    	bool bCpuWrite;
    	bool bGpuWrite;
    };
    
    
    
    class IndexBuffer
    {
    public:
    	IndexBuffer(void* data, UINT count);
    	~IndexBuffer();
    
    	UINT Count() { return count; }
    	ID3D11Buffer* Buffer() { return buffer; }
    
    	void Render();
    
    private:
    	ID3D11Buffer* buffer;
    
    	void* data;
    	UINT count;
    };
    
    
    
    class ConstantBuffer
    {
    public:
    	ConstantBuffer(void* data, UINT dataSize);
    	~ConstantBuffer();
    
    	ID3D11Buffer* Buffer() { return buffer; }
    
    	void Render();
    
    private:
    	ID3D11Buffer* buffer;
    
    	void* data;
    	UINT dataSize;
    };
    
    
    
    class CsResource
    {
    public:
    	CsResource();
    	virtual ~CsResource();
    
    protected:
    	virtual void CreateInput() {}
    	virtual void CreateSRV() {}
    
    	virtual void CreateOutput() {}
    	virtual void CreateUAV() {}
    
    	virtual void CreateResult() {}
    
    	void CreateBuffer();
    
    public:
    	ID3D11ShaderResourceView* SRV() { return srv; }
    	ID3D11UnorderedAccessView* UAV() { return uav; }
    
    protected:
    	ID3D11Resource* input = NULL;
    	ID3D11ShaderResourceView* srv = NULL; //Input
    
    	ID3D11Resource* output = NULL;
    	ID3D11UnorderedAccessView* uav = NULL; //Output
    
    	ID3D11Resource* result = NULL;
    };
    
    
    
    class RawBuffer : public CsResource
    {
    public:
    	RawBuffer(void* inputData, UINT inputByte, UINT outputByte);
    	~RawBuffer();
    
    private:
    	void CreateInput() override;
    	void CreateSRV() override;
    
    	void CreateOutput() override;
    	void CreateUAV() override;
    
    	void CreateResult() override;
    
    public:
    	void CopyToInput(void* data);
    	void CopyFromOuput(void* data);
    
    private:
    	void* inputData;
    	
    	UINT inputByte;
    	UINT outputByte;
    };
    
    
    
    class StructuredBuffer : public CsResource
    {
    public:
    	StructuredBuffer(void* inputData, UINT inputStride, UINT inputCount, UINT outputStride = 0, UINT outputCount = 0);
    	~StructuredBuffer();
    
    private:
    	void CreateInput() override;
    	void CreateSRV() override;
    
    	void CreateOutput() override;
    	void CreateUAV() override;
    
    	void CreateResult() override;
    
    public:
    	UINT InputByteWidth() { return inputStride * inputCount; }
    	UINT OutputByteWidth() { return outputStride * outputCount; }
    
    	void CopyToInput(void* data);
    	void CopyFromOutput(void* data);
    
    private:
    	void* inputData;
    
    	UINT inputStride;
    	UINT inputCount;
    
    	UINT outputStride;
    	UINT outputCount;
    };
    
    
    
    class TextureBuffer : public CsResource
    {
    public:
    	TextureBuffer(ID3D11Texture2D* src);
    	~TextureBuffer();
    
    private:
    	void CreateSRV() override;
    
    	void CreateOutput() override;
    	void CreateUAV() override;
    
    	void CreateResult() override;
    
    public:
    	UINT Width() { return width; }
    	UINT Height() { return height; }
    	UINT ArraySize() { return arraySize; }
    
    	ID3D11Texture2D* Output() { return (ID3D11Texture2D *)output; }
    	ID3D11ShaderResourceView* OutputSRV() { return outputSRV; }
    
    	void CopyToInput(ID3D11Texture2D* texture);
    	ID3D11Texture2D* CopyFromOutput();
    	ID3D11Texture2D* Result() { return (ID3D11Texture2D *)result; }
    
    private:
    	UINT width, height, arraySize;
    	DXGI_FORMAT format;
    
    	ID3D11ShaderResourceView* outputSRV;
    };

     

     

    Buffers.cpp

    더보기
    #include "Framework.h"
    #include "Buffers.h"
    
    VertexBuffer::VertexBuffer(void * data, UINT count, UINT stride, UINT slot, bool bCpuWrite, bool bGpuWrite)
    	: data(data), count(count), stride(stride), slot(slot)
    	, bCpuWrite(bCpuWrite), bGpuWrite(bGpuWrite)
    {
    	D3D11_BUFFER_DESC desc;
    	ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
    	desc.ByteWidth = stride * count;
    	desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    
    	if (bCpuWrite == false && bGpuWrite == false)
    	{
    		desc.Usage = D3D11_USAGE_IMMUTABLE; //GPU 읽기
    	}
    	else if (bCpuWrite == true && bGpuWrite == false)
    	{
    		desc.Usage = D3D11_USAGE_DYNAMIC; //CPU 쓰기, GPU 읽기
    		desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    	}
    	else if (bCpuWrite == false && bGpuWrite == true)
    	{
    		//CPU 쓰기 가능 - UpdateSubResource
    		desc.Usage = D3D11_USAGE_DEFAULT;
    	}
    	else
    	{
    		desc.Usage = D3D11_USAGE_STAGING;
    		desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
    	}
    
    	D3D11_SUBRESOURCE_DATA subResource = { 0 };
    	subResource.pSysMem = data;
    
    	Check(D3D::GetDevice()->CreateBuffer(&desc, &subResource, &buffer));
    }
    
    VertexBuffer::~VertexBuffer()
    {
    	SafeRelease(buffer);
    }
    
    void VertexBuffer::Render()
    {
    	UINT offset = 0;
    	D3D::GetDC()->IASetVertexBuffers(slot, 1, &buffer, &stride, &offset);
    }
    
    
    
    IndexBuffer::IndexBuffer(void * data, UINT count)
    	: data(data), count(count)
    {
    	D3D11_BUFFER_DESC desc;
    	ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
    
    	desc.ByteWidth = sizeof(UINT) * count;
    	desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    	desc.Usage = D3D11_USAGE_IMMUTABLE;
    
    
    	D3D11_SUBRESOURCE_DATA subResource = { 0 };
    	subResource.pSysMem = data;
    
    	Check(D3D::GetDevice()->CreateBuffer(&desc, &subResource, &buffer));
    }
    
    IndexBuffer::~IndexBuffer()
    {
    	SafeRelease(buffer);
    }
    
    void IndexBuffer::Render()
    {
    	D3D::GetDC()->IASetIndexBuffer(buffer, DXGI_FORMAT_R32_UINT, 0);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    ConstantBuffer::ConstantBuffer(void * data, UINT dataSize)
    	: data(data), dataSize(dataSize)
    {
    	D3D11_BUFFER_DESC desc;
    	ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
    
    	desc.ByteWidth = dataSize;
    	desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    	desc.Usage = D3D11_USAGE_DYNAMIC;
    	desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    
    	Check(D3D::GetDevice()->CreateBuffer(&desc, NULL, &buffer));
    }
    
    ConstantBuffer::~ConstantBuffer()
    {
    	SafeRelease(buffer);
    }
    
    void ConstantBuffer::Render()
    {
    	D3D11_MAPPED_SUBRESOURCE subResource;
    	D3D::GetDC()->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
    	{
    		memcpy(subResource.pData, data, dataSize);
    	}
    	D3D::GetDC()->Unmap(buffer, 0);
    }
    
    
    
    CsResource::CsResource()
    {
    
    }
    
    CsResource::~CsResource()
    {
    	SafeRelease(input);
    	SafeRelease(srv);
    
    	SafeRelease(output);
    	SafeRelease(uav);
    
    	SafeRelease(result);
    }
    
    void CsResource::CreateBuffer()
    {
    	CreateInput();
    	CreateSRV();
    
    	CreateOutput();
    	CreateUAV();
    
    	CreateResult();
    }
    
    
    
    RawBuffer::RawBuffer(void * inputData, UINT inputByte, UINT outputByte)
    	: CsResource()
    	, inputData(inputData), inputByte(inputByte), outputByte(outputByte)
    {
    	CreateBuffer();
    }
    
    RawBuffer::~RawBuffer()
    {
    
    }
    
    void RawBuffer::CreateInput()
    {
    	if (inputByte < 1) return;
    
    
    	ID3D11Buffer* buffer = NULL;
    
    	D3D11_BUFFER_DESC desc;
    	ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
    
    	desc.ByteWidth = inputByte;
    	desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    	desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
    	desc.Usage = D3D11_USAGE_DYNAMIC;
    	desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    
    	D3D11_SUBRESOURCE_DATA subResource = { 0 };
    	subResource.pSysMem = inputData;
    
    	Check(D3D::GetDevice()->CreateBuffer(&desc, inputData != NULL ? &subResource : NULL, &buffer));
    
    	input = (ID3D11Resource *)buffer;
    }
    
    void RawBuffer::CreateSRV()
    {
    	if (inputByte < 1) return;
    
    
    	ID3D11Buffer* buffer = (ID3D11Buffer *)input;
    
    	D3D11_BUFFER_DESC desc;
    	buffer->GetDesc(&desc);
    
    
    	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
    	ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
    	srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
    	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
    	srvDesc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
    	srvDesc.BufferEx.NumElements = desc.ByteWidth / 4;
    
    	Check(D3D::GetDevice()->CreateShaderResourceView(buffer, &srvDesc, &srv));
    }
    
    void RawBuffer::CreateOutput()
    {
    	ID3D11Buffer* buffer = NULL;
    
    	D3D11_BUFFER_DESC desc;
    	ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
    
    	desc.ByteWidth = outputByte;
    	desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
    	desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
    
    	Check(D3D::GetDevice()->CreateBuffer(&desc, NULL, &buffer));
    
    	output = (ID3D11Resource *)buffer;
    }
    
    void RawBuffer::CreateUAV()
    {
    	ID3D11Buffer* buffer = (ID3D11Buffer *)output;
    
    	D3D11_BUFFER_DESC desc;
    	buffer->GetDesc(&desc);
    
    
    	D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
    	ZeroMemory(&uavDesc, sizeof(D3D11_UNORDERED_ACCESS_VIEW_DESC));
    	uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
    	uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
    	uavDesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
    	uavDesc.Buffer.NumElements = desc.ByteWidth / 4;
    
    	Check(D3D::GetDevice()->CreateUnorderedAccessView(buffer, &uavDesc, &uav));
    }
    
    void RawBuffer::CreateResult()
    {
    	ID3D11Buffer* buffer;
    
    	D3D11_BUFFER_DESC desc;
    	((ID3D11Buffer *)output)->GetDesc(&desc);
    	desc.Usage = D3D11_USAGE_STAGING;
    	desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    	desc.BindFlags = D3D11_USAGE_DEFAULT;
    	desc.MiscFlags = 0;
    
    	Check(D3D::GetDevice()->CreateBuffer(&desc, NULL, &buffer));
    
    	result = (ID3D11Resource *)buffer;
    }
    
    void RawBuffer::CopyToInput(void * data)
    {
    	D3D11_MAPPED_SUBRESOURCE subResource;
    	D3D::GetDC()->Map(input, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
    	{
    		memcpy(subResource.pData, data, inputByte);
    	}
    	D3D::GetDC()->Unmap(input, 0);
    }
    
    void RawBuffer::CopyFromOuput(void * data)
    {
    	D3D::GetDC()->CopyResource(result, output);
    
    	D3D11_MAPPED_SUBRESOURCE subResource;
    	D3D::GetDC()->Map(result, 0, D3D11_MAP_READ, 0, &subResource);
    	{
    		memcpy(data, subResource.pData, outputByte);
    	}
    	D3D::GetDC()->Unmap(result, 0);
    }
    
    
    
    StructuredBuffer::StructuredBuffer(void* inputData, UINT inputStride, UINT inputCount, UINT outputStride, UINT outputCount)
    	: CsResource()
    	, inputData(inputData)
    	, inputStride(inputStride), inputCount(inputCount)
    	, outputStride(outputStride), outputCount(outputCount)
    {
    	if (outputStride == 0 || outputCount == 0)
    	{
    		this->outputStride = inputStride;
    		this->outputCount = inputCount;
    	}
    
    	CreateBuffer();
    }
    
    StructuredBuffer::~StructuredBuffer()
    {
    
    }
    
    void StructuredBuffer::CreateInput()
    {
    	ID3D11Buffer* buffer = NULL;
    
    	D3D11_BUFFER_DESC desc;
    	ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
    
    	desc.ByteWidth = InputByteWidth();
    	desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    	desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
    	desc.StructureByteStride = inputStride;
    	desc.Usage = D3D11_USAGE_DYNAMIC;
    	desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    
    	D3D11_SUBRESOURCE_DATA subResource = { 0 };
    	subResource.pSysMem = inputData;
    
    	Check(D3D::GetDevice()->CreateBuffer(&desc, inputData != NULL ? &subResource : NULL, &buffer));
    
    	input = (ID3D11Resource *)buffer;
    }
    
    void StructuredBuffer::CreateSRV()
    {
    	ID3D11Buffer* buffer = (ID3D11Buffer *)input;
    
    	D3D11_BUFFER_DESC desc;
    	buffer->GetDesc(&desc);
    
    
    	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
    	ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
    	srvDesc.Format = DXGI_FORMAT_UNKNOWN;
    	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
    	srvDesc.BufferEx.NumElements = inputCount;
    
    	Check(D3D::GetDevice()->CreateShaderResourceView(buffer, &srvDesc, &srv));
    }
    
    void StructuredBuffer::CreateOutput()
    {
    	ID3D11Buffer* buffer = NULL;
    
    	D3D11_BUFFER_DESC desc;
    	ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
    
    	desc.ByteWidth = OutputByteWidth();
    	desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
    	desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
    	desc.StructureByteStride = outputStride;
    
    	Check(D3D::GetDevice()->CreateBuffer(&desc, NULL, &buffer));
    
    	output = (ID3D11Resource *)buffer;
    }
    
    void StructuredBuffer::CreateUAV()
    {
    	ID3D11Buffer* buffer = (ID3D11Buffer *)output;
    
    	D3D11_BUFFER_DESC desc;
    	buffer->GetDesc(&desc);
    
    
    	D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
    	ZeroMemory(&uavDesc, sizeof(D3D11_UNORDERED_ACCESS_VIEW_DESC));
    	uavDesc.Format = DXGI_FORMAT_UNKNOWN;
    	uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
    	uavDesc.Buffer.NumElements = outputCount;
    
    	Check(D3D::GetDevice()->CreateUnorderedAccessView(buffer, &uavDesc, &uav));
    }
    
    void StructuredBuffer::CreateResult()
    {
    	ID3D11Buffer* buffer;
    
    	D3D11_BUFFER_DESC desc;
    	((ID3D11Buffer *)output)->GetDesc(&desc);
    	desc.Usage = D3D11_USAGE_STAGING;
    	desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    	desc.BindFlags = 0;
    	desc.MiscFlags = 0;
    
    	Check(D3D::GetDevice()->CreateBuffer(&desc, NULL, &buffer));
    
    	result = (ID3D11Resource *)buffer;
    }
    
    void StructuredBuffer::CopyToInput(void * data)
    {
    	D3D11_MAPPED_SUBRESOURCE subResource;
    	D3D::GetDC()->Map(input, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
    	{
    		memcpy(subResource.pData, data, InputByteWidth());
    	}
    	D3D::GetDC()->Unmap(input, 0);
    }
    
    void StructuredBuffer::CopyFromOutput(void * data)
    {
    	D3D::GetDC()->CopyResource(result, output);
    
    	D3D11_MAPPED_SUBRESOURCE subResource;
    	D3D::GetDC()->Map(result, 0, D3D11_MAP_READ, 0, &subResource);
    	{
    		memcpy(data, subResource.pData, OutputByteWidth());
    	}
    	D3D::GetDC()->Unmap(result, 0);
    }
    
    
    
    TextureBuffer::TextureBuffer(ID3D11Texture2D * src)
    {
    	D3D11_TEXTURE2D_DESC srcDesc;
    	src->GetDesc(&srcDesc);
    
    	width = srcDesc.Width;
    	height = srcDesc.Height;
    	arraySize = srcDesc.ArraySize;
    	format = srcDesc.Format;
    
    
    	D3D11_TEXTURE2D_DESC desc;
    	ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
    	desc.Width = width;
    	desc.Height = height;
    	desc.ArraySize = arraySize;
    	desc.Format = format;
    	desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    	desc.MipLevels = 1;
    	desc.SampleDesc.Count = 1;
    
    	ID3D11Texture2D* texture = NULL;
    	Check(D3D::GetDevice()->CreateTexture2D(&desc, NULL, &texture));
    	D3D::GetDC()->CopyResource(texture, src);
    
    	input = (ID3D11Resource *)texture;
    
    	CreateBuffer();
    }
    
    TextureBuffer::~TextureBuffer()
    {
    
    }
    
    void TextureBuffer::CreateSRV()
    {
    	ID3D11Texture2D* texture = (ID3D11Texture2D *)input;
    
    	D3D11_TEXTURE2D_DESC desc;
    	texture->GetDesc(&desc);
    
    	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
    	ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
    	srvDesc.Format = desc.Format;
    	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
    	srvDesc.Texture2DArray.MipLevels = 1;
    	srvDesc.Texture2DArray.ArraySize = arraySize;
    
    	Check(D3D::GetDevice()->CreateShaderResourceView(texture, &srvDesc, &srv));
    }
    
    void TextureBuffer::CreateOutput()
    {
    	ID3D11Texture2D* texture = NULL;
    
    	D3D11_TEXTURE2D_DESC desc;
    	ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
    	desc.Width = width;
    	desc.Height = height;
    	desc.ArraySize = arraySize;
    	desc.Format = format;
    	desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
    	desc.MipLevels = 1;
    	desc.SampleDesc.Count = 1;
    	Check(D3D::GetDevice()->CreateTexture2D(&desc, NULL, &texture));
    
    	output = (ID3D11Resource *)texture;
    
    
    	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
    	ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
    	srvDesc.Format = desc.Format;
    	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
    	srvDesc.Texture2DArray.MipLevels = 1;
    	srvDesc.Texture2DArray.ArraySize = arraySize;
    
    	Check(D3D::GetDevice()->CreateShaderResourceView(texture, &srvDesc, &outputSRV));
    }
    
    void TextureBuffer::CreateUAV()
    {
    	ID3D11Texture2D* texture = (ID3D11Texture2D*)output;
    
    	D3D11_TEXTURE2D_DESC desc;
    	texture->GetDesc(&desc);
    
    
    	D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
    	ZeroMemory(&uavDesc, sizeof(D3D11_UNORDERED_ACCESS_VIEW_DESC));
    	uavDesc.Format = DXGI_FORMAT_UNKNOWN;
    	uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
    	uavDesc.Texture2DArray.ArraySize = arraySize;
    
    	Check(D3D::GetDevice()->CreateUnorderedAccessView(texture, &uavDesc, &uav));
    }
    
    void TextureBuffer::CreateResult()
    {
    	ID3D11Texture2D* texture;
    
    	D3D11_TEXTURE2D_DESC desc;
    	((ID3D11Texture2D *)output)->GetDesc(&desc);
    	desc.Usage = D3D11_USAGE_STAGING;
    	desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    	desc.BindFlags = 0;
    	desc.MiscFlags = 0;
    
    	Check(D3D::GetDevice()->CreateTexture2D(&desc, NULL, &texture));
    
    	result = (ID3D11Resource *)texture;
    }
    
    void TextureBuffer::CopyToInput(ID3D11Texture2D * texture)
    {
    	D3D::GetDC()->CopyResource(input, texture);
    }
    
    ID3D11Texture2D * TextureBuffer::CopyFromOutput()
    {
    	D3D::GetDC()->CopyResource(result, output);
    
    	return (ID3D11Texture2D *)result;
    }

     

     


     

    GetMultiBoneDemo

     

    GetMultiBoneDemo.h

    더보기
    #pragma once
    #include "Systems/IExecute.h"
    
    class GetMultiBoneDemo : public IExecute
    {
    public:
    	virtual void Initialize() override;
    	virtual void Ready() override {}
    	virtual void Destroy() override {}
    	virtual void Update() override;
    	virtual void PreRender() override {}
    	virtual void Render() override;
    	virtual void PostRender() override {}
    	virtual void ResizeScreen() override {}
    
    private:
    	void Mesh();
    	void Airplane();
    	void Kachujin();
    	void KachujinCollider();
    	void KachujinWeapon();
    
    	void Pass(UINT mesh, UINT model, UINT anim);
    
    private:
    	Shader* shader;
    
    	CubeSky* sky;
    
    	Material* floor;
    	Material* stone;
    	Material* brick;
    	Material* wall;
    
    	MeshRender* cube;
    	MeshRender* cylinder;
    	MeshRender* sphere;
    	MeshRender* grid;
    
    	ModelRender* airplane = NULL;
    
    
    	ModelAnimator* kachujin = NULL;
    	Transform* colliderInitTransforms; //무기에 대한 Transform
    	ColliderObject** colliders;
    
    	ModelRender* weapon = NULL;
    	Transform* weaponInitTransform;
    
    	vector<MeshRender *> meshes;
    	vector<ModelRender *> models;
    	vector<ModelAnimator *> animators;
    };

     

     

    GetMultiBoneDemo.cpp

    더보기
    #include "stdafx.h"
    #include "GetMultiBoneDemo.h"
    
    void GetMultiBoneDemo::Initialize()
    {
    	Context::Get()->GetCamera()->RotationDegree(20, 0, 0);
    	Context::Get()->GetCamera()->Position(1, 36, -85);
    
    
    	shader = new Shader(L"55_Render.fx");
    
    	sky = new CubeSky(L"Environment/GrassCube1024.dds");
    	
    	Mesh();
    	Airplane();
    	
    	Kachujin();
    	KachujinCollider();
    	KachujinWeapon();
    }
    
    void GetMultiBoneDemo::Update()
    {
    	//Weapon
    	{
    		Vector3 position;
    		weaponInitTransform->Position(&position);
    		ImGui::SliderFloat3("Weapon Position", position, -20, 20);
    
    		Vector3 scale;
    		weaponInitTransform->Scale(&scale);
    		ImGui::SliderFloat3("Weapon Scale", scale, 0.1f, 3.0f);
    
    		Vector3 rotation;
    		weaponInitTransform->Rotation(&rotation);
    		ImGui::SliderFloat3("Weapon Rotation", rotation, -1.0f, 1.0f);
    
    		weaponInitTransform->Position(position);
    		weaponInitTransform->Scale(scale);
    		weaponInitTransform->Rotation(rotation);
    	}
    
    	//Collider
    	{
    		Vector3 position;
    		colliderInitTransforms->Position(&position);
    		ImGui::SliderFloat3("Collider Position", position, -20, 20);
    
    		Vector3 scale;
    		colliderInitTransforms->Scale(&scale);
    		ImGui::SliderFloat3("Collider Scale", scale, 10.0f, 100.0f);
    
    		Vector3 rotation;
    		colliderInitTransforms->Rotation(&rotation);
    		ImGui::SliderFloat3("Collider Rotation", rotation, -1.0f, 1.0f);
    
    		colliderInitTransforms->Position(position);
    		colliderInitTransforms->Scale(scale);
    		colliderInitTransforms->Rotation(rotation);
    	}
    
    
    	sky->Update();
    
    	cube->Update();
    	grid->Update();
    	cylinder->Update();
    	sphere->Update();
    
    	airplane->Update();
    	kachujin->Update();
    
    	Matrix worlds[MAX_MODEL_TRANSFORMS];
    	for (UINT i = 0; i < kachujin->GetTransformCount(); i++)
    	{
    		kachujin->GetAttachTransform(i, worlds);
    		colliders[i]->Collider->GetTransform()->World(worlds[40]);
    		colliders[i]->Collider->Update();
    
    		//만들어둔 기준(weaponInitTransform->World())에서 이동한 만큼(worlds[40]) 곱해준다.
    		weapon->GetTransform(i)->World(weaponInitTransform->World() * worlds[40]);
    	}
    
    	weapon->UpdateTransforms();
    	weapon->Update();
    }
    
    void GetMultiBoneDemo::Render()
    {
    	sky->Render();
    
    	
    	Pass(0, 1, 2);
    
    	wall->Render();
    	sphere->Render();
    
    	brick->Render();
    	cylinder->Render();
    
    	stone->Render();
    	cube->Render();
    
    	floor->Render();
    	grid->Render();
    
    	airplane->Render();
    	
    	kachujin->Render();
    	weapon->Render();
    	for (UINT i = 0; i < kachujin->GetTransformCount(); i++)
    		colliders[i]->Collider->Render();
    }
    
    void GetMultiBoneDemo::Mesh()
    {
    	//Create Material
    	{
    		floor = new Material(shader);
    		floor->DiffuseMap("Floor.png");
    		//floor->SpecularMap("Floor_Specular.png");
    		//floor->NormalMap("Floor_Normal.png");
    		//floor->Specular(1, 1, 1, 20);
    
    		stone = new Material(shader);
    		stone->DiffuseMap("Stones.png");
    		//stone->SpecularMap("Stones_Specular.png");
    		//stone->NormalMap("Stones_Normal.png");
    		//stone->Specular(1, 1, 1, 20);
    
    		brick = new Material(shader);
    		brick->DiffuseMap("Bricks.png");
    		//brick->SpecularMap("Bricks_Specular.png");
    		//brick->NormalMap("Bricks_Normal.png");
    		//brick->Specular(1, 0.3f, 0.3f, 20);
    
    		wall = new Material(shader);
    		wall->DiffuseMap("Wall.png");
    		//wall->SpecularMap("Wall_Specular.png");
    		//wall->NormalMap("Wall_Normal.png");
    		//wall->Specular(1, 1, 1, 20);
    	}
    
    	//Create Mesh
    	{
    		Transform* transform = NULL;
    
    		cube = new MeshRender(shader, new MeshCube());
    		transform = cube->AddTransform();
    		transform->Position(0, 5, 0);
    		transform->Scale(20, 10, 20);
    
    		grid = new MeshRender(shader, new MeshGrid(5, 5));
    		transform = grid->AddTransform();
    		transform->Position(0, 0, 0);
    		transform->Scale(12, 1, 12);
    
    		cylinder = new MeshRender(shader, new MeshCylinder(0.5f, 3.0f, 20, 20));
    		sphere = new MeshRender(shader, new MeshSphere(0.5f, 20, 20));
    		for (UINT i = 0; i < 5; i++)
    		{
    			transform = cylinder->AddTransform();
    			transform->Position(-30, 6, -15.0f + (float)i * 15.0f);
    			transform->Scale(5, 5, 5);
    
    			transform = cylinder->AddTransform();
    			transform->Position(30, 6, -15.0f + (float)i * 15.0f);
    			transform->Scale(5, 5, 5);
    
    
    			transform = sphere->AddTransform();
    			transform->Position(-30, 15.5f, -15.0f + (float)i * 15.0f);
    			transform->Scale(5, 5, 5);
    
    			transform = sphere->AddTransform();
    			transform->Position(30, 15.5f, -15.0f + (float)i * 15.0f);
    			transform->Scale(5, 5, 5);
    		}
    	}
    
    	sphere->UpdateTransforms();
    	cylinder->UpdateTransforms();
    	cube->UpdateTransforms();
    	grid->UpdateTransforms();
    
    	meshes.push_back(sphere);
    	meshes.push_back(cylinder);
    	meshes.push_back(cube);
    	meshes.push_back(grid);
    }
    
    void GetMultiBoneDemo::Airplane()
    {
    	airplane = new ModelRender(shader);
    	airplane->ReadMesh(L"B787/Airplane");
    	airplane->ReadMaterial(L"B787/Airplane");
    
    	Transform* transform = airplane->AddTransform();
    	transform->Position(2.0f, 9.91f, 2.0f);
    	transform->Scale(0.004f, 0.004f, 0.004f);
    	airplane->UpdateTransforms();
    
    	models.push_back(airplane);
    }
    
    void GetMultiBoneDemo::Kachujin()
    {
    	kachujin = new ModelAnimator(shader);
    	kachujin->ReadMesh(L"Kachujin/Mesh");
    	kachujin->ReadMaterial(L"Kachujin/Mesh");
    	kachujin->ReadClip(L"Kachujin/Sword And Shield Idle");
    	kachujin->ReadClip(L"Kachujin/Sword And Shield Walk");
    	kachujin->ReadClip(L"Kachujin/Sword And Shield Run");
    	kachujin->ReadClip(L"Kachujin/Sword And Shield Slash");
    	kachujin->ReadClip(L"Kachujin/Salsa Dancing");
    
    
    	Transform* transform = NULL;
    
    	transform = kachujin->AddTransform();
    	transform->Position(0, 0, -30);
    	transform->Scale(0.075f, 0.075f, 0.075f);
    	kachujin->PlayTweenMode(0, 0, 1.0f);
    
    	transform = kachujin->AddTransform();
    	transform->Position(-15, 0, -30);
    	transform->Scale(0.075f, 0.075f, 0.075f);
    	kachujin->PlayTweenMode(1, 1, 1.0f);
    
    	transform = kachujin->AddTransform();
    	transform->Position(-30, 0, -30);
    	transform->Scale(0.075f, 0.075f, 0.075f);
    	kachujin->PlayTweenMode(2, 2, 0.75f);
    
    	transform = kachujin->AddTransform();
    	transform->Position(15, 0, -30);
    	transform->Scale(0.075f, 0.075f, 0.075f);
    	kachujin->PlayBlendMode(3, 0, 1, 2);
    	kachujin->SetBlendAlpha(3, 1.5f);
    
    	transform = kachujin->AddTransform();
    	transform->Position(30, 0, -32.5f);
    	transform->Scale(0.075f, 0.075f, 0.075f);
    	kachujin->PlayTweenMode(4, 4, 0.75f);
    
    	kachujin->UpdateTransforms();
    
    	animators.push_back(kachujin);
    }
    
    void GetMultiBoneDemo::KachujinCollider()
    {
    	UINT count = kachujin->GetTransformCount();
    	colliders = new  ColliderObject*[count];
    
    	colliderInitTransforms = new Transform();
    	colliderInitTransforms->Position(-2.9f, 1.45f, -50.0f);
    	colliderInitTransforms->Scale(5, 5, 75);
    
    	for (UINT i = 0; i < count; i++)
    	{
    		colliders[i] = new ColliderObject();
    
    		//colliders[i]->Init = new Transform();
    		//colliders[i]->Init->Position(0, 0, 0);
    		//colliders[i]->Init->Scale(10, 30, 10);
    
    		colliders[i]->Transform = new Transform();
    		//colliders[i]->Collider = new Collider(colliders[i]->Transform, colliders[i]->Init);
    		colliders[i]->Collider = new Collider(colliders[i]->Transform, colliderInitTransforms);
    	}
    }
    
    void GetMultiBoneDemo::KachujinWeapon()
    {
    	weapon = new ModelRender(shader);
    	weapon->ReadMesh(L"Weapon/Sword");
    	weapon->ReadMaterial(L"Weapon/Sword");
    
    	UINT count = kachujin->GetTransformCount();
    	for (UINT i = 0; i < count; i++)
    		weapon->AddTransform();
    
    	weapon->UpdateTransforms();
    	models.push_back(weapon);
    
    	
    	weaponInitTransform = new Transform();
    	weaponInitTransform->Position(-2.9f, 1.45f, -6.45f);
    	weaponInitTransform->Scale(0.5f, 0.5f, 0.75f);
    	weaponInitTransform->Rotation(0, 0, 1);
    }
    
    void GetMultiBoneDemo::Pass(UINT mesh, UINT model, UINT anim)
    {
    	for (MeshRender* temp : meshes)
    		temp->Pass(mesh);
    
    	for (ModelRender* temp : models)
    		temp->Pass(model);
    
    	for (ModelAnimator* temp : animators)
    		temp->Pass(anim);
    }

    무기에 Collider를 붙여주었다.

     


     

     

    실행화면