From f07b6fdd6273a96223187a50cc5917ab040570a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20=C5=81ukasik?= Date: Thu, 25 Feb 2021 21:46:41 +0100 Subject: [PATCH] particle --- shaders/shader_particles.frag | 10 +++ shaders/shader_particles.vert | 18 +++++ src/ParticleEmiter.cpp | 128 ++++++++++++++++++++++++++++++++++ src/ParticleEmiter.h | 37 ++++++++++ src/projekt.cpp | 57 ++++++++++++--- 5 files changed, 241 insertions(+), 9 deletions(-) create mode 100644 shaders/shader_particles.frag create mode 100644 shaders/shader_particles.vert create mode 100644 src/ParticleEmiter.cpp create mode 100644 src/ParticleEmiter.h diff --git a/shaders/shader_particles.frag b/shaders/shader_particles.frag new file mode 100644 index 0000000..f0486df --- /dev/null +++ b/shaders/shader_particles.frag @@ -0,0 +1,10 @@ +#version 330 core + +in float lifeTime; +out vec4 fragColor; + +void main() +{ + float normalizedLifeTime = lifeTime / 2; + fragColor = vec4( 5.f, normalizedLifeTime, 0.f, normalizedLifeTime); +}; \ No newline at end of file diff --git a/shaders/shader_particles.vert b/shaders/shader_particles.vert new file mode 100644 index 0000000..313cca5 --- /dev/null +++ b/shaders/shader_particles.vert @@ -0,0 +1,18 @@ +#version 330 core + +layout ( location = 0 ) in vec3 vertex_position; +layout ( location = 4 ) in vec4 position; + +uniform mat4 M_v; +uniform mat4 M_p; +uniform mat4 transformation; +uniform float particleSize; +out float lifeTime; + +void main() +{ + vec4 position_viewspace = M_v * transformation * vec4( position.xyz , 1 ); + position_viewspace.xy += particleSize * (vertex_position.xy - vec2(0.5f)); + gl_Position = M_p * position_viewspace; + lifeTime = position.w; +}; \ No newline at end of file diff --git a/src/ParticleEmiter.cpp b/src/ParticleEmiter.cpp new file mode 100644 index 0000000..b8f87fd --- /dev/null +++ b/src/ParticleEmiter.cpp @@ -0,0 +1,128 @@ +#include "ParticleEmiter.h" +#include + +//ParticleEmitter::ParticleEmitter(GLuint* program) +//{ +// this->program = program; +// +// this->positionsArr = new float[PARTICLES_COUNT * 4]; +// +// particles.resize(PARTICLES_COUNT); +// for (int i = 0; i < PARTICLES_COUNT; ++i) +// { +// particles[i].position = glm::vec3(0); +// particles[i].lifetime = randomFloat(1.0f, 2.0f); +// particles[i].radius = 0.01f; +// } +// +// generateBuffers(); +//} + +ParticleEmitter::ParticleEmitter(GLuint* program, int particleCount, float particleSize) +{ + this->program = program; + + this->positionsArr = new float[particleCount * 4]; + this->particleSize = particleSize; + + particles.resize(particleCount); + for (int i = 0; i < particleCount; ++i) + { + particles[i].position = glm::vec3(0, 100, 0); + particles[i].lifetime = randomFloat(1.0f, 2.0f); + particles[i].radius = 0.003f; + } + + generateBuffers(); +} + +void ParticleEmitter::generateBuffers() +{ + glGenBuffers(1, &particleVertexBuffer); + + std::vector< float > vertices; + vertices.push_back(0.0f); vertices.push_back(0.0f); vertices.push_back(0.0f); + vertices.push_back(1.0f); vertices.push_back(0.0f); vertices.push_back(0.0f); + vertices.push_back(0.0f); vertices.push_back(1.0f); vertices.push_back(0.0f); + vertices.push_back(1.0f); vertices.push_back(1.0f); vertices.push_back(0.0f); + + glBindBuffer(GL_ARRAY_BUFFER, particleVertexBuffer); + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW); + + glGenBuffers(1, &particlePositionBuffer); + glBindBuffer(GL_ARRAY_BUFFER, particlePositionBuffer); + glBufferData(GL_ARRAY_BUFFER, particles.size() * 4 * sizeof(float), positionsArr, GL_DYNAMIC_DRAW); +} + +void ParticleEmitter::setupUniforms(const glm::mat4 transformation, glm::mat4 cameraMatrix, glm::mat4 perspectiveMatrix) +{ + glUniformMatrix4fv(glGetUniformLocation(*program, "transformation"), 1, GL_FALSE, (float*)&transformation); + glUniformMatrix4fv(glGetUniformLocation(*program, "M_v"), 1, GL_FALSE, (float*)&cameraMatrix); + glUniformMatrix4fv(glGetUniformLocation(*program, "M_p"), 1, GL_FALSE, (float*)&perspectiveMatrix); + glUniform1f(glGetUniformLocation(*program, "particleSize"), this->particleSize); +} + +void ParticleEmitter::update(const float dt, const glm::mat4 transformation, glm::mat4 cameraMatrix, glm::mat4 perspectiveMatrix) +{ + glUseProgram(*program); + + setupUniforms(transformation, cameraMatrix, perspectiveMatrix); + + + for (int i = 0; i < particles.size(); ++i) + { + particles[i].lifetime -= dt; + particles[i].radius += 0.0002; + + if (particles[i].lifetime <= 0.0f) + { + particles[i].position = glm::vec3(0); + particles[i].lifetime = randomFloat(1.0f, 2.0f); + particles[i].radius = 0.003f; + } + + float radius = particles[i].radius; + particles[i].position -= glm::vec3(randomFloat(-radius, radius), dt / 2, randomFloat(-radius, radius)); + + positionsArr[i * 4 + 0] = particles[i].position[0]; + positionsArr[i * 4 + 1] = particles[i].position[1]; + positionsArr[i * 4 + 2] = particles[i].position[2]; + positionsArr[i * 4 + 3] = particles[i].lifetime; + } +} + +void ParticleEmitter::draw() +{ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(4); + + glBindBuffer(GL_ARRAY_BUFFER, particlePositionBuffer); + glBufferSubData(GL_ARRAY_BUFFER, 0, particles.size() * 4 * sizeof(float), positionsArr); + + glBindBuffer(GL_ARRAY_BUFFER, particleVertexBuffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glBindBuffer(GL_ARRAY_BUFFER, particlePositionBuffer); + glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 0, nullptr); + glVertexAttribDivisor(4, 1); + + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, particles.size()); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(4); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glUseProgram(0); +} + +float ParticleEmitter::randomFloat(float min, float max) { + return (max - min) * ((((float)rand()) / (float)RAND_MAX)) + min; +} + +ParticleEmitter::~ParticleEmitter() +{ + glDeleteBuffers(1, &particleVertexBuffer); + glDeleteBuffers(1, &particlePositionBuffer); +} \ No newline at end of file diff --git a/src/ParticleEmiter.h b/src/ParticleEmiter.h new file mode 100644 index 0000000..562edaf --- /dev/null +++ b/src/ParticleEmiter.h @@ -0,0 +1,37 @@ +#include "glew.h" +#include "freeglut.h" +#include "glm.hpp" +#include + + +#define PARTICLES_COUNT 0 + +class ParticleEmitter +{ +public: + ParticleEmitter(GLuint* program); + ParticleEmitter(GLuint* program, int particleCount, float particleSize); + ~ParticleEmitter(); + + void update(const float dt, const glm::mat4 transformation, glm::mat4 cameraMatrix, glm::mat4 perspectiveMatrix); + void draw(); + +private: + struct Particle + { + glm::vec3 position; + float lifetime = 0.0f; + float radius = 0.0f; + }; + + float* positionsArr; + float particleSize = 0.015f; + GLuint* program; + GLuint particleVertexBuffer; + GLuint particlePositionBuffer; + std::vector< Particle > particles; + + float randomFloat(float min, float max); + void generateBuffers(); + void setupUniforms(const glm::mat4 transformation, glm::mat4 cameraMatrix, glm::mat4 perspectiveMatrix); +}; \ No newline at end of file diff --git a/src/projekt.cpp b/src/projekt.cpp index a99245b..7020259 100644 --- a/src/projekt.cpp +++ b/src/projekt.cpp @@ -12,6 +12,7 @@ #include "Texture.h" #include "Physics.h" #include "Skybox.h" +#include "ParticleEmiter.h" #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" @@ -20,14 +21,18 @@ GLuint programColor; GLuint programTexture; GLuint programSkybox; GLuint programSun; +GLuint programParticle; GLuint cubemapTexture; GLuint cubemapTexture2; GLuint cubemapTexture3; GLuint cubemapTexture4; GLuint cubemapTexture5; - GLuint skyboxVAO, skyboxVBO; +ParticleEmitter* particleEmitterOrbit; +ParticleEmitter* particleEmitterStartShip; +ParticleEmitter* particleEmitterStartBooster; + Core::Shader_Loader shaderLoader; obj::Model planeModel; @@ -65,11 +70,18 @@ GLuint textureMoon; Core::RenderContext shipContextOrbit, sphereContextOrbit, stationContextOrbit; +float acceleration = 0.f; float frustumScale = 1.f; bool loading = false; bool reload = false; bool end = false; float orbitSpeed = 0.003f; +const glm::mat4 particleStartShipTranslation = glm::translate(glm::vec3(-2.f, 3.1f, 0.f)); +const glm::mat4 particleStartBoosterTranslation = glm::translate(glm::vec3(-2.f, -4.5f, 0.f)); +const glm::vec3 particleOrbitOffset = glm::vec3(2.75f, 0.f, -0.f); +const glm::mat4 particleOrbitRotation = glm::rotate(glm::radians(90.0f), glm::vec3(0, 0, 1)); +const glm::mat4 particleOrbitTranslation = glm::translate(glm::vec3(2.75f, 0.f, -0.f)) * glm::rotate(glm::radians(90.0f), glm::vec3(0, 0, 1)); +float particleLife = 0.f; // skybox std::vector faces @@ -298,12 +310,20 @@ void keyboard(unsigned char key, int x, int y) case 'w': if (orbitSpeed < 0.02f) { - orbitSpeed += 0.0001f; + if (!loading) { + acceleration += 0.1f; + } + else if (!end) { + orbitSpeed += 0.0001f; + } + + } break; case 's': if (orbitSpeed > 0.001f) { orbitSpeed -= 0.0001f; + particleLife -= 0.01f; } break; @@ -413,6 +433,8 @@ void drawObjectTexture(Core::RenderContext* context, glm::mat4 modelMatrix, GLui } + + void shutdown() { shaderLoader.DeleteProgram(programColor); @@ -450,6 +472,8 @@ void renderScene() // Update of camera and perspective matrices cameraMatrix = createCameraMatrix(); perspectiveMatrix = Core::createPerspectiveMatrix(0.1f, 1500.f); + glm::mat4 shipModelStartMatrix = glm::translate(cameraPos + cameraDir * 4.f + glm::vec3(0, -0.25f, 0)) * glm::rotate(glm::orientedAngle(glm::vec3(0, 0, 1), cameraDir, glm::vec3(0, 1, 0)), glm::vec3(0, 1, 0)) * glm::scale(glm::vec3(0.2)) * glm::translate(glm::vec3(2, 0, 0)); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(0.0f, 0.1f, 0.3f, 1.0f); @@ -458,18 +482,24 @@ void renderScene() // update transforms from physics simulation updateTransforms(); + std::cout << acceleration << std::endl; - - if (time > 2 && time < 7) { - boxBodies[0]->setLinearVelocity(PxVec3(0, time * 0.8, 0)); - boxBodies[1]->setLinearVelocity(PxVec3(0, time * 0.8, 0)); + if (acceleration > 1 && acceleration < 20) { + boxBodies[0]->setLinearVelocity(PxVec3(0, acceleration, 0)); + boxBodies[1]->setLinearVelocity(PxVec3(0, acceleration, 0)); + particleEmitterStartBooster->update(0.01f, shipModelStartMatrix * particleStartBoosterTranslation, cameraMatrix, perspectiveMatrix); + particleEmitterStartBooster->draw(); + + } - if (time > 7 && time < 15) { - boxBodies[1]->setLinearVelocity(PxVec3(0, 15, 0)); + if (acceleration > 20 && acceleration < 40) { + boxBodies[1]->setLinearVelocity(PxVec3(0, acceleration, 0)); + particleEmitterStartShip->update(0.01f, shipModelStartMatrix * particleStartShipTranslation, cameraMatrix, perspectiveMatrix); + particleEmitterStartShip->draw(); } - if (time > 15) { + if (acceleration > 40) { loading = true; lightDir = glm::normalize(glm::vec3(1.0f, -1.0f, -1.0f)); lightPos = glm::vec3(0, 0, -800); @@ -484,6 +514,7 @@ void renderScene() drawObjectTexture(renderable->context, renderable->modelMatrix, renderable->textureId); } + glutSwapBuffers(); } @@ -580,6 +611,9 @@ void renderScene() glUniform3f(glGetUniformLocation(programSun, "cameraPos"), cameraPos.x, cameraPos.y, cameraPos.z); drawObject(programSun, sphereContextOrbit, glm::translate(lightPos) * glm::scale(glm::vec3(10.f)), glm::vec3(1.0f, 0.8f, 0.2f)); + particleEmitterOrbit->update(0.01f, shipModelOrbitMatrix * particleOrbitTranslation, cameraMatrix, perspectiveMatrix); + particleEmitterOrbit->draw(); + glUseProgram(0); glutSwapBuffers(); @@ -627,6 +661,7 @@ void init() programColor = shaderLoader.CreateProgram("shaders/shader_color.vert", "shaders/shader_color.frag"); programTexture = shaderLoader.CreateProgram("shaders/shader_tex.vert", "shaders/shader_tex.frag"); programSkybox = shaderLoader.CreateProgram("shaders/shader_skybox.vert", "shaders/shader_skybox.frag"); + programParticle = shaderLoader.CreateProgram("shaders/shader_particles.vert", "shaders/shader_particles.frag"); cubemapTexture = Skybox::loadCubemap(faces); cubemapTexture2 = Skybox::loadCubemap(faces2); @@ -634,6 +669,10 @@ void init() cubemapTexture4 = Skybox::loadCubemap(faces4); cubemapTexture5 = Skybox::loadCubemap(faces5); + particleEmitterOrbit = new ParticleEmitter(&programParticle, 1000, 0.02f); + particleEmitterStartShip = new ParticleEmitter(&programParticle, 1000, 0.02f); + particleEmitterStartBooster = new ParticleEmitter(&programParticle, 2000, 0.1f); + glEnable(GL_DEPTH_TEST); programSun = shaderLoader.CreateProgram("shaders/shader_4_2.vert", "shaders/shader_4_2.frag");