diff --git a/assets/shaders/forward.frag b/assets/shaders/forward.frag index 6f5c7c8c..954f48c1 100644 --- a/assets/shaders/forward.frag +++ b/assets/shaders/forward.frag @@ -7,8 +7,8 @@ // By using glBindFragDataLocation(GLuint program, GLuint colorNumber, const char * name), it is not necessary to use the layout qualifier and vice-versa. // However, if both are used and are in conflict, the layout qualifier in the vertex shader has priority. layout (location = 0) out vec4 out_colour; -layout (location = 1) out vec4 out_position; -layout (location = 2) out vec4 out_normal; +layout (location = 1) out vec3 out_position; +layout (location = 2) out vec3 out_normal; // Inputs in io_block { @@ -35,7 +35,7 @@ uniform vec4 u_specular_colour; uniform float u_gloss; uniform float u_displacement_scale; -// Texture +// Textures uniform bool u_texture_diffuse_enabled; uniform bool u_texture_normal_enabled; uniform bool u_texture_specular_enabled; @@ -48,6 +48,10 @@ uniform sampler2D u_texture_specular; uniform sampler2D u_texture_gloss; uniform sampler2D u_texture_displacement; +// Shadow +uniform sampler2D u_texture_shadows[max_lights]; +uniform samplerCube u_cubemap_shadows[max_lights]; + // Light struct light { int mode_; @@ -72,10 +76,6 @@ uniform int u_num_lights; uniform vec4 u_ambient_light; uniform light u_lights[max_lights]; -// Shadow -uniform sampler2D u_texture_shadows[max_lights]; -uniform samplerCube u_cubemap_shadows[max_lights]; - // Includes vec2 parallax_occlusion(const in sampler2D _texture, const in vec2 _tex_coord, float _disp_scale, const in vec3 _frag_pos, const in mat3 _inv_tbn_matrix, const in vec3 _normal); @@ -184,12 +184,12 @@ void main() { bool cast_shadow[max_lights]; get_cast_shadow(normal, cast_shadow); + const vec4 ambient = get_diffuse(tex_coord) * u_ambient_light; const vec4 diffuse = get_diffuse(tex_coord) * get_light_diffuse(io_position, normal, cast_shadow); const vec4 specular = get_specular(tex_coord) * get_light_specular(io_position, normal, gloss, cast_shadow); - const vec4 ambient = get_diffuse(tex_coord) * u_ambient_light; const vec3 phong = (ambient + diffuse + specular).rgb; out_colour = vec4(phong, 1.0f); - out_position = vec4(io_position, 1.0f); - out_normal = vec4(io_normal, 1.0f); + out_position = io_position; + out_normal = io_normal; } \ No newline at end of file diff --git a/assets/shaders/forward.vert b/assets/shaders/forward.vert index fdc69431..77ba61f2 100644 --- a/assets/shaders/forward.vert +++ b/assets/shaders/forward.vert @@ -27,18 +27,14 @@ uniform vec2 u_texture_offset; uniform vec2 u_texture_scale; void main() { - io_tex_coord = (v_tex_coord + vec3(u_texture_offset, 0.0f)) * vec3(u_texture_scale, 1.0f); - io_position = (u_view_matrix * v_model_matrix * vec4(v_position, 1.0f)).xyz; - io_normal = normalize(v_normal_matrix * v_normal); - - /* This is the Gramm-Schmidt process. dot(Tangent, Normal) gives us the length of the projection of the tangent along the normal vector. - The product of this length by the normal itself is the component of the tangent along the normal. - Substract that from the tangent and we get a new vector which is perpendicular to the normal. - This is our new tangent. */ - vec3 n = io_normal; + vec3 n = normalize(v_normal_matrix * v_normal); vec3 t = normalize(v_normal_matrix * v_tangent); t = normalize(t - dot(t, n) * n); vec3 b = cross(n, t); + + io_tex_coord = (v_tex_coord + vec3(u_texture_offset, 0.0f)) * vec3(u_texture_scale, 1.0f); + io_position = (u_view_matrix * v_model_matrix * vec4(v_position, 1.0f)).xyz; + io_normal = n; io_tbn_matrix = mat3(t, b, n); gl_Position = u_projection_matrix * u_view_matrix * v_model_matrix * vec4(v_position, 1.0f); diff --git a/assets/shaders/geometry.frag b/assets/shaders/geometry.frag index 5ba88974..c55d08eb 100644 --- a/assets/shaders/geometry.frag +++ b/assets/shaders/geometry.frag @@ -1,8 +1,8 @@ #version 460 core // IMPORTANT: All transforms in the fragment shader is in camera space, where the camera is at the origin. -layout (location = 0) out vec4 out_position; -layout (location = 1) out vec4 out_normal; +layout (location = 0) out vec3 out_position; +layout (location = 1) out vec3 out_normal; layout (location = 2) out vec4 out_diffuse; layout (location = 3) out vec4 out_specular; layout (location = 4) out float out_gloss; @@ -10,19 +10,18 @@ layout (location = 4) out float out_gloss; // Inputs in io_block { vec3 io_tex_coord; - vec3 io_position; // Vertex position in camera space. - vec3 io_normal; // Vertex normal in camera space. - mat3 io_normal_matrix; - mat3 io_tbn_matrix; // Converts from tangent space to camera space. - mat3 io_inv_tbn_matrix; // Converts from camera space to tangent space. + vec3 io_position;// Vertex position in camera space. + vec3 io_normal;// Vertex normal in camera space. + mat3 io_tbn_matrix;// Converts from tangent space to camera space. }; -// Uniforms +// Material uniform vec4 u_diffuse_colour; uniform vec4 u_specular_colour; uniform float u_gloss; uniform float u_displacement_scale; +// Textures uniform bool u_texture_diffuse_enabled; uniform bool u_texture_normal_enabled; uniform bool u_texture_specular_enabled; @@ -35,56 +34,21 @@ uniform sampler2D u_texture_specular; uniform sampler2D u_texture_gloss; uniform sampler2D u_texture_displacement; -vec2 parallax(const vec2 _tex_coord) { - vec3 view_direction = normalize(io_inv_tbn_matrix * io_position); - float depth = 1.0f - texture(u_texture_displacement, _tex_coord).r; - return (view_direction.xy / -view_direction.z) * depth * u_displacement_scale; // Parallax Mapping without Offset Limiting -} - -vec2 parallax_occlusion(const vec2 _tex_coord) { - const vec2 max_uv_displacement = parallax(_tex_coord); - const int min_displacement_samples = 8; - const int max_displacement_samples = 32; - const float dot_product = dot(io_normal, normalize(-io_position)); - const int num_samples = int(mix(max_displacement_samples, min_displacement_samples, dot_product)); - - float previous_layer_depth = 0.0f; - vec2 previous_uv_displacement = vec2(0.0f, 0.0f); - float previous_texture_depth = 0.0f; - for (int i = 0; i < num_samples; ++i) { - const float current_layer_depth = float(i)/float(num_samples); - const vec2 current_uv_displacement = current_layer_depth * max_uv_displacement; - const float current_texture_depth = 1.0f - texture(u_texture_displacement, _tex_coord + current_uv_displacement).r; - - if (current_layer_depth > current_texture_depth) { - const float excess_depth = current_layer_depth - current_texture_depth; - const float lacking_depth = previous_texture_depth - previous_layer_depth; - return mix(previous_uv_displacement, current_uv_displacement, lacking_depth / (lacking_depth + excess_depth)); - } - - previous_layer_depth = current_layer_depth; - previous_uv_displacement = current_uv_displacement; - previous_texture_depth = current_texture_depth; - } - - return max_uv_displacement; -} - -vec2 get_tex_coord() { - return u_texture_displacement_enabled ? (io_tex_coord.xy + parallax_occlusion(io_tex_coord.xy)) : io_tex_coord.xy; -} +// Includes +vec2 parallax_occlusion(const in sampler2D _texture, const in vec2 _tex_coord, float _disp_scale, const in vec3 _frag_pos, const in mat3 _inv_tbn_matrix, const in vec3 _normal); vec3 get_normal(const in vec2 _tex_coord) { if (u_texture_normal_enabled) { - vec3 normal = texture(u_texture_normal, _tex_coord).rgb; - normal *= 2.0f; - normal -= vec3(1.0f, 1.0f, 1.0f); - normal = normalize(normal); - return io_tbn_matrix * normal; + const vec3 normal = 2.0f * texture(u_texture_normal, _tex_coord).rgb - vec3(1.0f, 1.0f, 1.0f); // Convert into the [-1, 1] range. + return io_tbn_matrix * normal; // Convert the normal from tangent space to camera space. } return io_normal; } +float get_gloss(const in vec2 _tex_coord) { + return u_texture_gloss_enabled ? texture(u_texture_gloss, _tex_coord).r * u_gloss : u_gloss; +} + vec4 get_diffuse(const in vec2 _tex_coord) { return u_texture_diffuse_enabled ? texture(u_texture_diffuse, _tex_coord) * u_diffuse_colour : u_diffuse_colour; } @@ -93,15 +57,15 @@ vec4 get_specular(const in vec2 _tex_coord) { return u_texture_specular_enabled ? texture(u_texture_specular, _tex_coord) * u_specular_colour : u_specular_colour; } -float get_gloss(const in vec2 _tex_coord) { - return u_texture_gloss_enabled ? texture(u_texture_gloss, _tex_coord).r * u_gloss : u_gloss; +vec2 get_tex_coord() { + return u_texture_displacement_enabled ? parallax_occlusion(u_texture_displacement, io_tex_coord.xy, u_displacement_scale, io_position, io_tbn_matrix, io_normal) : io_tex_coord.xy; } void main() { const vec2 tex_coord = get_tex_coord(); - out_position = vec4(io_position, 1.0f); - out_normal = vec4(get_normal(tex_coord), 1.0f); + out_position = io_position; + out_normal = get_normal(tex_coord); out_diffuse = get_diffuse(tex_coord); out_specular = get_specular(tex_coord); out_gloss = get_gloss(tex_coord); diff --git a/assets/shaders/geometry.vert b/assets/shaders/geometry.vert index d85b1729..77ba61f2 100644 --- a/assets/shaders/geometry.vert +++ b/assets/shaders/geometry.vert @@ -17,38 +17,25 @@ out io_block { vec3 io_tex_coord; vec3 io_position; // Vertex position in camera space. vec3 io_normal; // Vertex normal in camera space. - mat3 io_normal_matrix; mat3 io_tbn_matrix; // Converts from tangent space to camera space. - mat3 io_inv_tbn_matrix; // Converts from camera space to tangent space. }; // Uniforms uniform mat4 u_view_matrix; uniform mat4 u_projection_matrix; -uniform mat4 u_view_projection_matrix; uniform vec2 u_texture_offset; uniform vec2 u_texture_scale; void main() { + vec3 n = normalize(v_normal_matrix * v_normal); + vec3 t = normalize(v_normal_matrix * v_tangent); + t = normalize(t - dot(t, n) * n); + vec3 b = cross(n, t); + io_tex_coord = (v_tex_coord + vec3(u_texture_offset, 0.0f)) * vec3(u_texture_scale, 1.0f); + io_position = (u_view_matrix * v_model_matrix * vec4(v_position, 1.0f)).xyz; + io_normal = n; + io_tbn_matrix = mat3(t, b, n); - mat4 model_view_matrix = u_view_matrix * v_model_matrix; - io_position = (model_view_matrix * vec4(v_position, 1.0f)).xyz; - io_normal = normalize(v_normal_matrix * v_normal); - io_normal_matrix = v_normal_matrix; - - // This is the Gramm-Schmidt process. dot(Tangent, Normal) gives us the length of the projection of the tangent along the normal vector. - // The product of this length by the normal itself is the component of the tangent along the normal. - // Substract that from the tangent and we get a new vector which is perpendicular to the normal. - // This is our new tangent (just remember to normalize it as well...). - vec3 tangent = normalize(v_tangent - dot(v_tangent, v_normal) * v_normal); - // A cross product between the tangent and the normal gives us the bitangent. - vec3 bitangent = normalize(cross(v_normal, tangent)); - - io_tbn_matrix[0] = normalize(v_normal_matrix * tangent); - io_tbn_matrix[1] = normalize(v_normal_matrix * bitangent); - io_tbn_matrix[2] = io_normal; - io_inv_tbn_matrix = transpose(io_tbn_matrix); // Since TBN is an orthogonal matrix, its transpose is also its inverse. - - gl_Position = u_view_projection_matrix * v_model_matrix * vec4(v_position, 1.0f); + gl_Position = u_projection_matrix * u_view_matrix * v_model_matrix * vec4(v_position, 1.0f); } \ No newline at end of file diff --git a/assets/shaders/light.frag b/assets/shaders/light.frag deleted file mode 100644 index be90f5c4..00000000 --- a/assets/shaders/light.frag +++ /dev/null @@ -1,150 +0,0 @@ -#version 460 core - -layout (location = 0) out vec4 out_composite; -layout (location = 1) out vec4 out_diffuse; -layout (location = 2) out vec4 out_specular; - -// Inputs -in io_block { - vec3 io_tex_coord; -}; - -// Variables -const int light_point = 0; -const int light_spot = 1; -const int light_directional = 2; - -const int max_lights = 8; - -struct light { - int mode_; - float power_; - vec4 colour_; - - float attenuation_constant_; - float attenuation_linear_; - float attenuation_quadratic_; - - float spotlight_inner_cosine_; - float spotlight_outer_cosine_; - - vec3 position_camera_space_; - vec3 direction_camera_space_; -}; - -// GPass to LPass -uniform sampler2D u_texture_frag_position; -uniform sampler2D u_texture_frag_normal; -uniform sampler2D u_texture_frag_diffuse; -uniform sampler2D u_texture_frag_specular; -uniform sampler2D u_texture_frag_gloss; - -// LPass to LPass -uniform sampler2D u_texture_light_diffuse; -uniform sampler2D u_texture_light_specular; - -// Uniforms -uniform vec4 u_ambient_light; -uniform int u_num_lights; -uniform light u_lights[max_lights]; - -float light_attenuation(const in light _light, const in vec3 _frag_position) { - vec3 direction = _light.position_camera_space_ - _frag_position; - float distance_squared = dot(direction, direction); - float distance = sqrt(distance_squared); - return _light.power_ / max(1.0f, _light.attenuation_constant_ + (_light.attenuation_linear_ * distance) + (_light.attenuation_quadratic_ * distance_squared)); -} - -vec3 vertex_to_light(const in light _light, const in vec3 _frag_position) { - if (_light.mode_ == light_directional) { - return normalize(-_light.direction_camera_space_); - } - return normalize(_light.position_camera_space_ - _frag_position); -} - -float spotlight_effect(const in light _light, const in vec3 _frag_position) { - vec3 light_to_vertex = normalize(_frag_position - _light.position_camera_space_); - float vertex_angle_cosine = dot(light_to_vertex, _light.direction_camera_space_); - return clamp((vertex_angle_cosine - _light.spotlight_outer_cosine_) / (_light.spotlight_inner_cosine_ - _light.spotlight_outer_cosine_), 0.0f, 1.0f); -} - -float diffuse_intensity(const in light _light, const in vec3 _frag_position, const in vec3 _frag_normal) { - return clamp(dot(vertex_to_light(_light, _frag_position), _frag_normal), 0.0f, 1.0f); -} - -float specular_intensity(const in light _light, const in vec3 _frag_position, const in vec3 _frag_normal, float _gloss) { - vec3 specular_direction = reflect(vertex_to_light(_light, _frag_position), _frag_normal); - vec3 view_direction = normalize(_frag_position); - return pow(max(dot(specular_direction, view_direction), 0.0f), _gloss); -} - -vec4 light_diffuse(const in vec3 _frag_position, const in vec3 _frag_normal) { - vec4 colour = vec4(0.0f, 0.0f, 0.0f, 1.0f); - for (int i = 0; i < u_num_lights; ++i) { - switch (u_lights[i].mode_) { - case light_point: - colour += - diffuse_intensity(u_lights[i], _frag_position, _frag_normal) * - u_lights[i].colour_ * u_lights[i].power_ * - light_attenuation(u_lights[i], _frag_position); - break; - case light_spot: - colour += - diffuse_intensity(u_lights[i], _frag_position, _frag_normal) * - u_lights[i].colour_ * u_lights[i].power_ * - light_attenuation(u_lights[i], _frag_position) * - spotlight_effect(u_lights[i], _frag_position); - break; - case light_directional: - colour += u_lights[i].colour_ * - diffuse_intensity(u_lights[i], _frag_position, _frag_normal) * - u_lights[i].power_; - break; - } - } - return colour; -} - -vec4 light_specular(const in vec3 _frag_position, const in vec3 _frag_normal, float _gloss) { - vec4 colour = vec4(0.0f, 0.0f, 0.0f, 1.0f); - for (int i = 0; i < u_num_lights; ++i) { - switch (u_lights[i].mode_) { - case light_point: - colour += - u_lights[i].colour_ * - specular_intensity(u_lights[i], _frag_position, _frag_normal, _gloss) * - light_attenuation(u_lights[i], _frag_position); - break; - case light_spot: - colour += - u_lights[i].colour_ * - specular_intensity(u_lights[i], _frag_position, _frag_normal, _gloss) * - light_attenuation(u_lights[i], _frag_position) * - spotlight_effect(u_lights[i], _frag_position); - break; - case light_directional: - colour += - u_lights[i].colour_ * - specular_intensity(u_lights[i], _frag_position, _frag_normal, _gloss) * - u_lights[i].power_; - break; - } - } - return colour; -} - -void main() { - const vec3 position = texture(u_texture_frag_position, io_tex_coord.xy).rgb; - const vec3 normal = texture(u_texture_frag_normal, io_tex_coord.xy).rgb; - const vec4 diffuse = texture(u_texture_frag_diffuse, io_tex_coord.xy); - const vec4 specular = texture(u_texture_frag_specular, io_tex_coord.xy); - const float gloss = texture(u_texture_frag_gloss, io_tex_coord.xy).r; - - const vec4 ambient_colour = diffuse * u_ambient_light; - const vec4 diffuse_colour = diffuse * light_diffuse(position, normal) + texture(u_texture_light_diffuse, io_tex_coord.xy); - const vec4 specular_colour = specular * light_specular(position, normal, gloss) + texture(u_texture_light_specular, io_tex_coord.xy); - - out_composite = vec4((ambient_colour + diffuse_colour + specular_colour).rgb, 1.0f); - out_diffuse = diffuse_colour; - out_specular = specular_colour; -} \ No newline at end of file diff --git a/assets/shaders/lighting.incl b/assets/shaders/light.incl similarity index 100% rename from assets/shaders/lighting.incl rename to assets/shaders/light.incl diff --git a/assets/shaders/lighting.frag b/assets/shaders/lighting.frag new file mode 100644 index 00000000..6759e6b2 --- /dev/null +++ b/assets/shaders/lighting.frag @@ -0,0 +1,145 @@ +#version 460 core + +layout (location = 0) out vec4 out_colour; + +// Inputs +in io_block { + vec3 io_tex_coord; +}; + +// Constants +const int max_lights = 4; + +const int light_point = 0; +const int light_spot = 1; +const int light_directional = 2; + +// Transform +uniform mat4 u_inv_view_matrix; + +// Textures +uniform sampler2D u_texture_position; +uniform sampler2D u_texture_normal; +uniform sampler2D u_texture_diffuse; +uniform sampler2D u_texture_specular; +uniform sampler2D u_texture_gloss; + +// Shadow +uniform sampler2D u_texture_shadows[max_lights]; +uniform samplerCube u_cubemap_shadows[max_lights]; + +// Light +struct light { + int mode_; + float power_; + vec4 colour_; + + float attenuation_constant_; + float attenuation_linear_; + float attenuation_quadratic_; + + float spotlight_inner_cosine_; + float spotlight_outer_cosine_; + + vec3 position_; + vec3 direction_; + + float shadow_distance_; + mat4 view_projection_matrix_; +}; + +uniform int u_num_lights; +uniform vec4 u_ambient_light; +uniform light u_lights[max_lights]; + +// Includes +bool cast_point_shadow(const in samplerCube _cubemap, const in vec3 _pos, const in vec3 _normal, const in mat4 _inv_view_matrix, const in vec3 _light_pos, float _cast_dist, float _bias); +bool cast_spot_shadow(const in sampler2D _texture, const in vec3 _pos, const in vec3 _normal, const in mat4 _inv_view_matrix, const in mat4 _light_vp_mat, const in vec3 _light_dir, float _bias); +bool cast_directional_shadow(const in sampler2D _texture, const in vec3 _pos, const in vec3 _normal, const in mat4 _inv_view_matrix, const in mat4 _light_vp_mat, const in vec3 _light_dir, float _bias); + +float light_attenuation(const in vec3 _pos, const in vec3 _light_pos, const in float _attn_const, const in float _attn_linear, const in float _attn_quad); +float spotlight_effect(const in vec3 _pos, const in vec3 _light_pos, const in vec3 _light_dir, const in float _inner_cos, const in float _outer_cos); +float diffuse_intensity(const in vec3 _pos, const in vec3 _normal, const in vec3 _light_pos, const in vec3 _light_dir, bool _is_dir_light); +float specular_intensity(const in vec3 _pos, const in vec3 _normal, const in vec3 _light_pos, const in vec3 _light_dir, bool _is_dir_light, float _gloss); + +// Local Functions +void get_cast_shadow(const in vec3 _position, const in vec3 _normal, inout bool cast_shadow[max_lights]) { + const float bias = 0.005f; + for (int i = 0; i < u_num_lights; ++i) { + cast_shadow[i] = (u_lights[i].mode_ == light_point && cast_point_shadow(u_cubemap_shadows[i], _position, _normal, u_inv_view_matrix, u_lights[i].position_, u_lights[i].shadow_distance_, bias)) || + (u_lights[i].mode_ == light_spot && cast_spot_shadow(u_texture_shadows[i], _position, _normal, u_inv_view_matrix, u_lights[i].view_projection_matrix_, u_lights[i].direction_, bias)) || + (u_lights[i].mode_ == light_directional && cast_directional_shadow(u_texture_shadows[i], _position, _normal, u_inv_view_matrix, u_lights[i].view_projection_matrix_, u_lights[i].direction_, bias)); + } +} + +vec4 get_light_diffuse(const in vec3 _pos, const in vec3 _normal, const in bool _cast_shadow[max_lights]) { + vec4 colour = vec4(0.0f, 0.0f, 0.0f, 1.0f); + for (int i = 0; i < u_num_lights; ++i) { + if (_cast_shadow[i]) { continue; } // Check if there is shadow. + switch (u_lights[i].mode_) { + case light_point: + colour += diffuse_intensity(_pos, _normal, u_lights[i].position_, u_lights[i].direction_, false) * + u_lights[i].colour_ * u_lights[i].power_ * + light_attenuation(_pos, u_lights[i].position_, u_lights[i].attenuation_constant_, u_lights[i].attenuation_linear_, u_lights[i].attenuation_quadratic_); + break; + case light_spot: + colour += diffuse_intensity(_pos, _normal, u_lights[i].position_, u_lights[i].direction_, false) * + u_lights[i].colour_ * u_lights[i].power_ * + light_attenuation(_pos, u_lights[i].position_, u_lights[i].attenuation_constant_, u_lights[i].attenuation_linear_, u_lights[i].attenuation_quadratic_) * + spotlight_effect(_pos, u_lights[i].position_, u_lights[i].direction_, u_lights[i].spotlight_inner_cosine_, u_lights[i].spotlight_outer_cosine_); + break; + case light_directional: + colour += diffuse_intensity(_pos, _normal, u_lights[i].position_, u_lights[i].direction_, true) * + u_lights[i].colour_ * u_lights[i].power_; + break; + default: + break; + } + } + return colour; +} + +vec4 get_light_specular(const in vec3 _pos, const in vec3 _normal, float _gloss, const in bool _cast_shadow[max_lights]) { + vec4 colour = vec4(0.0f, 0.0f, 0.0f, 1.0f); + for (int i = 0; i < u_num_lights; ++i) { + if (_cast_shadow[i]) { continue; } // Check if there is shadow. + switch (u_lights[i].mode_) { + case light_point: + colour += specular_intensity(_pos, _normal, u_lights[i].position_, u_lights[i].direction_, false, _gloss) * + u_lights[i].colour_ * u_lights[i].power_ * + light_attenuation(_pos, u_lights[i].position_, u_lights[i].attenuation_constant_, u_lights[i].attenuation_linear_, u_lights[i].attenuation_quadratic_); + break; + case light_spot: + colour += specular_intensity(_pos, _normal, u_lights[i].position_, u_lights[i].direction_, false, _gloss) * + u_lights[i].colour_ * u_lights[i].power_ * + light_attenuation(_pos, u_lights[i].position_, u_lights[i].attenuation_constant_, u_lights[i].attenuation_linear_, u_lights[i].attenuation_quadratic_) * + spotlight_effect(_pos, u_lights[i].position_, u_lights[i].direction_, u_lights[i].spotlight_inner_cosine_, u_lights[i].spotlight_outer_cosine_); + break; + case light_directional: + colour += specular_intensity(_pos, _normal, u_lights[i].position_, u_lights[i].direction_, true, _gloss) * + u_lights[i].colour_ * u_lights[i].power_; + break; + default: + break; + } + } + return colour; +} + +void main() { + const vec3 pos = texture(u_texture_position, io_tex_coord.xy).rgb; + const vec3 norm = texture(u_texture_normal, io_tex_coord.xy).rgb; + const vec4 diff = texture(u_texture_diffuse, io_tex_coord.xy); + const vec4 spec = texture(u_texture_specular, io_tex_coord.xy); + const float gloss = texture(u_texture_gloss, io_tex_coord.xy).r; + + bool cast_shadow[max_lights]; + get_cast_shadow(pos, norm, cast_shadow); + + const vec4 ambient = diff * u_ambient_light; + const vec4 diffuse = diff * get_light_diffuse(pos, norm, cast_shadow); + const vec4 specular = spec * get_light_specular(pos, norm, gloss, cast_shadow); + const vec3 phong = (ambient + diffuse + specular).rgb; + + out_colour = vec4(phong, 1.0f); +} \ No newline at end of file diff --git a/assets/shaders/light.vert b/assets/shaders/lighting.vert similarity index 100% rename from assets/shaders/light.vert rename to assets/shaders/lighting.vert diff --git a/src/game/scene/game_scene.cpp b/src/game/scene/game_scene.cpp index 7764a473..3b8ee87d 100644 --- a/src/game/scene/game_scene.cpp +++ b/src/game/scene/game_scene.cpp @@ -12,7 +12,7 @@ #include "graphics/renderer/graphics_renderer.h" #include "graphics/shader/forward_shader.h" #include "graphics/shader/geometry_shader.h" -#include "graphics/shader/light_shader.h" +#include "graphics/shader/lighting_shader.h" #include "graphics/shader/post_proc_shader.h" #include "graphics/shader/skybox_shader.h" #include "graphics/shader/shadow_2d_shader.h" @@ -46,7 +46,7 @@ namespace mkr { } void game_scene::init_input() { - input_manager::instance().set_relative_mouse(true); + // input_manager::instance().set_relative_mouse(true); // Register Buttons input_manager::instance().register_button(quit, input_context_default, controller_index_default, kc_escape); @@ -127,21 +127,24 @@ namespace mkr { void game_scene::init_shaders() { // shader_manager::instance().make_shader("skybox", {"./../assets/shaders/skybox.vert"}, {"./../assets/shaders/skybox.frag"}); + shader_manager::instance().make_shader("shadow_2d", {"./../assets/shaders/shadow_2d.vert"}, {"./../assets/shaders/shadow_2d.frag"}); + shader_manager::instance().make_shader("shadow_cubemap", {"./../assets/shaders/shadow_cubemap.vert"}, {"./../assets/shaders/shadow_cubemap.geom"}, {"./../assets/shaders/shadow_cubemap.frag"}); + shader_manager::instance().make_shader("geometry", {"./../assets/shaders/geometry.vert"}, {"./../assets/shaders/geometry.frag", + "./../assets/shaders/parallax.incl"}); + shader_manager::instance().make_shader("lighting", {"./../assets/shaders/lighting.vert"}, {"./../assets/shaders/lighting.frag", + "./../assets/shaders/shadow.incl", + "./../assets/shaders/light.incl"}); shader_manager::instance().make_shader("forward", {"./../assets/shaders/forward.vert"}, {"./../assets/shaders/forward.frag", "./../assets/shaders/parallax.incl", "./../assets/shaders/shadow.incl", - "./../assets/shaders/lighting.incl"}); - // shader_manager::instance().make_shader("geometry", {"./../assets/shaders/geometry.vert"}, {"./../assets/shaders/geometry.frag"}); - // shader_manager::instance().make_shader("light", {"./../assets/shaders/light.vert"}, {"./../assets/shaders/light.frag"}); + "./../assets/shaders/light.incl"}); // shader_manager::instance().make_shader("post_proc_invert", {"./../assets/shaders/post_proc.vert"}, {"./../assets/shaders/post_proc_invert.frag"}); // shader_manager::instance().make_shader("post_proc_greyscale", {"./../assets/shaders/post_proc.vert"}, {"./../assets/shaders/post_proc_greyscale.frag"}); // shader_manager::instance().make_shader("post_proc_blur", {"./../assets/shaders/post_proc.vert"}, {"./../assets/shaders/post_proc_blur.frag"}); // shader_manager::instance().make_shader("post_proc_outline", {"./../assets/shaders/post_proc.vert"}, {"./../assets/shaders/post_proc_outline.frag"}); - shader_manager::instance().make_shader("shadow_2d", {"./../assets/shaders/shadow_2d.vert"}, {"./../assets/shaders/shadow_2d.frag"}); - shader_manager::instance().make_shader("shadow_cubemap", {"./../assets/shaders/shadow_cubemap.vert"}, {"./../assets/shaders/shadow_cubemap.geom"}, {"./../assets/shaders/shadow_cubemap.frag"}); - // material::geometry_shader_ = shader_manager::instance().get_shader("geometry"); - // material::light_shader_ = shader_manager::instance().get_shader("light"); + material::geometry_shader_ = shader_manager::instance().get_shader("geometry"); + material::light_shader_ = shader_manager::instance().get_shader("lighting"); material::shadow_shader_2d_ = shader_manager::instance().get_shader("shadow_2d"); material::shadow_shader_cube_ = shader_manager::instance().get_shader("shadow_cubemap"); } @@ -167,7 +170,7 @@ namespace mkr { tiles->texture_scale_ = vector2{1.0f, 1.0f} * 50.0f; tiles->displacement_scale_ = 0.1f; tiles->forward_shader_ = shader_manager::instance().get_shader("forward"); - tiles->render_path_ = render_path::forward_opaque; + // tiles->render_path_ = render_path::forward_opaque; // Cube auto brick_wall = material_manager::instance().make_material("brick_wall"); @@ -176,9 +179,7 @@ namespace mkr { brick_wall->texture_displacement_ = texture_manager::instance().make_texture2d("brick_wall_001_displacement", "./../assets/textures/materials/brick_wall/brick_wall_001_displacement.png"); brick_wall->texture_gloss_ = texture_manager::instance().make_texture2d("brick_wall_001_gloss", "./../assets/textures/materials/brick_wall/brick_wall_001_gloss.png"); brick_wall->texture_specular_ = texture_manager::instance().make_texture2d("brick_wall_001_specular", "./../assets/textures/materials/brick_wall/brick_wall_001_specular.png"); - brick_wall->displacement_scale_ = 0.05f; brick_wall->forward_shader_ = shader_manager::instance().get_shader("forward"); - brick_wall->render_path_ = render_path::forward_opaque; auto metal_pattern = material_manager::instance().make_material("metal_pattern"); metal_pattern->texture_diffuse_ = texture_manager::instance().make_texture2d("metal_pattern_albedo", "./../assets/textures/materials/metal/metal_pattern_001_albedo.png"); @@ -186,7 +187,6 @@ namespace mkr { metal_pattern->texture_displacement_ = texture_manager::instance().make_texture2d("metal_pattern_displacement", "./../assets/textures/materials/metal/metal_pattern_001_displacement.png"); metal_pattern->texture_gloss_ = texture_manager::instance().make_texture2d("metal_pattern_gloss", "./../assets/textures/materials/metal/metal_pattern_001_gloss.png"); metal_pattern->texture_specular_ = texture_manager::instance().make_texture2d("metal_pattern_specular", "./../assets/textures/materials/metal/metal_pattern_001_specular.png"); - metal_pattern->displacement_scale_ = 0.05f; metal_pattern->forward_shader_ = shader_manager::instance().get_shader("forward"); metal_pattern->render_path_ = render_path::forward_opaque; @@ -197,11 +197,10 @@ namespace mkr { green->render_path_ = render_path::forward_opaque; // Cube - auto brick2 = material_manager::instance().make_material("brick2"); + auto brick2 = material_manager::instance().make_material("brick"); brick2->texture_diffuse_ = texture_manager::instance().make_texture2d("brick_diffuse", "./../assets/textures/tutorial/brick_diffuse.png"); brick2->texture_normal_ = texture_manager::instance().make_texture2d("brick_normal", "./../assets/textures/tutorial/brick_normal.png"); brick2->texture_displacement_ = texture_manager::instance().make_texture2d("brick_displacement", "./../assets/textures/tutorial/brick_displacement.png"); - brick2->displacement_scale_ = 0.05f; brick2->forward_shader_ = shader_manager::instance().get_shader("forward"); brick2->render_path_ = render_path::forward_opaque; } @@ -230,7 +229,7 @@ namespace mkr { cube_trans.set_rotation(quaternion{vector3::y_axis(), maths_util::pi}); render_mesh cube_rend{}; cube_rend.mesh_ = mesh_manager::instance().get_mesh("cube"); - cube_rend.material_ = material_manager::instance().get_material("brick2"); + cube_rend.material_ = material_manager::instance().get_material("brick"); world_.entity().set(cube_trans).set(cube_rend).add(); } diff --git a/src/graphics/framebuffer/forward_buffer.h b/src/graphics/framebuffer/forward_buffer.h index d4d16292..29609b80 100644 --- a/src/graphics/framebuffer/forward_buffer.h +++ b/src/graphics/framebuffer/forward_buffer.h @@ -21,8 +21,8 @@ namespace mkr { // Colour attachments. colour_attachments_.resize(colour_attachments::num_attachments); colour_attachments_[colour_attachments::colour] = std::make_unique("colour", _width, _height, sized_format::rgba8); - colour_attachments_[colour_attachments::position] = std::make_unique("position", _width, _height, sized_format::rgba16f); - colour_attachments_[colour_attachments::normal] = std::make_unique("normal", _width, _height, sized_format::rgba16f); + colour_attachments_[colour_attachments::position] = std::make_unique("position", _width, _height, sized_format::rgb16f); + colour_attachments_[colour_attachments::normal] = std::make_unique("normal", _width, _height, sized_format::rgb16f); for (auto i = 0; i < colour_attachments_.size(); ++i) { glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + i, colour_attachments_[i]->handle(), 0); } diff --git a/src/graphics/framebuffer/framebuffer.cpp b/src/graphics/framebuffer/framebuffer.cpp index 57499950..74dad961 100644 --- a/src/graphics/framebuffer/framebuffer.cpp +++ b/src/graphics/framebuffer/framebuffer.cpp @@ -31,7 +31,7 @@ namespace mkr { GLbitfield mask = (_colour ? GL_COLOR_BUFFER_BIT : 0) | (_depth ? GL_DEPTH_BUFFER_BIT : 0) | (_stencil ? GL_STENCIL_BUFFER_BIT : 0); // If filter is not GL_NEAREST and mask includes GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT, no data is transferred and a GL_INVALID_OPERATION error is generated. // So for simplicity let's just use GL_NEAREST. Don't act smart and use GL_LINEAR. - glBlitNamedFramebuffer(handle_, _other->handle_, _src_x0, _src_y0, _src_x1, _src_y1, _dst_x0, _dst_y0, _dst_x1, _dst_y1, mask, GL_NEAREST); + glBlitNamedFramebuffer(handle_, _other ? _other->handle_ : 0, _src_x0, _src_y0, _src_x1, _src_y1, _dst_x0, _dst_y0, _dst_x1, _dst_y1, mask, GL_NEAREST); } void framebuffer::set_read_colour_attachment(int32_t _attachment) { diff --git a/src/graphics/framebuffer/geometry_buffer.cpp b/src/graphics/framebuffer/geometry_buffer.cpp deleted file mode 100644 index d7017e7e..00000000 --- a/src/graphics/framebuffer/geometry_buffer.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "graphics/framebuffer/geometry_buffer.h" - -namespace mkr { - geometry_buffer::geometry_buffer(uint32_t _width, uint32_t _height) - : framebuffer(_width, _height) { - // Create GL buffer. - glCreateFramebuffers(1, &handle_); - - // Colour attachments. - // We use GL_RGBA16F over GL_RGB16F as GPUs generally prefer 4-component formats to 3-component formats due to byte alignment. - // Some drivers may fail to complete the framebuffer otherwise. [https://www.khronos.org/opengl/wiki/Image_Format#Texture_and_Renderbuffer] - colour_attachments_.resize(colour_attachments::num_attachments); - colour_attachments_[colour_attachments::position] = std::make_unique("position", _width, _height, sized_format::rgba16f); - colour_attachments_[colour_attachments::normal] = std::make_unique("normal", _width, _height, sized_format::rgba16f); - colour_attachments_[colour_attachments::diffuse] = std::make_unique("diffuse", _width, _height, sized_format::rgba8); - colour_attachments_[colour_attachments::specular] = std::make_unique("specular", _width, _height, sized_format::rgba8); - colour_attachments_[colour_attachments::gloss] = std::make_unique("gloss", _width, _height, sized_format::r16f); - for (auto i = 0; i < colour_attachments_.size(); ++i) { - glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + i, colour_attachments_[i]->handle(), 0); - } - - // Depth-Stencil attachments. - depth_stencil_attachment_ = std::make_unique("depth_stencil", _width, _height, sized_format::depth24_stencil8); - glNamedFramebufferTexture(handle_, GL_DEPTH_STENCIL_ATTACHMENT, depth_stencil_attachment_->handle(), 0); - - // Completeness check. - if (!is_complete()) { - throw std::runtime_error("incomplete geometry buffer"); - } - } - - geometry_buffer::~geometry_buffer() { - glDeleteFramebuffers(1, &handle_); - } -} // mkr \ No newline at end of file diff --git a/src/graphics/framebuffer/geometry_buffer.h b/src/graphics/framebuffer/geometry_buffer.h index fdac1876..48c545d4 100644 --- a/src/graphics/framebuffer/geometry_buffer.h +++ b/src/graphics/framebuffer/geometry_buffer.h @@ -15,8 +15,36 @@ namespace mkr { num_attachments, }; - geometry_buffer(uint32_t _width, uint32_t _height); + geometry_buffer(uint32_t _width, uint32_t _height) : framebuffer(_width, _height) { + // Create GL buffer. + glCreateFramebuffers(1, &handle_); - virtual ~geometry_buffer(); + // Colour attachments. + /* Be careful when using GL_RGB16F over GL_RGBA16F as GPUs generally prefer 4-component formats to 3-component formats due to byte alignment. + Some drivers may fail to complete the framebuffer. [https://www.khronos.org/opengl/wiki/Image_Format#Texture_and_Renderbuffer] + It should be fine since we're using textures, but some of these formats may not be supported by renderbuffers. */ + colour_attachments_.resize(colour_attachments::num_attachments); + colour_attachments_[colour_attachments::position] = std::make_unique("position", _width, _height, sized_format::rgb16f); + colour_attachments_[colour_attachments::normal] = std::make_unique("normal", _width, _height, sized_format::rgb16f); + colour_attachments_[colour_attachments::diffuse] = std::make_unique("diffuse", _width, _height, sized_format::rgba8); + colour_attachments_[colour_attachments::specular] = std::make_unique("specular", _width, _height, sized_format::rgba8); + colour_attachments_[colour_attachments::gloss] = std::make_unique("gloss", _width, _height, sized_format::r16f); + for (auto i = 0; i < colour_attachments_.size(); ++i) { + glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + i, colour_attachments_[i]->handle(), 0); + } + + // Depth-Stencil attachments. + depth_stencil_attachment_ = std::make_unique("depth_stencil", _width, _height, sized_format::depth24_stencil8); + glNamedFramebufferTexture(handle_, GL_DEPTH_STENCIL_ATTACHMENT, depth_stencil_attachment_->handle(), 0); + + // Completeness check. + if (!is_complete()) { + throw std::runtime_error("incomplete geometry buffer"); + } + } + + virtual ~geometry_buffer() { + glDeleteFramebuffers(1, &handle_); + } }; } // mkr \ No newline at end of file diff --git a/src/graphics/framebuffer/light_buffer.cpp b/src/graphics/framebuffer/light_buffer.cpp deleted file mode 100644 index 86857ba0..00000000 --- a/src/graphics/framebuffer/light_buffer.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "graphics/framebuffer/light_buffer.h" - -namespace mkr { - light_buffer::light_buffer(uint32_t _width, uint32_t _height) - : framebuffer(_width, _height) { - // Create GL buffer. - glCreateFramebuffers(1, &handle_); - - // Colour attachments. - colour_attachments_.resize(colour_attachments::num_attachments); - colour_attachments_[colour_attachments::composite] = std::make_unique("composite", _width, _height, sized_format::rgba8); - colour_attachments_[colour_attachments::diffuse] = std::make_unique("diffuse", _width, _height, sized_format::rgba8); - colour_attachments_[colour_attachments::specular] = std::make_unique("specular", _width, _height, sized_format::rgba8); - for (auto i = 0; i < colour_attachments_.size(); ++i) { - glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + i, colour_attachments_[i]->handle(), 0); - } - - // Back buffers. - diffuse_back_ = std::make_unique("diffuse", _width, _height, sized_format::rgba8); - specular_back_ = std::make_unique("specular", _width, _height, sized_format::rgba8); - - // Completeness check. - if (!is_complete()) { - throw std::runtime_error("incomplete light buffer"); - } - } - - light_buffer::~light_buffer() { - glDeleteFramebuffers(1, &handle_); - } - - void light_buffer::swap_buffers() { - colour_attachments_[colour_attachments::diffuse].swap(diffuse_back_); - colour_attachments_[colour_attachments::specular].swap(specular_back_); - glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + colour_attachments::diffuse, colour_attachments_[colour_attachments::diffuse]->handle(), 0); - glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + colour_attachments::specular, colour_attachments_[colour_attachments::specular]->handle(), 0); - } -} // mkr \ No newline at end of file diff --git a/src/graphics/framebuffer/light_buffer.h b/src/graphics/framebuffer/light_buffer.h deleted file mode 100644 index 375cd803..00000000 --- a/src/graphics/framebuffer/light_buffer.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include "graphics/framebuffer/framebuffer.h" - -namespace mkr { - class light_buffer : public framebuffer { - public: - enum colour_attachments : int32_t { - composite = 0, // The scene rendered with geometry and lights. - diffuse, // Light diffuse colour to be used as an input by the next pass in order to support unlimited lights. - specular, // Light specular colour to be used as an input by the next pass in order to support unlimited lights. - num_attachments, - }; - - protected: - // In order to support unlimited lights, it may be necessary to run the lighting pass multiple times. - // For each run, we calculate the lighting of each light of this run. Then we read the buffers of the previous runs to get their values. - // Then we add the results together, and write to the diffuse and specular buffers again. - // In order to do that, we will need 2 diffuse and specular buffers to prevent read and writing to the same buffer in the same run. - // Otherwise, this will result in a read-write race condition and produce artifacts as multiple fragments are reading and writing to the same buffers. - std::unique_ptr diffuse_back_; - std::unique_ptr specular_back_; - - public: - light_buffer(uint32_t _width, uint32_t _height); - - virtual ~light_buffer(); - - virtual void swap_buffers(); - }; -} // mkr \ No newline at end of file diff --git a/src/graphics/framebuffer/lighting_buffer.h b/src/graphics/framebuffer/lighting_buffer.h new file mode 100644 index 00000000..40835b6a --- /dev/null +++ b/src/graphics/framebuffer/lighting_buffer.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include "graphics/framebuffer/framebuffer.h" + +namespace mkr { + class lighting_buffer : public framebuffer { + protected: + /* In order to support unlimited lights, it may be necessary to run the lighting pass multiple times. + For each run, we calculate the lighting of each light of this run. Then we read the buffers of the previous runs to get their values. + Then we add the results together, and write to the diffuse and specular buffers again. + In order to do that, we will need 2 diffuse and specular buffers to prevent read and writing to the same buffer in the same run. + Otherwise, this will result in a read-write race condition and produce artifacts as multiple fragments are reading and writing to the same buffers. */ + std::unique_ptr diffuse_back_; + std::unique_ptr specular_back_; + + public: + enum colour_attachments : int32_t { + colour = 0, // The scene rendered with geometry and lights. + diffuse, // Light diffuse colour to be used as an input by the next pass in order to support unlimited lights. + specular, // Light specular colour to be used as an input by the next pass in order to support unlimited lights. + num_attachments, + }; + + lighting_buffer(uint32_t _width, uint32_t _height) : framebuffer(_width, _height) { + // Create GL buffer. + glCreateFramebuffers(1, &handle_); + + // Colour attachments. + colour_attachments_.resize(colour_attachments::num_attachments); + colour_attachments_[colour_attachments::colour] = std::make_unique("colour", _width, _height, sized_format::rgba8); + colour_attachments_[colour_attachments::diffuse] = std::make_unique("diffuse", _width, _height, sized_format::rgba8); + colour_attachments_[colour_attachments::specular] = std::make_unique("specular", _width, _height, sized_format::rgba8); + for (auto i = 0; i < colour_attachments_.size(); ++i) { + glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + i, colour_attachments_[i]->handle(), 0); + } + + // Back buffers. + diffuse_back_ = std::make_unique("diffuse", _width, _height, sized_format::rgba8); + specular_back_ = std::make_unique("specular", _width, _height, sized_format::rgba8); + + // Completeness check. + if (!is_complete()) { + throw std::runtime_error("incomplete lighting buffer"); + } + } + + virtual ~lighting_buffer() { + glDeleteFramebuffers(1, &handle_); + } + + virtual void swap_buffers() { + colour_attachments_[colour_attachments::diffuse].swap(diffuse_back_); + colour_attachments_[colour_attachments::specular].swap(specular_back_); + glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + colour_attachments::diffuse, colour_attachments_[colour_attachments::diffuse]->handle(), 0); + glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + colour_attachments::specular, colour_attachments_[colour_attachments::specular]->handle(), 0); + } + }; +} // mkr \ No newline at end of file diff --git a/src/graphics/framebuffer/post_buffer.h b/src/graphics/framebuffer/post_buffer.h new file mode 100644 index 00000000..54ea9668 --- /dev/null +++ b/src/graphics/framebuffer/post_buffer.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include "graphics/framebuffer/framebuffer.h" + +namespace mkr { + class post_buffer : public framebuffer { + protected: + std::unique_ptr colour_back_; + + public: + enum colour_attachments : int32_t { + colour = 0, // The scene rendered with geometry and lights. + num_attachments, + }; + + post_buffer(uint32_t _width, uint32_t _height) : framebuffer(_width, _height) { + // Create GL buffer. + glCreateFramebuffers(1, &handle_); + + // Colour attachments. + colour_attachments_.resize(colour_attachments::num_attachments); + colour_attachments_[colour_attachments::colour] = std::make_unique("colour", _width, _height, sized_format::rgba8); + for (auto i = 0; i < colour_attachments_.size(); ++i) { + glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + i, colour_attachments_[i]->handle(), 0); + } + + colour_back_ = std::make_unique("colour", _width, _height, sized_format::rgba8); + + // Completeness check. + if (!is_complete()) { + throw std::runtime_error("incomplete post buffer"); + } + } + + virtual ~post_buffer() { + glDeleteFramebuffers(1, &handle_); + } + + virtual void swap_buffers() { + colour_attachments_[colour_attachments::colour].swap(colour_back_); + glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + colour_attachments::colour, colour_attachments_[colour_attachments::colour]->handle(), 0); + } + }; +} // mkr \ No newline at end of file diff --git a/src/graphics/framebuffer/post_proc_buffer.cpp b/src/graphics/framebuffer/post_proc_buffer.cpp deleted file mode 100644 index dba2db9d..00000000 --- a/src/graphics/framebuffer/post_proc_buffer.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "graphics/framebuffer/post_proc_buffer.h" - -namespace mkr { - post_proc_buffer::post_proc_buffer(uint32_t _width, uint32_t _height) - : framebuffer(_width, _height) { - // Create GL buffer. - glCreateFramebuffers(1, &handle_); - - // Colour attachments. - colour_attachments_.resize(colour_attachments::num_attachments); - colour_attachments_[colour_attachments::composite] = std::make_unique("composite", _width, _height, sized_format::rgba8); - for (auto i = 0; i < colour_attachments_.size(); ++i) { - glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + i, colour_attachments_[i]->handle(), 0); - } - - composite_back_ = std::make_unique("composite", _width, _height, sized_format::rgba8); - - // Completeness check. - if (!is_complete()) { - throw std::runtime_error("incomplete post process buffer"); - } - } - - post_proc_buffer::~post_proc_buffer() { - glDeleteFramebuffers(1, &handle_); - } - - void post_proc_buffer::swap_buffers() { - colour_attachments_[colour_attachments::composite].swap(composite_back_); - glNamedFramebufferTexture(handle_, GL_COLOR_ATTACHMENT0 + colour_attachments::composite, colour_attachments_[colour_attachments::composite]->handle(), 0); - } -} // mkr \ No newline at end of file diff --git a/src/graphics/framebuffer/post_proc_buffer.h b/src/graphics/framebuffer/post_proc_buffer.h deleted file mode 100644 index 6d442237..00000000 --- a/src/graphics/framebuffer/post_proc_buffer.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include "graphics/framebuffer/framebuffer.h" - -namespace mkr { - class post_proc_buffer : public framebuffer { - public: - enum colour_attachments : int32_t { - composite = 0, // The scene rendered with geometry and lights. - num_attachments, - }; - - protected: - // Similar to lbuffer. - std::unique_ptr composite_back_; - - public: - post_proc_buffer(uint32_t _width, uint32_t _height); - - virtual ~post_proc_buffer(); - - virtual void swap_buffers(); - }; -} // mkr \ No newline at end of file diff --git a/src/graphics/renderer/graphics_renderer.cpp b/src/graphics/renderer/graphics_renderer.cpp index a09e24c4..f79258f6 100644 --- a/src/graphics/renderer/graphics_renderer.cpp +++ b/src/graphics/renderer/graphics_renderer.cpp @@ -5,7 +5,7 @@ #include "graphics/shader/texture_unit.h" #include "graphics/shader/forward_shader.h" #include "graphics/shader/geometry_shader.h" -#include "graphics/shader/light_shader.h" +#include "graphics/shader/lighting_shader.h" #include "graphics/shader/post_proc_shader.h" #include "graphics/shader/skybox_shader.h" #include "graphics/shader/shadow_2d_shader.h" @@ -48,6 +48,8 @@ namespace mkr { screen_quad_ = mesh_builder::make_screen_quad("screen_quad"); // Framebuffers + g_buff_ = std::make_unique(app_window_->width(), app_window_->height()); + l_buff_ = std::make_unique(app_window_->width(), app_window_->height()); f_buff_ = std::make_unique(app_window_->width(), app_window_->height()); for (auto i = 0; i < lighting::max_lights; ++i) { s2d_buff_[i] = std::make_unique(2048); @@ -127,8 +129,17 @@ namespace mkr { : matrix_util::orthographic_matrix(cam.aspect_ratio_, cam.ortho_size_, cam.near_plane_, cam.far_plane_); const auto inv_view_matrix = matrix_util::inverse_matrix(view_matrix).value_or(matrix4x4::identity()); - // Render forward pass. - forward_pass(view_matrix, projection_matrix, inv_view_matrix, view_dir_z, view_dir_y, view_dir_x); + // Render passes. + geometry_pass(view_matrix, projection_matrix); + lighting_pass(view_matrix, inv_view_matrix, view_dir_x, view_dir_y, view_dir_z); + forward_pass(view_matrix, projection_matrix, inv_view_matrix, view_dir_x, view_dir_y, view_dir_z); + + // Blit result to default framebuffer. + framebuffer::bind_default_buffer(); + framebuffer::clear_default_buffer_colour(); + framebuffer::clear_default_depth_stencil(); + f_buff_->set_read_colour_attachment(forward_buffer::colour_attachments::colour); + f_buff_->blit_to(nullptr, true, false, false, 0, 0, app_window_->width(), app_window_->height(), 0, 0, f_buff_->width(), f_buff_->height()); // Pop camera off the priority queue. cameras_.pop(); @@ -160,33 +171,38 @@ namespace mkr { projection_matrix * matrix_util::view_matrix(_trans.position_, vector3::backwards(), vector3::down()), }; - for (auto& material_iter : forward_opaque_meshes_) { - auto shader = mkr::material::shadow_shader_cube_; - shader->use(); - shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices0, false, view_projection_matrices[0]); - shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices1, false, view_projection_matrices[1]); - shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices2, false, view_projection_matrices[2]); - shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices3, false, view_projection_matrices[3]); - shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices4, false, view_projection_matrices[4]); - shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices5, false, view_projection_matrices[5]); - shader->set_uniform(shadow_cubemap_shader::uniform::u_light_pos, _trans.position_); - shader->set_uniform(shadow_cubemap_shader::uniform::u_shadow_distance, _light.get_shadow_distance()); - - // Draw to screen. - for (auto& mesh_iter : material_iter.second) { - auto mesh_ptr = mesh_iter.first; - auto& model_matrices = mesh_iter.second; - - std::vector batch; - for (auto& model_matrix : model_matrices) { - batch.push_back({model_matrix, matrix3x3::identity()}); + auto shader = mkr::material::shadow_shader_cube_; + shader->use(); + shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices0, false, view_projection_matrices[0]); + shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices1, false, view_projection_matrices[1]); + shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices2, false, view_projection_matrices[2]); + shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices3, false, view_projection_matrices[3]); + shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices4, false, view_projection_matrices[4]); + shader->set_uniform(shadow_cubemap_shader::uniform::u_view_projection_matrices5, false, view_projection_matrices[5]); + shader->set_uniform(shadow_cubemap_shader::uniform::u_light_pos, _trans.position_); + shader->set_uniform(shadow_cubemap_shader::uniform::u_shadow_distance, _light.get_shadow_distance()); + + const auto draw_func = [&](std::unordered_map>>& _meshes) -> void { + for (auto& material_iter : _meshes) { + for (auto& mesh_iter : material_iter.second) { + auto mesh_ptr = mesh_iter.first; + auto& model_matrices = mesh_iter.second; + + std::vector batch; + for (auto& model_matrix : model_matrices) { + batch.push_back({model_matrix, matrix3x3::identity()}); + } + + mesh_ptr->bind(); + mesh_ptr->set_instance_data(batch); + glDrawElementsInstanced(GL_TRIANGLES, mesh_ptr->num_indices(), GL_UNSIGNED_INT, 0, model_matrices.size()); } - - mesh_ptr->bind(); - mesh_ptr->set_instance_data(batch); - glDrawElementsInstanced(GL_TRIANGLES, mesh_ptr->num_indices(), GL_UNSIGNED_INT, 0, model_matrices.size()); } - } + }; + + draw_func(deferred_meshes_); + draw_func(forward_opaque_meshes_); + draw_func(forward_transparent_meshes_); return matrix4x4::identity(); } @@ -203,27 +219,32 @@ namespace mkr { const auto view_matrix = matrix_util::view_matrix(_trans.position_, _trans.forward_, _trans.up_); const auto projection_matrix = matrix_util::perspective_matrix(1.0f, _light.get_spotlight_outer_angle(), 0.1f, _light.get_shadow_distance()); - for (auto& material_iter : forward_opaque_meshes_) { - auto shader = mkr::material::shadow_shader_2d_; - shader->use(); - shader->set_uniform(shadow_2d_shader::uniform::u_view_matrix, false, view_matrix); - shader->set_uniform(shadow_2d_shader::uniform::u_projection_matrix, false, projection_matrix); - - // Draw to screen. - for (auto& mesh_iter : material_iter.second) { - auto mesh_ptr = mesh_iter.first; - auto& model_matrices = mesh_iter.second; - - std::vector batch; - for (auto& model_matrix : model_matrices) { - batch.push_back({model_matrix, matrix3x3::identity()}); + auto shader = mkr::material::shadow_shader_2d_; + shader->use(); + shader->set_uniform(shadow_2d_shader::uniform::u_view_matrix, false, view_matrix); + shader->set_uniform(shadow_2d_shader::uniform::u_projection_matrix, false, projection_matrix); + + const auto draw_func = [&](std::unordered_map>>& _meshes) -> void { + for (auto& material_iter : _meshes) { + for (auto& mesh_iter : material_iter.second) { + auto mesh_ptr = mesh_iter.first; + auto& model_matrices = mesh_iter.second; + + std::vector batch; + for (auto& model_matrix : model_matrices) { + batch.push_back({model_matrix, matrix3x3::identity()}); + } + + mesh_ptr->bind(); + mesh_ptr->set_instance_data(batch); + glDrawElementsInstanced(GL_TRIANGLES, mesh_ptr->num_indices(), GL_UNSIGNED_INT, 0, model_matrices.size()); } - - mesh_ptr->bind(); - mesh_ptr->set_instance_data(batch); - glDrawElementsInstanced(GL_TRIANGLES, mesh_ptr->num_indices(), GL_UNSIGNED_INT, 0, model_matrices.size()); } - } + }; + + draw_func(deferred_meshes_); + draw_func(forward_opaque_meshes_); + draw_func(forward_transparent_meshes_); return projection_matrix * view_matrix; } @@ -251,11 +272,77 @@ namespace mkr { const auto view_matrix = matrix_util::view_matrix(light_view_matrix_inverse * bounds.centre(), _light_trans.forward_, _light_trans.up_); const auto projection_matrix = matrix_util::orthographic_matrix(width / height, height, near, far); - for (auto& material_iter : forward_opaque_meshes_) { - auto shader = mkr::material::shadow_shader_2d_; + auto shader = mkr::material::shadow_shader_2d_; + shader->use(); + shader->set_uniform(shadow_2d_shader::uniform::u_view_matrix, false, view_matrix); + shader->set_uniform(shadow_2d_shader::uniform::u_projection_matrix, false, projection_matrix); + + const auto draw_func = [&](std::unordered_map>>& _meshes) -> void { + for (auto& material_iter : _meshes) { + for (auto& mesh_iter : material_iter.second) { + auto mesh_ptr = mesh_iter.first; + auto& model_matrices = mesh_iter.second; + + std::vector batch; + for (auto& model_matrix : model_matrices) { + batch.push_back({model_matrix, matrix3x3::identity()}); + } + + mesh_ptr->bind(); + mesh_ptr->set_instance_data(batch); + glDrawElementsInstanced(GL_TRIANGLES, mesh_ptr->num_indices(), GL_UNSIGNED_INT, 0, model_matrices.size()); + } + } + }; + + draw_func(deferred_meshes_); + draw_func(forward_opaque_meshes_); + draw_func(forward_transparent_meshes_); + + return projection_matrix * view_matrix; + } + + void graphics_renderer::geometry_pass(const matrix4x4& _view_matrix, const matrix4x4& _projection_matrix) { + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LESS); + glViewport(0, 0, g_buff_->width(), g_buff_->height()); // Viewport size MUST be buffer size, else it won't render to the buffer correctly. + + g_buff_->bind(); + g_buff_->set_draw_colour_attachment_all(); + g_buff_->clear_colour_all(); + g_buff_->clear_depth_stencil(); + + for (auto& material_iter : deferred_meshes_) { + auto material_ptr = material_iter.first; + auto shader = material::geometry_shader_; shader->use(); - shader->set_uniform(shadow_2d_shader::uniform::u_view_matrix, false, view_matrix); - shader->set_uniform(shadow_2d_shader::uniform::u_projection_matrix, false, projection_matrix); + + // Bind textures. + if (material_ptr->texture_diffuse_) { material_ptr->texture_diffuse_->bind(texture_unit::texture_diffuse); } + if (material_ptr->texture_normal_) { material_ptr->texture_normal_->bind(texture_unit::texture_normal); } + if (material_ptr->texture_specular_) { material_ptr->texture_specular_->bind(texture_unit::texture_specular); } + if (material_ptr->texture_gloss_) { material_ptr->texture_gloss_->bind(texture_unit::texture_gloss); } + if (material_ptr->texture_displacement_) { material_ptr->texture_displacement_->bind(texture_unit::texture_displacement); } + + // Transform + shader->set_uniform(geometry_shader::uniform::u_view_matrix, false, _view_matrix); + shader->set_uniform(geometry_shader::uniform::u_projection_matrix, false, _projection_matrix); + shader->set_uniform(geometry_shader::uniform::u_texture_offset, material_ptr->texture_offset_); + shader->set_uniform(geometry_shader::uniform::u_texture_scale, material_ptr->texture_scale_); + + // Material + shader->set_uniform(geometry_shader::uniform::u_diffuse_colour, material_ptr->diffuse_colour_); + shader->set_uniform(geometry_shader::uniform::u_specular_colour, material_ptr->specular_colour_); + shader->set_uniform(geometry_shader::uniform::u_gloss, material_ptr->gloss_); + shader->set_uniform(geometry_shader::uniform::u_displacement_scale, material_ptr->displacement_scale_); + + // Textures + shader->set_uniform(geometry_shader::uniform::u_texture_diffuse_enabled, material_ptr->texture_diffuse_ != nullptr); + shader->set_uniform(geometry_shader::uniform::u_texture_normal_enabled, material_ptr->texture_normal_ != nullptr); + shader->set_uniform(geometry_shader::uniform::u_texture_specular_enabled, material_ptr->texture_specular_ != nullptr); + shader->set_uniform(geometry_shader::uniform::u_texture_gloss_enabled, material_ptr->texture_gloss_ != nullptr); + shader->set_uniform(geometry_shader::uniform::u_texture_displacement_enabled, material_ptr->texture_displacement_ != nullptr); // Draw to screen. for (auto& mesh_iter : material_iter.second) { @@ -264,7 +351,9 @@ namespace mkr { std::vector batch; for (auto& model_matrix : model_matrices) { - batch.push_back({model_matrix, matrix3x3::identity()}); + const auto model_view_inverse = matrix_util::inverse_matrix(_view_matrix * model_matrix).value_or(matrix4x4::identity()); + const auto normal_matrix = matrix_util::minor_matrix(model_view_inverse.transposed(), 3, 3); + batch.push_back({model_matrix, normal_matrix}); } mesh_ptr->bind(); @@ -272,21 +361,111 @@ namespace mkr { glDrawElementsInstanced(GL_TRIANGLES, mesh_ptr->num_indices(), GL_UNSIGNED_INT, 0, model_matrices.size()); } } + } - return projection_matrix * view_matrix; + void graphics_renderer::lighting_pass(const matrix4x4& _view_matrix, const matrix4x4& _inv_view_matrix, const vector3& _view_dir_x, const vector3& _view_dir_y, const vector3& _view_dir_z) { + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + glViewport(0, 0, l_buff_->width(), l_buff_->height()); + + l_buff_->bind(); + l_buff_->set_draw_colour_attachment_all(); + l_buff_->clear_colour_all(); + + // Use shader. + auto shader = material::light_shader_; + shader->use(); + + // Bind mesh. + screen_quad_->bind(); + screen_quad_->set_instance_data({{matrix4x4::identity(), matrix3x3::identity()}}); + + // Bind textures. + g_buff_->get_colour_attachment(geometry_buffer::colour_attachments::position)->bind(texture_unit::texture_position); + g_buff_->get_colour_attachment(geometry_buffer::colour_attachments::normal)->bind(texture_unit::texture_normal); + g_buff_->get_colour_attachment(geometry_buffer::colour_attachments::diffuse)->bind(texture_unit::texture_diffuse); + g_buff_->get_colour_attachment(geometry_buffer::colour_attachments::specular)->bind(texture_unit::texture_specular); + g_buff_->get_colour_attachment(geometry_buffer::colour_attachments::gloss)->bind(texture_unit::texture_gloss); + + // Bind shadow maps. + const auto num_lights = maths_util::min(lights_.size(), lighting::max_lights); + for (auto i = 0; i < num_lights; ++i) { + if (light_mode::point == lights_[i].light_.get_mode()) { + scube_buff_[i]->get_depth_stencil_attachment()->bind(texture_unit::cubemap_shadows0 + i); + } else { + s2d_buff_[i]->get_depth_stencil_attachment()->bind(texture_unit::texture_shadows0 + i); + } + } + + // Transform + shader->set_uniform(lighting_shader::uniform::u_inv_view_matrix, false, _inv_view_matrix); + + // Lights. + shader->set_uniform(lighting_shader::uniform::u_num_lights, num_lights); + shader->set_uniform(lighting_shader::uniform::u_ambient_light, lighting::ambient_light_); + + for (auto i = 0; i < num_lights; ++i) { + const auto& t = lights_[i].transform_; + const auto& l = lights_[i].light_; + + const auto light_pos_view = _view_matrix * t.position_; // Light position in view space. + const auto light_dir_view = vector3{_view_dir_x.dot(t.forward_), _view_dir_y.dot(t.forward_), _view_dir_z.dot(t.forward_)}.normalised(); // Light direction in view space. + + shader->set_uniform(i + lighting_shader::uniform::u_light_mode0, l.get_mode()); + shader->set_uniform(i + lighting_shader::uniform::u_light_power0, l.get_power()); + shader->set_uniform(i + lighting_shader::uniform::u_light_colour0, l.get_colour()); + + shader->set_uniform(i + lighting_shader::uniform::u_light_attenuation_constant0, l.get_attenuation_constant()); + shader->set_uniform(i + lighting_shader::uniform::u_light_attenuation_linear0, l.get_attenuation_linear()); + shader->set_uniform(i + lighting_shader::uniform::u_light_attenuation_quadratic0, l.get_attenuation_quadratic()); + + shader->set_uniform(i + lighting_shader::uniform::u_light_spotlight_inner_cosine0, l.get_spotlight_inner_consine()); + shader->set_uniform(i + lighting_shader::uniform::u_light_spotlight_outer_cosine0, l.get_spotlight_outer_consine()); + + shader->set_uniform(i + lighting_shader::uniform::u_light_position0, light_pos_view); + shader->set_uniform(i + lighting_shader::uniform::u_light_direction0, light_dir_view); + + shader->set_uniform(i + lighting_shader::uniform::u_light_shadow_distance0, l.get_shadow_distance()); + shader->set_uniform(i + lighting_shader::uniform::u_light_view_projection_matrix0, false, light_view_projection_matrix_[i]); + } + + // Draw. + glDrawElementsInstanced(GL_TRIANGLES, screen_quad_->num_indices(), GL_UNSIGNED_INT, 0, 1); } - void graphics_renderer::forward_pass(const matrix4x4& _view_matrix, const matrix4x4& _projection_matrix, const matrix4x4& _inv_view_matrix, const vector3& _view_dir_z, const vector3& _view_dir_y, const vector3& _view_dir_x) { + void graphics_renderer::forward_pass(const matrix4x4& _view_matrix, const matrix4x4& _projection_matrix, const matrix4x4& _inv_view_matrix, const vector3& _view_dir_x, const vector3& _view_dir_y, const vector3& _view_dir_z) { glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LESS); - glViewport(0, 0, app_window_->width(), app_window_->height()); // Viewport size MUST be buffer size, else it won't render to the buffer correctly. + glViewport(0, 0, f_buff_->width(), f_buff_->height()); + + // Clear colour attachments. + f_buff_->bind(); + f_buff_->set_draw_colour_attachment_all(); + f_buff_->clear_colour_all(); + + // Blit colour. + l_buff_->set_read_colour_attachment(lighting_buffer::colour_attachments::colour); + f_buff_->set_draw_colour_attachment(forward_buffer::colour_attachments::colour); + l_buff_->blit_to(f_buff_.get(), true, false, false, 0, 0, l_buff_->width(), l_buff_->height(), 0, 0, f_buff_->width(), f_buff_->height()); + + // Blit positions. + g_buff_->set_read_colour_attachment(geometry_buffer::colour_attachments::position); + f_buff_->set_draw_colour_attachment(forward_buffer::colour_attachments::position); + g_buff_->blit_to(f_buff_.get(), true, false, false, 0, 0, g_buff_->width(), g_buff_->height(), 0, 0, f_buff_->width(), f_buff_->height()); + + // Blit normals. + g_buff_->set_read_colour_attachment(geometry_buffer::colour_attachments::normal); + f_buff_->set_draw_colour_attachment(forward_buffer::colour_attachments::normal); + g_buff_->blit_to(f_buff_.get(), true, false, false, 0, 0, g_buff_->width(), g_buff_->height(), 0, 0, f_buff_->width(), f_buff_->height()); + + // Blit depth-stencil. + g_buff_->blit_to(f_buff_.get(), false, true, true, 0, 0, g_buff_->width(), g_buff_->height(), 0, 0, f_buff_->width(), f_buff_->height()); - framebuffer::bind_default_buffer(); - framebuffer::clear_default_buffer_colour(colour::blue()); - framebuffer::clear_default_depth_stencil(); + // Set draw attachments. + f_buff_->set_draw_colour_attachment_all(); - auto view_projection_matrix = _projection_matrix * _view_matrix; for (auto& material_iter : forward_opaque_meshes_) { auto material_ptr = material_iter.first; auto shader = material_ptr->forward_shader_; @@ -390,15 +569,12 @@ namespace mkr { if (_render_mesh.material_ == nullptr || _render_mesh.mesh_ == nullptr) { return; } switch (_render_mesh.material_->render_path_) { case render_path::deferred: - // if (material::geometry_shader_ && material::light_shader_) {} deferred_meshes_[_render_mesh.material_][_render_mesh.mesh_].push_back(_transform.transform_); break; case render_path::forward_opaque: - // if (_render_mesh.material_->forward_shader_) {} forward_opaque_meshes_[_render_mesh.material_][_render_mesh.mesh_].push_back(_transform.transform_); break; case render_path::forward_transparent: - // if (_render_mesh.material_->forward_shader_) {} forward_transparent_meshes_[_render_mesh.material_][_render_mesh.mesh_].push_back(_transform.transform_); break; default: diff --git a/src/graphics/renderer/graphics_renderer.h b/src/graphics/renderer/graphics_renderer.h index f51b44f7..f4f74d7d 100644 --- a/src/graphics/renderer/graphics_renderer.h +++ b/src/graphics/renderer/graphics_renderer.h @@ -5,13 +5,14 @@ #include #include #include +#include "graphics/renderer/stencil.h" #include "graphics/app_window.h" #include "graphics/framebuffer/geometry_buffer.h" -#include "graphics/framebuffer/light_buffer.h" -#include "graphics/framebuffer/post_proc_buffer.h" +#include "graphics/framebuffer/lighting_buffer.h" #include "graphics/framebuffer/forward_buffer.h" #include "graphics/framebuffer/shadow_2d_buffer.h" #include "graphics/framebuffer/shadow_cubemap_buffer.h" +#include "graphics/framebuffer/post_buffer.h" #include "graphics/lighting/lighting.h" #include "graphics/material/material.h" #include "graphics/mesh/mesh_instance_data.h" @@ -22,18 +23,6 @@ #include "component/light.h" namespace mkr { - // There are 8 bits in the stencil buffer. - enum stencil_value : uint8_t { - placeholder0 = 1, - placeholder1 = 2, - placeholder2 = 4, - placeholder3 = 8, - placeholder4 = 16, - placeholder5 = 32, - placeholder6 = 64, - placeholder7 = 128, - }; - class graphics_renderer : public singleton { friend class singleton; @@ -55,13 +44,12 @@ namespace mkr { uint32_t window_height_ = 1080; // Framebuffers - // std::unique_ptr g_buff_; - // std::unique_ptr l_buff_; - // std::unique_ptr pp_buff_; - + std::unique_ptr g_buff_; + std::unique_ptr l_buff_; std::unique_ptr f_buff_; std::unique_ptr s2d_buff_[lighting::max_lights]; std::unique_ptr scube_buff_[lighting::max_lights]; + matrix4x4 light_view_projection_matrix_[lighting::max_lights]; // Screen Meshes @@ -88,11 +76,9 @@ namespace mkr { matrix4x4 spot_shadow(shadow_2d_buffer* _buffer, const local_to_world& _trans, const light& _light); matrix4x4 directional_shadow(shadow_2d_buffer* _buffer, const local_to_world& _light_trans, const light& _light, const local_to_world& _cam_trans, const camera& _cam); - void forward_pass(const matrix4x4& _view_matrix, const matrix4x4& _projection_matrix, const matrix4x4& _inv_view_matrix, const vector3& _view_dir_z, const vector3& _view_dir_y, const vector3& _view_dir_x); - - // void geometry_pass(const matrix4x4& _view_matrix, const matrix4x4& _projection_matrix); - // void light_pass(const matrix4x4& _view_matrix, const vector3& _view_forward, const vector3& _view_up, const vector3& _view_right); - // void post_proc_pass(float _near, float _far); + void geometry_pass(const matrix4x4& _view_matrix, const matrix4x4& _projection_matrix); + void lighting_pass(const matrix4x4& _view_matrix, const matrix4x4& _inv_view_matrix, const vector3& _view_dir_x, const vector3& _view_dir_y, const vector3& _view_dir_z); + void forward_pass(const matrix4x4& _view_matrix, const matrix4x4& _projection_matrix, const matrix4x4& _inv_view_matrix, const vector3& _view_dir_x, const vector3& _view_dir_y, const vector3& _view_dir_z); public: void init(); diff --git a/src/graphics/renderer/stencil.h b/src/graphics/renderer/stencil.h new file mode 100644 index 00000000..8592e6d0 --- /dev/null +++ b/src/graphics/renderer/stencil.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace mkr { + // There are 8 bits in the stencil buffer. + enum stencil : uint8_t { + placeholder0 = 1, + placeholder1 = 2, + placeholder2 = 4, + placeholder3 = 8, + placeholder4 = 16, + placeholder5 = 32, + placeholder6 = 64, + placeholder7 = 128, + }; +} \ No newline at end of file diff --git a/src/graphics/shader/forward_shader.cpp b/src/graphics/shader/forward_shader.cpp index e69ed8dc..4ece7ec6 100644 --- a/src/graphics/shader/forward_shader.cpp +++ b/src/graphics/shader/forward_shader.cpp @@ -39,22 +39,17 @@ namespace mkr { // Lights uniform_handles_[uniform::u_ambient_light] = get_uniform_location("u_ambient_light"); uniform_handles_[uniform::u_num_lights] = get_uniform_location("u_num_lights"); - for (auto i = 0; i < lighting::max_lights; ++i) { uniform_handles_[i + uniform::u_light_mode0] = get_uniform_location("u_lights[" + std::to_string(i) + "].mode_"); uniform_handles_[i + uniform::u_light_power0] = get_uniform_location("u_lights[" + std::to_string(i) + "].power_"); uniform_handles_[i + uniform::u_light_colour0] = get_uniform_location("u_lights[" + std::to_string(i) + "].colour_"); - uniform_handles_[i + uniform::u_light_attenuation_constant0] = get_uniform_location("u_lights[" + std::to_string(i) + "].attenuation_constant_"); uniform_handles_[i + uniform::u_light_attenuation_linear0] = get_uniform_location("u_lights[" + std::to_string(i) + "].attenuation_linear_"); uniform_handles_[i + uniform::u_light_attenuation_quadratic0] = get_uniform_location("u_lights[" + std::to_string(i) + "].attenuation_quadratic_"); - uniform_handles_[i + uniform::u_light_spotlight_inner_cosine0] = get_uniform_location("u_lights[" + std::to_string(i) + "].spotlight_inner_cosine_"); uniform_handles_[i + uniform::u_light_spotlight_outer_cosine0] = get_uniform_location("u_lights[" + std::to_string(i) + "].spotlight_outer_cosine_"); - uniform_handles_[i + uniform::u_light_position0] = get_uniform_location("u_lights[" + std::to_string(i) + "].position_"); uniform_handles_[i + uniform::u_light_direction0] = get_uniform_location("u_lights[" + std::to_string(i) + "].direction_"); - uniform_handles_[i + uniform::u_light_shadow_distance0] = get_uniform_location("u_lights[" + std::to_string(i) + "].shadow_distance_"); uniform_handles_[i + uniform::u_light_view_projection_matrix0] = get_uniform_location("u_lights[" + std::to_string(i) + "].view_projection_matrix_"); } diff --git a/src/graphics/shader/forward_shader.h b/src/graphics/shader/forward_shader.h index 629a8548..a95aff15 100644 --- a/src/graphics/shader/forward_shader.h +++ b/src/graphics/shader/forward_shader.h @@ -41,21 +41,16 @@ namespace mkr { // Lights u_num_lights = lighting::max_lights + u_cubemap_shadows0, u_ambient_light, - u_light_mode0, // Light Mode 0 to N u_light_power0 = lighting::max_lights + u_light_mode0, // Light Power 0 to N u_light_colour0 = lighting::max_lights + u_light_power0, // Light Colour 0 to N - u_light_attenuation_constant0 = lighting::max_lights + u_light_colour0, // Light Attenuation Constant 0 to N u_light_attenuation_linear0 = lighting::max_lights + u_light_attenuation_constant0, // Light Attenuation Linear 0 to N u_light_attenuation_quadratic0 = lighting::max_lights + u_light_attenuation_linear0, // Light Attenuation Quadratic 0 to N - u_light_spotlight_inner_cosine0 = lighting::max_lights + u_light_attenuation_quadratic0, // Spotlight Inner Cosine 0 to N u_light_spotlight_outer_cosine0 = lighting::max_lights + u_light_spotlight_inner_cosine0, // Spotlight Outer Cosine 0 to N - u_light_position0 = lighting::max_lights + u_light_spotlight_outer_cosine0, // Light Position Camera Space 0 to N u_light_direction0 = lighting::max_lights + u_light_position0, // Light Direction Camera Space 0 to N - u_light_shadow_distance0 = lighting::max_lights + u_light_direction0, // Light's shadow casting distance. u_light_view_projection_matrix0 = lighting::max_lights + u_light_shadow_distance0, // Spotlight/Directional Light View Projection Matrix diff --git a/src/graphics/shader/geometry_shader.cpp b/src/graphics/shader/geometry_shader.cpp index 91f6fa02..a0a00ab7 100644 --- a/src/graphics/shader/geometry_shader.cpp +++ b/src/graphics/shader/geometry_shader.cpp @@ -12,7 +12,6 @@ namespace mkr { // Vertex Shader uniform_handles_[uniform::u_view_matrix] = get_uniform_location("u_view_matrix"); uniform_handles_[uniform::u_projection_matrix] = get_uniform_location("u_projection_matrix"); - uniform_handles_[uniform::u_view_projection_matrix] = get_uniform_location("u_view_projection_matrix"); uniform_handles_[uniform::u_texture_offset] = get_uniform_location("u_texture_offset"); uniform_handles_[uniform::u_texture_scale] = get_uniform_location("u_texture_scale"); diff --git a/src/graphics/shader/geometry_shader.h b/src/graphics/shader/geometry_shader.h index e943ddb8..997dc71c 100644 --- a/src/graphics/shader/geometry_shader.h +++ b/src/graphics/shader/geometry_shader.h @@ -9,7 +9,6 @@ namespace mkr { // Vertex Shader u_view_matrix, u_projection_matrix, - u_view_projection_matrix, u_texture_offset, u_texture_scale, diff --git a/src/graphics/shader/light_shader.cpp b/src/graphics/shader/light_shader.cpp deleted file mode 100644 index 67ee70b7..00000000 --- a/src/graphics/shader/light_shader.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "graphics/shader/light_shader.h" -#include "graphics/shader/texture_unit.h" - -namespace mkr { - light_shader::light_shader(const std::string& _name, const std::vector& _vs_sources, const std::vector& _fs_sources) - : shader_program(_name, _vs_sources, _fs_sources, uniform::num_shader_uniforms) { - assign_uniforms(); - assign_textures(); - } - - void light_shader::assign_uniforms() { - // Fragment Shader - uniform_handles_[uniform::u_texture_frag_position] = get_uniform_location("u_texture_frag_position"); - uniform_handles_[uniform::u_texture_frag_normal] = get_uniform_location("u_texture_frag_normal"); - uniform_handles_[uniform::u_texture_frag_diffuse] = get_uniform_location("u_texture_frag_diffuse"); - uniform_handles_[uniform::u_texture_frag_specular] = get_uniform_location("u_texture_frag_specular"); - uniform_handles_[uniform::u_texture_frag_gloss] = get_uniform_location("u_texture_frag_gloss"); - - uniform_handles_[uniform::u_texture_light_diffuse] = get_uniform_location("u_texture_light_diffuse"); - uniform_handles_[uniform::u_texture_light_specular] = get_uniform_location("u_texture_light_specular"); - - uniform_handles_[uniform::u_ambient_light] = get_uniform_location("u_ambient_light"); - uniform_handles_[uniform::u_num_lights] = get_uniform_location("u_num_lights"); - for (auto i = 0; i < max_lights; ++i) { - uniform_handles_[i + uniform::u_light_mode0] = get_uniform_location("u_lights[" + std::to_string(i) + "].mode_"); - uniform_handles_[i + uniform::u_light_power0] = get_uniform_location("u_lights[" + std::to_string(i) + "].power_"); - uniform_handles_[i + uniform::u_light_colour0] = get_uniform_location("u_lights[" + std::to_string(i) + "].colour_"); - uniform_handles_[i + uniform::u_light_attenuation_constant0] = get_uniform_location("u_lights[" + std::to_string(i) + "].attenuation_constant_"); - uniform_handles_[i + uniform::u_light_attenuation_linear0] = get_uniform_location("u_lights[" + std::to_string(i) + "].attenuation_linear_"); - uniform_handles_[i + uniform::u_light_attenuation_quadratic0] = get_uniform_location("u_lights[" + std::to_string(i) + "].attenuation_quadratic_"); - uniform_handles_[i + uniform::u_light_spotlight_inner_cosine0] = get_uniform_location("u_lights[" + std::to_string(i) + "].spotlight_inner_cosine_"); - uniform_handles_[i + uniform::u_light_spotlight_outer_cosine0] = get_uniform_location("u_lights[" + std::to_string(i) + "].spotlight_outer_cosine_"); - uniform_handles_[i + uniform::u_light_position0] = get_uniform_location("u_lights[" + std::to_string(i) + "].position_"); - uniform_handles_[i + uniform::u_light_direction0] = get_uniform_location("u_lights[" + std::to_string(i) + "].direction_"); - } - } - - void light_shader::assign_textures() { - // set_uniform(uniform::u_texture_frag_position, (int32_t)texture_unit::texture_frag_position); - // set_uniform(uniform::u_texture_frag_normal, (int32_t)texture_unit::texture_frag_normal); - // set_uniform(uniform::u_texture_frag_diffuse, (int32_t)texture_unit::texture_frag_diffuse); - // set_uniform(uniform::u_texture_frag_specular, (int32_t)texture_unit::texture_frag_specular); - // set_uniform(uniform::u_texture_frag_gloss, (int32_t)texture_unit::texture_frag_gloss); - // set_uniform(uniform::u_texture_light_diffuse, (int32_t)texture_unit::texture_light_diffuse); - // set_uniform(uniform::u_texture_light_specular, (int32_t)texture_unit::texture_light_specular); - } -} // mkr \ No newline at end of file diff --git a/src/graphics/shader/light_shader.h b/src/graphics/shader/light_shader.h deleted file mode 100644 index 5a1bb7ed..00000000 --- a/src/graphics/shader/light_shader.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include "graphics/shader/shader_program.h" - -namespace mkr { - class light_shader : public shader_program { - public: - static constexpr uint32_t max_lights = 8; - - enum uniform : uint32_t { - u_texture_frag_position, - u_texture_frag_normal, - u_texture_frag_diffuse, - u_texture_frag_specular, - u_texture_frag_gloss, - - u_texture_light_diffuse, - u_texture_light_specular, - - u_ambient_light, - u_num_lights, - u_light_mode0, // Light Mode 0 to N - u_light_power0 = max_lights + u_light_mode0, // Light Power 0 to N - u_light_colour0 = max_lights + u_light_power0, // Light Colour 0 to N - u_light_attenuation_constant0 = max_lights + u_light_colour0, // Light Attenuation Constant 0 to N - u_light_attenuation_linear0 = max_lights + u_light_attenuation_constant0, // Light Attenuation Linear 0 to N - u_light_attenuation_quadratic0 = max_lights + u_light_attenuation_linear0, // Light Attenuation Quadratic 0 to N - u_light_spotlight_inner_cosine0 = max_lights + u_light_attenuation_quadratic0, // Light Spotlight Inner Cosine 0 to N - u_light_spotlight_outer_cosine0 = max_lights + u_light_spotlight_inner_cosine0, // Light Spotlight Outer Cosine 0 to N - u_light_position0 = max_lights + u_light_spotlight_outer_cosine0, // Light Position Camera Space 0 to N - u_light_direction0 = max_lights + u_light_position0, // Light Direction Camera Space 0 to N - - num_shader_uniforms = max_lights + u_light_direction0, - }; - - protected: - /** - * Assign uniforms to uniform_handles_. - */ - void assign_uniforms(); - - /** - * Assign textures to GL_TEXTURE0 to GL_TEXTUREN. - * For some weird reason, glProgramUniform1i and glProgramUniform1iv are the only two functions - * that may be used to load uniform variables defined as sampler types. - * Loading samplers with any other function will result in a GL_INVALID_OPERATION error. - * Thus, we must cast texture_unit to a signed integer. - */ - void assign_textures(); - - public: - light_shader(const std::string& _name, const std::vector& _vs_sources, const std::vector& _fs_sources); - - virtual ~light_shader() {} - }; -} // mkr \ No newline at end of file diff --git a/src/graphics/shader/lighting_shader.cpp b/src/graphics/shader/lighting_shader.cpp new file mode 100644 index 00000000..e8e49b38 --- /dev/null +++ b/src/graphics/shader/lighting_shader.cpp @@ -0,0 +1,59 @@ +#include "graphics/shader/lighting_shader.h" +#include "graphics/shader/texture_unit.h" + +namespace mkr { + lighting_shader::lighting_shader(const std::string& _name, const std::vector& _vs_sources, const std::vector& _fs_sources) + : shader_program(_name, _vs_sources, _fs_sources, uniform::num_shader_uniforms) { + assign_uniforms(); + assign_textures(); + } + + void lighting_shader::assign_uniforms() { + // Transform + uniform_handles_[uniform::u_inv_view_matrix] = get_uniform_location("u_inv_view_matrix"); + + // Textures + uniform_handles_[uniform::u_texture_position] = get_uniform_location("u_texture_position"); + uniform_handles_[uniform::u_texture_normal] = get_uniform_location("u_texture_normal"); + uniform_handles_[uniform::u_texture_diffuse] = get_uniform_location("u_texture_diffuse"); + uniform_handles_[uniform::u_texture_specular] = get_uniform_location("u_texture_specular"); + uniform_handles_[uniform::u_texture_gloss] = get_uniform_location("u_texture_gloss"); + + // Shadows + for (auto i = 0; i < lighting::max_lights; ++i) { + uniform_handles_[i + uniform::u_texture_shadows0] = get_uniform_location("u_texture_shadows[" + std::to_string(i) + "]"); + uniform_handles_[i + uniform::u_cubemap_shadows0] = get_uniform_location("u_cubemap_shadows[" + std::to_string(i) + "]"); + } + + // Lights + uniform_handles_[uniform::u_ambient_light] = get_uniform_location("u_ambient_light"); + uniform_handles_[uniform::u_num_lights] = get_uniform_location("u_num_lights"); + for (auto i = 0; i < lighting::max_lights; ++i) { + uniform_handles_[i + uniform::u_light_mode0] = get_uniform_location("u_lights[" + std::to_string(i) + "].mode_"); + uniform_handles_[i + uniform::u_light_power0] = get_uniform_location("u_lights[" + std::to_string(i) + "].power_"); + uniform_handles_[i + uniform::u_light_colour0] = get_uniform_location("u_lights[" + std::to_string(i) + "].colour_"); + uniform_handles_[i + uniform::u_light_attenuation_constant0] = get_uniform_location("u_lights[" + std::to_string(i) + "].attenuation_constant_"); + uniform_handles_[i + uniform::u_light_attenuation_linear0] = get_uniform_location("u_lights[" + std::to_string(i) + "].attenuation_linear_"); + uniform_handles_[i + uniform::u_light_attenuation_quadratic0] = get_uniform_location("u_lights[" + std::to_string(i) + "].attenuation_quadratic_"); + uniform_handles_[i + uniform::u_light_spotlight_inner_cosine0] = get_uniform_location("u_lights[" + std::to_string(i) + "].spotlight_inner_cosine_"); + uniform_handles_[i + uniform::u_light_spotlight_outer_cosine0] = get_uniform_location("u_lights[" + std::to_string(i) + "].spotlight_outer_cosine_"); + uniform_handles_[i + uniform::u_light_position0] = get_uniform_location("u_lights[" + std::to_string(i) + "].position_"); + uniform_handles_[i + uniform::u_light_direction0] = get_uniform_location("u_lights[" + std::to_string(i) + "].direction_"); + uniform_handles_[i + uniform::u_light_shadow_distance0] = get_uniform_location("u_lights[" + std::to_string(i) + "].shadow_distance_"); + uniform_handles_[i + uniform::u_light_view_projection_matrix0] = get_uniform_location("u_lights[" + std::to_string(i) + "].view_projection_matrix_"); + } + } + + void lighting_shader::assign_textures() { + set_uniform(uniform::u_texture_position, (int32_t) texture_unit::texture_position); + set_uniform(uniform::u_texture_normal, (int32_t) texture_unit::texture_normal); + set_uniform(uniform::u_texture_diffuse, (int32_t) texture_unit::texture_diffuse); + set_uniform(uniform::u_texture_specular, (int32_t) texture_unit::texture_specular); + set_uniform(uniform::u_texture_gloss, (int32_t) texture_unit::texture_gloss); + + for (auto i = 0; i < lighting::max_lights; ++i) { + set_uniform(i + uniform::u_texture_shadows0, (int32_t) (i + texture_unit::texture_shadows0)); + set_uniform(i + uniform::u_cubemap_shadows0, (int32_t) (i + texture_unit::cubemap_shadows0)); + } + } +} // mkr \ No newline at end of file diff --git a/src/graphics/shader/lighting_shader.h b/src/graphics/shader/lighting_shader.h new file mode 100644 index 00000000..08194237 --- /dev/null +++ b/src/graphics/shader/lighting_shader.h @@ -0,0 +1,63 @@ +#pragma once + +#include "graphics/shader/shader_program.h" +#include "graphics/lighting/lighting.h" + +namespace mkr { + class lighting_shader : public shader_program { + public: + enum uniform : uint32_t { + // Transform + u_inv_view_matrix, + + // Textures + u_texture_position, + u_texture_normal, + u_texture_diffuse, + u_texture_specular, + u_texture_gloss, + + // Shadows + u_texture_shadows0, + u_cubemap_shadows0 = lighting::max_lights + u_texture_shadows0, + + // Lights + u_num_lights = lighting::max_lights + u_cubemap_shadows0, + u_ambient_light, + u_light_mode0, // Light Mode 0 to N + u_light_power0 = lighting::max_lights + u_light_mode0, // Light Power 0 to N + u_light_colour0 = lighting::max_lights + u_light_power0, // Light Colour 0 to N + u_light_attenuation_constant0 = lighting::max_lights + u_light_colour0, // Light Attenuation Constant 0 to N + u_light_attenuation_linear0 = lighting::max_lights + u_light_attenuation_constant0, // Light Attenuation Linear 0 to N + u_light_attenuation_quadratic0 = lighting::max_lights + u_light_attenuation_linear0, // Light Attenuation Quadratic 0 to N + u_light_spotlight_inner_cosine0 = lighting::max_lights + u_light_attenuation_quadratic0, // Spotlight Inner Cosine 0 to N + u_light_spotlight_outer_cosine0 = lighting::max_lights + u_light_spotlight_inner_cosine0, // Spotlight Outer Cosine 0 to N + u_light_position0 = lighting::max_lights + u_light_spotlight_outer_cosine0, // Light Position Camera Space 0 to N + u_light_direction0 = lighting::max_lights + u_light_position0, // Light Direction Camera Space 0 to N + u_light_shadow_distance0 = lighting::max_lights + u_light_direction0, // Light's shadow casting distance. + u_light_view_projection_matrix0 = lighting::max_lights + u_light_shadow_distance0, // Spotlight/Directional Light View Projection Matrix + + num_shader_uniforms = lighting::max_lights + u_light_view_projection_matrix0, + }; + + protected: + /** + * Assign uniforms to uniform_handles_. + */ + void assign_uniforms(); + + /** + * Assign textures to GL_TEXTURE0 to GL_TEXTUREN. + * For some weird reason, glProgramUniform1i and glProgramUniform1iv are the only two functions + * that may be used to load uniform variables defined as sampler types. + * Loading samplers with any other function will result in a GL_INVALID_OPERATION error. + * Thus, we must cast texture_unit to a signed integer. + */ + void assign_textures(); + + public: + lighting_shader(const std::string& _name, const std::vector& _vs_sources, const std::vector& _fs_sources); + + virtual ~lighting_shader() {} + }; +} // mkr \ No newline at end of file diff --git a/src/graphics/shader/texture_unit.h b/src/graphics/shader/texture_unit.h index f5b8f709..3c668cd9 100644 --- a/src/graphics/shader/texture_unit.h +++ b/src/graphics/shader/texture_unit.h @@ -13,23 +13,12 @@ namespace mkr { texture_specular, texture_gloss, texture_displacement, + texture_position, - // For every shadow index, since only either the texture2d or cubemap will be bound at any given time, - // they can share the same index. + // For every shadow index, since only either the texture2d or cubemap will be bound at any given time, they can share the same index. texture_shadows0, // Range: [texture_shadows0, texture_shadows0 + lighting::max_lights) cubemap_shadows0 = texture_shadows0, // Range: [cubemap_shadows0, cubemap_shadows0 + lighting::max_lights) num_texture_units = lighting::max_lights + cubemap_shadows0, - - // texture_frag_position, // L-Pass, P-Pass - // texture_frag_normal, // L-Pass, P-Pass - // texture_frag_diffuse, // L-Pass - // texture_frag_specular, // L-Pass - // texture_frag_gloss, // L-Pass - // texture_light_diffuse, // L-Pass - // texture_light_specular, // L-Pass - - // texture_composite, // P-Pass - // texture_depth_stencil, // P-Pass }; } // mkr \ No newline at end of file