Added very basic particle system and rendering

This commit is contained in:
Antoine Pilote
2023-08-02 14:17:33 -04:00
parent 7af3a79b0e
commit eecfd3c375
9 changed files with 192 additions and 18 deletions

View File

@@ -53,22 +53,20 @@ namespace Nuake
s_CurrentWindow->Update(s_TimeStep);
// Play mode update all the entities, Editor does not.
if (Engine::IsPlayMode())
{
s_FixedUpdateDifference += s_TimeStep;
// Fixed update
while (s_FixedUpdateDifference >= s_FixedUpdateRate)
{
s_CurrentWindow->FixedUpdate(s_FixedUpdateDifference);
s_FixedUpdateDifference -= s_FixedUpdateRate;
}
}
else
if (!Engine::IsPlayMode())
{
GetCurrentScene()->EditorUpdate(s_TimeStep);
}
s_FixedUpdateDifference += s_TimeStep;
// Fixed update
while (s_FixedUpdateDifference >= s_FixedUpdateRate)
{
s_CurrentWindow->FixedUpdate(s_FixedUpdateDifference);
s_FixedUpdateDifference -= s_FixedUpdateRate;
}
}
Input::Update();

View File

@@ -3,9 +3,11 @@
#include "src/Scene/Components/BSPBrushComponent.h"
#include "src/Scene/Components/SpriteComponent.h"
#include "src/Scene/Components/ParticleEmitterComponent.h"
#include <GL\glew.h>
namespace Nuake
{
void SceneRenderer::Init()
@@ -231,6 +233,7 @@ namespace Nuake
Renderer::SubmitMesh(sprite.SpriteMesh, finalQuadTransform, (uint32_t)e);
}
Renderer::Flush(shader, true);
}
}
@@ -286,7 +289,7 @@ namespace Nuake
// Sprites
auto spriteView = scene.m_Registry.view<TransformComponent, SpriteComponent, VisibilityComponent>();
for (auto e : spriteView)
for (auto& e : spriteView)
{
auto [transform, sprite, visibility] = spriteView.get<TransformComponent, SpriteComponent, VisibilityComponent>(e);
@@ -316,6 +319,34 @@ namespace Nuake
Renderer::SubmitMesh(sprite.SpriteMesh, finalQuadTransform, (uint32_t)e);
}
Renderer::Flush(gBufferShader, false);
// Particles
auto particleEmitterView = scene.m_Registry.view<TransformComponent, ParticleEmitterComponent, VisibilityComponent>();
for (auto& e : particleEmitterView)
{
auto [transform, emitterComponent, visibility] = particleEmitterView.get<TransformComponent, ParticleEmitterComponent, VisibilityComponent>(e);
if (!visibility.Visible)
continue;
auto initialTransform = transform.GetGlobalTransform();
for (auto& p : emitterComponent.Emitter.Particles)
{
Matrix4 particleTransform = initialTransform;
particleTransform = glm::inverse(mView);
// Translation
const Vector3& particleGlobalPosition = transform.GetGlobalPosition() + p.Position;
particleTransform[3] = Vector4(particleGlobalPosition, 1.0f);
// Scale
particleTransform = glm::scale(particleTransform, transform.GetGlobalScale());
Renderer::SubmitMesh(Renderer::QuadMesh, particleTransform, (uint32_t)e);
}
}
Renderer::Flush(gBufferShader, false);
}
}

View File

@@ -1,7 +1,10 @@
#pragma once
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
#include "src/Resource/Serializable.h"
#include <src/Core/Maths.h>
#include "src/Scene/Systems/ParticleEmitter.h"
namespace Nuake
{
@@ -21,6 +24,8 @@ namespace Nuake
// For now use a radius, later should use shape.
float Radius;
ParticleEmitter Emitter;
public:
json Serialize();
bool Deserialize(const std::string& str);

View File

@@ -0,0 +1,13 @@
#pragma once
#include "src/Core/Maths.h"
namespace Nuake
{
struct Particle
{
Vector3 Position;
Vector3 Velocity;
Color Color;
float Life;
};
}

View File

@@ -0,0 +1,63 @@
#include "ParticleEmitter.h"
namespace Nuake
{
ParticleEmitter::ParticleEmitter()
{
m_MT = std::mt19937(std::random_device()());
m_Random = std::uniform_real_distribution<float>(-Radius, Radius);
}
void ParticleEmitter::SpawnParticle()
{
const bool canSpawnParticle = Particles.size() < Amount;
if (!canSpawnParticle)
{
return;
}
const auto initialPosition = Vector3(m_Random(m_MT), m_Random(m_MT), m_Random(m_MT));
const auto initialVelocity = Vector3();
const auto initialColor = Color(1, 0, 0, 1); // TODO: Use color.
const float initialLife = Life;
Particles.push_back({
initialPosition,
initialVelocity,
initialColor,
initialLife
});
}
void ParticleEmitter::Update(Timestep ts)
{
std::vector<uint32_t> deletionQueue;
int i = 0;
for (auto& p : Particles)
{
p.Life -= ts;
if (p.Life <= 0.0f) // The particle has died.
{
deletionQueue.push_back(i);
}
i++;
}
// Delete all dead particles.
int shiftOffset = 0;
for (int d = deletionQueue.size() - 1; d > 0; d--)
{
// Erase shifts the elements
const auto it = d;
Particles.erase(Particles.begin() + it);
}
for (auto& p : Particles)
{
p.Velocity += Gravity * static_cast<float>(ts);
p.Position += p.Velocity * static_cast<float>(ts);
}
}
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include "Particle.h"
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
#include "src/Core/Timestep.h"
#include <random>
namespace Nuake
{
class ParticleEmitter
{
public:
float Amount = 0.0f;
float Life = 5.0f;
Vector3 Gravity = Vector3(0, 0, 0);
float GravityRandom = 0.0f;
float Radius = 1.0f;
private:
std::mt19937 m_MT;
std::uniform_real_distribution<float> m_Random;
public:
ParticleEmitter();
~ParticleEmitter() = default;
void SpawnParticle();
void Update(Timestep ts);
std::vector<Particle> Particles;
};
}

View File

@@ -1,7 +1,9 @@
#include "ParticleSystem.h"
#include "src/Scene/Scene.h"
#include "src/Scene/Components/QuakeMap.h"
#include "src/Scene/Entities/Entity.h"
#include "src/Scene/Components/ParticleEmitterComponent.h"
namespace Nuake
{
@@ -17,12 +19,35 @@ namespace Nuake
void ParticleSystem::Update(Timestep ts)
{
auto& view = m_Scene->m_Registry.view<TransformComponent, ParticleEmitterComponent>();
for (auto& e : view)
{
auto [transformComponent, emitterComponent] = view.get<TransformComponent, ParticleEmitterComponent>(e);
Entity ent = Entity({ e, m_Scene });
// Copy emitter settings from component to real emitter
auto& emitter = emitterComponent.Emitter;
emitter.Amount = emitterComponent.Amount;
emitter.Gravity = emitterComponent.Gravity;
emitter.GravityRandom = emitterComponent.GravityRandom;
emitter.Radius = emitterComponent.Radius;
emitter.Life = emitterComponent.Life;
// Spawn particle if possible
emitterComponent.Emitter.SpawnParticle();
}
}
void ParticleSystem::FixedUpdate(Timestep ts)
{
auto& view = m_Scene->m_Registry.view<TransformComponent, ParticleEmitterComponent>();
for (auto& e : view)
{
auto [transformComponent, emitterComponent] = view.get<TransformComponent, ParticleEmitterComponent>(e);
Entity ent = Entity({ e, m_Scene });
emitterComponent.Emitter.Update(ts);
}
}
void ParticleSystem::EditorUpdate()

View File

@@ -1,5 +1,9 @@
#pragma once
#include <src/Scene/Systems/System.h>
#include <src/Core/Maths.h>
#include <random>
namespace Nuake
{
@@ -13,7 +17,5 @@ namespace Nuake
void EditorUpdate() override;
void FixedUpdate(Timestep ts) override;
void Exit() override;
private:
};
}

View File

@@ -56,6 +56,9 @@ namespace Nuake {
void ScriptingSystem::FixedUpdate(Timestep ts)
{
if (!Engine::IsPlayMode())
return;
auto entities = m_Scene->m_Registry.view<WrenScriptComponent>();
for (auto& e : entities)
{