Geometry Shader는 정점 셰이더(Vertex shader) 뒤와 픽셀 셰이더(Pixel shader) 앞에서 실행되는 셰이더 유형이다. 이것은 정점 셰이더 단독보다 더 복잡한 기하학적 조작을 가능하게 하며, 새로운 꼭짓점을 생성하거나 메쉬의 위상을 변경하거나 기하학에 다른 변환을 적용하는 데 사용한다.

 

목차

     

     


     

     

     

     

    Geometry Shader

     

    Shaders
       Light.fx
     Billboard.fx
    Framework
      Viewer
      Billboard.h .cpp 
    P
      BillboardDemo.h .cpp 
       

     

     

     

     


     

     

    렌더링 순서 DirectX9  vs.  DirectX10 

     

    DirectX9

    • IA → VS → RS → PS → OM

     

     

    DirectX10

    • IA → VS → GS →SO(요즘은 잘 안 쓴다)    RS → PS → OM

     

     


     

     

     

    Light.fx 추가코드

     

    Light.fx 추가코드

    더보기
    float4 PS_AllLight(MeshOutput input)
    {
    NormalMapping(input.Uv, input.Normal, input.Tangent);
    Texture(Material.Diffuse, DiffuseMap, input.Uv);
    Texture(Material.Specular, SpecularMap, input.Uv);
    MaterialDesc output = MakeMaterial();
    MaterialDesc result = MakeMaterial();
    ComputeLight(output, input.Normal, input.wPosition);
    AddMaterial(result, output);
    ComputePointLight(output, input.Normal, input.wPosition);
    AddMaterial(result, output);
    ComputeSpotLight(output, input.Normal, input.wPosition);
    AddMaterial(result, output);
    return float4(MaterialToColor(result).rgb, 1.0f);
    }

     


     

     

     

    Billboard.fx

     

    Billboard.fx

    더보기
    #include "00_Global.fx"
    #include "00_Light.fx"
    #include "00_Render.fx"
    float4 PS(MeshOutput input) : SV_Target
    {
    return PS_AllLight(input);
    }
    struct VertexBillboard
    {
    float4 Position : Position;
    float2 Scale : Scale;
    uint MapIndex : MapIndex;
    //uint VertexIndex : SV_VertexID;
    };
    struct VertexOutput
    {
    float4 Position : Position;
    float2 Scale : Scale;
    uint MapIndex : MapIndex;
    };
    VertexOutput VS(VertexBillboard input)
    {
    VertexOutput output;
    output.Position = WorldPosition(input.Position);
    output.Scale = input.Scale;
    output.MapIndex = input.MapIndex;
    return output;
    }
    struct GeometryOutput
    {
    float4 Position : SV_Position;
    float2 Uv : Uv;
    uint MapIndex : MapIndex;
    };
    [maxvertexcount(4)]
    void GS_Billboard(point VertexOutput input[1], inout TriangleStream<GeometryOutput> stream)
    {
    float3 up = float3(0, 1, 0);
    //float3 forward = float3(0, 0, 1);
    float3 forward = input[0].Position.xyz - ViewPosition();
    float3 right = normalize(cross(up, forward));//up과 forward를 외적한 후에 정규화해준다.
    float2 size = input[0].Scale * 0.5f;
    float4 position[4];
    position[0] = float4(input[0].Position.xyz - size.x * right - size.y * up, 1);//좌하단
    position[1] = float4(input[0].Position.xyz - size.x * right + size.y * up, 1);//좌상단
    position[2] = float4(input[0].Position.xyz + size.x * right - size.y * up, 1);//우하단
    position[3] = float4(input[0].Position.xyz + size.x * right + size.y * up, 1);//우상단
    float2 uv[4] =
    {
    float2(0, 1), float2(0, 0), float2(1, 1), float2(1, 0)
    };
    GeometryOutput output; //자료형
    [unroll(4)] //정점 4개 처리
    for (int i = 0; i < 4; i++)
    {
    output.Position = ViewProjection(position[i]);
    output.Uv = uv[i];
    output.MapIndex = input[0].MapIndex;
    stream.Append(output);//TriangleStream을 추가한다.
    }
    }
    [maxvertexcount(8)]
    void GS_Cross(point VertexOutput input[1], inout TriangleStream<GeometryOutput> stream)
    {
    float3 up = float3(0, 1, 0);
    float3 forward = float3(0, 0, 1);
    float3 right = normalize(cross(up, forward));
    float2 size = input[0].Scale * 0.5f;
    float4 position[8];
    position[0] = float4(input[0].Position.xyz - size.x * right - size.y * up, 1);
    position[1] = float4(input[0].Position.xyz - size.x * right + size.y * up, 1);
    position[2] = float4(input[0].Position.xyz + size.x * right - size.y * up, 1);
    position[3] = float4(input[0].Position.xyz + size.x * right + size.y * up, 1);
    position[4] = float4(input[0].Position.xyz - size.x * forward - size.y * up, 1);
    position[5] = float4(input[0].Position.xyz - size.x * forward + size.y * up, 1);
    position[6] = float4(input[0].Position.xyz + size.x * forward - size.y * up, 1);
    position[7] = float4(input[0].Position.xyz + size.x * forward + size.y * up, 1);
    float2 uv[4] =
    {
    float2(0, 1), float2(0, 0), float2(1, 1), float2(1, 0)
    };
    GeometryOutput output;
    [unroll(8)]
    for (int i = 0; i < 8; i++)
    {
    output.Position = ViewProjection(position[i]);
    output.Uv = uv[i % 4];
    output.MapIndex = input[0].MapIndex;
    stream.Append(output);
    [flatten]
    if(i == 3)
    stream.RestartStrip();
    }
    }
    Texture2DArray BillboardMap;
    float4 PS_Billboard(GeometryOutput input) : SV_Target
    {
    return BillboardMap.Sample(LinearSampler, float3(input.Uv, input.MapIndex)) * 1.75f;
    }
    technique11 T0
    {
    P_VP(P0, VS_Mesh, PS)
    P_VP(P1, VS_Model, PS)
    P_VP(P2, VS_Animation, PS)
    P_BS_VGP(P3, AlphaBlend, VS, GS_Billboard, PS_Billboard)
    P_RS_BS_VGP(P4, CullMode_None, AlphaBlend_AlphaToCoverageEnable, VS, GS_Cross, PS_Billboard)
    }

    void GS_Billboard(point VertexOutput input[1], inout TriangleStream<GeometryOutput> stream)

    • point VertexOutput input[1]
      • point list이기 때문에 하나만 받아온다. 
    • inout TriangleStream stream
      • Geometry Shader는 삼각형만 다룬다.(사각형으로 사용이 불가능하다). 템플릿 문법을 사용하였다.

     

     

     

     


     

     

    Billboard

     

    Billboard.h

    더보기
    #pragma once
    #define MAX_BILLBOARD_COUNT 10000
    class Billboard : public Renderer
    {
    public:
    Billboard(Shader* shader);
    ~Billboard();
    void Update();
    void Render();
    void Add(Vector3& position, Vector2& scale, UINT mapIndex);
    void AddTexture(wstring file);
    private:
    struct VertexBillboard
    {
    Vector3 Position;
    Vector2 Scale;
    UINT MapIndex;
    };
    private:
    vector<VertexBillboard> vertices;
    vector<wstring> textureNames;
    TextureArray* textureArray = NULL;
    ID3DX11EffectShaderResourceVariable* sDiffuseMap;
    };

     

     

     

    Billboard.cpp

    더보기
    #include "Framework.h"
    #include "Billboard.h"
    Billboard::Billboard(Shader* shader)
    : Renderer(shader)
    {
    Topology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
    sDiffuseMap = shader->AsSRV("BillboardMap");
    }
    Billboard::~Billboard()
    {
    SafeDelete(textureArray);
    }
    void Billboard::Update()
    {
    Super::Update();
    }
    void Billboard::Render()
    {
    if (textureNames.size() > 0 && textureArray == NULL)
    {
    SafeDelete(textureArray); //textureArray가 바뀌는 경우가 발생하므로 지우고
    textureArray = new TextureArray(textureNames);//textureArray를 그려준다.
    }
    if (vertexCount != vertices.size())
    {
    vertexCount = vertices.size();
    SafeDelete(vertexBuffer);
    vertexBuffer = new VertexBuffer(&vertices[0], vertices.size(), sizeof(VertexBillboard));
    }
    Super::Render();
    sDiffuseMap->SetResource(textureArray->SRV());
    shader->Draw(0, Pass(), vertexCount);
    }
    void Billboard::AddTexture(wstring file)
    {
    textureNames.push_back(file);
    }
    void Billboard::Add(Vector3 & position, Vector2 & scale, UINT mapIndex)
    {
    VertexBillboard vertex =
    {
    position, scale, mapIndex
    };
    vertices.push_back(vertex);
    }

     

     


     

     

    BillboardDemo

     

    BillboardDemo.h

    더보기
    #pragma once
    #include "Systems/IExecute.h"
    class BillboardDemo : 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;
    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;
    };

     

     

     

    BillboardDemo.cpp

    더보기
    #include "stdafx.h"
    #include "BillboardDemo.h"
    void BillboardDemo::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");
    sky = new CubeSky(L"Environment/GrassCube1024.dds");
    Billboards();
    Mesh();
    Airplane();
    Kachujin();
    KachujinCollider();
    KachujinWeapon();
    PointLighting();
    SpotLighting();
    }
    void BillboardDemo::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();
    }
    void BillboardDemo::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();
    }
    void BillboardDemo::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 BillboardDemo::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 BillboardDemo::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 BillboardDemo::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 BillboardDemo::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 BillboardDemo::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 BillboardDemo::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 BillboardDemo::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 BillboardDemo::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);
    }

     

     


     

     

     

    실행화면