[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
댓글을 사용할 수 없습니다.