기능 구현에 필요한 코드외 생략 하도록 합니다.
이전에 구현하는 눈내리는 효과와는 다르게 하나의 정점에서 시작되어 파티클이 퍼지는 효과입니다.
파티클은 퍼지는 강도, 중력값 등의 조절을 통하여 퍼지는 방식을 변경할 수 있습니다.
피격, 스킬, 블러드 이펙트 등등에 사용할 수 있지않을까 생각합니다.
폭죽 효과를 적용하기 위한 클래스 생성 (접은글 참조)
더보기
// Pop.h
#pragma once
struct POP_DESC
{
float duration; // 총 재생시간
float time; // 현재 재생중인시간
float gravity; // 중력값
float padding;
POP_DESC()
{
gravity = 60.0f;
}
};
class Pop : public Actor, public Particle
{
static ID3D11Buffer* PopBuffer;
public:
POP_DESC desc;
Vector2 particleScale = Vector2(0, 0); //이미지 크기값
int particleCount = 10;
float velocityScalar = 10.0f;
static void CreateStaticMember();
static void DeleteStaticMember();
static Pop* Create(string name = "Pop");
virtual void Render();
virtual void Update();
void RenderDetail();
void Reset();
virtual void Play();
virtual void Stop();
};
// Pop.cpp
#include "framework.h"
ID3D11Buffer* Pop::PopBuffer = nullptr;
void Pop::CreateStaticMember()
{
{
D3D11_BUFFER_DESC desc = { 0 };
desc.ByteWidth = sizeof(POP_DESC);
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;//상수버퍼
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
desc.StructureByteStride = 0;
HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, NULL, &PopBuffer);
assert(SUCCEEDED(hr));
}
}
void Pop::DeleteStaticMember()
{
SafeRelease(PopBuffer);
}
Pop* Pop::Create(string name)
{
Pop* temp = new Pop();
temp->name = name;
temp->mesh = make_shared<Mesh>();
temp->mesh->LoadFile("8.Billboard.mesh");
temp->shader = RESOURCE->shaders.Load("8.Pop.hlsl");
temp->shader->LoadGeometry();
temp->type = ObType::Pop;
return temp;
}
void Pop::Render()
{
desc.duration = duration;
//재생을 시작한 시간
desc.time = playTime;
{
D3D11_MAPPED_SUBRESOURCE mappedResource;
D3D->GetDC()->Map(PopBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
memcpy_s(mappedResource.pData, sizeof(POP_DESC), &desc,
sizeof(POP_DESC));
D3D->GetDC()->Unmap(PopBuffer, 0);
D3D->GetDC()->VSSetConstantBuffers(10, 1, &PopBuffer);
}
if (isPlaying)
Actor::Render();
}
void Pop::Update()
{
Particle::UpdateParticle();
Actor::Update();
}
void Pop::Reset()
{
delete[](VertexPSV*)mesh->vertices;
delete[] mesh->indices;
mesh->vertices = new VertexPSV[particleCount];
mesh->indices = new UINT[particleCount];
mesh->vertexCount = particleCount;
mesh->indexCount = particleCount;
Vector2 scale;
for (UINT i = 0; i < particleCount; i++)
{
//이미지 크기 가로세로를 랜덤값
//4~8 사이값
scale.x = RANDOM->Float(-particleScale.x, particleScale.x);
scale.y = RANDOM->Float(-particleScale.y, particleScale.y);
scale.x = S._11 + scale.x;
scale.y = S._22 + scale.y;
if (scale.x < 1.0f)scale.x = 1.0f;
if (scale.y < 1.0f)scale.y = 1.0f;
Vector3 position = Vector3(0, 0, 0);
//방향벡터 Right
Vector3 velocity = Vector3(1, 0, 0);
//임의의 회전된 3개축
Vector3 rot;
rot.x = RANDOM->Float(0.0f, PI * 2.0f);
rot.y = RANDOM->Float(0.0f, PI * 2.0f);
rot.z = RANDOM->Float(0.0f, PI * 2.0f);
//임의의 회전행렬
Matrix matRot = Matrix::CreateFromYawPitchRoll(rot.y, rot.x, rot.z);
// v = v * R
velocity = Vector3::TransformNormal(velocity, matRot);
velocity *= velocityScalar;
//내가 방향벡터를 3개축을 랜덤값으로 회전시켜 잡는다.
((VertexPSV*)mesh->vertices)[i].velocity = velocity;
((VertexPSV*)mesh->vertices)[i].position = position;
((VertexPSV*)mesh->vertices)[i].size = scale;
mesh->indices[i] = i;
}
SafeRelease(mesh->vertexBuffer);
SafeRelease(mesh->indexBuffer);
//CreateVertexBuffer
{
D3D11_BUFFER_DESC desc;
desc = { 0 };
desc.Usage = D3D11_USAGE_DEFAULT;
desc.ByteWidth = sizeof(VertexPSV) * particleCount;
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA data = { 0 };
data.pSysMem = mesh->vertices;
HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, &data, &mesh->vertexBuffer);
assert(SUCCEEDED(hr));
}
//Create Index Buffer
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = sizeof(UINT) * particleCount;
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
D3D11_SUBRESOURCE_DATA data = { 0 };
data.pSysMem = mesh->indices;
HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, &data, &mesh->indexBuffer);
assert(SUCCEEDED(hr));
}
}
void Pop::Play()
{
Reset();
Particle::Play();
}
void Pop::Stop()
{
Particle::Stop();
}
void Pop::RenderDetail()
{
Actor::RenderDetail();
if (ImGui::BeginTabBar("MyTabBar3"))
{
if (ImGui::BeginTabItem("Pop"))
{
Particle::Gui();
ImGui::SliderFloat("gravity", &desc.gravity, -100.0f, 100.0f);
ImGui::SliderFloat("velocityScalar", &velocityScalar, 0.0f, 1000.0f);
ImGui::SliderFloat2("particleScale", (float*)&particleScale, 0, 100);
ImGui::SliderInt("particleCount", &particleCount, 1, 100);
if (ImGui::Button("Reset"))
{
Reset();
}
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
Mesh, Shader 생성 ( Shader 파일 접은글 참조 )
이번효과 또한 Mesh는 1개의 정점으로 구성되어진 Mesh를 사용하였습니다.
더보기
#include "Common.hlsl"
struct VertexInput
{
float4 Position : POSITION0;
float2 Size : SIZE0;
float3 Velocity : VELOCITY0;
};
struct VertexOutput
{
float4 Position : POSITION0;
float2 Size : SIZE0;
};
struct PixelInput
{
float4 Position : SV_POSITION;
float2 Uv : UV0;
};
cbuffer VS_Data : register(b10)
{
float duration;
float time;
float gravity;
float padding1;
}
VertexOutput VS(VertexInput input)
{
VertexOutput output;
input.Velocity.y -= gravity * time;
//중심점값
output.Position = mul(input.Position, World);
//벨로시티값으로 퍼지기
output.Position.xyz += (input.Velocity * time);
output.Size = input.Size;
output.Position.w = 1.0f;
output.Position = mul(output.Position, View);
return output;
}
static const float2 TEXCOORD[4] =
{
float2(0.0f, 1.0f),
float2(0.0f, 0.0f),
float2(1.0f, 1.0f),
float2(1.0f, 0.0f)
};
[maxvertexcount(4)]
void GS(point VertexOutput input[1], inout TriangleStream<PixelInput> output)
{
//한개의 점을 네개로 나누기
// 월드변환후 뷰 프로젝션변환
float3 up = float3(0, 1, 0);
float3 forward = float3(0, 0, 1);
float3 right = float3(1, 0, 0);
float2 halfSize = input[0].Size * 0.5f;
float4 vertices[4];
//input[0].Position.xyz (기준좌표,중점)
//왼쪽 아래
// vertices[0] = float4(input[0].Position.xyz - halfSize.x * right - halfSize.y * up, 1.0f);
vertices[0] = float4(input[0].Position.xyz - right * halfSize.x - up * halfSize.y, 1.0f);
// 왼 위
vertices[1] = float4(input[0].Position.xyz - right * halfSize.x + up * halfSize.y, 1.0f);
// 오 아래
vertices[2] = float4(input[0].Position.xyz + right * halfSize.x - up * halfSize.y, 1.0f);
// 오 위
vertices[3] = float4(input[0].Position.xyz + right * halfSize.x + up * halfSize.y, 1.0f);
PixelInput pixelInput;
[unroll(4)]
for (int i = 0; i < 4; i++)
{
//월드에서 다시 ndc까지 변환
pixelInput.Position = mul(vertices[i], GSProj);
pixelInput.Uv = TEXCOORD[i];
output.Append(pixelInput);
}
}
float4 PS(PixelInput input) : SV_TARGET
{
float4 BaseColor = DiffuseMapping(input.Uv);
if (BaseColor.a == 0)
discard;
return BaseColor;
}
조심해야 할것은 지난번 눈내리는 효과와같습니다.
이전글 참조
'공부 > DirectX3D' 카테고리의 다른 글
[DirectX3D] 뷰행렬을 사용한 회전(CreateLookAt()함수사용) (1) | 2023.09.14 |
---|---|
[DirectX3D] Slash trail (0) | 2023.09.04 |
[DirectX3D] 눈내리는 효과(파티클효과 응용) (0) | 2023.08.29 |
[DirectX3D] PostEffect 블러(Blur)효과 적용하기 ( + Filter ) (0) | 2023.08.22 |
[DirectX3D] 로딩씬(씬전환) (0) | 2023.08.21 |
댓글