Compute Shader는 DirectX 11의 도구로 GPU 상에서 복잡한 연산을 수행할 수 있으며, 애니메이션의 경우 Compute Shader를 사용하여 Skeletal Animation System에서 Bone의 변환을 효율적으로 계산할 수 있어 CPU 오버헤드를 최소화하면서 실시간 애니메이션을 구현할 수 있다.

 

목차

     

     


     

     

    Compute Shader - GetAnimationBone 구현하기

     

    컴퓨팅 셰이더(Compute Shader)는 그래픽 렌더링에 주로 사용되는 정점 및 픽셀 셰이더와 같은 다른 유형의 셰이더와 달리, Compute Shader는 더 유연하고 다용도적으로 설계되어 있다.

    Compute Shader에서는 GPU 상의 여러 스레드(multiple threads)에 걸쳐 복잡한 연산을 병렬로 수행하는 코드를 작성할 수 있으며, 이는 물리 시뮬레이션, 데이터 처리, 머신 러닝 알고리즘 등 다양한 작업에 유용할 수 있다.

    DirectX 11의 애니메이션에 관해서는 Compute Shader를 사용하여 3D 모델의 이동과 관련된 계산을 수행할 수 있다. 구체적으로, Compute Shaderskeletal animation system에서 뼈의 변환을 계산하는 데 사용될 수 있다.

    Skeletal Animation System에서 3D 모델은 일련의 상호 연결된 뼈로 구성된다. 각 Bone에는 부모 Bone에 대한 위치, 방향 및 척도를 결정하는 고유한 변환 행렬이 있다. 모형에 있는 모든 골격의 변환 행렬을 결합하여 망사의 각 정점의 최종 위치를 계산할 수 있다.

    이러한 계산을 효율적으로 수행하기 위해 컴퓨팅 셰이더를 사용하여 GPU 상의 여러 스레드(Multiple Threads)에 걸쳐 각 골격의 변환을 병렬로 계산할 수 있다. 이를 통해 CPU에 미치는 성능 영향을 최소화하면서 애니메이션을 실시간으로 수행할 수 있다.

    Compute Shader는 DirectX 11의 강력한 도구로 GPU 상에서 복잡한 연산을 수행할 수 있으며, 애니메이션의 경우 Compute Shader를 사용하여 Skeletal Animation System에서 Bone의 변환을 효율적으로 계산할 수 있어 CPU 오버헤드를 최소화하면서 실시간 애니메이션을 구현할 수 있다.

     

     

     

    Structure Buffer - 구조체 1차원 배열로 넘김.

    Bone 번호를 주고 해당 Bone의 위치(SRT)를 Compute Shader를 통해서 구해준다.

    충돌체(Bounding Box)를 삽입하여 추후에 마우스클릭이 가능하도록 만든다.  이 때 투영의 개념을 이해하여야 한다. 마우스 클릭은 OBB 개념을 활용하여 OBB Ray와 OBB rock을 사용한다. 

     

    Shader
      RawBuffer.fx
    GetAnimationBone.fx 생성
    Framework
      Render
      Buffer.h .cpp
    Render2D.h .cpp 
    UnitTest
      DirectCompute
      RawBufferDemo.h .cpp
      Main.h .cpp

     


     

    GetAnimationBone.fx

     

    GetAnimationBone.fx

    더보기
    #include "00_Global.fx"
    #include "00_Render.fx"
    
    struct InputDesc
    {
        matrix Bone;
    };
    StructuredBuffer<InputDesc> Input; //입력받을 구조체가 들어옴
    
    struct OutputDesc
    {
        matrix Result;
    };
    RWStructuredBuffer<OutputDesc> Output; 
    
    
    cbuffer CB_AttachBone
    {
        uint AttachBoneIndex; //어느 Bone 번호를 구할건지
    };
    
    matrix TweenMode(uint index)
    {
        uint boneIndex[2];
        matrix result = 0;
    
        //.Curr.Clip(=한 면) * MAX_MODEL_KEYFRAMES(=Y) * MAX_MODEL_TRANSFORMS(=X) //전체크기
        boneIndex[0] = (TweenFrames[index].Curr.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
        //.Curr.CurrFrame(=Y) * MAX_MODEL_TRANSFORMS(=건너뛸 크기(Y프레임 개수))
    	boneIndex[0] += (TweenFrames[index].Curr.CurrFrame * MAX_MODEL_TRANSFORMS);
        //AttachBoneIndex(=X방향)
    	boneIndex[0] += AttachBoneIndex;
        
        boneIndex[1] = (TweenFrames[index].Curr.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
        boneIndex[1] += (TweenFrames[index].Curr.NextFrame* MAX_MODEL_TRANSFORMS);
        boneIndex[1] += AttachBoneIndex;
    
        
        matrix currFrame = Input[boneIndex[0]].Bone; //현재 프레임
        matrix nextFrame = Input[boneIndex[1]].Bone; //다음 프레임
        
        result = lerp(currFrame, nextFrame, TweenFrames[index].Curr.Time);
        
        [flatten]
        if(TweenFrames[index].Next.Clip > -1)
        {
            boneIndex[0] = (TweenFrames[index].Next.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
            boneIndex[0] += (TweenFrames[index].Next.CurrFrame * MAX_MODEL_TRANSFORMS);
            boneIndex[0] += AttachBoneIndex;
        
            boneIndex[1] = (TweenFrames[index].Next.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
            boneIndex[1] += (TweenFrames[index].Next.NextFrame * MAX_MODEL_TRANSFORMS);
            boneIndex[1] += AttachBoneIndex;
            
            matrix currFrame = Input[boneIndex[0]].Bone;
            matrix nextFrame = Input[boneIndex[1]].Bone;
        
            matrix nextAnim = lerp(currFrame, nextFrame, TweenFrames[index].Next.Time);
            
            result = lerp(result, nextAnim, TweenFrames[index].TweenTime);
        }
        
        return result;
    }
    
    matrix BlendMode(uint index)
    {
        uint boneIndex[2];
        matrix animation[3];
        
        
        BlendFrame frame = BlendFrames[index];
        
        [unroll(3)]
        for (int i = 0; i < 3; i++)
        {
            boneIndex[0] = (frame.Clip[i].Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
            boneIndex[0] += (frame.Clip[i].CurrFrame * MAX_MODEL_TRANSFORMS);
            boneIndex[0] += AttachBoneIndex;
        
            boneIndex[1] = (frame.Clip[i].Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
            boneIndex[1] += (frame.Clip[i].NextFrame * MAX_MODEL_TRANSFORMS);
            boneIndex[1] += AttachBoneIndex;
        
            matrix currFrame = Input[boneIndex[0]].Bone;
            matrix nextFrame = Input[boneIndex[1]].Bone;
        
            animation[i] = lerp(currFrame, nextFrame, TweenFrames[index].Curr.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;
            }
        }
            
        return lerp(animation[clipA], animation[clipB], alpha);
    }
    
    //최대 스레드의 개수를 사용한다. 스레드 하나 당 instance 하나를 대입하여 실행한다.
    [numthreads(MAX_MODEL_INSTANCE, 1, 1)] 
    void CS(uint GroupIndex : SV_GroupIndex)
    {
        matrix result = 0;
        if(BlendFrames[GroupIndex].Mode == 0)
            result = TweenMode(GroupIndex);
        else
            result = BlendMode(GroupIndex);
        
        Output[GroupIndex].Result = result;
    }
    
    technique11 T0
    {
        pass P0
        {
            SetVertexShader(NULL);
            SetPixelShader(NULL);
    
            SetComputeShader(CompileShader(cs_5_0, CS()));
        }
    }

     

    핵심코드

    더보기
    matrix TweenMode(uint index)
    {
        uint boneIndex[2];
        matrix result = 0;
    
        ////.Curr.Clip(=한 면) * MAX_MODEL_KEYFRAMES(=Y) * MAX_MODEL_TRANSFORMS(=X) //전체크기
        boneIndex[0] = (TweenFrames[index].Curr.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
        ////.Curr.CurrFrame(=Y) * MAX_MODEL_TRANSFORMS(=건너뛸 크기(Y프레임 개수))
    	boneIndex[0] += (TweenFrames[index].Curr.CurrFrame * MAX_MODEL_TRANSFORMS);
        //AttachBoneIndex(=X방향)
    	boneIndex[0] += AttachBoneIndex;
        
        boneIndex[1] = (TweenFrames[index].Curr.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
        boneIndex[1] += (TweenFrames[index].Curr.NextFrame* MAX_MODEL_TRANSFORMS);
        boneIndex[1] += AttachBoneIndex;
    
        
        matrix currFrame = Input[boneIndex[0]].Bone; //현재 프레임
        matrix nextFrame = Input[boneIndex[1]].Bone; //다음 프레임
        
        result = lerp(currFrame, nextFrame, TweenFrames[index].Curr.Time);
        
        ...
        
        return result;
    }
    
    //최대 스레드의 개수를 사용한다. 스레드 하나 당 instance 하나를 대입하여 실행한다.
    [numthreads(MAX_MODEL_INSTANCE, 1, 1)]

     

     


     

    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 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; }
    
    private:
    	UINT width, height, arraySize;
    	DXGI_FORMAT format;
    
    	ID3D11ShaderResourceView* outputSRV;
    };
    
    
    
    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 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;
    };

     

     

     

    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);
    }
    
    
    
    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;
    }
    
    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 = (ID3D11Texture2D*)output;
    
    	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, &outputSRV));
    }
    
    
    //inputData=구조체 초기화 데이터(입력받는 데이터의 크기), inputStride=구조체 하나의 크기, inputCount=구조체 개수(배열의 개수), outputStride=출력될 구조체 하나의 크기, outputCount=출력될 구조체의 개수 
    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; //Resource는 전부 SRV로 연결된다.
    	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; //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; //UNKOWN 포맷으로 설정.
    	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);
    }