[DirectX11] 083~84 Billboard
DirectX 11에서 빌보드는 항상 카메라를 향하고 있는 2D 이미지로, 3D 개체의 환영을 만든다. 빌보드는 폭발, 연기 또는 화재와 같은 입자 효과 등에 사용된다. 빌보드를 만들려면 이미지를 3D 공간에 배치하고 법선이 카메라의 보기 방향과 수직이 되도록 정렬한다. 이렇게 하면 위치나 방향에 관계없이 이미지가 항상 카메라를 향하게 된다. 그러면 빌보드가 적절한 크기로 조정되고 텍스처 쿼드로 렌더링된다.
목차
Billboard
DirectX 11에서 빌보드는 항상 카메라를 향하고 있는 2D 이미지로, 3D 개체의 환영을 만든다. 빌보드는 폭발, 연기 또는 화재와 같은 입자 효과 등에 사용된다.
빌보드를 만들려면 이미지를 3D 공간에 배치하고 법선이 카메라의 보기 방향과 수직이 되도록 정렬한다. 이렇게 하면 위치나 방향에 관계없이 이미지가 항상 카메라를 향하게 된다. 그러면 빌보드가 적절한 크기로 조정되고 텍스처 쿼드로 렌더링된다.
사실적인 입자 효과를 얻기 위해 광고판을 투명도, 혼합 및 음영 처리와 같은 다른 기술과 결합할 수 있다. 예를 들어 연기 입자는 알파 채널이 있는 투명 텍스처를 사용하여 희미하고 불규칙한 연기 모양을 시뮬레이션할 수 있다. 또한 블렌딩을 사용하여 입자를 뒤에 있는 장면과 혼합할 수 있으며 음영을 사용하여 입자에 하이라이트와 그림자를 만들 수 있다.
빌보드는 실시간으로 동적인 입자 효과를 만들기에 효과적인 방법이다.
면에 필요한 개수를 구한 후 Draw Index → 인덱스를 정점으로 사용 → Uv를 이용하여 면처럼 만든다.
Shader | |
Billboard.fx 생성 | |
Framework | |
Objects | |
Billboard.h .cpp 생성 | |
UnitTest | |
Objects | |
BillboardDemo.h. cpp 생성 |
tangent는 u방향에 Mapping 시키는게 정석적인 방법이다.
Billboard.fx
Billboard.fx
#include "00_Global.fx"
#include "00_Light.fx"
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)); //(1, 0, 0)
position.xyz += (input.Uv.x - 0.5f) * right * input.Scale.x;
position.xyz += (1.0f - input.Uv.y - 0.5f) * up * input.Scale.y; //2D 3D좌표는 뒤집혀있다.
position.w = 1.0f;
output.Position = ViewProjection(position);
output.Uv = input.Uv;
return output;
}
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;
}
technique11 T0
{
P_VP(P0, VS, PS)
}
Billboard
Billboard.h
#pragma once
#define MAX_BILLBOARD_COUNT 100000
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; //drawCount는 그릴 개수
UINT prevCount = 0;
Texture* texture;
ID3DX11EffectShaderResourceVariable* sDiffuseMap;
};
Billboard.cpp
#include "Framework.h"
#include "Billboard.h"
Billboard::Billboard(wstring file)
: Renderer(L"83_Billboard.fxo")
{
vertexCount = MAX_BILLBOARD_COUNT * 4;
vertices = new VertexBillboard[vertexCount]; //vertices 동적할당
vertexBuffer = new VertexBuffer(vertices, vertexCount, sizeof(VertexBillboard), 0, true);
indexCount = MAX_BILLBOARD_COUNT * 6;
indices = new UINT[indexCount]; //indices 동적할당
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"); //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) * vertexBuffer->Count());
}
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++;
}
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"82_NormalMapping.fxo");
sky = new CubeSky(L"Environment/GrassCube1024.dds");
Billboards();
Mesh();
Airplane();
Kachujin();
KachujinCollider();
KachujinWeapon();
PointLighting();
SpotLighting();
}
void BillboardDemo::Update()
{
static UINT selected = 3;
ImGui::InputInt("NormalMap Selected", (int *)&selected);
selected %= 4;
shader->AsScalar("Selected")->SetInt(selected);
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(L"Terrain/grass_14.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);
}
}
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);
}
실행화면
'⭐ DirectX > DirectX11 3D' 카테고리의 다른 글
[DirectX11] 089~94 Particle System (0) | 2023.04.04 |
---|---|
[DirectX11] 085~88 Weather (Rain, Snow) (0) | 2023.04.02 |
[DirectX11] 081~82 Normal Mapping (0) | 2023.03.27 |
[DirectX11] 080 Spot Lighting (0) | 2023.03.26 |
[DirectX11] 078~79 Point Lighting, HLSL [flatten] [branch] (0) | 2023.03.21 |
댓글
이 글 공유하기
다른 글
-
[DirectX11] 089~94 Particle System
[DirectX11] 089~94 Particle System
2023.04.04 -
[DirectX11] 085~88 Weather (Rain, Snow)
[DirectX11] 085~88 Weather (Rain, Snow)
2023.04.02 -
[DirectX11] 081~82 Normal Mapping
[DirectX11] 081~82 Normal Mapping
2023.03.27 -
[DirectX11] 080 Spot Lighting
[DirectX11] 080 Spot Lighting
2023.03.26