• Home
  • About
    • 게임 개발자 유정룡 photo

      게임 개발자 유정룡

      포트폴리오

    • Learn More
    • Email
    • Github
    • Bitbucket
  • Projects
    • All Projects
    • All Tags

Direct3D11 공부 40일차(Geometry Shader)

02 Aug 2021

Reading time ~3 minutes

PipeLine

Geometry Shader를 언제 사용하는지 알기 위해 파이프라인을 다시 살펴봐야 한다.

DXD9까지 파이프라인은 지금까지 알고있는 순서로 작동한다

IA - VS - RS - PS - OM

하지만 DXD10부터는 두개의 단계가 추가된다

IA - VS - GS(Geometry Shader) - SO (Stream Output) - RS - PS - OM

  • Geometry Shader
    • Vertex Shader에서는 할 수 없는 점이나, 선, 삼각형 등의 도형을 생성할 수 있는 기능을 갖고있다.
    • 테셀레이션이나 그림자 효과, 큐브 맵을 한번의 처리로 렌더링하는 데에 주로 쓰인다.
  • Stream Output
    • 3D Shader 결과를 리턴해준다.
    • 하지만 DXD11에서는 사용 하지 않고 ComputeShader를 사용한다.

Geometry Shader

쉽게 생각하면 지금까지 VertexShader에서 했던 각 정점을 Index값으로 이어주던 것을 정점 하나로 도형을 만들어 주는 셰이더이다.

이렇게 해주면 메모리를 더욱 절약할 수 있다.

이 Geometry Shader로 Billboard를 바꿔보자

96_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;
};

struct VertexOutput
{
    float4 Position : Position;
    float2 Scale : Scale;
};

VertexOutput VS(VertexBillboard input)
{
    VertexOutput output;
    
    output.Position = WorldPosition(input.Position);
    output.Scale = input.Scale;

    return output;
}

struct GeometryOutput
{
    float4 Position : SV_Position;
    float2 Uv : Uv;
};

[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));
    
    float2 size = input[0].Scale * 0.5f;
    
    
    float4 position[4];
    // x방향으로 -0.5
    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)]
    for (int i = 0; i < 4; i++)
    {
        output.Position = ViewProjection(position[i]);
        output.Uv = uv[i];

        stream.Append(output);
    }
}

float4 PS_Billboard(GeometryOutput input) : SV_Target
{
    return BillboardMap.Sample(LinearSampler, float3(input.Uv, input.MapIndex)) * 1.75;
}

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

큰 타이는 없지만 Input에 정점 한개를 받아서 그 위치에정점 4개를 만들고 Index를 3개 만든 뒤 이어준다.

Billboard

그리고 지금까지 만들었던 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);
	void SetTexture(wstring file);

private:
	struct VertexBillboard
	{
		Vector3 Position;
		Vector2 Scale;
	};

private:
	vector<VertexBillboard> vertices;

	Texture* texture = 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 (vertexCount != vertices.size())
	{
		vertexCount = vertices.size();

		SafeDelete(vertexBuffer);
		vertexBuffer = new VertexBuffer(&vertices[0], vertices.size(), sizeof(VertexBillboard));
	}

	Super::Render();

	sDiffuseMap->SetResource(textureArray->SRV());
	shader->DrawIndex(0, Pass(), indexCount);
}

void Billboard::Add(Vector3 & position, Vector2 & scale)
{
	VertexBillboard vertex =
	{
		position, scale
	};

	vertices.push_back(vertex);
}

void Billboard::SetTexture(wstring file)
{
	texture = new Texture(file);
}

이상태로 실행하면



DirectX Share Tweet +1