DirectX 11에서 애니메이션을 인스턴스화하는 것은 장면에서 많은 수의 애니메이션 객체를 효율적으로 렌더링하는 데 사용되는 기술이다. 이 기술을 사용하면 단일 개체를 애니메이션화한 다음 서로 다른 변환 또는 애니메이션 상태로 여러 번 그릴 수 있다.

 

목차

     


     

     

    Instancing Animation

     

    DirectX 11에서 애니메이션을 인스턴스화하는 것은 장면에서 많은 수의 애니메이션 객체를 효율적으로 렌더링하는 데 사용되는 기술다. 이 기술을 사용하면 단일 개체를 애니메이션화한 다음 서로 다른 변환 또는 애니메이션 상태로 여러 번 그릴 수 있다.

    인스턴스 애니메이션 기법은 단일 지오메트리 버퍼를 사용하여 객체의 지오메트리를 정의하고, 개별 버퍼를 사용하여 객체의 각 인스턴스에 대한 인스턴스 데이터를 저장함으로써 작동한다. 인스턴스 데이터 버퍼에는 일반적으로 각 인스턴스의 위치, 회전 및 축척에 대한 정보뿐만 아니라 현재 애니메이션 프레임과 같이 셰이더로 전달해야 하는 다른 모든 인스턴스별 데이터가 포함된다.

    인스턴스 개체를 애니메이션화하기 위해 그래픽 파이프라인은 지오메트리 버퍼와 인스턴스 데이터 버퍼를 모두 읽는다. 각 인스턴스에 대해 파이프라인은 인스턴스별 데이터를 사용하여 객체의 지오메트리를 객체 공간에서 월드 공간으로 변환하는 변환 행렬을 계산한다. 또한 파이프라인은 인스턴스별 데이터를 사용하여 각 인스턴스의 현재 애니메이션 프레임을 결정한다.

    현재 애니메이션 프레임은 일반적으로 텍스처 버퍼 또는 상수 버퍼에 저장되며, 매개 변수로 정점 셰이더에 전달된다. 그런 다음 정점 셰이더는 이 매개 변수를 사용하여 현재 애니메이션 프레임을 기반으로 객체의 각 정점의 위치와 방향을 계산한다. 이렇게 하면 각 프레임에 대한 지오메트리나 변환 행렬을 다시 계산하지 않고도 객체를 애니메이션화할 수 있다.

    Instancing animation의 주요 장점은 상대적으로 낮은 CPU 및 GPU 비용으로 많은 수의 애니메이션 개체를 효율적으로 렌더링할 수 있다는 것입니다. 그래픽 드라이버가 하드웨어 가속을 사용하여 Instancing(인스턴스화) 및 애니메이션 작업을 수행할 수 있기 때문에 각 객체에 대해 각 Transform Matrix(변환 매트릭스) 및 애니메이션 상태를 개별적으로 계산하는 것보다 훨씬 빠르다.

    애니메이션을 인스턴스화하는 것은 특히 많은 수의 캐릭터, 곤충 떼 또는 유사한 애니메이션 객체가 있는 다른 장면을 렌더링하는 데 유용합니다. 또한 걷기, 달리기, 점프 또는 기타 동작을 수행할 수 있는 캐릭터와 같이 여러 애니메이션 상태를 가진 복잡한 객체를 효율적으로 렌더링하는 데 사용할 수 있습니다.

     

    더보기

    Instancing animation in DirectX 11 is a technique used to efficiently render large numbers of animated objects in a scene. This technique allows you to animate a single object and then draw it multiple times with different transformations or animation states.

    The instancing animation technique works by using a single geometry buffer to define the geometry of the object, and a separate buffer to store the instance data for each instance of the object. The instance data buffer typically contains information about the position, rotation, and scale of each instance, as well as any other per-instance data that needs to be passed to the shader, such as the current animation frame.

    To animate the instanced object, the graphics pipeline reads both the geometry buffer and the instance data buffer. For each instance, the pipeline uses the per-instance data to compute a transformation matrix that transforms the object's geometry from object space to world space. The pipeline also uses the per-instance data to determine the current animation frame for each instance.

    The current animation frame is typically stored in a texture buffer or a constant buffer, and is passed to the vertex shader as a parameter. The vertex shader then uses this parameter to calculate the position and orientation of each vertex of the object based on the current animation frame. This allows the object to be animated without having to recompute the geometry or transform matrices for each frame.

    The main advantage of instancing animation is that it allows you to efficiently render large numbers of animated objects with a relatively low CPU and GPU cost. This is because the graphics driver can use hardware acceleration to perform the instancing and animation operations, which is much faster than computing each transformation matrix and animation state separately for each object.

    Instancing animation is particularly useful for rendering large crowds of characters, swarms of insects, or any other scene with many similar animated objects. It can also be used to efficiently render complex objects that have multiple animation states, such as a character that can walk, run, jump, or perform other actions.

     

     

    Shader
      00_Global.fx
    00_Render.fx
    51_InstancingMesh
    Framework
      Environment
       
      Meshes
      Mesh.h .cpp
    MeshCube.h. cpp
    MeshCylinder.h .cpp
    MeshGrid.h .cpp
    MeshQuad.h .cpp
    MeshSphere.h .cpp
    MeshRender.h .cpp
      Model
      ModelAnimator.h .cpp
    ModelMesh.h .cpp
    ModelEditor
      Demo
      MeshDemo.h .cpp
    ModelDemo.h .cpp
      Main.h .cpp

     

     


    fx

     

    00_Render.fx

    더보기
    float4 PS_Sky(MeshOutput input) : SV_Target
    {
        return SkyCubeMap.Sample(LinearSampler, input.oPosition);
    }
    ///////////////////////////////////////////////////////////////////////////////
    
    struct VertexMesh
    {
        float4 Position : Position;
        float2 Uv : Uv;
        float3 Normal : Normal;
        float3 Tangent : Tangent;
        
        matrix Transform : Inst1_Transform;
        float4 Color : Inst2_Color;
    };
    
    //////////////////////////////////////////////////////////////////////////////
    
    #define VS_GENERATE \
    output.oPosition = input.Position.xyz; \
    \
    output.Position = WorldPosition(input.Position); \
    output.wPosition = output.Position.xyz; \
    output.Position = ViewProjection(output.Position); \
    output.wvpPosition = output.Position; \
    output.wvpPosition_Sub = output.Position; \
    \
    output.sPosition = WorldPosition(input.Position); \
    output.sPosition = mul(output.sPosition, ShadowView); \
    output.sPosition = mul(output.sPosition, ShadowProjection); \
    \
    output.Normal = WorldNormal(input.Normal); \
    output.Tangent = WorldTangent(input.Tangent); \
    \
    output.Uv = input.Uv; \
    output.Color = input.Color;
    
    ///////////////////////////////////////////////////////////////////////////////
    
    struct DepthOutput
    {
        float4 Position : SV_Position;
        float4 sPosition : Position1;
    };
    
    float4 PS_Depth(DepthOutput input) : SV_Target
    {
        float depth = input.Position.z / input.Position.w;
        
        return float4(depth, depth, depth, 1.0f);
    }
    
    #define VS_DEPTH_GENERATE \
    output.Position = WorldPosition(input.Position); \
    output.Position = mul(output.Position, ShadowView); \
    output.Position = mul(output.Position, ShadowProjection); \
    \
    output.sPosition = output.Position;
    
    ///////////////////////////////////////////////////////////////////////////////
    
    void SetMeshWorld(inout matrix world, VertexMesh input)
    {
        world = input.Transform;
    }
    
    MeshOutput VS_Mesh(VertexMesh input)
    {
        MeshOutput output;
        
        SetMeshWorld(World, input);
        VS_GENERATE
        
        return output;
    }
    
    DepthOutput VS_Depth_Mesh(VertexMesh input)
    {
        DepthOutput output;
        
        SetMeshWorld(World, input);
        VS_DEPTH_GENERATE
        
        return output;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    struct VertexModel
    {
        float4 Position : Position;
        float2 Uv : Uv;
        float3 Normal : Normal;
        float3 Tangent : Tangent;
        float4 BlendIndices : BlendIndices;
        float4 BlendWeights : BlendWeights;
        
        uint InstanceID : SV_InstanceID;
        
        matrix Transform : Inst1_Transform;
        float4 Color : Inst2_Color;
    };
    
    Texture2DArray TransformsMap;
    #define MAX_MODEL_TRANSFORMS 250
    
    cbuffer CB_Bone
    {
        //matrix BoneTransforms[MAX_MODEL_TRANSFORMS];
        
        uint BoneIndex;
    };
    
    void SetModelWorld(inout matrix world, VertexModel input)
    {
        //world = mul(BoneTransforms[BoneIndex], world);
        
        float4 m0 = TransformsMap.Load(int4(BoneIndex * 4 + 0, input.InstanceID, 0, 0));
        float4 m1 = TransformsMap.Load(int4(BoneIndex * 4 + 1, input.InstanceID, 0, 0));
        float4 m2 = TransformsMap.Load(int4(BoneIndex * 4 + 2, input.InstanceID, 0, 0));
        float4 m3 = TransformsMap.Load(int4(BoneIndex * 4 + 3, input.InstanceID, 0, 0));
        
        matrix transform = matrix(m0, m1, m2, m3);
        world = mul(transform, input.Transform);
    }
    
    MeshOutput VS_Model(VertexModel input)
    {
        MeshOutput output;
        
        SetModelWorld(World, input);
        VS_GENERATE
        
        return output;
    }
    
    DepthOutput VS_Depth_Model(VertexModel input)
    {
        DepthOutput output;
        
        SetModelWorld(World, input);
        VS_DEPTH_GENERATE
        
        return output;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    #define MAX_MODEL_KEYFRAMES 500
    #define MAX_MODEL_INSTANCE 500
    
    struct AnimationFrame
    {
        int Clip;
    
        uint CurrFrame;
        uint NextFrame;
    
        float Time;
        float Running;
    
        float3 Padding;
    };
    
    struct TweenFrame
    {
        float TakeTime;
        float TweenTime;
        float RunningTime;
        float Padding;
    
        AnimationFrame Curr;
        AnimationFrame Next;
    };
    
    cbuffer CB_TweenFrame
    {
        TweenFrame TweenFrames[MAX_MODEL_INSTANCE];
    };
    
    void SetTweenWorld(inout matrix world, VertexModel input)
    {
        float indices[4] = { input.BlendIndices.x, input.BlendIndices.y, input.BlendIndices.z, input.BlendIndices.w };
        float weights[4] = { input.BlendWeights.x, input.BlendWeights.y, input.BlendWeights.z, input.BlendWeights.w };
        
        
        int clip[2];
        int currFrame[2];
        int nextFrame[2];
        float time[2];
        
        clip[0] = TweenFrames[input.InstanceID].Curr.Clip;
        currFrame[0] = TweenFrames[input.InstanceID].Curr.CurrFrame;
        nextFrame[0] = TweenFrames[input.InstanceID].Curr.NextFrame;
        time[0] = TweenFrames[input.InstanceID].Curr.Time;
        
        clip[1] = TweenFrames[input.InstanceID].Next.Clip;
        currFrame[1] = TweenFrames[input.InstanceID].Next.CurrFrame;
        nextFrame[1] = TweenFrames[input.InstanceID].Next.NextFrame;
        time[1] = TweenFrames[input.InstanceID].Next.Time;
        
        
        
        float4 c0, c1, c2, c3;
        float4 n0, n1, n2, n3;
        
        matrix curr = 0, next = 0;
        matrix currAnim = 0;
        matrix nextAnim = 0;
        
        matrix transform = 0;
        
        [unroll(4)]
        for (int i = 0; i < 4; i++)
        {
            c0 = TransformsMap.Load(int4(indices[i] * 4 + 0, currFrame[0], clip[0], 0));
            c1 = TransformsMap.Load(int4(indices[i] * 4 + 1, currFrame[0], clip[0], 0));
            c2 = TransformsMap.Load(int4(indices[i] * 4 + 2, currFrame[0], clip[0], 0));
            c3 = TransformsMap.Load(int4(indices[i] * 4 + 3, currFrame[0], clip[0], 0));
            curr = matrix(c0, c1, c2, c3);
            
            n0 = TransformsMap.Load(int4(indices[i] * 4 + 0, nextFrame[0], clip[0], 0));
            n1 = TransformsMap.Load(int4(indices[i] * 4 + 1, nextFrame[0], clip[0], 0));
            n2 = TransformsMap.Load(int4(indices[i] * 4 + 2, nextFrame[0], clip[0], 0));
            n3 = TransformsMap.Load(int4(indices[i] * 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(indices[i] * 4 + 0, currFrame[1], clip[1], 0));
                c1 = TransformsMap.Load(int4(indices[i] * 4 + 1, currFrame[1], clip[1], 0));
                c2 = TransformsMap.Load(int4(indices[i] * 4 + 2, currFrame[1], clip[1], 0));
                c3 = TransformsMap.Load(int4(indices[i] * 4 + 3, currFrame[1], clip[1], 0));
                curr = matrix(c0, c1, c2, c3);
            
                n0 = TransformsMap.Load(int4(indices[i] * 4 + 0, nextFrame[1], clip[1], 0));
                n1 = TransformsMap.Load(int4(indices[i] * 4 + 1, nextFrame[1], clip[1], 0));
                n2 = TransformsMap.Load(int4(indices[i] * 4 + 2, nextFrame[1], clip[1], 0));
                n3 = TransformsMap.Load(int4(indices[i] * 4 + 3, nextFrame[1], clip[1], 0));
                next = matrix(n0, n1, n2, n3);
            
                nextAnim = lerp(curr, next, time[1]);
                
                currAnim = lerp(currAnim, nextAnim, TweenFrames[input.InstanceID].TweenTime);
            }
            
            
            transform += mul(weights[i], currAnim);
        }
        
        world = mul(transform, input.Transform);
    }
    
    struct BlendFrame
    {
        uint Mode;
        float Alpha;
        float2 Padding;
        
        AnimationFrame Clip[3];
    };
    
    cbuffer CB_BlendFrame
    {
        BlendFrame BlendFrames[MAX_MODEL_INSTANCE];
    };
    
    void SetBlendWorld(inout matrix world, VertexModel input)
    {
        float indices[4] = { input.BlendIndices.x, input.BlendIndices.y, input.BlendIndices.z, input.BlendIndices.w };
        float weights[4] = { input.BlendWeights.x, input.BlendWeights.y, input.BlendWeights.z, input.BlendWeights.w };
        
        
        float4 c0, c1, c2, c3;
        float4 n0, n1, n2, n3;
        
        matrix curr = 0, next = 0;
        matrix currAnim[3];
        matrix anim = 0;
        matrix transform = 0;
        
        BlendFrame frame = BlendFrames[input.InstanceID];
        
        [unroll(4)]
        for (int i = 0; i < 4; i++)
        {
            [unroll(3)]
            for (int k = 0; k < 3; k++)
            {
                c0 = TransformsMap.Load(int4(indices[i] * 4 + 0, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0));
                c1 = TransformsMap.Load(int4(indices[i] * 4 + 1, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0));
                c2 = TransformsMap.Load(int4(indices[i] * 4 + 2, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0));
                c3 = TransformsMap.Load(int4(indices[i] * 4 + 3, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0));
                curr = matrix(c0, c1, c2, c3);
            
                n0 = TransformsMap.Load(int4(indices[i] * 4 + 0, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0));
                n1 = TransformsMap.Load(int4(indices[i] * 4 + 1, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0));
                n2 = TransformsMap.Load(int4(indices[i] * 4 + 2, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0));
                n3 = TransformsMap.Load(int4(indices[i] * 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);
            
            transform += mul(weights[i], anim);
        }
        
        world = mul(transform, input.Transform);
    }
    
    MeshOutput VS_Animation(VertexModel input)
    {
        MeshOutput output;
        
        if (BlendFrames[input.InstanceID].Mode == 0)
            SetTweenWorld(World, input);
        else
            SetBlendWorld(World, input);
        
        VS_GENERATE
        
        return output;
    }
    
    DepthOutput VS_Depth_Animation(VertexModel input)
    {
        DepthOutput output;
        
        if (BlendFrames[input.InstanceID].Mode == 0)
            SetTweenWorld(World, input);
        else
            SetBlendWorld(World, input);
        
        VS_DEPTH_GENERATE
        
        return output;
    }

     

    TweenFrame TweenFrames;를 배열로 만들어준다. TweenFrame TweenFrames[MAX_MODEL_INSTANCE];

    BlendFrame BlendFrames;를 배열로 만들어준다. BlendFrame BlendFrames[MAX_MODEL_INSTANCE];

     

    53_InstancingAnimation.fx

    더보기
    #include "00_Global.fx"
    #include "00_Light.fx"
    #include "00_Render.fx"
    
    float4 PS(MeshOutput input) : SV_Target
    {
        float3 normal = normalize(input.Normal);
        float3 light = -GlobalLight.Direction;
        
        return DiffuseMap.Sample(LinearSampler, input.Uv) * dot(light, normal);
    }
    
    technique11 T0
    {
        P_VP(P0, VS_Mesh, PS)
        P_VP(P1, VS_Model, PS)
        P_VP(P2, VS_Animation, PS)
    }

     


     

    Model Animator

     

    ModelAnimator.h

    더보기
    #pragma once
    
    class ModelAnimator
    {
    public:
    	ModelAnimator(Shader* shader);
    	~ModelAnimator();
    
    	void Update();
    private:
    	void UpdateTweenMode(UINT index); //UINT index는 인스턴스 아이디
    	void UpdateBlendMode(UINT index); //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();
    
    	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);
    
    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;
    
    	ConstantBuffer* frameBuffer;
    	ID3DX11EffectConstantBuffer* sFrameBuffer;
    
    	//애니메이션 개수만큼 적용. 배열
    	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]; //배열
    
    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;
    };

     

     

    삭제

    Transform* GetTransform() { return transform; }

    Transform* transform;

     

    삽입

    Transform* AddTransform();
    Transform* GetTransform(UINT index) { return transforms[index]; }
    void UpdateTransforms();

    VertexBuffer* instanceBuffer;

     

    UINT index는 인스턴스 아이디이다.

     

     

    ModelAnimator.cpp

    더보기
    #include "Framework.h"
    #include "ModelAnimator.h"
    
    ModelAnimator::ModelAnimator(Shader * shader)
    	: shader(shader)
    {
    	model = new Model();
    
    	frameBuffer = new ConstantBuffer(&tweenDesc, sizeof(TweenDesc) * MAX_MODEL_INSTANCE);//배열이니 * MAX_MODEL_INSTANCE
    	sFrameBuffer = 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);
    }
    
    ModelAnimator::~ModelAnimator()
    {
    	SafeDelete(model);
    
    	SafeDeleteArray(clipTransforms);
    	SafeRelease(texture);
    	SafeRelease(srv);
    
    	SafeDelete(frameBuffer);
    	SafeDelete(blendBuffer);
    
    	SafeDelete(instanceBuffer);
    }
    
    void ModelAnimator::Update()
    {
    	for (UINT i = 0; i < transforms.size(); i++)
    	{
    		if (blendDesc[i].Mode == 0)
    			UpdateTweenMode(i);
    		else
    			UpdateBlendMode(i);
    	}
    
    
    
    	if (texture == NULL)
    	{
    		for (ModelMesh* mesh : model->Meshes())
    			mesh->SetShader(shader);
    
    		CreateTexture();
    	}
    
    	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()
    {
    	frameBuffer->Render();
    	sFrameBuffer->SetConstantBuffer(frameBuffer->Buffer());
    
    	blendBuffer->Render();
    	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::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);
    }

     


     

    Model Mesh

     

    ModelMesh.h

    더보기
    #pragma once
    
    class ModelBone
    {
    public:
    	friend class Model;
    
    private:
    	ModelBone();
    	~ModelBone();
    
    public:
    	int Index() { return index; }
    
    	int ParentIndex() { return parentIndex; }
    	ModelBone* Parent() { return parent; }
    
    	wstring Name() { return name; }
    
    	Matrix& Transform() { return transform; }
    	void Transform(Matrix& matrix) { transform = matrix; }
    
    	vector<ModelBone *>& Childs() { return childs; }
    
    private:
    	int index;
    	wstring name;
    
    	int parentIndex;
    	ModelBone* parent;
    
    	Matrix transform;
    	vector<ModelBone *> childs;
    };
    
    ///////////////////////////////////////////////////////////////////////////////
    
    class ModelMesh
    {
    public:
    	friend class Model;
    
    private:
    	ModelMesh();
    	~ModelMesh();
    
    	void Binding(Model* model);
    
    public:
    	void Pass(UINT val) { pass = val; }
    	void SetShader(Shader* shader);
    
    	void Update();
    	void Render(UINT drawCount);
    
    	wstring Name() { return name; }
    
    	int BoneIndex() { return boneIndex; }
    	class ModelBone* Bone() { return bone; }
    
    	void TransformsSRV(ID3D11ShaderResourceView* srv) { transformsSRV = srv; }
    
    private:
    	struct BoneDesc
    	{
    		UINT Index;
    		float Padding[3];
    	} boneDesc;
    
    private:
    	wstring name;
    
    	Shader* shader;
    	UINT pass = 0;
    
    	PerFrame* perFrame = NULL;
    
    	wstring materialName = L"";
    	Material* material;
    
    	int boneIndex;
    	class ModelBone* bone;
    
    	VertexBuffer* vertexBuffer;
    	UINT vertexCount;
    	Model::ModelVertex* vertices;
    
    	IndexBuffer* indexBuffer;
    	UINT indexCount;
    	UINT* indices;
    
    	ConstantBuffer* boneBuffer;
    	ID3DX11EffectConstantBuffer* sBoneBuffer;
    
    	ID3D11ShaderResourceView* transformsSRV = NULL;
    	ID3DX11EffectShaderResourceVariable* sTransformsSRV;
    };

     

    삭제

    void Render();

    Matrix Transforms[MAX_MODEL_TRANSFORMS];

    Transform* transform = NULL;

     

     

    ModelMesh.cpp

    더보기
    #include "Framework.h"
    #include "ModelMesh.h"
    
    ModelBone::ModelBone()
    {
    
    }
    
    ModelBone::~ModelBone()
    {
    
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    ModelMesh::ModelMesh()
    {
    	boneBuffer = new ConstantBuffer(&boneDesc, sizeof(BoneDesc));
    }
    
    ModelMesh::~ModelMesh()
    {
    	SafeDelete(perFrame);
    
    	SafeDelete(material);
    
    	SafeDeleteArray(vertices);
    	SafeDeleteArray(indices);
    
    	SafeDelete(vertexBuffer);
    	SafeDelete(indexBuffer);
    
    	SafeDelete(boneBuffer);
    }
    
    void ModelMesh::Binding(Model * model)
    {
    	vertexBuffer = new VertexBuffer(vertices, vertexCount, sizeof(Model::ModelVertex));
    	indexBuffer = new IndexBuffer(indices, indexCount);
    
    
    	Material* srcMaterial = model->MaterialByName(materialName);
    
    	material = new Material();
    	material->CopyFrom(srcMaterial);
    }
    
    void ModelMesh::SetShader(Shader * shader)
    {
    	this->shader = shader;
    
    	SafeDelete(perFrame);
    	perFrame = new PerFrame(shader);
    
    	sBoneBuffer = shader->AsConstantBuffer("CB_Bone");
    
    	material->SetShader(shader);
    
    	sTransformsSRV = shader->AsSRV("TransformsMap");
    }
    
    void ModelMesh::Update()
    {
    	boneDesc.Index = boneIndex;
    
    	perFrame->Update();
    }
    
    void ModelMesh::Render(UINT drawCount)
    {
    	boneBuffer->Render();
    	sBoneBuffer->SetConstantBuffer(boneBuffer->Buffer());
    
    	perFrame->Render();
    	material->Render();
    
    	vertexBuffer->Render();
    	indexBuffer->Render();
    
    	if (transformsSRV != NULL)
    		sTransformsSRV->SetResource(transformsSRV);
    
    	D3D::GetDC()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    
    	shader->DrawIndexedInstanced(0, pass, indexCount, drawCount);
    }

     

    삭제

    transform 관련 부분 삭제

    void ModelMesh::Render() 

     


     

     

     

    실행화면

     

     

     

     


     

    Process와 Thread

     


     

    Process 단위의 실행

     

    IPC(Inter Process Communication)

    • IPC 종류: MessageMap, pipeline
    • IPC의 문제점: 필연적으로 Interupt을 발생시킨다.
    • Interupt의 대표적인 발생조건은 Input/Output

     

    Thread 단위의 실행

     

    Thread는 CPU에 할당될 수 있는 최소한의 단위. CPU에서 실행될 수 있는 최소한의 단위. 쓰레드는 함수단위.

     

    Context Switching = Thread에 교체되는데 사용되는 비용.

     

    여러 개의 Thread를 사용하는 경우를 멀티쓰레드라고 부른다.

     

    동기화 vs  비동기화

    • 동기화는 순서대로 실행 .
    • 비동기화는 순서대로 실행되지 않고 동시에 실행.
    • 비동기화를 더 많이 사용한다. 

     


     

     

    '⭐ DirectX > DirectX11 3D' 카테고리의 다른 글

    [DirectX11] 056 Thread  (0) 2023.02.22
    [DirectX11] 055 Framework  (0) 2023.02.22
    [DirectX11] 051~52 Instancing Mesh & Model  (0) 2023.02.18
    [DirectX11] 050 Instancing  (0) 2023.02.18
    [DirectX11] 048 Play Animation  (0) 2023.02.16