Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Task 7 - Dynamically generate objects in a 3D scene
- // - Implement a particle system where particles have position and speed
- // - Any object can be a generator and can add objects to the scene
- // - Create dynamic effect such as fireworks, rain etc.
- // - Encapsulate camera in a class
- #include <iostream>
- #include <memory>
- #include <vector>
- #include <map>
- #include <list>
- #define GLM_ENABLE_EXPERIMENTAL
- #include <glm/glm.hpp>
- #include <glm/gtc/matrix_transform.hpp>
- #include <glm/gtx/euler_angles.hpp>
- #include <glm/gtx/transform.hpp>
- #include <ppgso/ppgso.h>
- #include <shaders/color_vert_glsl.h>
- #include <shaders/color_frag_glsl.h>
- const unsigned int SIZE = 512;
- class Camera {
- public:
- // TODO: Add parameters
- glm::mat4 viewMatrix;
- glm::mat4 projectionMatrix;
- /// Representaiton of
- /// \param fov - Field of view (in degrees)
- /// \param ratio - Viewport ratio (width/height)
- /// \param near - Distance of the near clipping plane
- /// \param far - Distance of the far clipping plane
- Camera(float fov = 45.0f, float ratio = 1.0f, float near = 0.1f, float far = 10.0f) {
- // TODO: Initialize perspective projection (hint: glm::perspective)
- projectionMatrix = glm::perspective((ppgso::PI / 180.f) * fov, ratio, near, far);
- }
- /// Recalculate viewMatrix from position, rotation and scale
- void update() {
- viewMatrix = glm::lookAt(glm::vec3{1, 0, 0}, glm::vec3{0, 1.5, -6}, glm::vec3{0, 1, 0});
- }
- };
- /// Abstract renderable object interface
- class Renderable; // Forward declaration for Scene
- using Scene = std::list<std::unique_ptr<Renderable>>; // Type alias
- class Renderable {
- public:
- // Virtual destructor is needed for abstract interfaces
- virtual ~Renderable() = default;
- /// Render the object
- /// \param camera - Camera to use for rendering
- virtual void render(const Camera &camera) = 0;
- /// Update the object. Useful for specifing animation and behaviour.
- /// \param dTime - Time delta
- /// \param scene - Scene reference
- /// \return - Return true to keep object in scene
- virtual bool update(float dTime, Scene &scene) = 0;
- };
- class ParticleCorona final : public Renderable {
- // Static resources shared between all particles
- static std::unique_ptr<ppgso::Mesh> mesh;
- static std::unique_ptr<ppgso::Shader> program;
- public:
- glm::vec3 velocity;
- glm::vec3 acceleration;
- glm::vec3 position;
- glm::vec3 scale;
- glm::vec3 color;
- glm::mat4 modelMatrix;
- void init(glm::vec3 pos, glm::vec3 clr, glm::vec3 spd, float size){
- velocity = {spd.x, spd.y, spd.z};
- acceleration = {1.5, 0, 0};
- scale = {size, size, size};
- position = {pos.x, pos.y, pos.z};
- color = {clr.x, clr.y, clr.z};
- *program = {color_vert_glsl, color_frag_glsl};
- modelMatrix = glm::mat4{1.0f};
- }
- bool update(float dTime, Scene &scene) override {
- if(velocity.x >= 0)
- return false;
- velocity.x = acceleration.x * dTime;
- velocity.y = acceleration.y * dTime;
- velocity.z = acceleration.z * dTime;
- position.x += velocity.x;
- position.y += velocity.y;
- position.z += velocity.z;
- modelMatrix = glm::translate(position);
- return true;
- }
- void render(const Camera &camera) override {
- program->setUniform("OverallColor", color);
- program->setUniform("ModelMatrix", modelMatrix);
- program->setUniform("ViewMatrix", camera.viewMatrix);
- program->setUniform("ProjectionMatrix", camera.projectionMatrix);
- mesh->render();
- }
- ParticleCorona(glm::vec3 position, glm::vec3 color, glm::vec3 speed, float scl){
- init(position, color, speed, scl);
- if (!program) program = std::make_unique<ppgso::Shader>(color_vert_glsl, color_frag_glsl);
- if (!mesh) mesh = std::make_unique<ppgso::Mesh>("sphere.obj");
- }
- };
- class ParticleWater final : public Renderable {
- // Static resources shared between all particles
- static std::unique_ptr<ppgso::Mesh> mesh;
- static std::unique_ptr<ppgso::Shader> program;
- public:
- glm::vec3 velocity;
- glm::vec3 acceleration;
- glm::vec3 position;
- glm::vec3 scale;
- glm::vec3 color;
- double tts = 0.5;
- glm::mat4 modelMatrix;
- void init(glm::vec3 pos, glm::vec3 clr, float size){
- velocity = {-8, static_cast <float> (rand()) / static_cast <float> (RAND_MAX), static_cast <float> (rand()) / static_cast <float> (RAND_MAX) / 2 - 1.};
- acceleration = {1, -9.81, 0};
- scale = {size, size, size};
- position = {pos.x, pos.y, pos.z};
- color = {clr.x, clr.y, clr.z};
- *program = {color_vert_glsl, color_frag_glsl};
- modelMatrix = glm::mat4{1.0f};
- }
- bool update(float dTime, Scene &scene) override {
- if(position.y <= 0)
- return false;
- velocity.x = acceleration.x * dTime;
- velocity.y = acceleration.y * dTime;
- velocity.z = acceleration.z * dTime;
- position.x += velocity.x;
- position.y += velocity.y;
- position.z += velocity.z;
- if(tts <= 0 && tts >= -1){
- std::unique_ptr<ParticleCorona> ptr(new ParticleCorona{position, {0, 1, 0}, velocity, 0.2f});
- scene.push_back(std::move(ptr));
- }
- tts -= dTime;
- modelMatrix = glm::translate(position);
- return true;
- }
- void render(const Camera &camera) override {
- program->setUniform("OverallColor", color);
- program->setUniform("ModelMatrix", modelMatrix);
- program->setUniform("ViewMatrix", camera.viewMatrix);
- program->setUniform("ProjectionMatrix", camera.projectionMatrix);
- mesh->render();
- }
- ParticleWater(glm::vec3 position, glm::vec3 color, float scl){
- init(position, color, scl);
- if (!program) program = std::make_unique<ppgso::Shader>(color_vert_glsl, color_frag_glsl);
- if (!mesh) mesh = std::make_unique<ppgso::Mesh>("sphere.obj");
- }
- };
- // Static resources need to be instantiated outside of the class as they are globals
- std::unique_ptr<ppgso::Mesh> ParticleWater::mesh;
- std::unique_ptr<ppgso::Shader> ParticleWater::program;
- std::unique_ptr<ppgso::Mesh> ParticleCorona::mesh;
- std::unique_ptr<ppgso::Shader> ParticleCorona::program;
- class ParticleWindow : public ppgso::Window {
- private:
- // Scene of objects
- Scene scene;
- // Create camera
- Camera camera = {120.0f, (float) width / (float) height, 1.0f, 400.0f};
- // Store keyboard state
- std::map<int, int> keys;
- public:
- ParticleWindow() : Window{"task7_particles", SIZE, SIZE} {
- // Initialize OpenGL state
- // Enable Z-buffer
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_LEQUAL);
- }
- void onKey(int key, int scanCode, int action, int mods) override {
- // Collect key state in a map
- keys[key] = action;
- if (keys[GLFW_KEY_SPACE]) {
- auto particle = std::make_unique<ParticleWater>({2, 2, -6}, {0, 0, 1}, 0.4f});
- scene.push_back(std::move(particle));
- }
- }
- void onIdle() override {
- // Track time
- static auto time = (float) glfwGetTime();
- // Compute time delta
- float dTime = (float) glfwGetTime() - time;
- time = (float) glfwGetTime();
- // Set gray background
- glClearColor(.1f, .1f, .1f, 1.0f);
- // Clear depth and color buffers
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- // Update all objects in scene
- // Because we need to delete while iterating this is implemented using c++ iterators
- // In most languages mutating the container during iteration is undefined behaviour
- auto i = std::begin(scene);
- while (i != std::end(scene)) {
- // Update object and remove from list if needed
- auto obj = i->get();
- if (!obj->update(dTime, scene))
- i = scene.erase(i);
- else
- ++i;
- }
- // Render every object in scene
- for (auto &object : scene) {
- object->render(camera);
- }
- }
- };
- int main() {
- // Create new window
- auto window = ParticleWindow{};
- // Main execution loop
- while (window.pollEvents()) {}
- return EXIT_SUCCESS;
- }
Advertisement
Add Comment
Please, Sign In to add comment