본문으로 바로가기

2020_1125 SpriteEffect

category DX11 3D Game Programming 2020. 11. 25. 17:35

 

 

 

1.  SpriteEffect

더보기
#pragma once
class SpriteEffect : public BillBoard
{
	class SpriteFrameBuffer : public ConstBuffer
	{
	public:
		struct Data
		{
			Float2 startPos{};
			Float2 size{ 1.0f, 1.0f };
			Float2 maxSize{ 1.0f, 1.0f };
			float padding[2];
		}data;
		//
	public:
		SpriteFrameBuffer() : ConstBuffer(&data, sizeof(Data)) {}
	};
	//
	struct Clip
	{
		Float2 startPos{};
		Float2 size{ 1.0f, 1.0f };
		Float2 maxSize{ 1.0f, 1.0f };
		//
		Clip() {}
	};
	///////////////////////////////////
public:
	bool isActive;
	///////////////////////////////////
private:
	UINT maxFrameX;
	UINT maxFrameY;
	float playTime;
	float speed;
	//
	float frameTime;
	float totalTime;
	UINT currentFrameIdx;
	UINT maxFrameCount;
	///////////////////////////////////
	SpriteFrameBuffer* frameBuffer;
	vector<Clip*> clips;
	///////////////////////////////////
public:
	SpriteEffect(wstring diffuseFile, UINT maxFrameX, UINT maxFrameY, float playTime, float speed);
	~SpriteEffect();
	///////////////////////////////////
	void Update();
	void Render();
	///////////////////////////////////
	void Play(Vector3 value);
	void End();
};
///////////////////////////////////////////////////////////////////////////
#include "Framework.h"

SpriteEffect::SpriteEffect(wstring diffuseFile, UINT maxFrameX, UINT maxFrameY,
	float playTime, float speed)
	:BillBoard(diffuseFile, L"SpriteEffect"),
	isActive(false),
	maxFrameX(maxFrameX), maxFrameY(maxFrameY), speed(speed), playTime(playTime),
	frameTime(0), totalTime(0), currentFrameIdx(0), maxFrameCount(0),
	frameBuffer(nullptr), clips{}
{
	//
	frameBuffer = new SpriteFrameBuffer();
	maxFrameCount = maxFrameX * maxFrameY;
	Float2 maxSize = { (float)GetMaterial()->diffuseMap->Width(),
						(float)GetMaterial()->diffuseMap->Height() };
	Float2 size = { maxSize.x / (float)maxFrameX, maxSize.y / (float)maxFrameY };
	//
	for (UINT y = 0; y < maxFrameY; ++y)
		for (UINT x = 0; x < maxFrameX; ++x)
		{
			Clip* clip = new Clip();
			clip->maxSize = maxSize;
			clip->size = size;
			clip->startPos = { x * size.x, y * size.y };
			clips.emplace_back(clip);
		}
	//
	frameBuffer->data.maxSize = maxSize;
	frameBuffer->data.size = size;
	frameBuffer->data.startPos = clips[0]->startPos;
}

SpriteEffect::~SpriteEffect()
{
	delete frameBuffer;
	//
	for (Clip* clip : clips)
		delete clip;
}

void SpriteEffect::Update()
{
	if (isActive == false) return;
	//
	frameTime += DELTA;
	if (speed < frameTime)
	{
		totalTime += frameTime;
		frameTime = 0;
		(++currentFrameIdx) %= maxFrameCount;
	}
	if (totalTime > playTime)
	{
		totalTime = 0;
		isActive = false;
	}
	//
	frameBuffer->data.startPos = clips[currentFrameIdx]->startPos;
	//
	BillBoard::Update();
}

void SpriteEffect::Render()
{
	if (isActive == false) return;
	//
	frameBuffer->SetPSBuffer(6);
	BillBoard::Render();
}

void SpriteEffect::Play(Vector3 value)
{
	position = value;
	isActive = true;
}

void SpriteEffect::End()
{
	position = {};
	isActive = false;
}

 

2. SpriteEffect shader

더보기
#include "Header.hlsli"

/* in Header
cbuffer SpriteFrame : register(b6)
{
    float2 startPos;
    float2 size;
    float2 maxSize;
}
*/

struct PixelInput
{
    float4 pos : SV_Position;
    float2 uv : UV;
};

PixelInput VS(VertexUV input)
{
    PixelInput output;
    
    output.pos = mul(input.pos, world);
    output.pos = mul(output.pos, view);
    output.pos = mul(output.pos, projection);
    
    output.uv = input.uv;
    
    return output;
}

float4 PS(PixelInput input) : SV_Target
{
    float2 uv = (startPos / maxSize) + input.uv * (size / maxSize);
    //
    return diffuseMap.Sample(samp, uv) * mDiffuse;
}

 

3. EffectManager

더보기
#pragma once

class EffectManager : public Singleton<EffectManager>
{
private:	
	friend class Singleton;
	///////////////////////////////////////////
private:
	map<string, vector<SpriteEffect*>> totalEffect;
	///////////////////////////////////////////
private:
	EffectManager();
	~EffectManager();
	///////////////////////////////////////////
public:
	void Update();
	void Render();
	//
	void Add(string key, UINT poolCount, wstring textureFile,
		UINT maxFrameX, UINT maxFrameY,
		float playTime = 1.0f, float speed = 0.1f);
	void Play(string key, Vector3 pos);
	void Stop();
	///////////////////////////////////////////
	vector<SpriteEffect*> GetSpriteEffect(string key) { return totalEffect[key]; }
};
///////////////////////////////////////////////////////////////////////////
#include "Framework.h"

EffectManager::EffectManager()
{
}

EffectManager::~EffectManager()
{
	for (auto effects : totalEffect)
		for (SpriteEffect* effect : effects.second)
			delete effect;
}

void EffectManager::Update()
{
	for (auto effects : totalEffect)
		for (SpriteEffect* effect : effects.second)
			effect->Update();
}

void EffectManager::Render()
{
	for (auto effects : totalEffect)
		for (SpriteEffect* effect : effects.second)
			effect->Render();
}

void EffectManager::Add(string key, UINT poolCount, wstring textureFile,
	UINT maxFrameX, UINT maxFrameY,
	float playTime, float speed)
{
	if (totalEffect.count(key) > 0)
		return;
	//
	vector<SpriteEffect*> effects;
	//
	for (UINT i = 0; i < poolCount; ++i)
	{
		SpriteEffect* effect = new SpriteEffect(textureFile, maxFrameX, maxFrameY, playTime, speed);
		effects.emplace_back(effect);
	}
	totalEffect[key] = effects;
}

void EffectManager::Play(string key, Vector3 pos)
{
	if (totalEffect.count(key) == 0)
		return;

	for (SpriteEffect* effect : totalEffect[key])
	{
		if (effect->isActive) continue;
		//
		effect->Play(pos);
		return;
	}
}

void EffectManager::Stop()
{
	for (auto effects : totalEffect)
		for (SpriteEffect* effect : effects.second)
			effect->End();
}

 

4. Scene

더보기
#pragma once

class ParticleScene : public Scene
{
private:
	Collider* collider;
	//
	Contact contact;
	//
	BlendState* blendState[2];
	DepthStencilState* depthState[2];
	////////////////////////////////
public:
	ParticleScene();
	~ParticleScene();
	// Scene을(를) 통해 상속됨
	virtual void Update() override;
	virtual void PreRender() override;
	virtual void Render() override;
	virtual void PostRender() override;
	////////////////////////////////
	void Pick();
};
///////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "ParticleScene.h"

ParticleScene::ParticleScene()
{
	collider = new SphereCollider();
	collider->scale = { 10.0f, 10.0f, 10.0f };
	collider->UpdateWorld();
	//
	EffectManager::Get()->Add("FX", 100, L"Textures/Effect/Scan.png", 2, 6, 5.0f);
	//
	blendState[0] = new BlendState();
	blendState[1] = new BlendState();
	//blendState[1]->Alpha(true);
	blendState[1]->AlphaToCoverage(true);
}

ParticleScene::~ParticleScene()
{
	delete blendState[0];
	delete blendState[1];
	//
	delete collider;
}

void ParticleScene::Update()
{
	collider->UpdateWorld();
	Pick();
	//
	EffectManager::Get()->Update();
}

void ParticleScene::PreRender()
{
}

void ParticleScene::Render()
{
	collider->Render();
	//
	blendState[1]->SetState();
	EffectManager::Get()->Render();
	blendState[0]->SetState();
}

void ParticleScene::PostRender()
{
	ImGui::Begin("[ParticleScene]");
	///////////////////////////////
	ImGui::Text("HitPoint : ( %.1f , %.1f , %.1f )",
		contact.hitPoint.x, contact.hitPoint.y, contact.hitPoint.z);
	ImGui::Text("HitDist : %.1f",
		contact.distance);
	//
	Vector3 rot = EffectManager::Get()->GetSpriteEffect("FX")[0]->rotation;
	ImGui::Text("EffectRot : ( %.1f , %.1f , %.1f )",
		rot.x, rot.y, rot.z);
	///////////////////////////////
	ImGui::End();
}

void ParticleScene::Pick()
{
	if (KEY_UP(VK_LBUTTON))
	{
		Ray ray = CAMERA->ScreenPointToRay(MOUSEPOS);
		if (collider->RayCollision(ray, &contact))
			EffectManager::Get()->Play("FX", contact.hitPoint);
	}
}