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);
    }

     

     


     

     

     

    실행화면