[DirectX11] 095 Particle Editor
DirectX11의 Particle Editor는 DirectX11 응용 프로그램에서 사용할 입자 효과를 만들고 관리하는 데 사용되는 소프트웨어 도구이다. 그것은 개발자들이 개별 입자의 행동과 모양을 제어함으로써 연기, 화재, 물, 폭발과 같은 복잡하고 역동적인 효과를 만들 수 있게 한다.
목차
Particle Editor
파티클 편집기에는 일반적으로 개발자가 파티클 시스템을 시각적으로 만들고 수정할 수 있는 시각적 편집기가 포함되어 있다. 일반적으로 크기, 색상, 불투명도 및 수명과 같은 입자 속성에 대한 제어를 제공하며 개발자가 입자 시스템의 동작 및 모양을 실시간으로 조정할 수 있다. 또한 DirectX11의 Particle Editor는 개발자가 입자에 이미지를 적용할 수 있는 텍스처 매핑 및 고급 물리 시뮬레이션과 같은 기능을 제공하여 보다 현실적인 입자 효과를 생성할 수 있다.
파티클 시스템이 생성되면 XML 또는 JSON과 같은 다양한 파일 형식으로 내보낼 수 있으며, DirectX11 응용 프로그램에서 쉽게 로드하고 사용할 수 있다. 내보낸 입자 시스템은 개발자가 고급 입자 효과를 효율적으로 구현할 수 있는 Direct3D 11 Compute Shader와 같은 DirectX11의 입자 시스템 API를 사용하여 애플리케이션에 통합할 수 있다.
Shaders | |
Particle.fx |
|
Framework | |
Particle | |
ParticleData.h ParticleSystem.h .cpp |
|
ParticleEditor | |
Editor.h .cpp 생성 Viewer.h. cpp Main.h .cpp |
|
ParticleSystem
ParticleSystem.h
더보기
#pragma once
class ParticleSystem : public Renderer
{
public:
ParticleSystem(wstring file);
~ParticleSystem();
void Reset(); //초기화 함수
void Add(Vector3& position); //외부에서 추가
public:
void Update();//업데이트 함수. 외부에서 Update를 콜할때 사용
private:
void MapVertices();
void Activate();
void Deactivate();
public:
void Render();
ParticleData& GetData() { return data; }
void SetTexture(wstring file);
private:
void ReadFile(wstring file);
private:
struct VertexParticle
{
Vector3 Position;
Vector2 Corner; //(-1 ~ +1)
Vector3 Velocity; //파티클이 움직이는 속도
Vector4 Random; //x:주기, y:크기, z:회전, w:색상
float Time; //현재 속도
};
private:
struct Desc
{
Color MinColor;
Color MaxColor;
Vector3 Gravity;
float EndVelocity;
Vector2 StartSize;
Vector2 EndSize;
Vector2 RotateSpeed;
float ReadyTime;
float ReadyRandomTime;
float ColorAmount;
float CurrentTime;
float Padding[2];
} desc;
private:
ParticleData data; //파티클 정보
Texture* map = NULL;
ID3DX11EffectShaderResourceVariable* sMap;
ConstantBuffer* buffer;
ID3DX11EffectConstantBuffer* sBuffer;
VertexParticle* vertices = NULL;
UINT* indices = NULL;
float currentTime = 0.0f; //현재 시간
float lastAddTime = 0.0f; //마지막 파티클이 추가된 시간
UINT leadCount = 0;
UINT gpuCount = 0;
UINT activeCount = 0;
UINT deactiveCount = 0;
};
ParticleSystem.cpp
더보기
#include "Framework.h"
#include "ParticleSystem.h"
#include "Utilities/Xml.h"
ParticleSystem::ParticleSystem(wstring file)
: Renderer(L"89_Particle.fxo")
{
ReadFile(L"../../_Textures/Particles/" + file + L".xml");//.xml파일을 읽는다.
buffer = new ConstantBuffer(&desc, sizeof(Desc));
sBuffer = shader->AsConstantBuffer("CB_Particle");
sMap = shader->AsSRV("ParticleMap");
Reset();
}
ParticleSystem::~ParticleSystem()
{
SafeDelete(map);
SafeDelete(buffer);
SafeDeleteArray(vertices);
SafeDeleteArray(indices);
}
void ParticleSystem::Reset()
{
currentTime = 0.0f;
lastAddTime = Time::Get()->Running();
gpuCount = leadCount = activeCount = deactiveCount = 0;
SafeDeleteArray(vertices);
SafeDeleteArray(indices);
SafeDelete(vertexBuffer);
SafeDelete(indexBuffer);
vertices = new VertexParticle[data.MaxParticles * 4];
for (UINT i = 0; i < data.MaxParticles; i++)
{
vertices[i * 4 + 0].Corner = Vector2(-1, -1);
vertices[i * 4 + 1].Corner = Vector2(-1, +1);
vertices[i * 4 + 2].Corner = Vector2(+1, -1);
vertices[i * 4 + 3].Corner = Vector2(+1, +1);
}
indices = new UINT[data.MaxParticles * 6];
for (UINT i = 0; i < data.MaxParticles; 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;
}
vertexBuffer = new VertexBuffer(vertices, data.MaxParticles * 4, sizeof(VertexParticle), 0, true); //정점 버퍼
indexBuffer = new IndexBuffer(indices, data.MaxParticles * 6); //인덱스 버퍼
}
void ParticleSystem::Add(Vector3 & position)
{
if (Time::Get()->Running() - lastAddTime < 60.0f / 1000.0f) //60프레임 제한
return;
lastAddTime = Time::Get()->Running();
UINT count = leadCount + 1; //시작해서 갈 카운트
if (count >= data.MaxParticles)
{
if (data.bLoop == true)
{
count = 0;
}
else
{
count = data.MaxParticles;
return;
}
}
if (count == deactiveCount)
return;
Vector3 velocity = Vector3(1, 1, 1); //기본 속도이자 방향
velocity *= data.StartVelocity;
float horizontalVelocity = Math::Lerp(data.MinHorizontalVelocity, data.MaxHorizontalVelocity, Math::Random(0.0f, 1.0f));//수평이동 속도를 선형보간으로 만든다.
float horizontalAngle = Math::PI * 2.0f * Math::Random(0.0f, 1.0f);//z방향 회전
velocity.x += horizontalVelocity * cosf(horizontalAngle);//x속도
velocity.y += horizontalVelocity * sinf(horizontalAngle);//y속도
velocity.z += Math::Lerp(data.MinHorizontalVelocity, data.MaxHorizontalVelocity, Math::Random(0.0f, 1.0f));//z속도
Vector4 random = Math::RandomVec4(0.0f, 1.0f);
for (UINT i = 0; i < 4; i++)
{
vertices[leadCount * 4 + i].Position = position;
vertices[leadCount * 4 + i].Velocity = velocity;
vertices[leadCount * 4 + i].Random = random;
vertices[leadCount * 4 + i].Time = currentTime;
}
leadCount = count;
}
void ParticleSystem::Update()
{
Super::Update();
currentTime += Time::Delta();
MapVertices();
Activate();
Deactivate();
if (activeCount == leadCount)
currentTime = 0.0f;
desc.MinColor = data.MinColor;
desc.MaxColor = data.MaxColor;
desc.ColorAmount = data.ColorAmount;
desc.Gravity = data.Gravity;
desc.EndVelocity = data.EndVelocity;
desc.RotateSpeed = Vector2(data.MinRotateSpeed, data.MaxRotateSpeed);
desc.StartSize = Vector2(data.MinStartSize, data.MaxStartSize);
desc.EndSize = Vector2(data.MinEndSize, data.MaxEndSize);
desc.ReadyTime = data.ReadyTime;
desc.ReadyRandomTime = data.ReadyRandomTime;
}
void ParticleSystem::MapVertices()
{
if (gpuCount == leadCount) return;
D3D11_MAPPED_SUBRESOURCE subResource;
if (leadCount > gpuCount)
{
D3D::GetDC()->Map(vertexBuffer->Buffer(), 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &subResource);
{
UINT start = gpuCount * 4;
UINT size = (leadCount - gpuCount) * sizeof(VertexParticle) * 4;
UINT offset = gpuCount * sizeof(VertexParticle) * 4;
BYTE* p = (BYTE *)subResource.pData + offset;
memcpy(p, vertices + start, size);
}
D3D::GetDC()->Unmap(vertexBuffer->Buffer(), 0);
}
else //(leadCount < gpuCount)인 경우
{
D3D::GetDC()->Map(vertexBuffer->Buffer(), 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &subResource);
{
UINT start = gpuCount * 4;
UINT size = (data.MaxParticles - gpuCount) * sizeof(VertexParticle) * 4;
UINT offset = gpuCount * sizeof(VertexParticle) * 4;
BYTE* p = (BYTE *)subResource.pData + offset;
memcpy(p, vertices + start, size);
}
if (leadCount > 0)
{
UINT size = leadCount * sizeof(VertexParticle) * 4;
memcpy(subResource.pData, vertices, size);
}
D3D::GetDC()->Unmap(vertexBuffer->Buffer(), 0);
}
gpuCount = leadCount;
}
void ParticleSystem::Activate()
{
while (activeCount != gpuCount)
{
float age = currentTime - vertices[activeCount * 4].Time;
if (age < data.ReadyTime)
return;
vertices[activeCount * 4].Time = currentTime;
activeCount++;
if (activeCount >= data.MaxParticles)
activeCount = (data.bLoop == true) ? 0 : data.MaxParticles;
}
}
void ParticleSystem::Deactivate()
{
while (activeCount != deactiveCount)
{
float age = currentTime - vertices[deactiveCount * 4].Time;
if (age > data.ReadyTime)
return;
deactiveCount++;
if (deactiveCount >= data.MaxParticles)
deactiveCount = (data.bLoop == true) ? 0 : data.MaxParticles;
}
}
void ParticleSystem::Render()
{
Super::Render();
desc.CurrentTime = currentTime;
buffer->Render();
sBuffer->SetConstantBuffer(buffer->Buffer());
sMap->SetResource(map->SRV());
if (leadCount == activeCount)
return;
UINT pass = (UINT)data.Type;
if (leadCount > activeCount)
{
shader->DrawIndexed(0, pass, (leadCount - activeCount) * 6, activeCount * 6);
}
else
{
shader->DrawIndexed(0, pass, (data.MaxParticles - activeCount) * 6, activeCount * 6);
if (leadCount > 0)
shader->DrawIndexed(0, pass, leadCount * 6);
}
}
void ParticleSystem::SetTexture(wstring file)
{
SafeDelete(map);
map = new Texture(file);
}
void ParticleSystem::ReadFile(wstring file)
{
Xml::XMLDocument* document = new Xml::XMLDocument();
Xml::XMLError error = document->LoadFile(String::ToString(file).c_str());
assert(error == Xml::XML_SUCCESS);
Xml::XMLElement* root = document->FirstChildElement();
Xml::XMLElement* node = root->FirstChildElement();
data.Type = (ParticleData::BlendType)node->IntText();
node = node->NextSiblingElement();
data.bLoop = node->BoolText();
node = node->NextSiblingElement();
wstring textureFile = String::ToWString(node->GetText());
data.TextureFile = L"Particles/" + textureFile;
map = new Texture(data.TextureFile);
node = node->NextSiblingElement();
data.MaxParticles = node->IntText();
node = node->NextSiblingElement();
data.ReadyTime = node->FloatText();
node = node->NextSiblingElement();
data.ReadyRandomTime = node->FloatText();
node = node->NextSiblingElement();
data.StartVelocity = node->FloatText();
node = node->NextSiblingElement();
data.EndVelocity = node->FloatText();
node = node->NextSiblingElement();
data.MinHorizontalVelocity = node->FloatText();
node = node->NextSiblingElement();
data.MaxHorizontalVelocity = node->FloatText();
node = node->NextSiblingElement();
data.MinVerticalVelocity = node->FloatText();
node = node->NextSiblingElement();
data.MaxVerticalVelocity = node->FloatText();
node = node->NextSiblingElement();
data.Gravity.x = node->FloatAttribute("X");
data.Gravity.y = node->FloatAttribute("Y");
data.Gravity.z = node->FloatAttribute("Z");
node = node->NextSiblingElement();
data.ColorAmount = node->FloatText();
node = node->NextSiblingElement();
data.MinColor.r = node->FloatAttribute("R");
data.MinColor.g = node->FloatAttribute("G");
data.MinColor.b = node->FloatAttribute("B");
data.MinColor.a = node->FloatAttribute("A");
node = node->NextSiblingElement();
data.MaxColor.r = node->FloatAttribute("R");
data.MaxColor.g = node->FloatAttribute("G");
data.MaxColor.b = node->FloatAttribute("B");
data.MaxColor.a = node->FloatAttribute("A");
node = node->NextSiblingElement();
data.MinRotateSpeed = node->FloatText();
node = node->NextSiblingElement();
data.MaxRotateSpeed = node->FloatText();
node = node->NextSiblingElement();
data.MinStartSize = node->FloatText();
node = node->NextSiblingElement();
data.MaxStartSize = node->FloatText();
node = node->NextSiblingElement();
data.MinEndSize = node->FloatText();
node = node->NextSiblingElement();
data.MaxEndSize = node->FloatText();
SafeDelete(document);
}
Editor
Editor.h
더보기
#pragma once
#include "Systems/IExecute.h"
class Editor : 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 Mesh();
private:
void UpdateParticleList();
void UpdateTextureList();
void OnGUI();
void OnGUI_List();
void OnGUI_Settings();
void OnGUI_Write();
void WriteFile(wstring file);
private:
Shader* shader;
CubeSky* sky;
float windowWidth = 500; //윈도우 창 너비
bool bLoop = false; //루프
UINT maxParticle = 0;
vector<wstring> particleList;
vector<wstring> textureList; //particle 폴더 안의 textureList
wstring file = L""; //선택한 파일명을 저장하는 변수
ParticleSystem* particleSystem = NULL;
Material* floor;
Material* stone;
MeshRender* sphere;
MeshRender* grid;
};
Editor.cpp
더보기
#include "stdafx.h"
#include "Editor.h"
#include "Utilities/Xml.h"
void Editor::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");
Mesh();
UpdateParticleList(); //ParticleList 갱신
UpdateTextureList(); //TextureList 갱신
}
void Editor::Destroy()
{
}
void Editor::Update()
{
OnGUI();
sky->Update();
sphere->Update();
grid->Update();
Vector3 position;
sphere->GetTransform(0)->Position(&position);
if (Keyboard::Get()->Press('L'))
position.x += 20 * Time::Delta();
else if (Keyboard::Get()->Press('J'))
position.x -= 20 * Time::Delta();
if (Keyboard::Get()->Press('I'))
position.z += 20 * Time::Delta();
else if (Keyboard::Get()->Press('K'))
position.z -= 20 * Time::Delta();
if (Keyboard::Get()->Press('O'))
position.y += 20 * Time::Delta();
else if (Keyboard::Get()->Press('U'))
position.y -= 20 * Time::Delta();
sphere->GetTransform(0)->Position(position);
sphere->UpdateTransforms();
if (particleSystem != NULL)
{
particleSystem->Add(position);
particleSystem->Update();
}
}
void Editor::Render()
{
sky->Render();
stone->Render();
sphere->Render();
floor->Render();
grid->Render();
if (particleSystem != NULL)
particleSystem->Render();
}
void Editor::Mesh()
{
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");
Transform* transform = NULL;
grid = new MeshRender(shader, new MeshGrid(5, 5));
transform = grid->AddTransform();
transform->Position(0, 0, 0);
transform->Scale(12, 1, 12);
grid->UpdateTransforms();
sphere = new MeshRender(shader, new MeshSphere(0.5f, 20, 20));
transform = sphere->AddTransform();
transform->Position(0, 5, 0);
transform->Scale(5, 5, 5);
sphere->UpdateTransforms();
}
void Editor::UpdateParticleList()
{
particleList.clear();
Path::GetFiles(&particleList, L"../../_Textures/Particles/", L"*.xml", false); //Particles폴더 내의 .xml 파일들을 가져온다. 이때 자식폴더는 검색하지 않는다.
for (wstring& file : particleList)
file = Path::GetFileNameWithoutExtension(file); //파일을 확장자 제거하여 가져온다.
}
void Editor::UpdateTextureList()
{
textureList.clear();
vector<wstring> files;
Path::GetFiles(&files, L"../../_Textures/Particles/", L"*.*", false);
for (wstring file : files)
{
wstring ext = Path::GetExtension(file);
transform(ext.begin(), ext.end(), ext.begin(), toupper);
file = Path::GetFileName(file);
if (ext == L"PNG" || ext == L"TGA" || ext == L"JPG")
textureList.push_back(file); //png, tga, jpg이면 가져와서 넣어준다.
}
}
void Editor::OnGUI()
{
float width = D3D::Width();
float height = D3D::Height();
bool bOpen = true;
bOpen = ImGui::Begin("Particle", &bOpen);
ImGui::SetWindowPos(ImVec2(width - windowWidth, 0));
ImGui::SetWindowSize(ImVec2(windowWidth, height));
{
OnGUI_List();
OnGUI_Settings();
}
ImGui::End();
}
void Editor::OnGUI_List()
{
if (ImGui::CollapsingHeader("Particle List", ImGuiTreeNodeFlags_DefaultOpen))//CollapsingHeader는 눌러서 펼치게 해주는 역할
{
for (UINT i = 0; i < particleList.size(); i++)
{
if (ImGui::Button(String::ToString(particleList[i]).c_str(), ImVec2(200, 0)))
{
SafeDelete(particleSystem);//파티클 지움
file = particleList[i];//선택한 파일 저장
particleSystem = new ParticleSystem(particleList[i]);
bLoop = particleSystem->GetData().bLoop;
maxParticle = particleSystem->GetData().MaxParticles;
}
}//for(i)
}//ImGui::CollapsingHeader
}
void Editor::OnGUI_Settings()
{
if (particleSystem == NULL) return;
ImGui::Spacing();
if (ImGui::CollapsingHeader("Particle Settings", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Separator();
ImGui::SliderInt("MaxParticles", (int *)&maxParticle, 1, 1000);
ImGui::Checkbox("Loop", &bLoop);
if (ImGui::Button("Apply"))
{
particleSystem->GetData().bLoop = bLoop;
particleSystem->GetData().MaxParticles = maxParticle;
particleSystem->Reset();
}
ImGui::Separator();
const char* types[] = { "Opaque", "Additive", "AlphaBlend" };
ImGui::Combo("BlendType", (int *)&particleSystem->GetData().Type, types, 3);
ImGui::SliderFloat("ReadyTime", &particleSystem->GetData().ReadyTime, 0.1f, 10.0f);
ImGui::SliderFloat("ReadyRandomTime", &particleSystem->GetData().ReadyRandomTime, 0.0f, 100.0f);
ImGui::SliderFloat("StartVelocity", &particleSystem->GetData().StartVelocity, 0.0f, 10.0f);
ImGui::SliderFloat("EndVelocity", &particleSystem->GetData().EndVelocity, -100.0f, 100.0f);
ImGui::SliderFloat("MinHorizontalVelocity", &particleSystem->GetData().MinHorizontalVelocity, -100.0f, 100.0f);
ImGui::SliderFloat("MaxHorizontalVelocity", &particleSystem->GetData().MaxHorizontalVelocity, -100.0f, 100.0f);
ImGui::SliderFloat("MinVerticalVelocity", &particleSystem->GetData().MinVerticalVelocity, -100.0f, 100.0f);
ImGui::SliderFloat("MaxVerticalVelocity", &particleSystem->GetData().MaxVerticalVelocity, -100.0f, 100.0f);
ImGui::SliderFloat3("Gravity", particleSystem->GetData().Gravity, -100, 100);
ImGui::SliderFloat("Color Amount", &particleSystem->GetData().ColorAmount, 0.1f, 5.0f);
ImGui::ColorEdit4("MinColor", particleSystem->GetData().MinColor);
ImGui::ColorEdit4("MaxColor", particleSystem->GetData().MaxColor);
ImGui::SliderFloat("MinRotateSpeed", &particleSystem->GetData().MinRotateSpeed, -10, 10);
ImGui::SliderFloat("MaxRotateSpeed", &particleSystem->GetData().MaxRotateSpeed, -10, 10);
ImGui::SliderFloat("MinStartSize", &particleSystem->GetData().MinStartSize, 0, 500);
ImGui::SliderFloat("MaxStartSize", &particleSystem->GetData().MaxStartSize, 0, 500);
ImGui::SliderFloat("MinEndSize", &particleSystem->GetData().MinEndSize, 0, 500);
ImGui::SliderFloat("MaxEndSize", &particleSystem->GetData().MaxEndSize, 0, 500);
ImGui::Spacing();
OnGUI_Write();
ImGui::Spacing();
ImGui::Separator();
if (ImGui::CollapsingHeader("TextureList", ImGuiTreeNodeFlags_DefaultOpen))
{
for (wstring textureFile : textureList)
{
if (ImGui::Button(String::ToString(textureFile).c_str(), ImVec2(200, 0)))
{
particleSystem->GetData().TextureFile = textureFile;
particleSystem->SetTexture(L"Particles/" + textureFile);
}
}//for(i)
}
}
}
void Editor::OnGUI_Write()
{
ImGui::Separator();
if (ImGui::Button("WriteParticle"))
{
D3DDesc desc = D3D::GetDesc();
Path::SaveFileDialog
(
file, L"Particle file\0*.xml", L"../../_Textures/Particles",
bind(&Editor::WriteFile, this, placeholders::_1),
desc.Handle
);
}
}
void Editor::WriteFile(wstring file)
{
Xml::XMLDocument* document = new Xml::XMLDocument();
Xml::XMLDeclaration* decl = document->NewDeclaration();
document->LinkEndChild(decl);
Xml::XMLElement* root = document->NewElement("Particle");
root->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
root->SetAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
document->LinkEndChild(root);
Xml::XMLElement* node = NULL;
node = document->NewElement("BlendState");
node->SetText((int)particleSystem->GetData().Type);
root->LinkEndChild(node);
string textureFile = String::ToString(particleSystem->GetData().TextureFile);
String::Replace(&textureFile, "Particles/", "");
node = document->NewElement("Loop");
node->SetText(particleSystem->GetData().bLoop);
root->LinkEndChild(node);
node = document->NewElement("TextureFile");
node->SetText(textureFile.c_str());
root->LinkEndChild(node);
node = document->NewElement("MaxParticles");
node->SetText(particleSystem->GetData().MaxParticles);
root->LinkEndChild(node);
node = document->NewElement("ReadyTime");
node->SetText(particleSystem->GetData().ReadyTime);
root->LinkEndChild(node);
node = document->NewElement("ReadyRandomTime");
node->SetText(particleSystem->GetData().ReadyRandomTime);
root->LinkEndChild(node);
node = document->NewElement("StartVelocity");
node->SetText(particleSystem->GetData().StartVelocity);
root->LinkEndChild(node);
node = document->NewElement("EndVelocity");
node->SetText(particleSystem->GetData().EndVelocity);
root->LinkEndChild(node);
node = document->NewElement("MinHorizontalVelocity");
node->SetText(particleSystem->GetData().MinHorizontalVelocity);
root->LinkEndChild(node);
node = document->NewElement("MaxHorizontalVelocity");
node->SetText(particleSystem->GetData().MaxHorizontalVelocity);
root->LinkEndChild(node);
node = document->NewElement("MinVerticalVelocity");
node->SetText(particleSystem->GetData().MinVerticalVelocity);
root->LinkEndChild(node);
node = document->NewElement("MaxVerticalVelocity");
node->SetText(particleSystem->GetData().MaxVerticalVelocity);
root->LinkEndChild(node);
node = document->NewElement("Gravity");
node->SetAttribute("X", particleSystem->GetData().Gravity.x);
node->SetAttribute("Y", particleSystem->GetData().Gravity.y);
node->SetAttribute("Z", particleSystem->GetData().Gravity.z);
root->LinkEndChild(node);
node = document->NewElement("ColorAmount");
node->SetText(particleSystem->GetData().ColorAmount);
root->LinkEndChild(node);
node = document->NewElement("MinColor");
node->SetAttribute("R", particleSystem->GetData().MinColor.r);
node->SetAttribute("G", particleSystem->GetData().MinColor.g);
node->SetAttribute("B", particleSystem->GetData().MinColor.b);
node->SetAttribute("A", particleSystem->GetData().MinColor.a);
root->LinkEndChild(node);
node = document->NewElement("MaxColor");
node->SetAttribute("R", particleSystem->GetData().MaxColor.r);
node->SetAttribute("G", particleSystem->GetData().MaxColor.g);
node->SetAttribute("B", particleSystem->GetData().MaxColor.b);
node->SetAttribute("A", particleSystem->GetData().MaxColor.a);
root->LinkEndChild(node);
node = document->NewElement("MinRotateSpeed");
node->SetText(particleSystem->GetData().MinRotateSpeed);
root->LinkEndChild(node);
node = document->NewElement("MaxRotateSpeed");
node->SetText(particleSystem->GetData().MaxRotateSpeed);
root->LinkEndChild(node);
node = document->NewElement("MinStartSize");
node->SetText((int)particleSystem->GetData().MinStartSize);
root->LinkEndChild(node);
node = document->NewElement("MaxStartSize");
node->SetText((int)particleSystem->GetData().MaxStartSize);
root->LinkEndChild(node);
node = document->NewElement("MinEndSize");
node->SetText((int)particleSystem->GetData().MinEndSize);
root->LinkEndChild(node);
node = document->NewElement("MaxEndSize");
node->SetText((int)particleSystem->GetData().MaxEndSize);
root->LinkEndChild(node);
wstring folder = Path::GetDirectoryName(file);
wstring fileName = Path::GetFileNameWithoutExtension(file);
document->SaveFile(String::ToString(folder + fileName + L".xml").c_str());
SafeDelete(document);
UpdateParticleList();
}
실행화면
'⭐ DirectX > DirectX11 3D' 카테고리의 다른 글
[DirectX11] 099~102 Render Target, Post Effect(Color Tone) (0) | 2023.04.18 |
---|---|
[DirectX11] 096~98 Geometry Shader (0) | 2023.04.12 |
[DirectX11] 089~94 Particle System (0) | 2023.04.04 |
[DirectX11] 085~88 Weather (Rain, Snow) (0) | 2023.04.02 |
[DirectX11] 083~84 Billboard (0) | 2023.03.28 |
댓글
이 글 공유하기
다른 글
-
[DirectX11] 099~102 Render Target, Post Effect(Color Tone)
[DirectX11] 099~102 Render Target, Post Effect(Color Tone)
2023.04.18 -
[DirectX11] 096~98 Geometry Shader
[DirectX11] 096~98 Geometry Shader
2023.04.12 -
[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