diff --git a/ParticleGenerator/src/Scene/Scenes/MeshGenerator.cpp b/ParticleGenerator/src/Scene/Scenes/MeshGenerator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48065d54fd7e866de8bfd8cbd11354a27d1e55bd --- /dev/null +++ b/ParticleGenerator/src/Scene/Scenes/MeshGenerator.cpp @@ -0,0 +1,164 @@ +#include "MeshGenerator.hpp" + +#include "../../Mesh/Model.hpp" + +#define GLM_ENABLE_EXPERIMENTAL +#include <glm/gtx/normal.hpp> +#include <glm/gtc/matrix_transform.hpp> + +namespace pg::scene { + MeshGenerator::MeshGenerator() + : _mesh(), + _meshProgram(), + _meshPosition(0.f), + _meshRotation(0.f), + _generators(), + _particles(), + _billboard(), + _billboardTexture(), + _billboardProgram(), + _ubo(0) {} + + void MeshGenerator::initialize() { + if(!this->_mesh.isGenerated()) { + Model model("res/models/sphere.obj"); + + MeshGeometry geometry = model.getMeshGeometry(); + this->_mesh.generate(geometry.vertices, geometry.indices); + + auto & vertices = geometry.vertices; + auto & indices = geometry.indices; + + for(size_t i = 0; i < geometry.indices.size(); i+= 3) { + PhysicsParticleGenerator generator; + glm::vec3 & p1 = vertices[indices[i]].position, p2 = vertices[indices[i+1]].position, p3 = vertices[indices[i+2]].position; + + glm::vec3 baricenter = (p1 + p2 + p3) / 3.f; + generator.setPosition(baricenter); + + glm::vec3 normal = glm::triangleNormal(p1, p2, p3); + generator.setVelocity(glm::normalize(normal) / 50.f); + + this->_generators.push_back(generator); + } + } + + if(!this->_meshProgram.usable()) { + Source vert("res/shaders/scene/Color.vert", Source::Categorie::VERTEX); + Source frag("res/shaders/scene/Color.frag", Source::Categorie::FRAGMENT); + + this->_meshProgram << vert; + this->_meshProgram << frag; + + this->_meshProgram.link(); + + vert.release(); + frag.release(); + } + + this->_billboard.initialize(); + this->_billboardTexture.load("res/textures/smoke1.png"); + + if(!this->_billboardProgram.usable()) { + Source vert("res/shaders/scene/Billboard.vert", Source::Categorie::VERTEX); + Source frag("res/shaders/scene/Billboard.frag", Source::Categorie::FRAGMENT); + + this->_billboardProgram << vert; + this->_billboardProgram << frag; + + this->_billboardProgram.link(); + + vert.release(); + frag.release(); + } + + { + glCreateBuffers(1, &this->_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, this->_ubo); + glBufferData(GL_UNIFORM_BUFFER, 1024 * sizeof(glm::mat4), nullptr, GL_DYNAMIC_DRAW); + + GLuint uniforme_index = glGetUniformBlockIndex(this->_billboardProgram.id(), "uModels_t"); + glBindBufferBase(GL_UNIFORM_BUFFER, uniforme_index, this->_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } + } + + void MeshGenerator::update(double current_time) { + static auto start = std::chrono::high_resolution_clock::now(); + auto end = std::chrono::high_resolution_clock::now(); + + pg::Particle::purge(this->_particles, static_cast<size_t>(current_time), 2); + if(duration_cast<std::chrono::milliseconds>(end - start).count() >= 2500) { + start = std::chrono::high_resolution_clock::now(); + for(auto & generator : this->_generators) { + if((1 + this->_particles.size()) <= 1024) { + std::vector<std::unique_ptr<pg::Particle>> newParticles = generator.generate(1, static_cast<size_t>(current_time)); + this->_particles.insert(this->_particles.begin(), std::make_move_iterator(newParticles.begin()), std::make_move_iterator(newParticles.end())); + } + } + } + + if(duration_cast<std::chrono::milliseconds>(end - start).count() >= 10) { + for(auto& particle : this->_particles) { + particle->update(0.0); + } + } + } + + void MeshGenerator::render(const Camera & camera, double current_time) { + const glm::mat4 VIEW_MATRIX = camera.getViewMatrix(); + const glm::mat4 PROJECTION_MATRIX = camera.getViewFrustum().getProjectionMatrix(); + + // -------- + + this->_meshProgram.use(); + + this->_meshProgram.setUniform("uModel", glm::mat4(1.f)); + this->_meshProgram.setUniform("uView", VIEW_MATRIX); + this->_meshProgram.setUniform("uProj", PROJECTION_MATRIX); + + this->_meshProgram.setUniform("uColor", glm::vec4(0.6f, 0.2f, 0.4f, 1.f)); + + pg::error::OpenGLError::check(); + + this->_mesh.draw(); + + pg::error::OpenGLError::check(); + + // -------- + + std::vector<glm::mat4> models; + for(auto & particle : this->_particles) { + glm::mat4 model = glm::mat4(1.0); + model = glm::translate(model, glm::vec3(particle->getPosition())); + models.push_back(model); + } + + glBindBuffer(GL_UNIFORM_BUFFER, this->_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, models.size() * sizeof(glm::mat4), models.data()); + + pg::error::OpenGLError::check(); + + this->_billboardTexture.bind(0); + this->_billboardProgram.use(); + + this->_billboardProgram.setUniform("uView", VIEW_MATRIX); + this->_billboardProgram.setUniform("uProj", PROJECTION_MATRIX); + this->_billboardProgram.setUniform("uSlot", 0); + this->_billboardProgram.setUniform("uColor", glm::vec4(1.f, 1.f, 1.f, 1.f)); + + pg::error::OpenGLError::check(); + + this->_billboard.draw(this->_particles.size()); + + pg::error::OpenGLError::check(); + + // -------- + } + + void MeshGenerator::destroy() { + glDeleteBuffers(1, &this->_ubo); + this->_billboard.destroy(); + this->_particles.clear(); + } +} \ No newline at end of file diff --git a/ParticleGenerator/src/Scene/Scenes/MeshGenerator.hpp b/ParticleGenerator/src/Scene/Scenes/MeshGenerator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dae803e1db988ff803b66e03c539cb05e85ddb9f --- /dev/null +++ b/ParticleGenerator/src/Scene/Scenes/MeshGenerator.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include "Scene.hpp" + +#include <vector> +#include <memory> + +#include "../../Mesh/Mesh.hpp" +#include "../../Mesh/Billboard.hpp" +#include "../../Renderer/Renderer.hpp" +#include "../../Particle/generator/PhysicsParticleGenerator.hpp" + +namespace pg::scene { + class MeshGenerator : public Scene { + private: + Mesh _mesh; + Program _meshProgram; + glm::vec3 _meshPosition; + glm::vec3 _meshRotation; + + std::vector<PhysicsParticleGenerator> _generators; + std::vector<std::unique_ptr<Particle>> _particles; + Billboard _billboard; + Material _billboardTexture; + Program _billboardProgram; + GLuint _ubo; + + public: + MeshGenerator(); + + virtual void initialize(); + virtual void update(double); + virtual void render(const Camera &, double); + virtual void destroy(); + + virtual std::string name() const {return "Mesh Generator Scene";}; + virtual Interface * interface() {return nullptr;}; + + }; +} \ No newline at end of file diff --git a/ParticleGenerator/src/main.cpp b/ParticleGenerator/src/main.cpp index 9b1757ed2f18a18d4c4db6936a2ac32cfa37867f..b7616f4a502be75a9a695e119fd45ed71879850a 100644 --- a/ParticleGenerator/src/main.cpp +++ b/ParticleGenerator/src/main.cpp @@ -8,6 +8,7 @@ #include "Scene/Scenes/Physic.hpp" #include "Scene/Scenes/Path.hpp" #include "Scene/Scenes/Mesh.hpp" +#include "Scene/Scenes/MeshGenerator.hpp" #include "Interface/GlobalInterface.hpp" @@ -79,13 +80,16 @@ int main(int argc, const char * argv[]) { }; pg::scene::Physic physicScene; + pg::scene::MeshGenerator meshGeneratorScene; pg::scene::Path pathScene(&bezier, ctrlPoints); pg::scene::Mesh meshScene(&bezier, ctrlPoints); + pg::Manager manager(window, &physicScene); manager.add(physicScene); manager.add(pathScene); manager.add(meshScene); + manager.add(meshGeneratorScene); pg::GlobalInterface interface(window, manager, "Particle Generator Settings");