add particles (WIP)
This commit is contained in:
@@ -0,0 +1,53 @@
|
|||||||
|
#include "Emitter.hpp"
|
||||||
|
|
||||||
|
#include <glm/gtc/random.hpp>
|
||||||
|
|
||||||
|
#include "graphics/core/Texture.hpp"
|
||||||
|
|
||||||
|
Emitter::Emitter(
|
||||||
|
std::variant<glm::vec3, entityid_t> origin,
|
||||||
|
Particle prototype,
|
||||||
|
const Texture* texture,
|
||||||
|
float spawnInterval,
|
||||||
|
int count
|
||||||
|
)
|
||||||
|
: origin(std::move(origin)),
|
||||||
|
prototype(std::move(prototype)),
|
||||||
|
texture(texture),
|
||||||
|
spawnInterval(spawnInterval),
|
||||||
|
count(count) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const Texture* Emitter::getTexture() const {
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emitter::update(float delta, std::vector<Particle>& particles) {
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
glm::vec3 position {};
|
||||||
|
if (auto staticPos = std::get_if<glm::vec3>(&origin)) {
|
||||||
|
position = *staticPos;
|
||||||
|
} else {
|
||||||
|
// TODO: implement for entity origin
|
||||||
|
}
|
||||||
|
timer += delta;
|
||||||
|
while (count && timer > spawnInterval) {
|
||||||
|
// spawn particle
|
||||||
|
Particle particle = prototype;
|
||||||
|
particle.position = position;
|
||||||
|
particle.velocity += glm::ballRand(1.0f) * explosion;
|
||||||
|
particles.push_back(std::move(particle));
|
||||||
|
timer -= spawnInterval;
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emitter::setExplosion(const glm::vec3& magnitude) {
|
||||||
|
explosion = magnitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Emitter::isDead() const {
|
||||||
|
return count == 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <variant>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include "typedefs.hpp"
|
||||||
|
|
||||||
|
#include "maths/UVRegion.hpp"
|
||||||
|
|
||||||
|
struct Particle {
|
||||||
|
glm::vec3 position;
|
||||||
|
glm::vec3 velocity;
|
||||||
|
float lifetime;
|
||||||
|
UVRegion region;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Texture;
|
||||||
|
|
||||||
|
class Emitter {
|
||||||
|
/// @brief Static position or entity
|
||||||
|
std::variant<glm::vec3, entityid_t> origin;
|
||||||
|
/// @brief Particle prototype
|
||||||
|
Particle prototype;
|
||||||
|
/// @brief Particle
|
||||||
|
const Texture* texture;
|
||||||
|
/// @brief Particles spawn interval
|
||||||
|
float spawnInterval;
|
||||||
|
/// @brief Number of particles should be spawned before emitter deactivation.
|
||||||
|
/// -1 is infinite
|
||||||
|
int count;
|
||||||
|
/// @brief Spawn timer used to determine number of particles
|
||||||
|
/// to spawn on update. May be innacurate.
|
||||||
|
float timer = 0.0f;
|
||||||
|
/// @brief Random velocity magnitude applying to spawned particles
|
||||||
|
glm::vec3 explosion {1.0f};
|
||||||
|
public:
|
||||||
|
Emitter(
|
||||||
|
std::variant<glm::vec3, entityid_t> origin,
|
||||||
|
Particle prototype,
|
||||||
|
const Texture* texture,
|
||||||
|
float spawnInterval,
|
||||||
|
int count
|
||||||
|
);
|
||||||
|
|
||||||
|
const Texture* getTexture() const;
|
||||||
|
|
||||||
|
/// @brief Update emitter and spawn particles
|
||||||
|
/// @param delta delta time
|
||||||
|
/// @param particles destination particles vector
|
||||||
|
void update(float delta, std::vector<Particle>& particles);
|
||||||
|
|
||||||
|
void setExplosion(const glm::vec3& magnitude);
|
||||||
|
|
||||||
|
bool isDead() const;
|
||||||
|
};
|
||||||
@@ -52,6 +52,11 @@ void MainBatch::flush() {
|
|||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainBatch::begin() {
|
||||||
|
texture = nullptr;
|
||||||
|
blank->bind();
|
||||||
|
}
|
||||||
|
|
||||||
void MainBatch::prepare(int vertices) {
|
void MainBatch::prepare(int vertices) {
|
||||||
if (index + VERTEX_SIZE * vertices > capacity * VERTEX_SIZE) {
|
if (index + VERTEX_SIZE * vertices > capacity * VERTEX_SIZE) {
|
||||||
flush();
|
flush();
|
||||||
|
|||||||
@@ -29,13 +29,18 @@ public:
|
|||||||
|
|
||||||
~MainBatch();
|
~MainBatch();
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
|
||||||
void prepare(int vertices);
|
void prepare(int vertices);
|
||||||
void setTexture(const Texture* texture);
|
void setTexture(const Texture* texture);
|
||||||
void setTexture(const Texture* texture, const UVRegion& region);
|
void setTexture(const Texture* texture, const UVRegion& region);
|
||||||
void flush();
|
void flush();
|
||||||
|
|
||||||
inline void vertex(
|
inline void vertex(
|
||||||
glm::vec3 pos, glm::vec2 uv, glm::vec4 light, glm::vec3 tint
|
const glm::vec3& pos,
|
||||||
|
const glm::vec2& uv,
|
||||||
|
const glm::vec4& light,
|
||||||
|
const glm::vec3& tint
|
||||||
) {
|
) {
|
||||||
float* buffer = this->buffer.get();
|
float* buffer = this->buffer.get();
|
||||||
buffer[index++] = pos.x;
|
buffer[index++] = pos.x;
|
||||||
@@ -59,4 +64,53 @@ public:
|
|||||||
|
|
||||||
buffer[index++] = compressed.floating;
|
buffer[index++] = compressed.floating;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void quad(
|
||||||
|
const glm::vec3& pos,
|
||||||
|
const glm::vec3& right,
|
||||||
|
const glm::vec3& up,
|
||||||
|
const glm::vec2& size,
|
||||||
|
const glm::vec4& light,
|
||||||
|
const glm::vec3& tint,
|
||||||
|
const UVRegion& subregion
|
||||||
|
) {
|
||||||
|
prepare(6);
|
||||||
|
vertex(
|
||||||
|
pos - right * size.x * 0.5f - up * size.y * 0.5f,
|
||||||
|
{subregion.u1, subregion.v1},
|
||||||
|
light,
|
||||||
|
tint
|
||||||
|
);
|
||||||
|
vertex(
|
||||||
|
pos + right * size.x * 0.5f - up * size.y * 0.5f,
|
||||||
|
{subregion.u2, subregion.v1},
|
||||||
|
light,
|
||||||
|
tint
|
||||||
|
);
|
||||||
|
vertex(
|
||||||
|
pos + right * size.x * 0.5f + up * size.y * 0.5f,
|
||||||
|
{subregion.u2, subregion.v2},
|
||||||
|
light,
|
||||||
|
tint
|
||||||
|
);
|
||||||
|
|
||||||
|
vertex(
|
||||||
|
pos - right * size.x * 0.5f - up * size.y * 0.5f,
|
||||||
|
{subregion.u1, subregion.v1},
|
||||||
|
light,
|
||||||
|
tint
|
||||||
|
);
|
||||||
|
vertex(
|
||||||
|
pos + right * size.x * 0.5f + up * size.y * 0.5f,
|
||||||
|
{subregion.u2, subregion.v2},
|
||||||
|
light,
|
||||||
|
tint
|
||||||
|
);
|
||||||
|
vertex(
|
||||||
|
pos - right * size.x * 0.5f + up * size.y * 0.5f,
|
||||||
|
{subregion.u1, subregion.v2},
|
||||||
|
light,
|
||||||
|
tint
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#include "ParticlesRenderer.hpp"
|
||||||
|
|
||||||
|
#include "assets/Assets.hpp"
|
||||||
|
#include "graphics/core/Shader.hpp"
|
||||||
|
#include "graphics/core/Texture.hpp"
|
||||||
|
#include "graphics/render/MainBatch.hpp"
|
||||||
|
#include "window/Camera.hpp"
|
||||||
|
|
||||||
|
ParticlesRenderer::ParticlesRenderer(const Assets& assets)
|
||||||
|
: batch(std::make_unique<MainBatch>(1024)) {
|
||||||
|
|
||||||
|
Emitter emitter(glm::vec3(0, 100, 0), Particle {
|
||||||
|
glm::vec3(), glm::vec3(), 5.0f, UVRegion(0,0,1,1)
|
||||||
|
}, assets.get<Texture>("gui/error"), 0.003f, -1);
|
||||||
|
emitters.push_back(std::move(emitter));
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticlesRenderer::~ParticlesRenderer() = default;
|
||||||
|
|
||||||
|
void ParticlesRenderer::render(
|
||||||
|
const Assets& assets, const Camera& camera, float delta
|
||||||
|
) {
|
||||||
|
const auto& right = camera.right;
|
||||||
|
const auto& up = camera.up;
|
||||||
|
|
||||||
|
batch->begin();
|
||||||
|
for (auto& [texture, vec] : particles) {
|
||||||
|
batch->setTexture(texture);
|
||||||
|
|
||||||
|
auto iter = vec.begin();
|
||||||
|
while (iter != vec.end()) {
|
||||||
|
auto& particle = *iter;
|
||||||
|
|
||||||
|
particle.position += particle.velocity * delta;
|
||||||
|
|
||||||
|
batch->quad(
|
||||||
|
particle.position,
|
||||||
|
right,
|
||||||
|
up,
|
||||||
|
glm::vec2(0.3f),
|
||||||
|
glm::vec4(1),
|
||||||
|
glm::vec3(1.0f),
|
||||||
|
particle.region
|
||||||
|
);
|
||||||
|
|
||||||
|
particle.lifetime -= delta;
|
||||||
|
if (particle.lifetime <= 0.0f) {
|
||||||
|
iter = vec.erase(iter);
|
||||||
|
} else {
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
batch->flush();
|
||||||
|
|
||||||
|
auto iter = emitters.begin();
|
||||||
|
while (iter != emitters.end()) {
|
||||||
|
auto& emitter = *iter;
|
||||||
|
auto texture = emitter.getTexture();
|
||||||
|
const auto& found = particles.find(texture);
|
||||||
|
std::vector<Particle>* vec;
|
||||||
|
if (found == particles.end()) {
|
||||||
|
vec = &particles[texture];
|
||||||
|
} else {
|
||||||
|
vec = &found->second;
|
||||||
|
}
|
||||||
|
emitter.update(delta, *vec);
|
||||||
|
|
||||||
|
if (emitter.isDead()) {
|
||||||
|
iter = emitters.erase(iter);
|
||||||
|
} else {
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "Emitter.hpp"
|
||||||
|
|
||||||
|
class Texture;
|
||||||
|
class Assets;
|
||||||
|
class Camera;
|
||||||
|
class MainBatch;
|
||||||
|
|
||||||
|
class ParticlesRenderer {
|
||||||
|
std::unordered_map<const Texture*, std::vector<Particle>> particles;
|
||||||
|
std::vector<Emitter> emitters;
|
||||||
|
std::unique_ptr<MainBatch> batch;
|
||||||
|
public:
|
||||||
|
ParticlesRenderer(const Assets& assets);
|
||||||
|
~ParticlesRenderer();
|
||||||
|
|
||||||
|
void render(const Assets& assets, const Camera& camera, float delta);
|
||||||
|
};
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
#include "graphics/core/PostProcessing.hpp"
|
#include "graphics/core/PostProcessing.hpp"
|
||||||
#include "graphics/core/Shader.hpp"
|
#include "graphics/core/Shader.hpp"
|
||||||
#include "graphics/core/Texture.hpp"
|
#include "graphics/core/Texture.hpp"
|
||||||
|
#include "ParticlesRenderer.hpp"
|
||||||
#include "ChunksRenderer.hpp"
|
#include "ChunksRenderer.hpp"
|
||||||
#include "ModelBatch.hpp"
|
#include "ModelBatch.hpp"
|
||||||
#include "Skybox.hpp"
|
#include "Skybox.hpp"
|
||||||
@@ -56,9 +57,13 @@ WorldRenderer::WorldRenderer(
|
|||||||
frustumCulling(std::make_unique<Frustum>()),
|
frustumCulling(std::make_unique<Frustum>()),
|
||||||
lineBatch(std::make_unique<LineBatch>()),
|
lineBatch(std::make_unique<LineBatch>()),
|
||||||
modelBatch(std::make_unique<ModelBatch>(
|
modelBatch(std::make_unique<ModelBatch>(
|
||||||
20'000, engine->getAssets(), level->chunks.get(),
|
20'000,
|
||||||
|
engine->getAssets(),
|
||||||
|
level->chunks.get(),
|
||||||
&engine->getSettings()
|
&engine->getSettings()
|
||||||
)) {
|
)),
|
||||||
|
particles(std::make_unique<ParticlesRenderer>(*engine->getAssets())) {
|
||||||
|
|
||||||
renderer = std::make_unique<ChunksRenderer>(
|
renderer = std::make_unique<ChunksRenderer>(
|
||||||
level, frontend->getContentGfxCache(), &engine->getSettings()
|
level, frontend->getContentGfxCache(), &engine->getSettings()
|
||||||
);
|
);
|
||||||
@@ -189,7 +194,7 @@ void WorldRenderer::setupWorldShader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WorldRenderer::renderLevel(
|
void WorldRenderer::renderLevel(
|
||||||
const DrawContext&,
|
const DrawContext& ctx,
|
||||||
const Camera& camera,
|
const Camera& camera,
|
||||||
const EngineSettings& settings,
|
const EngineSettings& settings,
|
||||||
float delta,
|
float delta,
|
||||||
@@ -211,6 +216,7 @@ void WorldRenderer::renderLevel(
|
|||||||
delta,
|
delta,
|
||||||
pause
|
pause
|
||||||
);
|
);
|
||||||
|
particles->render(*assets, camera, delta);
|
||||||
modelBatch->render();
|
modelBatch->render();
|
||||||
|
|
||||||
auto shader = assets->get<Shader>("main");
|
auto shader = assets->get<Shader>("main");
|
||||||
|
|||||||
@@ -8,12 +8,15 @@
|
|||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include "Emitter.hpp"
|
||||||
|
|
||||||
class Level;
|
class Level;
|
||||||
class Player;
|
class Player;
|
||||||
class Camera;
|
class Camera;
|
||||||
class Batch3D;
|
class Batch3D;
|
||||||
class LineBatch;
|
class LineBatch;
|
||||||
class ChunksRenderer;
|
class ChunksRenderer;
|
||||||
|
class ParticlesRenderer;
|
||||||
class Shader;
|
class Shader;
|
||||||
class Frustum;
|
class Frustum;
|
||||||
class Engine;
|
class Engine;
|
||||||
@@ -40,6 +43,8 @@ class WorldRenderer {
|
|||||||
std::unique_ptr<Skybox> skybox;
|
std::unique_ptr<Skybox> skybox;
|
||||||
std::unique_ptr<Batch3D> batch3d;
|
std::unique_ptr<Batch3D> batch3d;
|
||||||
std::unique_ptr<ModelBatch> modelBatch;
|
std::unique_ptr<ModelBatch> modelBatch;
|
||||||
|
std::unique_ptr<ParticlesRenderer> particles;
|
||||||
|
|
||||||
float timer = 0.0f;
|
float timer = 0.0f;
|
||||||
|
|
||||||
bool drawChunk(size_t index, const Camera& camera, Shader* shader, bool culling);
|
bool drawChunk(size_t index, const Camera& camera, Shader* shader, bool culling);
|
||||||
|
|||||||
Reference in New Issue
Block a user