Particle system improvements + Emissive materials
Added option for Global particle positions Added material property for particles Added Emissive rendering
This commit is contained in:
@@ -38,6 +38,7 @@ uniform sampler2D m_Albedo;
|
||||
uniform sampler2D m_Material;
|
||||
uniform sampler2D m_Normal;
|
||||
uniform sampler2D m_SSAO;
|
||||
uniform sampler2D m_Emissive;
|
||||
|
||||
// Lights
|
||||
const int MaxLight = 32;
|
||||
@@ -223,10 +224,21 @@ void main()
|
||||
// Convert from [0, 1] to [-1, 1].
|
||||
vec3 albedo = texture(m_Albedo, UV).rgb;
|
||||
vec3 normal = texture(m_Normal, UV).rgb * 2.0 - 1.0;
|
||||
float metallic = texture(m_Material, UV).r;
|
||||
float roughness = texture(m_Material, UV).b;
|
||||
float ao = texture(m_Material, UV).g;
|
||||
float ssao = texture(m_SSAO, UV).r;
|
||||
|
||||
vec4 materialSample = texture(m_Material, UV);
|
||||
float metallic = materialSample.r;
|
||||
float ao = materialSample.g;
|
||||
float roughness = materialSample.b;
|
||||
float unlit = materialSample.a;
|
||||
float ssao = texture(m_SSAO, UV).r;
|
||||
float emissive = texture(m_Emissive, UV).r;
|
||||
|
||||
if (unlit > 0.1f)
|
||||
{
|
||||
FragColor = vec4(albedo * ssao * emissive, 1.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 N = normal;
|
||||
vec3 V = normalize(u_EyePosition - worldPos);
|
||||
vec3 R = reflect(-V, N);
|
||||
@@ -240,6 +252,7 @@ void main()
|
||||
vec3 fog = vec3(0.0);
|
||||
float shadow = 0.0f;
|
||||
|
||||
|
||||
if (true)
|
||||
{
|
||||
vec3 L = normalize(u_DirectionalLight.Direction);
|
||||
|
||||
@@ -40,6 +40,7 @@ layout(location = 0) out vec4 gAlbedo;
|
||||
layout(location = 1) out vec4 gNormal;
|
||||
layout(location = 2) out vec4 gMaterial;
|
||||
layout(location = 3) out int gEntityID;
|
||||
layout(location = 4) out float gEmissive;
|
||||
|
||||
in vec3 FragPos;
|
||||
in vec2 UV;
|
||||
@@ -67,6 +68,7 @@ layout(std140, binding = 32) uniform u_MaterialUniform
|
||||
int u_HasNormal; // 56 byte
|
||||
int u_HasDisplacement; // 60 byte
|
||||
int u_Unlit;
|
||||
float u_Emissive;
|
||||
};
|
||||
|
||||
void main()
|
||||
@@ -77,10 +79,10 @@ void main()
|
||||
normal = texture(m_Normal, UV).rgb;
|
||||
normal = normal * 2.0 - 1.0;
|
||||
normal = TBN * normalize(normal);
|
||||
gNormal = vec4(normal / 2.0 + 0.5, 1.0);
|
||||
gNormal = vec4(normal / 2.0 + 0.5, 1.0f);
|
||||
|
||||
// Albedo
|
||||
gAlbedo = vec4(m_AlbedoColor, 1.0);
|
||||
gAlbedo = vec4(m_AlbedoColor, 1.0f);
|
||||
if (u_HasAlbedo == 1)
|
||||
{
|
||||
vec4 albedoSample = texture(m_Albedo, UV);
|
||||
@@ -106,10 +108,12 @@ void main()
|
||||
if (u_HasRoughness == 1)
|
||||
finalRoughness = texture(m_Roughness, UV).r;
|
||||
|
||||
gMaterial = vec4(0, 0, 0, 1);
|
||||
gMaterial = vec4(0, 0, 0, u_Unlit);
|
||||
gMaterial.r = finalMetalness;
|
||||
gMaterial.g = finalAO;
|
||||
gMaterial.b = finalRoughness;
|
||||
|
||||
gEntityID = int(u_EntityID);
|
||||
|
||||
gEmissive = u_Emissive;
|
||||
}
|
||||
@@ -65,6 +65,7 @@ layout(location = 0) out vec4 gAlbedo;
|
||||
layout(location = 1) out vec4 gNormal;
|
||||
layout(location = 2) out vec4 gMaterial;
|
||||
layout(location = 3) out int gEntityID;
|
||||
layout(location = 4) out float gEmissive;
|
||||
|
||||
in vec3 FragPos;
|
||||
in vec2 UV;
|
||||
@@ -92,6 +93,7 @@ layout(std140, binding = 32) uniform u_MaterialUniform
|
||||
int u_HasNormal; // 56 byte
|
||||
int u_HasDisplacement; // 60 byte
|
||||
int u_Unlit;
|
||||
float u_Emissive;
|
||||
};
|
||||
|
||||
void main()
|
||||
@@ -102,10 +104,10 @@ void main()
|
||||
normal = texture(m_Normal, UV).rgb;
|
||||
normal = normal * 2.0 - 1.0;
|
||||
normal = TBN * normalize(normal);
|
||||
gNormal = vec4(normal / 2.0 + 0.5, 1.0);
|
||||
gNormal = vec4(normal / 2.0 + 0.5, 1.0f);
|
||||
|
||||
// Albedo
|
||||
gAlbedo = vec4(m_AlbedoColor, 1.0);
|
||||
gAlbedo = vec4(m_AlbedoColor, 1.0f);
|
||||
if (u_HasAlbedo == 1)
|
||||
{
|
||||
vec4 albedoSample = texture(m_Albedo, UV);
|
||||
@@ -131,10 +133,11 @@ void main()
|
||||
if (u_HasRoughness == 1)
|
||||
finalRoughness = texture(m_Roughness, UV).r;
|
||||
|
||||
gMaterial = vec4(0, 0, 0, 1);
|
||||
gMaterial = vec4(0, 0, 0, u_Unlit);
|
||||
gMaterial.r = finalMetalness;
|
||||
gMaterial.g = finalAO;
|
||||
gMaterial.b = finalRoughness;
|
||||
|
||||
gEntityID = int(u_EntityID);
|
||||
gEmissive = u_Emissive;
|
||||
}
|
||||
@@ -5,10 +5,15 @@
|
||||
#include <src/Core/Maths.h>
|
||||
#include <src/Scene/Components/ParticleEmitterComponent.h>
|
||||
#include <src/Scene/Entities/ImGuiHelper.h>
|
||||
#include "MaterialEditor.h"
|
||||
#include <src/Resource/ResourceLoader.h>
|
||||
#include <src/Resource/ResourceLoader.h>
|
||||
|
||||
class ParticleEmitterPanel : ComponentPanel
|
||||
{
|
||||
public:
|
||||
Scope<ModelResourceInspector> _modelInspector;
|
||||
|
||||
ParticleEmitterPanel() {}
|
||||
|
||||
void Draw(Nuake::Entity entity) override
|
||||
@@ -30,6 +35,50 @@ public:
|
||||
ImGui::TableNextColumn();
|
||||
ComponentTableReset(component.ParticleColor, Nuake::Vector4(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
ImGui::Text("Particle Material");
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
std::string label = "Empty";
|
||||
if (!component.ParticleMaterial->Path.empty())
|
||||
{
|
||||
label = component.ParticleMaterial->Path;
|
||||
}
|
||||
|
||||
if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Material"))
|
||||
{
|
||||
char* file = (char*)payload->Data;
|
||||
std::string fullPath = std::string(file, 256);
|
||||
|
||||
fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath);
|
||||
|
||||
Ref<Nuake::Material> material = Nuake::ResourceLoader::LoadMaterial(fullPath);
|
||||
component.ParticleMaterial = material;
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
//std::string childId = "materialEditorParticle";
|
||||
//ImGui::BeginChild(childId.c_str(), ImVec2(0, 0), false);
|
||||
//{
|
||||
// MaterialEditor editor;
|
||||
// editor.Draw(component.ParticleMaterial);
|
||||
//}
|
||||
//ImGui::EndChild();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ComponentTableReset(component.ParticleColor, Nuake::Vector4(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
ImGui::Text("Amount");
|
||||
@@ -40,6 +89,26 @@ public:
|
||||
ComponentTableReset(component.Amount, 10.0f);
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
ImGui::Text("Particle Size");
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGuiHelper::DrawVec3("##particleSize", &component.ParticleScale);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ComponentTableReset(component.ParticleScale, Nuake::Vector3(0.1, 0.1, 0.1));
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
ImGui::Text("Global Space");
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::Checkbox("##globalSpace", &component.GlobalSpace);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ComponentTableReset(component.GlobalSpace, false);
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
ImGui::Text("Rate");
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
@@ -15,11 +15,13 @@ namespace Nuake
|
||||
return false;
|
||||
}
|
||||
|
||||
bool String::EndsWith(const std::string& string, const std::string& end)
|
||||
bool String::EndsWith(const std::string& string, const std::string_view& end)
|
||||
{
|
||||
if (string.length() >= end.length())
|
||||
{
|
||||
return (0 == string.compare(string.length() - end.length(), end.length(), end));
|
||||
bool result = string.ends_with(end);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Nuake
|
||||
{
|
||||
public:
|
||||
static bool BeginsWith(const std::string& string, const std::string& begin);
|
||||
static bool EndsWith(const std::string& string, const std::string& end);
|
||||
static bool EndsWith(const std::string& string, const std::string_view& end);
|
||||
static bool IsDigit(const char& character);
|
||||
static std::string RemoveWhiteSpace(const std::string& string);
|
||||
static std::string Sanitize(const std::string& keyword);
|
||||
|
||||
@@ -119,6 +119,7 @@ namespace Nuake {
|
||||
case RendererEnum::STATIC_DRAW: return GL_STATIC_DRAW;
|
||||
case RendererEnum::DYNAMIC_DRAW: return GL_DYNAMIC_DRAW;
|
||||
case RendererEnum::STREAM_DRAW: return GL_STREAM_DRAW;
|
||||
case RendererEnum::BLENDING: return GL_BLEND;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Nuake {
|
||||
ELEMENT_ARRAY_BUFFER,
|
||||
TRIANGLES, LINES,
|
||||
DEPTH_ATTACHMENT, COLOR_ATTACHMENT0, COLOR_ATTACHMENT1,
|
||||
DEPTH_TEST, FACE_CULL,
|
||||
DEPTH_TEST, FACE_CULL, BLENDING,
|
||||
STATIC_DRAW, DYNAMIC_DRAW, STREAM_DRAW
|
||||
};
|
||||
|
||||
|
||||
@@ -16,10 +16,11 @@ namespace Nuake
|
||||
const auto defaultResolution = Vector2(1920, 1080);
|
||||
mGBuffer = CreateScope<FrameBuffer>(false, defaultResolution);
|
||||
mGBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_DEPTH_COMPONENT), GL_DEPTH_ATTACHMENT);
|
||||
mGBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RGB), GL_COLOR_ATTACHMENT0);
|
||||
mGBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RGB), GL_COLOR_ATTACHMENT1);
|
||||
mGBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RGB), GL_COLOR_ATTACHMENT2);
|
||||
mGBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RGB), GL_COLOR_ATTACHMENT0); // Albedo
|
||||
mGBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RGB), GL_COLOR_ATTACHMENT1); //
|
||||
mGBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RGBA), GL_COLOR_ATTACHMENT2); // Material + unlit
|
||||
mGBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RED_INTEGER, GL_R32I, GL_INT), GL_COLOR_ATTACHMENT3);
|
||||
mGBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RED, GL_R16F, GL_FLOAT), GL_COLOR_ATTACHMENT4); // Emissive
|
||||
|
||||
mShadingBuffer = CreateScope<FrameBuffer>(true, defaultResolution);
|
||||
mShadingBuffer->SetTexture(CreateRef<Texture>(defaultResolution, GL_RGB, GL_RGB16F, GL_FLOAT));
|
||||
@@ -306,6 +307,8 @@ namespace Nuake
|
||||
mGBuffer->Bind();
|
||||
mGBuffer->Clear();
|
||||
{
|
||||
RenderCommand::Disable(RendererEnum::BLENDING);
|
||||
|
||||
// Init
|
||||
RenderCommand::Enable(RendererEnum::FACE_CULL);
|
||||
Shader* gBufferShader = ShaderManager::GetShader("resources/Shaders/gbuffer.shader");
|
||||
@@ -349,6 +352,7 @@ namespace Nuake
|
||||
Renderer::Flush(gBufferShader, false);
|
||||
|
||||
RenderCommand::Disable(RendererEnum::FACE_CULL);
|
||||
|
||||
// Sprites
|
||||
auto spriteView = scene.m_Registry.view<TransformComponent, SpriteComponent, VisibilityComponent>();
|
||||
for (auto& e : spriteView)
|
||||
@@ -399,17 +403,27 @@ namespace Nuake
|
||||
particleTransform = glm::inverse(mView);
|
||||
|
||||
// Translation
|
||||
const Vector3& particleGlobalPosition = transform.GetGlobalPosition() + p.Position;
|
||||
Vector3 particleGlobalPosition;
|
||||
if (emitterComponent.GlobalSpace)
|
||||
{
|
||||
particleGlobalPosition = p.Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
particleGlobalPosition = Vector3(initialTransform[3]) + p.Position;
|
||||
}
|
||||
particleTransform[3] = Vector4(particleGlobalPosition, 1.0f);
|
||||
|
||||
// Scale
|
||||
particleTransform = glm::scale(particleTransform, transform.GetGlobalScale());
|
||||
particleTransform = glm::scale(particleTransform, emitterComponent.ParticleScale);
|
||||
|
||||
Renderer::QuadMesh->GetMaterial()->data.u_HasAlbedo = 0;
|
||||
Renderer::QuadMesh->GetMaterial()->data.m_AlbedoColor = p.Color;
|
||||
Renderer::SubmitMesh(Renderer::QuadMesh, particleTransform, (uint32_t)e);
|
||||
}
|
||||
|
||||
Renderer::QuadMesh->SetMaterial(emitterComponent.ParticleMaterial);
|
||||
|
||||
Renderer::Flush(gBufferShader, false);
|
||||
Renderer::QuadMesh->GetMaterial()->data.m_AlbedoColor = oldColor;
|
||||
}
|
||||
@@ -446,6 +460,8 @@ namespace Nuake
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RenderCommand::Enable(RendererEnum::BLENDING);
|
||||
}
|
||||
|
||||
void SceneRenderer::ShadingPass(Scene& scene)
|
||||
@@ -494,11 +510,13 @@ namespace Nuake
|
||||
mGBuffer->GetTexture(GL_COLOR_ATTACHMENT0)->Bind(6);
|
||||
mGBuffer->GetTexture(GL_COLOR_ATTACHMENT1)->Bind(7);
|
||||
mGBuffer->GetTexture(GL_COLOR_ATTACHMENT2)->Bind(8);
|
||||
mGBuffer->GetTexture(GL_COLOR_ATTACHMENT4)->Bind(10);
|
||||
|
||||
shadingShader->SetUniform1i("m_Depth", 5);
|
||||
shadingShader->SetUniform1i("m_Albedo", 6);
|
||||
shadingShader->SetUniform1i("m_Normal", 7);
|
||||
shadingShader->SetUniform1i("m_Material", 8);
|
||||
shadingShader->SetUniform1i("m_Emissive", 10);
|
||||
|
||||
RenderCommand::Disable(RendererEnum::FACE_CULL);
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Nuake
|
||||
int u_HasNormal;
|
||||
int u_HasDisplacement;
|
||||
int u_Unlit;
|
||||
float u_Emissive;
|
||||
};
|
||||
|
||||
class Material : ISerializable, public Resource
|
||||
@@ -50,7 +51,8 @@ namespace Nuake
|
||||
0.5f, // u_AOValue
|
||||
0, // u_HasNormal
|
||||
0, // u_HasDisplacement
|
||||
0
|
||||
0, // unlit
|
||||
1.0f // emissive
|
||||
};
|
||||
}
|
||||
public:
|
||||
@@ -114,15 +116,47 @@ namespace Nuake
|
||||
json Serialize() override
|
||||
{
|
||||
BEGIN_SERIALIZE();
|
||||
|
||||
j["UUID"] = static_cast<uint64_t>(ID);
|
||||
|
||||
j["HasAlbedo"] = this->HasAlbedo();
|
||||
if (HasAlbedo())
|
||||
{
|
||||
j["Albedo"] = this->m_Albedo->Serialize();
|
||||
}
|
||||
Vector3 AlbedoColor = data.m_AlbedoColor;
|
||||
SERIALIZE_VEC3(AlbedoColor);
|
||||
|
||||
SERIALIZE_VAL_LBL("Emissive", data.u_Emissive);
|
||||
SERIALIZE_VAL_LBL("AOValue", data.u_AOValue);
|
||||
SERIALIZE_VAL_LBL("MetalnessValue", data.u_MetalnessValue);
|
||||
SERIALIZE_VAL_LBL("RoughnessValue", data.u_RoughnessValue);
|
||||
SERIALIZE_VAL_LBL("Unlit", data.u_Unlit);
|
||||
|
||||
j["HasAO"] = this->HasAO();
|
||||
if (HasAO())
|
||||
{
|
||||
j["AO"] = m_AO->Serialize();
|
||||
}
|
||||
|
||||
j["HasMetalness"] = this->HasMetalness();
|
||||
if(HasMetalness())
|
||||
{
|
||||
j["Metalness"] = m_Metalness->Serialize();
|
||||
}
|
||||
|
||||
j["HasRoughness"] = this->HasRoughness();
|
||||
if (HasRoughness())
|
||||
{
|
||||
j["Roughness"] = m_Roughness->Serialize();
|
||||
}
|
||||
|
||||
j["HasNormal"] = this->HasNormal();
|
||||
if (HasNormal())
|
||||
{
|
||||
j["Normal"] = m_Normal->Serialize();
|
||||
}
|
||||
|
||||
j["HasDisplacement"] = this->HasDisplacement();
|
||||
|
||||
END_SERIALIZE();
|
||||
@@ -130,6 +164,7 @@ namespace Nuake
|
||||
|
||||
bool Deserialize(const json& j) override
|
||||
{
|
||||
|
||||
if (j.contains("Path"))
|
||||
{
|
||||
Path = FileSystem::RelativeToAbsolute(j["Path"]);
|
||||
@@ -149,6 +184,36 @@ namespace Nuake
|
||||
SetAlbedo(albedoTexture);
|
||||
}
|
||||
|
||||
if (j.contains("AlbedoColor"))
|
||||
{
|
||||
DESERIALIZE_VEC3(j["AlbedoColor"], data.m_AlbedoColor);
|
||||
}
|
||||
|
||||
if (j.contains("Emissive"))
|
||||
{
|
||||
data.u_Emissive = j["Emissive"];
|
||||
}
|
||||
|
||||
if (j.contains("MetalnessValue"))
|
||||
{
|
||||
data.u_MetalnessValue = j["MetalnessValue"];
|
||||
}
|
||||
|
||||
if (j.contains("RoughnessValue"))
|
||||
{
|
||||
data.u_RoughnessValue = j["RoughnessValue"];
|
||||
}
|
||||
|
||||
if (j.contains("AOValue"))
|
||||
{
|
||||
data.u_AOValue = j["AOValue"];
|
||||
}
|
||||
|
||||
if (j.contains("Unlit"))
|
||||
{
|
||||
data.u_Unlit = j["Unlit"];
|
||||
}
|
||||
|
||||
if (j.contains("Normal"))
|
||||
{
|
||||
const std::string absolutePath = FileSystem::RelativeToAbsolute(j["Normal"]["Path"]);
|
||||
|
||||
@@ -8,16 +8,16 @@ using json = nlohmann::json;
|
||||
#define SERIALIZE_VAL(v) j[#v] = this->v;
|
||||
|
||||
#define SERIALIZE_VEC2(v) \
|
||||
j[#v]["x"] = this->v.x; \
|
||||
j[#v]["y"] = this->v.y;
|
||||
j[#v]["x"] = v.x; \
|
||||
j[#v]["y"] = v.y;
|
||||
|
||||
#define SERIALIZE_VEC3(v) \
|
||||
SERIALIZE_VEC2(v) \
|
||||
j[#v]["z"] = this->v.z;
|
||||
j[#v]["z"] = v.z;
|
||||
|
||||
#define SERIALIZE_VEC4(v) \
|
||||
SERIALIZE_VEC3(v) \
|
||||
j[#v]["w"] = this->v.w;
|
||||
j[#v]["w"] = v.w;
|
||||
|
||||
#define DESERIALIZE_VAL(p) \
|
||||
if(j.contains(#p)) \
|
||||
|
||||
@@ -6,12 +6,17 @@ namespace Nuake
|
||||
{
|
||||
BEGIN_SERIALIZE();
|
||||
SERIALIZE_VEC4(ParticleColor);
|
||||
SERIALIZE_VEC3(ParticleScale);
|
||||
SERIALIZE_VAL(Amount);
|
||||
SERIALIZE_VAL(Life);
|
||||
SERIALIZE_VAL(Rate);
|
||||
SERIALIZE_VEC3(Gravity);
|
||||
SERIALIZE_VAL(GravityRandom);
|
||||
SERIALIZE_VAL(Radius);
|
||||
SERIALIZE_VAL(GlobalSpace);
|
||||
|
||||
SERIALIZE_OBJECT(ParticleMaterial);
|
||||
|
||||
END_SERIALIZE();
|
||||
}
|
||||
|
||||
@@ -25,6 +30,20 @@ namespace Nuake
|
||||
Rate = j["Rate"];
|
||||
}
|
||||
DESERIALIZE_VEC3(j["Gravity"], Gravity);
|
||||
if (j.contains("ParticleScale"))
|
||||
{
|
||||
DESERIALIZE_VEC3(j["ParticleScale"], ParticleScale);
|
||||
}
|
||||
if (j.contains("GlobalSpace"))
|
||||
{
|
||||
DESERIALIZE_VAL(GlobalSpace);
|
||||
}
|
||||
if (j.contains("ParticleMaterial"))
|
||||
{
|
||||
Ref<Material> newMaterial = CreateRef<Material>();
|
||||
newMaterial->Deserialize(j["ParticleMaterial"]);
|
||||
ParticleMaterial = newMaterial;
|
||||
}
|
||||
GravityRandom = j["GravityRandom"];
|
||||
Radius = j["Radius"];
|
||||
return true;
|
||||
|
||||
@@ -14,10 +14,15 @@ namespace Nuake
|
||||
ParticleEmitterComponent() = default;
|
||||
~ParticleEmitterComponent() = default;
|
||||
|
||||
Ref<Material> ParticleMaterial = CreateRef<Material>();
|
||||
|
||||
Color ParticleColor;
|
||||
float Amount;
|
||||
float Life = 1.0f;
|
||||
float Rate = 0.0f;
|
||||
Vector3 ParticleScale = Vector3(0.1, 0.1, 0.1);
|
||||
|
||||
bool GlobalSpace = false;
|
||||
|
||||
Vector3 Gravity;
|
||||
float GravityRandom;
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Nuake
|
||||
SpriteMesh = CreateRef<Mesh>();
|
||||
SpriteMesh->AddSurface(quadVertices, { 0, 1, 2, 3, 4, 5 });
|
||||
|
||||
auto& material = MaterialManager::Get()->GetMaterial(FileSystem::Root + SpritePath);
|
||||
auto material = MaterialManager::Get()->GetMaterial(FileSystem::Root + SpritePath);
|
||||
SpriteMesh->SetMaterial(material);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace Nuake
|
||||
|
||||
}
|
||||
|
||||
void ParticleEmitter::SetGlobalOrigin(const Vector3& origin)
|
||||
{
|
||||
GlobalOrigin = origin;
|
||||
}
|
||||
|
||||
void ParticleEmitter::SpawnParticle()
|
||||
{
|
||||
const bool canSpawnParticle = Particles.size() < Amount;
|
||||
@@ -23,11 +28,16 @@ namespace Nuake
|
||||
|
||||
if (Rate == 0.0f || RateTimer > Rate)
|
||||
{
|
||||
const auto initialPosition = Vector3(m_Random(m_MT), m_Random(m_MT), m_Random(m_MT));
|
||||
auto initialPosition = Vector3(m_Random(m_MT), m_Random(m_MT), m_Random(m_MT));
|
||||
const auto initialVelocity = Vector3();
|
||||
const auto initialColor = ParticleColor;
|
||||
const float initialLife = Life;
|
||||
|
||||
if (IsGlobalSpace)
|
||||
{
|
||||
initialPosition = initialPosition + GlobalOrigin;
|
||||
}
|
||||
|
||||
Particles.push_back({
|
||||
initialPosition,
|
||||
initialVelocity,
|
||||
|
||||
@@ -22,6 +22,9 @@ namespace Nuake
|
||||
float Rate = 0.0f;
|
||||
Color ParticleColor;
|
||||
|
||||
bool IsGlobalSpace = false;
|
||||
Vector3 GlobalOrigin;
|
||||
|
||||
private:
|
||||
float RateTimer = 0.0f;
|
||||
std::mt19937 m_MT;
|
||||
@@ -33,6 +36,8 @@ namespace Nuake
|
||||
ParticleEmitter();
|
||||
~ParticleEmitter() = default;
|
||||
|
||||
void SetGlobalOrigin(const Vector3& origin);
|
||||
|
||||
void SpawnParticle();
|
||||
void Update(Timestep ts);
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace Nuake
|
||||
emitter.SetRadius(emitterComponent.Radius);
|
||||
emitter.Life = emitterComponent.Life;
|
||||
emitter.Rate = emitterComponent.Rate;
|
||||
emitter.IsGlobalSpace = emitterComponent.GlobalSpace;
|
||||
emitter.GlobalOrigin = transformComponent.GetGlobalTransform()[3];
|
||||
|
||||
// Spawn particle if possible
|
||||
emitterComponent.Emitter.SpawnParticle();
|
||||
|
||||
Reference in New Issue
Block a user