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

      게임 개발자 유정룡

      포트폴리오

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

Direct3D11 공부 37일차(Billboard)

28 Jul 2021

Reading time ~3 minutes

Billboard

게임 내에서 오브젝트를 보면 항상 카메라를 향하고 있는 오브젝트들이 있다.

이런 오브젝트중 가장 많이 쓰이는 오브젝트인 풀을 이 Billboard를 활용해서 만들어보자

Shader

struct VertexInput
{
    float4 Position : Position;
    float2 Uv : Uv;
    float2 Scale : Scale;
};

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

VertexOutput VS(VertexInput input)
{
    VertexOutput output;
    
    float4 position = WorldPosition(input.Position);

    float3 up = float3(0, 1, 0);
    //float3 forward = float3(0, 0, 1);
    float3 forward = position.xyz - ViewPosition();
    float3 right = normalize(cross(up, forward));
    
    position.xyz += (input.Uv.x - 0.5f) * right * input.Scale.x;
    position.xyz += (1.0f - input.Uv.y - 0.5f) * up * input.Scale.y;
    position.w = 1.0f;
    
    output.Position = ViewProjection(position);
    output.Uv = input.Uv;
    
    return output;
}

각각 벡터를 계산해준다

forward는 항상 카메마를 바라봐야 하기 때문에 현재 위치에서 ViewPosition을 빼서 방향을 구해준다.

이제 이 벡터들을 활용해서 텍스처의 uv를 계산해준다.

float4 PS(VertexOutput input) : SV_Target
{
    float4 diffuse = DiffuseMap.Sample(LinearSampler, input.Uv);
    
    //clip(diffuse.a - 0.3f);
    if (diffuse.a < 0.3)
        discard;
    
    return diffuse;
}

그리고 각 픽셀의 투명값이 0.3 이하일 경우 제거해준다.

Billboard Class

#pragma once
#define MAX_BILLBOARD_COUNT 10000

class Billboard : public Renderer
{
public:
	Billboard(wstring file);
	~Billboard();

	void Update();
	void Render();

	void Add(Vector3& position, Vector2& scale);

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

private:
	VertexBillboard* vertices;
	UINT* indices;

	UINT drawCount = 0;
	UINT prevCount = 0;

	Texture* texture;
	ID3DX11EffectShaderResourceVariable* sDiffuseMap;
};

Shader에 넘겨줄 VertexBillboard 구조체를 만들어준다.

#include "Framework.h"
#include "Billboard.h"

Billboard::Billboard(wstring file)
	: Renderer(L"83_Billboard.fxo")
{
	vertexCount = MAX_BILLBOARD_COUNT * 4;
	vertices = new VertexBillboard[vertexCount];

	vertexBuffer = new VertexBuffer(vertices, vertexCount, sizeof(VertexBillboard), 0, true);


	indexCount = MAX_BILLBOARD_COUNT * 6;
	indices = new UINT[indexCount];

	for (UINT i = 0; i < MAX_BILLBOARD_COUNT; i++)
	{
		indices[i * 6 + 0] = i * 4 + 0;
		indices[i * 6 + 1] = i * 4 + 1;
		indices[i * 6 + 2] = i * 4 + 2;
		indices[i * 6 + 3] = i * 4 + 2;
		indices[i * 6 + 4] = i * 4 + 1;
		indices[i * 6 + 5] = i * 4 + 3;
	}
	indexBuffer = new IndexBuffer(indices, indexCount);


	texture = new Texture(file);
	sDiffuseMap = shader->AsSRV("DiffuseMap");
}

Billboard::~Billboard()
{
	SafeDeleteArray(vertices);
	SafeDeleteArray(indices);

	SafeDelete(texture);
}

void Billboard::Update()
{
	Super::Update();
}

void Billboard::Render()
{
	if (drawCount != prevCount)
	{
		prevCount = drawCount;

		D3D11_MAPPED_SUBRESOURCE subResource;
		D3D::GetDC()->Map(vertexBuffer->Buffer(), 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
		{
			memcpy(subResource.pData, vertices, sizeof(VertexBillboard) * vertexCount);
		}
		D3D::GetDC()->Unmap(vertexBuffer->Buffer(), 0);
	}

	Super::Render();

	sDiffuseMap->SetResource(texture->SRV());
	shader->DrawIndexed(0, Pass(), drawCount * 6);
}

void Billboard::Add(Vector3 & position, Vector2 & scale)
{
	vertices[drawCount * 4 + 0].Position = position;
	vertices[drawCount * 4 + 1].Position = position;
	vertices[drawCount * 4 + 2].Position = position;
	vertices[drawCount * 4 + 3].Position = position;

	vertices[drawCount * 4 + 0].Uv = Vector2(0, 1);
	vertices[drawCount * 4 + 1].Uv = Vector2(0, 0);
	vertices[drawCount * 4 + 2].Uv = Vector2(1, 1);
	vertices[drawCount * 4 + 3].Uv = Vector2(1, 0);

	vertices[drawCount * 4 + 0].Scale = scale;
	vertices[drawCount * 4 + 1].Scale = scale;
	vertices[drawCount * 4 + 2].Scale = scale;
	vertices[drawCount * 4 + 3].Scale = scale;

	drawCount++;
}

그리고 사각형을 받은 Position과 Scale을 만들어 Shader에 넘겨주고 그려준다.

이렇게 하고 이 Billboard를 만들어 실행시키면

각 풀들이 카메라를 향해 계속해서 움직인다.



DirectX Share Tweet +1