MRT(Multiple Render Targets)는 한 번의 추첨 통화에서 둘 이상의 렌더 대상에 렌더링할 수 있는 기능을 말한다. 기존 렌더링 파이프라인에서는 하나의 렌더링 대상(백 버퍼)만 사용하여 화면에 최종 결과를 표시한다. 그러나 복잡한 후 처리 효과를 구현하거나 지연된 렌더링 기법을 구현하거나 섀도 매핑을 수행하는 경우와 같이 여러 렌더 대상에 동시에 렌더링해야 하는 상황이 있다.

 

목차

     

     


     

     

     

    MRT(Multiple Render Targets)

     

    MRT(Multiple Render Targets)는 한 번의 추첨 통화에서 둘 이상의 렌더 대상에 렌더링할 수 있는 기능을 말한다.

    기존 렌더링 파이프라인에서는 하나의 렌더링 대상(백 버퍼)만 사용하여 화면에 최종 결과를 표시한다. 그러나 복잡한 후 처리 효과를 구현하거나 지연된 렌더링 기법을 구현하거나 섀도 매핑을 수행하는 경우와 같이 여러 렌더 대상에 동시에 렌더링해야 하는 상황이 있다.

    MRT를 사용하면 RTV(Render Target View)를 그래픽 파이프라인의 출력 병합 단계에 바인딩할 때 여러 렌더 대상을 지정할 수 있다. 렌더링 시 픽셀 셰이더의 출력이 지정된 모든 렌더링 대상에 동시에 기록된다. 이를 통해 특정 효과를 달성하는 데 필요한 추첨 통화 수를 크게 줄여 성능을 향상시킬 수 있다.

    DirectX11에서 MRT를 사용하려면 원하는 렌더 대상 수에 대해 여러 렌더 대상 뷰를 만들어야 한다. 그런 다음 ID3D11 DeviceContext:를 사용하여 이러한 렌더 대상 뷰를 출력 병합 단계로 설정한다. 렌더링 시 픽셀 셰이더의 출력을 셰이더 코드의 SV_Target 의미를 사용하여 지정된 렌더 대상에 쓸 수 있다.

    MRT는복잡한 장면과 후처리 효과를 보다 효율적으로 렌더링할 수 있다.

     

     

    Shaders
       Mrt.fx 생성
    Framework
      Viewer
      RenderTarget.h .cpp 
    UnitTest
      PostEffects
      MrtDemo.h .cpp 생성

     


     

     

     

    Mrt.fx

     

    Mrt.fx

    더보기
    #include "00_Global.fx"
    #include "00_Light.fx"
    float2 PixelSize;
    struct VertexOutput
    {
    float4 Position : SV_Position;
    float2 Uv : Uv;
    };
    VertexOutput VS(float4 Position : Position)
    {
    VertexOutput output;
    output.Position = Position;
    output.Uv.x = Position.x * 0.5f + 0.5f;
    output.Uv.y = -Position.y * 0.5f + 0.5f;
    return output;
    }
    struct PixelOutput
    {
    float4 Color0 : SV_Target0;
    float4 Color1 : SV_Target1;
    float4 Color2 : SV_Target2;
    };
    PixelOutput PS_Mrt(VertexOutput input)
    {
    PixelOutput output;
    output.Color0 = DiffuseMap.Sample(LinearSampler, input.Uv);
    output.Color1 = 1 - DiffuseMap.Sample(LinearSampler, input.Uv);
    float3 color = DiffuseMap.Sample(LinearSampler, input.Uv).rgb;
    float average = (color.r + color.g + color.b) / 3.0f;
    output.Color2 = float4(average, average, average, 1.0f);
    return output;
    }
    float4 PS(VertexOutput input) : SV_Target
    {
    return DiffuseMap.Sample(LinearSampler, input.Uv);;
    }
    technique11 T0
    {
    P_VP(P0, VS, PS_Mrt)
    P_VP(P1, VS, PS)
    }

     

     

     


     

    RenderTarget

     

    RenderTarget.h

    더보기
    #pragma once
    class RenderTarget
    {
    public:
    RenderTarget(UINT width = 0, UINT height = 0, DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM);
    ~RenderTarget();
    ID3D11RenderTargetView* RTV() { return rtv; }
    ID3D11ShaderResourceView* SRV() { return srv; }
    void SaveTexture(wstring file);
    void PreRender(class DepthStencil* depthStencil);
    static void PreRender(RenderTarget** targets, UINT count, class DepthStencil* depthStencil);
    private:
    UINT width, height;
    DXGI_FORMAT format;
    ID3D11Texture2D* texture;
    ID3D11RenderTargetView* rtv;
    ID3D11ShaderResourceView* srv;
    };

    함수 추가

    • static void PreRender(RenderTarget** targets, UINT count, class DepthStencil* depthStencil)

     

     

    RenderTarget.cpjp

    더보기
    #include "Framework.h"
    #include "RenderTarget.h"
    RenderTarget::RenderTarget(UINT width, UINT height, DXGI_FORMAT format)
    : format(format)
    {
    this->width = (width < 1) ? (UINT)D3D::Width() : width;
    this->height = (height < 1) ? (UINT)D3D::Height() : height;
    D3D11_TEXTURE2D_DESC textureDesc;
    ZeroMemory(&textureDesc, sizeof(D3D11_TEXTURE2D_DESC));
    textureDesc.Width = this->width;
    textureDesc.Height = this->height;
    textureDesc.ArraySize = 1;
    textureDesc.Format = format;
    textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
    textureDesc.MipLevels = 1;
    textureDesc.SampleDesc.Count = 1;
    Check(D3D::GetDevice()->CreateTexture2D(&textureDesc, NULL, &texture));
    D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
    ZeroMemory(&rtvDesc, sizeof(D3D11_RENDER_TARGET_VIEW_DESC));
    rtvDesc.Format = format;
    rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
    Check(D3D::GetDevice()->CreateRenderTargetView(texture, &rtvDesc, &rtv));
    D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
    ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
    srvDesc.Format = format;
    srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    srvDesc.Texture2D.MipLevels = 1;
    Check(D3D::GetDevice()->CreateShaderResourceView(texture, &srvDesc, &srv));
    }
    RenderTarget::~RenderTarget()
    {
    SafeRelease(texture);
    SafeRelease(rtv);
    SafeRelease(srv);
    }
    void RenderTarget::SaveTexture(wstring file)
    {
    Check(D3DX11SaveTextureToFile(D3D::GetDC(), texture, D3DX11_IFF_PNG, file.c_str()));
    }
    void RenderTarget::PreRender(DepthStencil * depthStencil)
    {
    D3D::GetDC()->OMSetRenderTargets(1, &rtv, depthStencil->DSV());
    D3D::Get()->Clear(Color(0, 0, 0, 1), rtv, depthStencil->DSV());
    }
    void RenderTarget::PreRender(RenderTarget ** targets, UINT count, DepthStencil * depthStencil)
    {
    vector<ID3D11RenderTargetView *> rtvs;
    for (UINT i = 0; i < count; i++)
    {
    ID3D11RenderTargetView* rtv = targets[i]->RTV();
    rtvs.push_back(rtv);
    D3D::GetDC()->ClearRenderTargetView(rtv, Color(0, 0, 0, 1));
    }
    D3D::GetDC()->ClearDepthStencilView(depthStencil->DSV(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1, 0);
    D3D::GetDC()->OMSetRenderTargets(rtvs.size(), &rtvs[0], depthStencil->DSV());
    }

    함수 정의

    • void RenderTarget::PreRender(RenderTarget ** targets, UINT count, DepthStencil * depthStencil)

     

     

     


     

    MrtDemo

     

    MrtDemo.h

    더보기
    #pragma once
    #include "Systems/IExecute.h"
    class MrtDemo : 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 Billboards();
    void Mesh();
    void Airplane();
    void Kachujin();
    void KachujinCollider();
    void KachujinWeapon();
    void PointLighting();
    void SpotLighting();
    void Pass(UINT mesh, UINT model, UINT anim);
    private:
    Shader* shader;
    RenderTarget* renderTarget;
    RenderTarget* mrt[3];
    DepthStencil* depthStencil;
    Viewport* viewport;
    Render2D* render2D;
    PostEffect* postEffect;
    Billboard* billboard;
    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;
    ColliderObject** colliders;
    ModelRender* weapon = NULL;
    Transform* weaponInitTransform;
    vector<MeshRender *> meshes;
    vector<ModelRender *> models;
    vector<ModelAnimator *> animators;
    };

     

     

     

    MrtDemo.cpp

    더보기
    #include "stdafx.h"
    #include "MrtDemo.h"
    void MrtDemo::Initialize()
    {
    Context::Get()->GetCamera()->RotationDegree(20, 0, 0);
    Context::Get()->GetCamera()->Position(1, 36, -85);
    ((Freedom *)Context::Get()->GetCamera())->Speed(50, 2);
    shader = new Shader(L"96_Billboard.fxo");
    float width = D3D::Width(), height = D3D::Height();
    width = height = 4096;
    renderTarget = new RenderTarget((UINT)width, (UINT)height);
    mrt[0] = new RenderTarget((UINT)width, (UINT)height);
    mrt[1] = new RenderTarget((UINT)width, (UINT)height);
    mrt[2] = new RenderTarget((UINT)width, (UINT)height);
    depthStencil = new DepthStencil((UINT)width, (UINT)height);
    viewport = new Viewport(width, height);
    render2D = new Render2D();
    render2D->GetTransform()->Scale(355, 200, 1);
    render2D->GetTransform()->Position(200, 120, 0);
    postEffect = new PostEffect(L"103_Mrt.fxo");
    postEffect->SRV(renderTarget->SRV());
    sky = new CubeSky(L"Environment/GrassCube1024.dds");
    Billboards();
    Mesh();
    Airplane();
    Kachujin();
    KachujinCollider();
    KachujinWeapon();
    PointLighting();
    SpotLighting();
    }
    void MrtDemo::Update()
    {
    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);
    weapon->GetTransform(i)->World(weaponInitTransform->World() * worlds[40]);
    }
    weapon->UpdateTransforms();
    weapon->Update();
    billboard->Update();
    render2D->Update();
    postEffect->Update();
    }
    void MrtDemo::PreRender()
    {
    renderTarget->PreRender(depthStencil);
    viewport->RSSetViewport();
    //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();
    billboard->Render();
    }
    //Mrt
    {
    RenderTarget::PreRender(mrt, 3, depthStencil);
    viewport->RSSetViewport();
    postEffect->SRV(renderTarget->SRV());
    postEffect->Render();
    }
    }
    void MrtDemo::Render()
    {
    }
    void MrtDemo::PostRender()
    {
    static UINT index = 0;
    ImGui::InputInt("Mrt Index", (int *)&index);
    index %= 3;
    postEffect->SRV(mrt[index]->SRV());
    postEffect->Render();
    render2D->SRV(renderTarget->SRV());
    render2D->Render();
    }
    void MrtDemo::Billboards()
    {
    billboard = new Billboard(shader);
    //billboard->Pass(3);
    billboard->Pass(4);
    billboard->AddTexture(L"Terrain/grass_14.tga");
    billboard->AddTexture(L"Terrain/grass_07.tga");
    billboard->AddTexture(L"Terrain/grass_11.tga");
    for (UINT i = 0; i < 1200; i++)
    {
    Vector2 scale = Math::RandomVec2(1, 3);
    Vector2 position = Math::RandomVec2(-60, 60);
    billboard->Add(Vector3(position.x, scale.y * 0.5f, position.y), scale, 0);
    }
    for (UINT i = 0; i < 300; i++)
    {
    Vector2 scale = Math::RandomVec2(1, 3);
    Vector2 position = Math::RandomVec2(-60, 60);
    billboard->Add(Vector3(position.x, scale.y * 0.5f, position.y), scale, 1);
    }
    for (UINT i = 0; i < 700; i++)
    {
    Vector2 scale = Math::RandomVec2(1, 3);
    Vector2 position = Math::RandomVec2(-60, 60);
    billboard->Add(Vector3(position.x, scale.y * 0.5f, position.y), scale, 2);
    }
    }
    void MrtDemo::Mesh()
    {
    //Create Material
    {
    floor = new Material(shader);
    floor->DiffuseMap("Floor.png");
    floor->Specular(1, 1, 1, 20);
    floor->SpecularMap("Floor_Specular.png");
    floor->NormalMap("Floor_Normal.png");
    stone = new Material(shader);
    stone->DiffuseMap("Stones.png");
    stone->Specular(1, 1, 1, 20);
    stone->SpecularMap("Stones_Specular.png");
    stone->Emissive(0.15f, 0.15f, 0.15f, 0.3f);
    stone->NormalMap("Stones_Normal.png");
    brick = new Material(shader);
    brick->DiffuseMap("Bricks.png");
    brick->Specular(1, 0.3f, 0.3f, 20);
    brick->SpecularMap("Bricks_Specular.png");
    brick->Emissive(0.15f, 0.15f, 0.15f, 0.3f);
    brick->NormalMap("Bricks_Normal.png");
    wall = new Material(shader);
    wall->DiffuseMap("Wall.png");
    wall->Specular(1, 1, 1, 20);
    wall->SpecularMap("Wall_Specular.png");
    wall->Emissive(0.15f, 0.15f, 0.15f, 0.3f);
    wall->NormalMap("Wall_Normal.png");
    }
    //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 MrtDemo::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 MrtDemo::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 MrtDemo::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 MrtDemo::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 MrtDemo::PointLighting()
    {
    PointLight light;
    light =
    {
    Color(0.0f, 0.0f, 0.0f, 1.0f), //Ambient
    Color(0.0f, 0.0f, 1.0f, 1.0f), //Diffuse
    Color(0.0f, 0.0f, 0.7f, 1.0f), //Specular
    Color(0.0f, 0.0f, 0.7f, 1.0f), //Emissive
    Vector3(-30, 10, -30), 5.0f, 0.9f
    };
    Lighting::Get()->AddPointLight(light);
    light =
    {
    Color(0.0f, 0.0f, 0.0f, 1.0f),
    Color(1.0f, 0.0f, 0.0f, 1.0f),
    Color(0.6f, 0.2f, 0.0f, 1.0f),
    Color(0.6f, 0.3f, 0.0f, 1.0f),
    Vector3(15, 10, -30), 10.0f, 0.3f
    };
    Lighting::Get()->AddPointLight(light);
    light =
    {
    Color(0.0f, 0.0f, 0.0f, 1.0f), //Ambient
    Color(0.0f, 1.0f, 0.0f, 1.0f), //Diffuse
    Color(0.0f, 0.7f, 0.0f, 1.0f), //Specular
    Color(0.0f, 0.7f, 0.0f, 1.0f), //Emissive
    Vector3(-5, 1, -17.5f), 5.0f, 0.9f
    };
    Lighting::Get()->AddPointLight(light);
    light =
    {
    Color(0.0f, 0.0f, 0.0f, 1.0f),
    Color(0.0f, 0.0f, 1.0f, 1.0f),
    Color(0.0f, 0.0f, 0.7f, 1.0f),
    Color(0.0f, 0.0f, 0.7f, 1.0f),
    Vector3(-10, 1, -17.5f), 5.0f, 0.9f
    };
    Lighting::Get()->AddPointLight(light);
    }
    void MrtDemo::SpotLighting()
    {
    SpotLight light;
    light =
    {
    Color(0.3f, 1.0f, 0.0f, 1.0f),
    Color(0.7f, 1.0f, 0.0f, 1.0f),
    Color(0.3f, 1.0f, 0.0f, 1.0f),
    Color(0.3f, 1.0f, 0.0f, 1.0f),
    Vector3(-15, 20, -30), 25.0f,
    Vector3(0, -1, 0), 30.0f, 0.4f
    };
    Lighting::Get()->AddSpotLight(light);
    light =
    {
    Color(1.0f, 0.2f, 0.9f, 1.0f),
    Color(1.0f, 0.2f, 0.9f, 1.0f),
    Color(1.0f, 0.2f, 0.9f, 1.0f),
    Color(1.0f, 0.2f, 0.9f, 1.0f),
    Vector3(0, 20, -30), 30.0f,
    Vector3(0, -1, 0), 40.0f, 0.55f
    };
    Lighting::Get()->AddSpotLight(light);
    }
    void MrtDemo::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);
    }

     

     


     

    실행화면