diff --git a/assets/shader/light.fsh b/assets/shader/light.fsh index 7d36ad3..90a7060 100644 --- a/assets/shader/light.fsh +++ b/assets/shader/light.fsh @@ -1,13 +1,13 @@ #version 460 core -in vec4 frag_pos; -out vec4 frag_colour; +in vec3 frag_pos; + +uniform float far_plane; void main() { float distance = length(frag_pos); - frag_colour = vec4(vec3(distance / 50.0f), 1); - gl_FragDepth = distance / 50.0f; + gl_FragDepth = distance / far_plane + 1e-4f; } diff --git a/assets/shader/light.gsh b/assets/shader/light.gsh index 6c57360..28101d0 100644 --- a/assets/shader/light.gsh +++ b/assets/shader/light.gsh @@ -6,18 +6,22 @@ layout (triangle_strip, max_vertices=18) out; uniform mat4 shadow_mats[6]; -out vec4 frag_pos; +in float emissive[]; +out vec3 frag_pos; void main() { + if(emissive[0] > 0) return; + for(int i = 0; i < 6; i++) { gl_Layer = i; for(int j = 0; j < 3; j++) { - frag_pos = gl_in[j].gl_Position; - gl_Position = shadow_mats[i] * frag_pos; + vec4 fp = gl_in[j].gl_Position; + gl_Position = shadow_mats[i] * fp; + frag_pos = fp.xyz; EmitVertex(); } diff --git a/assets/shader/light.vsh b/assets/shader/light.vsh index 991ba7f..4e3357e 100644 --- a/assets/shader/light.vsh +++ b/assets/shader/light.vsh @@ -2,12 +2,16 @@ #version 460 core layout (location = 2) in vec4 aPos; +layout (location = 5) in vec3 aMaterial; uniform mat4 model; uniform mat4 camera; +out float emissive; + void main() { gl_Position = camera * model * aPos; + emissive = aMaterial[2]; } diff --git a/assets/shader/main.fsh b/assets/shader/main.fsh index 8d5b4c0..72939f2 100644 --- a/assets/shader/main.fsh +++ b/assets/shader/main.fsh @@ -8,6 +8,18 @@ const float Epsilon = 0.00001; // Constant normal incidence Fresnel factor for all dielectrics. const vec3 Fdielectric = vec3(0.04); +const int SampleOffsetsLen = 8; +const vec3 SampleOffsets[SampleOffsetsLen] = { + vec3(-1.f,-1.f,-1.f), + vec3(-1.f,-1.f, 1.f), + vec3(-1.f, 1.f,-1.f), + vec3(-1.f, 1.f, 1.f), + vec3( 1.f,-1.f,-1.f), + vec3( 1.f,-1.f, 1.f), + vec3( 1.f, 1.f,-1.f), + vec3( 1.f, 1.f, 1.f), +}; + in VS_OUT { vec3 normal; vec4 colour; @@ -27,52 +39,58 @@ layout(std140, binding = 1) buffer ssbo_lights Light lights[]; }; +layout(std430, binding = 2) buffer ssbo_shadow_maps +{ + samplerCube shadow_maps[]; +}; + in flat sampler2D frag_tex; out vec4 frag_colour; uniform vec3 brightness; uniform vec3 camera_pos; - uniform int lights_count; +uniform float far_plane; +uniform bool shadows_enabled; vec3 FresnelSchlick(float cosTheta, vec3 F0) { - return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); + return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); } float DistributionGGX(vec3 N, vec3 H, float roughness) { - float a = roughness*roughness; - float a2 = a*a; - float NdotH = max(dot(N, H), 0.0); - float NdotH2 = NdotH*NdotH; + float a = roughness*roughness; + float a2 = a*a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH*NdotH; - float num = a2; - float denom = (NdotH2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; + float num = a2; + float denom = (NdotH2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; - return num / denom; + return num / denom; } float GeometrySchlickGGX(float NdotV, float roughness) { - float r = (roughness + 1.0); - float k = (r*r) / 8.0; + float r = (roughness + 1.0); + float k = (r*r) / 8.0; - float num = NdotV; - float denom = NdotV * (1.0 - k) + k; + float num = NdotV; + float denom = NdotV * (1.0 - k) + k; - return num / denom; + return num / denom; } float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { - float NdotV = max(dot(N, V), 0.0); - float NdotL = max(dot(N, L), 0.0); - float ggx2 = GeometrySchlickGGX(NdotV, roughness); - float ggx1 = GeometrySchlickGGX(NdotL, roughness); + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); - return ggx1 * ggx2; + return ggx1 * ggx2; } vec3 LinRGB_To_sRGB(vec3 c) @@ -121,21 +139,40 @@ void main() vec3 radiance = l.colour.rgb * atten; // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - vec3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); - - vec3 kS = F; - vec3 kD = vec3(1.0) - kS; - kD *= 1.0 - metalness; - - vec3 numerator = NDF * G * F; - float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001; - vec3 specular = numerator / denominator; - - // add to outgoing radiance Lo - float NdotL = max(dot(N, L), 0.0); - Lo += (kD * albedo_lin / PI + specular) * radiance * NdotL; + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + vec3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); + + vec3 kS = F; + vec3 kD = vec3(1.0) - kS; + kD *= 1.0 - metalness; + + vec3 numerator = NDF * G * F; + float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001; + vec3 specular = numerator / denominator; + + float amount = 0; + + if(shadows_enabled) + { + float texel_size = 1.f / textureSize(shadow_maps[i], 0)[0]; + + for(int j = 0; j < SampleOffsetsLen; j++) + { + amount += ((texture(shadow_maps[i], -L + SampleOffsets[j] * texel_size).r * far_plane > d) ? 1.f : 0.5f); + } + + amount /= SampleOffsetsLen; + } + + else + { + amount = 1.f; + } + + // add to outgoing radiance Lo + float NdotL = max(dot(N, L), 0.0); + Lo += (kD * albedo_lin / PI + specular) * radiance * NdotL * amount; } vec3 ambient = vec3(0.03f) * albedo_lin * brightness; diff --git a/src/graphics/mesh/gllight.cpp b/src/graphics/mesh/gllight.cpp new file mode 100644 index 0000000..7e98d5a --- /dev/null +++ b/src/graphics/mesh/gllight.cpp @@ -0,0 +1,88 @@ + +#include +#include + +#include "gllight.hpp" +#include "../shader.hpp" +#include "../window.hpp" +#include "texture.hpp" + +#include +#include + +using namespace Sim::Graphics; + +static glm::mat4 shadow_mats[6]; + +GLLight::GLLight(Light light) : light(light), size(4096) +{ + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + + for(int i = 0; i < 6; i++) + { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, size, size, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); + } + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, id, 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + + handle = glGetTextureHandleARB(id); + glMakeTextureHandleResidentARB(handle); +} + +GLLight::GLLight(GLLight&& o) : light(o.light), size(o.size) +{ + id = o.id; + handle = o.handle; + fbo = o.fbo; + + o.id = 0; + o.handle = 0; + o.fbo = 0; +} + +GLLight::~GLLight() +{ + std::cout << "Destructor called for " << fbo << ":" << id << ":" << handle << "\n"; + + if(fbo) + glDeleteFramebuffers(1, &fbo); + if(id) + glDeleteTextures(1, &id); +} + +void GLLight::render() +{ + glm::mat4 camera_mat = glm::translate(glm::mat4(1), -light.pos); + glUniformMatrix4fv(Shader::LIGHT["camera"], 1, false, &camera_mat[0][0]); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glViewport(0, 0, size, size); + Window::render_scene(); +} + +void GLLight::init() +{ + glm::mat4 shadow_proj = glm::perspective(M_PI * 0.5f, 1.0f, 0.01f, 100.f); + + shadow_mats[0] = shadow_proj * glm::lookAt(glm::vec3(0), { 1, 0, 0}, {0,-1, 0}); + shadow_mats[1] = shadow_proj * glm::lookAt(glm::vec3(0), {-1, 0, 0}, {0,-1, 0}); + shadow_mats[2] = shadow_proj * glm::lookAt(glm::vec3(0), { 0, 1, 0}, {0, 0, 1}); + shadow_mats[3] = shadow_proj * glm::lookAt(glm::vec3(0), { 0,-1, 0}, {0, 0,-1}); + shadow_mats[4] = shadow_proj * glm::lookAt(glm::vec3(0), { 0, 0, 1}, {0,-1, 0}); + shadow_mats[5] = shadow_proj * glm::lookAt(glm::vec3(0), { 0, 0,-1}, {0,-1, 0}); + + glUniformMatrix4fv(Shader::LIGHT["shadow_mats"], 6, false, &shadow_mats[0][0][0]); +} + diff --git a/src/graphics/mesh/gllight.hpp b/src/graphics/mesh/gllight.hpp new file mode 100644 index 0000000..e14e202 --- /dev/null +++ b/src/graphics/mesh/gllight.hpp @@ -0,0 +1,28 @@ + +#pragma once + +#include "light.hpp" + +namespace Sim::Graphics +{ + +struct GLLight +{ + const int size; + + unsigned int id, fbo; + unsigned long handle; + Light light; + + GLLight(Light light); + GLLight(GLLight&& o); + GLLight(const GLLight& o) = delete; + ~GLLight(); + + static void init(); + + void render(); +}; + +}; + diff --git a/src/graphics/mesh/glmesh.cpp b/src/graphics/mesh/glmesh.cpp index d364f74..6a260a2 100644 --- a/src/graphics/mesh/glmesh.cpp +++ b/src/graphics/mesh/glmesh.cpp @@ -56,7 +56,7 @@ void GLMesh::bind() void GLMesh::uniform() { - glUniformMatrix4fv(Shader::MAIN["model"], 1, false, &model_matrix[0][0]); + glUniformMatrix4fv(Shader::ACTIVE->get("model"), 1, false, &model_matrix[0][0]); } void GLMesh::set(const Mesh& m, int mode) diff --git a/src/graphics/shader.cpp b/src/graphics/shader.cpp index 5612fe1..3fc6df1 100644 --- a/src/graphics/shader.cpp +++ b/src/graphics/shader.cpp @@ -14,6 +14,7 @@ using namespace Sim::Graphics; Shader Shader::MAIN; Shader Shader::BLUR; Shader Shader::LIGHT; +Shader* Shader::ACTIVE; static int load_shader(const char* src, int type) { @@ -110,11 +111,14 @@ void Shader::load(const char* path, const char* file_vsh, const char* file_gsh, glDeleteShader(gsh_id); if(file_fsh) glDeleteShader(fsh_id); + + ACTIVE = this; } void Shader::use() { glUseProgram(prog_id); + ACTIVE = this; } unsigned int Shader::operator [](const char* pos) @@ -129,3 +133,8 @@ unsigned int Shader::operator [](const char* pos) return uniform_locations[pos] = glGetUniformLocation(prog_id, pos); } +unsigned int Shader::get(const char* pos) +{ + return operator[](pos); +} + diff --git a/src/graphics/shader.hpp b/src/graphics/shader.hpp index ef53da4..4901f16 100644 --- a/src/graphics/shader.hpp +++ b/src/graphics/shader.hpp @@ -18,6 +18,8 @@ public: static Shader BLUR; static Shader LIGHT; + static Shader* ACTIVE; + Shader(); Shader(const Shader& o) = delete; Shader(Shader&& o); @@ -28,6 +30,7 @@ public: void use(); unsigned int operator[](const char* pos); + unsigned int get(const char* pos); }; }; diff --git a/src/graphics/window.cpp b/src/graphics/window.cpp index 8bb27b2..c444cab 100644 --- a/src/graphics/window.cpp +++ b/src/graphics/window.cpp @@ -25,6 +25,7 @@ #include "monitor/secondary_loop.hpp" #include "monitor/turbine.hpp" #include "mesh/texture.hpp" +#include "mesh/gllight.hpp" #include "../system.hpp" #include "../util/streams.hpp" #include "ui.hpp" @@ -34,6 +35,7 @@ using namespace Sim::Graphics; static GLFWwindow* win; static bool win_should_close = false; static unsigned int ssbo_lights; +static unsigned int ssbo_shadow_maps; static double secs_wait_at = 0; static double secs_wait_now = 0; @@ -44,6 +46,8 @@ static GLMesh gm_dynamic_slow[2]; static GLMesh gm_dynamic_fast; static Mesh m_dynamic_fast; +static std::vector lights; + static Monitor::Vessel monitor_vessel; static Monitor::Core monitor_core; static Monitor::PrimaryLoop monitor_primary_loop; @@ -54,7 +58,12 @@ glm::mat4 Window::projection_matrix; static void GLAPIENTRY cb_debug_message(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { - if(severity != GL_DEBUG_SEVERITY_NOTIFICATION) + if(severity == GL_DEBUG_SEVERITY_HIGH) + { + throw std::runtime_error(message); + } + + else if(severity != GL_DEBUG_SEVERITY_NOTIFICATION) { std::cout << "GL CALLBACK: " << message << "\n"; } @@ -119,21 +128,23 @@ void Window::create() Font::init(); UI::init(); - Shader::LIGHT.load("../assets/shader", "light.vsh", "light.gsh", "light.fsh"); Shader::MAIN.load("../assets/shader", "main.vsh", "main.fsh"); glBindFramebuffer(GL_FRAMEBUFFER, 0); Sim::System& sys = *System::active; - Mesh m, m2; + Mesh m_scene; - m.load_model("../assets", "scene.glb"); + m_scene.load_model("../assets", "scene.glb"); + + m_scene.lights[0].pos.x = 6; + m_scene.lights[1].pos.x = 0; // find the floor parts of the model and set them slightly transparent - for(int i = 0; i < m.indices.size(); i += 3) + for(int i = 0; i < m_scene.indices.size(); i += 3) { - Arrays::Vertex& v1 = m.vertices[m.indices[i]]; - Arrays::Vertex& v2 = m.vertices[m.indices[i + 1]]; - Arrays::Vertex& v3 = m.vertices[m.indices[i + 2]]; + Arrays::Vertex& v1 = m_scene.vertices[m_scene.indices[i]]; + Arrays::Vertex& v2 = m_scene.vertices[m_scene.indices[i + 1]]; + Arrays::Vertex& v3 = m_scene.vertices[m_scene.indices[i + 2]]; if(v1.pos.z <= 0 && v2.pos.z <= 0 && v3.pos.z <= 0) { @@ -146,23 +157,51 @@ void Window::create() // send all the light data glGenBuffers(1, &ssbo_lights); glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_lights); - glBufferData(GL_SHADER_STORAGE_BUFFER, m.lights.size() * sizeof(m.lights[0]), &m.lights[0], GL_STATIC_DRAW); + glBufferData(GL_SHADER_STORAGE_BUFFER, m_scene.lights.size() * sizeof(m_scene.lights[0]), &m_scene.lights[0], GL_STATIC_DRAW); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo_lights); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); - glUniform1i(Shader::MAIN["lights_count"], m.lights.size()); + glUniform1i(Shader::MAIN["lights_count"], m_scene.lights.size()); - monitor_core.init(m); - monitor_vessel.init(m); - monitor_primary_loop.init(m); - monitor_secondary_loop.init(m); - monitor_turbine.init(m); + monitor_core.init(m_scene); + monitor_vessel.init(m_scene); + monitor_primary_loop.init(m_scene); + monitor_secondary_loop.init(m_scene); + monitor_turbine.init(m_scene); gm_scene.bind(); - gm_scene.set(m, GL_STATIC_DRAW); + gm_scene.set(m_scene, GL_STATIC_DRAW); glfwShowWindow(win); - glViewport(0, 0, 800, 600); +/* + // setup lighting and prerender shadows + Shader::LIGHT.load("../assets/shader", "light.vsh", "light.gsh", "light.fsh"); + glUniform1f(Shader::LIGHT["far_plane"], 100.0f); + GLLight::init(); + + std::vector light_handles; + + for(int i = 0; i < m_scene.lights.size(); i++) + { + GLLight light(m_scene.lights[i]); + light.render(); + + light_handles.push_back(light.handle); + lights.push_back(std::move(light)); + } + + for(int i = 0; i < lights.size(); i++) + { + std::cout << "handle " << i << ": " << light_handles[i] << "\n"; + } + + Shader::MAIN.use();*/ + glUniform1f(Shader::MAIN["far_plane"], 100.0f); + +/* // send all the light shadow map handles + glGenBuffers(1, &ssbo_shadow_maps); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_shadow_maps); + glBufferData(GL_SHADER_STORAGE_BUFFER, light_handles.size() * sizeof(light_handles[0]), &light_handles[0], GL_STATIC_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, ssbo_shadow_maps);*/ } void update_slow() @@ -217,7 +256,7 @@ void Window::update(double dt) } } -void render_scene() +void Window::render_scene() { gm_scene.bind(); gm_scene.uniform(); @@ -242,11 +281,17 @@ void render_scene() void Window::render() { + glm::vec<2, int> size = Resize::get_size(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, size.x, size.y); + glm::vec3 camera_pos = Camera::get_pos(); glm::mat4 mat_camera = Camera::get_matrix(); mat_camera = glm::scale(mat_camera, {1, 1, -1}); camera_pos.z *= -1; + Shader::MAIN.use(); + glm::vec3 brightness = glm::vec3(System::active->grid.get_light_intensity()); glm::mat4 mat_projection = glm::perspective(glm::radians(90.0f), Resize::get_aspect(), 0.01f, 20.f); glUniformMatrix4fv(Shader::MAIN["projection"], 1, false, &mat_projection[0][0]); @@ -257,6 +302,7 @@ void Window::render() glClearColor(0, 0, 0, 1.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glCullFace(GL_BACK); glFrontFace(GL_CW); render_scene(); diff --git a/src/graphics/window.hpp b/src/graphics/window.hpp index 12b44e9..3f0f155 100644 --- a/src/graphics/window.hpp +++ b/src/graphics/window.hpp @@ -15,6 +15,7 @@ bool should_close(); void create(); void update(double dt); void render(); +void render_scene(); void destroy(); void close();