-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added the OpenGL ParticleRenderer. #60
Owned by the OpenGLRenderer, ParticleRenderer iterates all the ParticleEmitters and updates their Particle vectors and renders them using the particle shader. Particle data is uploaded to an SSBO and instanced rendered.
- Loading branch information
1 parent
e422ff5
commit 9f6f0d3
Showing
8 changed files
with
233 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#version 430 core | ||
|
||
uniform sampler2D diffuse; | ||
|
||
in VS_OUT | ||
{ | ||
vec2 tex_coord; | ||
} fs_in; | ||
|
||
out vec4 Colour; | ||
|
||
void main() | ||
{ | ||
Colour = texture(diffuse, fs_in.tex_coord); | ||
|
||
if (Colour.a < 0.1) | ||
discard; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#version 430 core | ||
|
||
layout (location = 0) in vec3 VertexPosition; | ||
layout (location = 3) in vec2 VertexTexCoord; | ||
|
||
struct Particle | ||
{ | ||
vec4 position; | ||
vec4 velocity; | ||
}; | ||
layout(std430, binding = 3) buffer ParticlesBuffer | ||
{ | ||
uint number_of_particles; | ||
Particle particles[]; | ||
}; | ||
|
||
layout(shared) uniform ViewProperties | ||
{ | ||
mat4 view; | ||
mat4 projection; | ||
} viewProperties; | ||
|
||
out VS_OUT | ||
{ | ||
vec2 tex_coord; | ||
} vs_out; | ||
|
||
void main() | ||
{ | ||
vs_out.tex_coord = VertexTexCoord; | ||
gl_Position = viewProperties.projection * viewProperties.view * vec4(VertexPosition + particles[gl_InstanceID].position.xyz, 1.0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
#include "ParticleRenderer.hpp" | ||
|
||
#include "System/SceneSystem.hpp" | ||
|
||
#include "OpenGL/GLState.hpp" | ||
#include "OpenGL/Types.hpp" | ||
|
||
#include <random> | ||
|
||
namespace OpenGL | ||
{ | ||
ParticleRenderer::ParticleRenderer() | ||
: m_particle_shader{"particle"} | ||
, m_quad_VAO{} | ||
, m_quad_VBO{} | ||
, m_quad_EBO{} | ||
, m_particle_buffer{m_particle_shader.get_SSBO_backing("ParticlesBuffer").value()} | ||
{// Prepare the quad buffer for rendering. | ||
m_quad_VAO.bind(); | ||
m_quad_VBO.bind(); | ||
constexpr auto size = sizeof(float) * quad_vertices.size(); | ||
buffer_data(BufferType::ArrayBuffer, size, &quad_vertices.front(), BufferUsage::StaticDraw); | ||
vertex_attrib_pointer(0, 3, ShaderDataType::Float, false, sizeof(float) * 5, (void*)0); // Position | ||
enable_vertex_attrib_array(0); | ||
vertex_attrib_pointer(3, 2, ShaderDataType::Float, false, sizeof(float) * 5, (void*)(3 * sizeof(float))); // Texture | ||
enable_vertex_attrib_array(3); | ||
m_quad_EBO.bind(); | ||
buffer_data(BufferType::ElementArrayBuffer, sizeof(quad_indices), &quad_indices.front(), BufferUsage::StaticDraw); | ||
} | ||
|
||
void ParticleRenderer::update(const DeltaTime& p_delta_time, System::Scene& p_scene, const glm::vec3& p_camera_position) | ||
{ | ||
p_scene.m_entities.foreach([&](Component::ParticleEmitter& p_emitter) | ||
{ | ||
constexpr auto zero_seconds = std::chrono::seconds(0); | ||
|
||
{ // Spawning new particles every spawn_period | ||
p_emitter.time_to_next_spawn -= p_delta_time; | ||
if (p_emitter.time_to_next_spawn <= zero_seconds) | ||
{ | ||
p_emitter.time_to_next_spawn = p_emitter.spawn_period; // Reset time. | ||
|
||
ASSERT(p_emitter.particles.size() <= p_emitter.max_particle_count, "Particles container grew larger than max particle count limit!"); | ||
auto remaining_size = p_emitter.max_particle_count - p_emitter.particles.size(); | ||
auto new_particle_count = std::min(remaining_size, p_emitter.spawn_count); | ||
|
||
if (new_particle_count > 0) | ||
{// Create random number generators for each component | ||
std::random_device rd; | ||
std::mt19937 gen(rd()); | ||
std::uniform_real_distribution<float> distX(p_emitter.emit_velocity_min.x, p_emitter.emit_velocity_max.x); | ||
std::uniform_real_distribution<float> distY(p_emitter.emit_velocity_min.y, p_emitter.emit_velocity_max.y); | ||
std::uniform_real_distribution<float> distZ(p_emitter.emit_velocity_min.z, p_emitter.emit_velocity_max.z); | ||
|
||
for (auto i = 0; i < new_particle_count; i++) | ||
p_emitter.particles.push_back({glm::vec4(p_emitter.emit_position, 1.f), glm::vec4(distX(gen), distY(gen), distZ(gen), 1.f), p_emitter.lifetime}); | ||
} | ||
} | ||
} | ||
{// Update particle lifetimes and positions. | ||
// When the lifetime of a particle is below zero, remove it from the vector. | ||
// Otherwise, integrate its position by the velocity. | ||
for (auto it = p_emitter.particles.begin(); it != p_emitter.particles.end();) | ||
{ | ||
it->lifetime -= p_delta_time; | ||
|
||
if (it->lifetime <= zero_seconds) | ||
it = p_emitter.particles.erase(it); | ||
else | ||
{ | ||
it->position += (it->velocity * p_delta_time.count()); | ||
++it; | ||
} | ||
} | ||
} | ||
|
||
{// Upload the particle data to the SSBO in particle_shader | ||
m_particle_buffer->bind(); | ||
|
||
// TODO: set these by querying the SSBO using GL introspection. | ||
GLint particle_count_offset = 0; | ||
GLint particle_count_size = 16; // Size of the uint number_of_particles variable. | ||
GLint particle_array_start_offset = 16; // Starts after number_of_particles + padding. | ||
GLint particle_position_offset = 0; // Offset from the start of an index to the position var. | ||
GLint particle_velocity_offset = 16; // Offset from the start of an index to the velocity var. | ||
GLintptr particle_stride = 32; // Size of one particle | ||
|
||
auto particle_count = p_emitter.particles.size(); | ||
const auto required_size = particle_count_size + particle_count * particle_stride; | ||
// Resize the buffer to accomodate at least the directional_light_count | ||
if (required_size > m_particle_buffer->m_size) | ||
{ | ||
LOG("[OPENGL][PARTICLE RENDERER] ParticleEmitter particle count changed ({}), resized the particles buffer to {}B", particle_count, required_size); | ||
auto grow_size = required_size - m_particle_buffer->m_size; | ||
|
||
buffer_data(BufferType::ShaderStorageBuffer, required_size, NULL, BufferUsage::StaticDraw); | ||
m_particle_buffer->m_size = required_size; | ||
// Binding point = 3? | ||
bind_buffer_range(BufferType::ShaderStorageBuffer, m_particle_buffer->m_binding_point, m_particle_buffer->m_handle, 0, m_particle_buffer->m_size); | ||
|
||
if (particle_count_offset > particle_array_start_offset) | ||
{ // The var is after the variable sized array, update its offset by the growth of the variable-sized-array. | ||
particle_count_offset += grow_size; | ||
} | ||
} | ||
|
||
// Set the count | ||
auto uint_particle_count = static_cast<unsigned int>(particle_count); | ||
buffer_sub_data(BufferType::ShaderStorageBuffer, particle_count_offset, sizeof(unsigned int), &uint_particle_count); | ||
|
||
GLuint i = 0; | ||
for (auto i = 0; i < p_emitter.particles.size(); i++) | ||
{ | ||
buffer_sub_data(BufferType::ShaderStorageBuffer, particle_array_start_offset + particle_position_offset + (particle_stride * i), sizeof(glm::vec4), &p_emitter.particles[i].position); | ||
buffer_sub_data(BufferType::ShaderStorageBuffer, particle_array_start_offset + particle_velocity_offset + (particle_stride * i), sizeof(glm::vec4), &p_emitter.particles[i].velocity); | ||
} | ||
} | ||
{ // Draw the particles | ||
m_particle_shader.use(); | ||
m_particle_shader.set_uniform("diffuse", 0); | ||
active_texture(0); | ||
p_emitter.diffuse->m_GL_texture.bind(); | ||
m_quad_VAO.bind(); | ||
draw_elements_instanced(PrimitiveMode::Triangles, 6, p_emitter.particles.size()); | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#pragma once | ||
|
||
#include "OpenGL/Shader.hpp" | ||
#include "OpenGL/Types.hpp" | ||
|
||
#include "Component/ParticleEmitter.hpp" | ||
#include "Component/Mesh.hpp" | ||
|
||
#include "Utility/Config.hpp" | ||
|
||
#include "glm/fwd.hpp" | ||
|
||
#include <array> | ||
|
||
namespace System | ||
{ | ||
class Scene; | ||
} | ||
namespace OpenGL | ||
{ | ||
class ParticleRenderer | ||
{ | ||
static constexpr std::array<float, 20> quad_vertices = { | ||
// Positions // Texture coords | ||
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Top right | ||
1.0f, -1.0f, 0.0f, 1.0f, 1.0f, // Bottom right | ||
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, // Bottom left | ||
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f // Top left | ||
}; | ||
static constexpr std::array<unsigned int, 6> quad_indices = { | ||
3, 2, 1, // Second triangle | ||
3, 1, 0 // First triangle | ||
}; | ||
|
||
Shader m_particle_shader; | ||
VAO m_quad_VAO; | ||
VBO m_quad_VBO; | ||
EBO m_quad_EBO; | ||
Utility::ResourceRef<SSBO> m_particle_buffer; | ||
public: | ||
ParticleRenderer(); | ||
|
||
void update(const DeltaTime& p_delta_time, System::Scene& p_scene, const glm::vec3& p_camera_position); | ||
}; | ||
} |