Compare commits

...

3 Commits

Author SHA1 Message Date
5637868200 Add draft for multiple particle types
The type was changed from int to float, because comparing the int to values (e.g. type == 1) never returned true...
2021-05-08 19:03:29 +02:00
5016ee49d1 Make ground mesh, improve particles 2021-05-08 17:52:33 +02:00
82fae245a1 Add camera movement with keyboard & mouse 2021-05-08 17:27:16 +02:00
13 changed files with 217 additions and 99 deletions

View File

@ -62,11 +62,12 @@ void main() {
vec3 view_direction = normalize(fs_in.TangentViewPos - fs_in.TangentFragPos);
vec2 uv = fs_in.TexCoords;
uv = get_parallax_offset_uv(fs_in.TexCoords, view_direction);
uv = get_parallax_offset_uv(uv, view_direction);
// Discard if the parallax offset moved us outside of the texture
if (uv.x > 1.0 || uv.y > 1.0 || uv.x < 0.0 || uv.y < 0.0)
discard;
// TODO: Do this only if the mode is not REPEAT
//if (uv.x > 1.0 || uv.y > 1.0 || uv.x < 0.0 || uv.y < 0.0)
// discard;
// Get normal from normal map and scale it to -1..1
vec3 normal = texture(normalMap, uv).rgb;

View File

@ -3,6 +3,7 @@
uniform mat4 projection;
uniform mat4 view;
uniform vec3 camera_pos;
uniform vec3 quad1, quad2;
@ -13,20 +14,20 @@ layout(max_vertices = 4) out;
in vec3 color_pass[];
in float lifetime_pass[];
in float size_pass[];
in int type_pass[];
in float type_pass[];
smooth out vec2 tex_coords;
flat out vec4 color_part;
void main() {
if(type_pass[0] != 0) {
if(type_pass[0] != 0.0) {
// This is not a generator particle
vec3 old_pos = gl_in[0].gl_Position.xyz;
vec3 old_pos = gl_in[0].gl_Position.xyz - camera_pos;
float size = size_pass[0];
mat4 view_projection_matrix = projection * view;
color_part = vec4(color_pass[0], lifetime_pass[0]);
color_part = vec4(color_pass[0], 1.0);
vec3 pos = old_pos + (-quad1 - quad2) * size;
tex_coords = vec2(0.0, 0.0);

View File

@ -4,12 +4,12 @@ layout (location = 0) in vec3 position;
layout (location = 2) in vec3 color;
layout (location = 3) in float lifetime;
layout (location = 4) in float size;
layout (location = 5) in int type;
layout (location = 5) in float type;
out vec3 color_pass;
out float lifetime_pass;
out float size_pass;
out int type_pass;
out float type_pass;
void main()
{

View File

@ -10,7 +10,7 @@ in vec3 velocity_pass[];
in vec3 color_pass[];
in float lifetime_pass[];
in float size_pass[];
in int type_pass[];
in float type_pass[];
// All that we send further
out vec3 position_out;
@ -18,7 +18,7 @@ out vec3 velocity_out;
out vec3 color_out;
out float lifetime_out;
out float size_out;
out int type_out;
out float type_out;
uniform vec3 spawn_position; // Position where new particles are spawned
uniform vec3 spawn_gravity; // Gravity vector for particles - updates velocity of particles
@ -55,15 +55,15 @@ void main() {
position_out = position_pass[0];
velocity_out = velocity_pass[0];
if(type_pass[0] != 0) position_out += velocity_out * time_passed;
if(type_pass[0] != 0) velocity_out += spawn_gravity * time_passed;
if(type_pass[0] != 0.0) position_out += velocity_out * time_passed;
if(type_pass[0] != 0.0) velocity_out += spawn_gravity * time_passed;
color_out = color_pass[0];
lifetime_out = lifetime_pass[0] - time_passed;
size_out = size_pass[0];
type_out = type_pass[0];
if(type_out == 0) {
if(type_out == 0.0) {
// This is the emitter particle
EmitVertex();
EndPrimitive();
@ -80,14 +80,50 @@ void main() {
color_out = spawn_color;
lifetime_out = spawn_lifetime_min + spawn_lifetime_range * random_zero_to_one();
size_out = spawn_size;
type_out = 1;
type_out = 1.0;
EmitVertex();
EndPrimitive();
}
} else if(lifetime_out > 0.0) {
} else if (lifetime_out > 0.0) {
// This is a normal particle which is still alive
EmitVertex();
EndPrimitive();
} else if (type_out == 1.0) {
// The lifetime is over -- transform this particle in a new one or discard
for(int i = 0; i < 5; i++) {
// Keep the position
velocity_out = spawn_velocity_min + vec3(
spawn_velocity_range.x * random_zero_to_one(),
spawn_velocity_range.y * random_zero_to_one(),
spawn_velocity_range.z * random_zero_to_one()
);
color_out = vec3(1.0, 0, 0);
lifetime_out = spawn_lifetime_min + spawn_lifetime_range * random_zero_to_one();
size_out = spawn_size;
type_out = 2.0;
EmitVertex();
EndPrimitive();
}
} else if (type_out == 2.0) {
// The lifetime is over -- transform this particle in a new one or discard
for(int i = 0; i < 5; i++) {
// Keep the position
velocity_out = spawn_velocity_min + vec3(
spawn_velocity_range.x * random_zero_to_one(),
spawn_velocity_range.y * random_zero_to_one(),
spawn_velocity_range.z * random_zero_to_one()
);
color_out = vec3(0.0, 1.0, 0);
lifetime_out = spawn_lifetime_min + spawn_lifetime_range * random_zero_to_one();
size_out = spawn_size;
type_out = 3.0;
EmitVertex();
EndPrimitive();
}
}
}

View File

@ -5,14 +5,14 @@ layout (location = 1) in vec3 velocity;
layout (location = 2) in vec3 color;
layout (location = 3) in float lifetime;
layout (location = 4) in float size;
layout (location = 5) in int type;
layout (location = 5) in float type;
out vec3 position_pass;
out vec3 velocity_pass;
out vec3 color_pass;
out float lifetime_pass;
out float size_pass;
out int type_pass;
out float type_pass;
void main() {
position_pass = position;

View File

@ -1,6 +1,8 @@
#include "Gedeng/ParticleSystem.h"
#include "Gedeng/Logger.h"
#include <glm/gtc/random.hpp>
namespace Gedeng {
ParticleSystem::ParticleSystem() {
@ -40,7 +42,7 @@ ParticleSystem::ParticleSystem() {
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Particle), (const GLvoid *)24); // Color
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(Particle), (const GLvoid *)36); // Lifetime
glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(Particle), (const GLvoid *)40); // Size
glVertexAttribPointer(5, 1, GL_INT, GL_FALSE, sizeof(Particle), (const GLvoid *)44); // Type
glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(Particle), (const GLvoid *)44); // Type
}
current_read_buffer = 0;
@ -69,9 +71,8 @@ void ParticleSystem::update(float delta) {
update_shader.setInt("number_to_generate", target_particle_count);
elapsed_time -= next_generation_time;
glm::vec3 random_seed = glm::vec3(
10.0, 10.0,
10.0); // FIXME: Random glm::vec3(grandf(-10.0f, 20.0f), grandf(-10.0f, 20.0f), grandf(-10.0f, 20.0f));
glm::vec3 random_seed =
glm::vec3(glm::linearRand(-10.0f, 20.0f), glm::linearRand(-10.0f, 20.0f), glm::linearRand(-10.0f, 20.0f));
update_shader.setVec3("random_seed", random_seed);
}
@ -107,6 +108,8 @@ void ParticleSystem::set_camera(const Camera &camera) {
quad2 = glm::cross(camera.forward(), quad1);
quad2 = glm::normalize(quad2);
camera_pos = camera.get_translation();
}
void ParticleSystem::render() {
@ -120,6 +123,7 @@ void ParticleSystem::render() {
render_shader.setMat4("view", view_matrix);
render_shader.setVec3("quad1", quad1);
render_shader.setVec3("quad2", quad2);
render_shader.setVec3("camera_pos", camera_pos);
texture->bind_to(0);

View File

@ -16,10 +16,10 @@ void RenderBackend::initialize_window(unsigned int width, unsigned int height, S
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
glEnable(GL_DEPTH_TEST);
// glEnable(GL_CULL_FACE);
// glEnable(GL_BLEND);
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// FIXME: Disabled because of a bug with particles: they're discarded as if the floor moves with the camera
// glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
bool RenderBackend::is_window_created() {

View File

@ -1,9 +1,13 @@
#pragma once
#include <GLFW/glfw3.h>
#include <glm/ext/matrix_transform.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/dual_quaternion.hpp>
#include "Gedeng/Logger.h"
#include "Input.h"
#include "Spatial.h"
namespace Gedeng {
@ -28,4 +32,56 @@ class Camera : public Spatial {
glm::mat4 projection;
};
class FPSCamera : public Camera {
public:
FPSCamera(float fov, float width, float height, float near, float far)
: Camera(fov, width, height, near, far), move_speed(glm::vec3(5.0, 5.0, 5.0)), mouse_sensitivity(0.1),
last_mouse_position(Input::get_mouse_position()), pitch(0.0), yaw(0.0) {
}
void update(float delta) {
if (Input::is_key_down(GLFW_KEY_W)) {
translate(glm::vec3(0.0, 0.0, -1.0) * move_speed * delta);
}
if (Input::is_key_down(GLFW_KEY_S)) {
translate(-glm::vec3(0.0, 0.0, -1.0) * move_speed * delta);
}
if (Input::is_key_down(GLFW_KEY_D)) {
translate(glm::vec3(1.0, 0.0, 0.0) * move_speed * delta);
}
if (Input::is_key_down(GLFW_KEY_A)) {
translate(-glm::vec3(1.0, 0.0, 0.0) * move_speed * delta);
}
if (Input::is_key_down(GLFW_KEY_Q)) {
translate(glm::vec3(0.0, 1.0, 0.0) * move_speed * delta);
}
if (Input::is_key_down(GLFW_KEY_E)) {
translate(-glm::vec3(0.0, 1.0, 0.0) * move_speed * delta);
}
glm::vec2 mouse_difference = Input::get_mouse_position() - last_mouse_position;
yaw -= mouse_difference.x * mouse_sensitivity;
pitch -= mouse_difference.y * mouse_sensitivity;
if (pitch > 80.0f) pitch = 80.0f;
if (pitch < -80.0f) pitch = -80.0f;
glm::qua rotation = glm::angleAxis(glm::radians((float)yaw), glm::vec3(0.f, 1.f, 0.f));
rotation *= glm::angleAxis(glm::radians((float)pitch), glm::vec3(1.f, 0.f, 0.f));
set_rotation_from_quat(rotation);
last_mouse_position = Input::get_mouse_position();
}
private:
glm::vec3 move_speed;
float mouse_sensitivity;
glm::vec2 last_mouse_position;
float pitch;
float yaw;
};
} // namespace Gedeng

View File

@ -7,6 +7,8 @@
#include <GLFW/glfw3.h>
#include "RenderBackend.h"
#include <glm/fwd.hpp>
#include <glm/glm.hpp>
#include <map>
namespace Gedeng {
@ -15,6 +17,10 @@ class Input {
public:
static void initialize(GLFWwindow *window) {
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
is_mouse_active = true;
}
// FIXME: Ignore warnings produced by these unused variables -- they're required for the callback to work:
@ -25,6 +31,11 @@ class Input {
Input::set_key_down(key, action == GLFW_RELEASE ? false : true);
}
static void mouse_callback(GLFWwindow *window, double xpos, double ypos) {
mouse_position.x = xpos;
mouse_position.y = ypos;
}
static void poll_input() {
glfwPollEvents();
}
@ -37,7 +48,14 @@ class Input {
return keys_down[key];
}
static glm::vec2 get_mouse_position() {
return is_mouse_active ? mouse_position : glm::vec2(0.0, 0.0);
}
private:
inline static std::map<int, bool> keys_down;
inline static glm::vec2 mouse_position;
inline static bool is_mouse_active;
};
} // namespace Gedeng

View File

@ -53,10 +53,11 @@ class ParticleSystem {
int current_read_buffer;
int current_particle_count;
const int max_particle_count = 1000; // FIXME: Increase
const int max_particle_count = 1000000;
glm::mat4 projection_matrix, view_matrix;
glm::vec3 quad1, quad2;
glm::vec3 camera_pos;
float elapsed_time;
float next_generation_time;
@ -81,7 +82,7 @@ class ParticleSystem {
glm::vec3 color;
float lifetime;
float size;
int type;
float type;
};
};

View File

@ -13,21 +13,21 @@ namespace Gedeng {
// A simple 2x2 quad mesh consisting of two triangles. Oriented upwards by default.
class QuadMesh : public Spatial {
public:
QuadMesh() {
QuadMesh(float scale = 1.0f) {
// Positions
glm::vec3 pos1(-1.0f, 1.0f, 0.0f);
glm::vec3 pos2(-1.0f, -1.0f, 0.0f);
glm::vec3 pos3(1.0f, -1.0f, 0.0f);
glm::vec3 pos4(1.0f, 1.0f, 0.0f);
glm::vec3 pos1 = glm::vec3(-1.0f, 0.0f, 1.0f) * scale;
glm::vec3 pos2 = glm::vec3(-1.0f, 0.0f, -1.0f) * scale;
glm::vec3 pos3 = glm::vec3(1.0f, 0.0f, -1.0f) * scale;
glm::vec3 pos4 = glm::vec3(1.0f, 0.0f, 1.0f) * scale;
// Texture coordinates
glm::vec2 uv1(0.0f, 1.0f);
glm::vec2 uv2(0.0f, 0.0f);
glm::vec2 uv3(1.0f, 0.0f);
glm::vec2 uv4(1.0f, 1.0f);
glm::vec2 uv1 = glm::vec2(0.0f, 1.0f) * scale;
glm::vec2 uv2 = glm::vec2(0.0f, 0.0f) * scale;
glm::vec2 uv3 = glm::vec2(1.0f, 0.0f) * scale;
glm::vec2 uv4 = glm::vec2(1.0f, 1.0f) * scale;
// Normal vector
glm::vec3 nm(0.0f, 0.0f, 1.0f);
glm::vec3 nm(0.0f, 1.0f, 0.0f);
// Calculate tangent/bitangent vectors of both triangles
glm::vec3 tangent1, bitangent1;
@ -69,8 +69,7 @@ class QuadMesh : public Spatial {
bitangent2.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
bitangent2 = glm::normalize(bitangent2);
float quadVertices[] = {
// positions // normal // texcoords // tangent // bitangent
float quadVertices[] = {// positions // normal // texcoords // tangent // bitangent
pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x,
uv1.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
pos2.x, pos2.y, pos2.z, nm.x, nm.y, nm.z, uv2.x,
@ -94,17 +93,13 @@ class QuadMesh : public Spatial {
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(3 * sizeof(float)));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(6 * sizeof(float)));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)(6 * sizeof(float)));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(8 * sizeof(float)));
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)(8 * sizeof(float)));
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(11 * sizeof(float)));
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)(11 * sizeof(float)));
}
void render(Shader &shader) {
@ -120,4 +115,4 @@ class QuadMesh : public Spatial {
unsigned int quadVBO;
};
}
} // namespace Gedeng

View File

@ -16,7 +16,7 @@ class Spatial {
matrix = glm::translate(matrix, offset);
}
glm::vec3 get_translation() {
glm::vec3 get_translation() const {
return glm::vec3(matrix[3]);
}

View File

@ -1,5 +1,6 @@
#include "Gedeng/Logger.h"
#include "Gedeng/ParticleSystem.h"
#include "Gedeng/QuadMesh.h"
#include "Gedeng/TextLabel.h"
#include "Gedeng/Vector3.h"
#define GEDENG_MAIN
@ -9,37 +10,40 @@ class ParticleApp : public Gedeng::Application {
public:
ParticleApp(unsigned long ms_per_update, unsigned int window_size_x, unsigned int window_size_y,
Gedeng::String window_name)
: Application(ms_per_update, window_size_x, window_size_y, window_name),
camera(Gedeng::Camera(90, 1920, 1080, 0.1, 1000.0)),
: Application(ms_per_update, window_size_x, window_size_y, window_name), number_of_steps(10.0),
number_of_refinement_steps(10.0), bump_depth(0.1),
render_shader(Gedeng::Shader("Shader/bump.vs", "Shader/bump.fs")),
camera(Gedeng::FPSCamera(90, 1920, 1080, 0.1, 1000.0)),
albedo("Resources/Textures/PavingStones/PavingStones070_2K_Color.jpg", Gedeng::Texture::Settings()),
bump("Resources/Textures/PavingStones/PavingStones070_2K_Displacement.jpg", Gedeng::Texture::Settings()),
normal("Resources/Textures/PavingStones/PavingStones070_2K_Normal.jpg", Gedeng::Texture::Settings()) {
// Move and rotate the camera so we see the quad well
// camera.translate(glm::vec3(0.0, 0.0, -1.0));
// camera.rotate(180, glm::vec3(0.0, 1.0, 0.0));
normal("Resources/Textures/PavingStones/PavingStones070_2K_Normal.jpg", Gedeng::Texture::Settings()),
quad_mesh(Gedeng::QuadMesh(10.0)) {
particles.set_position(glm::vec3(0.0f, 0.0f, -5.0f));
particles.set_velocity(glm::vec3(-5, 0, -5), glm::vec3(5, 20, 5));
particles.set_gravity(glm::vec3(0, -5, 0));
particles.set_velocity(glm::vec3(-1, 0, -1), glm::vec3(1, 5, 1));
particles.set_gravity(glm::vec3(0, -2, 0));
particles.set_color(glm::vec3(0.0f, 0.5f, 1.0f));
particles.set_lifetime(1.5f, 3.0f);
particles.set_size(0.75f);
particles.set_interval(0.2f);
particles.set_number_of_particles(30);
particles.set_lifetime(1.0f, 1.5f);
particles.set_size(0.1);
particles.set_interval(0.05f);
particles.set_number_of_particles(1);
particles.set_texture(&albedo);
camera.translate(glm::vec3(0.0, 2.0, 1.0));
// camera.rotate(30, glm::vec3(1.0, 0.0, 0.0));
}
~ParticleApp() = default;
void fixed_update(double delta) override {
// camera.rotate(delta * 180, glm::vec3(0.0, 1.0, 0.0));
camera.update(delta);
}
void dynamic_update(double delta) override {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClearColor(0.1, 0.1f, 0.1, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* render_shader.use();
render_shader.use();
// Camera
render_shader.setMat4("projection", camera.get_projection());
@ -59,22 +63,24 @@ class ParticleApp : public Gedeng::Application {
bump.bind_to(2);
// Quad which is rendered onto
quad_mesh.rotate(delta * 25.0f, glm::normalize(glm::vec3(0.0, 0.0, 1.0)));
quad_mesh.render(render_shader);
debug_text.render_text(25.0f, 25.0f, 1.0f, Gedeng::Vector3(1.0, 1.0, 0.0)); */
// Particles
particles.set_camera(camera);
particles.update(delta);
particles.render();
}
private:
Gedeng::ParticleSystem particles;
float number_of_steps;
float number_of_refinement_steps;
float bump_depth;
Gedeng::Shader render_shader;
Gedeng::VertexBuffer vertex_rectangle;
Gedeng::Camera camera;
Gedeng::FPSCamera camera;
Gedeng::Texture albedo;
Gedeng::Texture bump;
@ -82,7 +88,7 @@ class ParticleApp : public Gedeng::Application {
Gedeng::QuadMesh quad_mesh;
Gedeng::TextLabel debug_text;
Gedeng::ParticleSystem particles;
};
Gedeng::Application *Gedeng::create_application() {