|
| 1 | +#version 450 |
| 2 | + |
| 3 | +layout(location = 0) out vec4 out_colour; |
| 4 | + |
| 5 | +struct directional_light { |
| 6 | + vec4 direction; |
| 7 | + vec4 colour; |
| 8 | +}; |
| 9 | + |
| 10 | +const int MAX_POINT_LIGHTS = 10; |
| 11 | + |
| 12 | +struct point_light { |
| 13 | + vec4 position; |
| 14 | + vec4 colour; |
| 15 | + // Usually 1, make sure denominator never gets smaller than 1 |
| 16 | + float constant; |
| 17 | + // Reduces light intensity linearly |
| 18 | + float linear; |
| 19 | + // Makes the light fall off slower at longer distances. |
| 20 | + float quadratic; |
| 21 | + |
| 22 | + float pad; |
| 23 | +}; |
| 24 | + |
| 25 | +struct pbr_properties { |
| 26 | + vec4 diffuse; |
| 27 | + vec3 pad; |
| 28 | + float shininess; |
| 29 | +}; |
| 30 | + |
| 31 | +layout(set = 1, binding = 0) uniform local_uniform_object { |
| 32 | + directional_light dir_light; |
| 33 | + point_light point_lights[MAX_POINT_LIGHTS]; |
| 34 | + int num_point_lights; |
| 35 | + pbr_properties props; |
| 36 | +} object_ubo; |
| 37 | + |
| 38 | +// Samplers, diffuse, spec |
| 39 | +const int SAMP_ALBEDO = 0; |
| 40 | +const int SAMP_NORMAL = 1; |
| 41 | +const int SAMP_METALLIC = 2; |
| 42 | +const int SAMP_ROUGHNESS = 3; |
| 43 | +const int SAMP_AO = 4; |
| 44 | +const int SAMP_IBL = 5; |
| 45 | + |
| 46 | +layout(set = 1, binding = 1) uniform sampler2D samplers[6]; |
| 47 | +layout(set = 1, binding = 1) uniform samplerCube samplersCube[6]; |
| 48 | + |
| 49 | +const float PI = 3.14159265359; |
| 50 | + |
| 51 | +layout(location = 0) flat in int in_mode; |
| 52 | +layout(location = 1) in struct dto { |
| 53 | + vec4 ambient; |
| 54 | + vec2 tex_coord; |
| 55 | + vec3 normal; |
| 56 | + vec3 view_position; |
| 57 | + vec3 frag_position; |
| 58 | + vec4 colour; |
| 59 | + vec4 tangent; |
| 60 | +} in_dto; |
| 61 | + |
| 62 | +mat3 TBN; |
| 63 | + |
| 64 | +float geometry_ggx(float normal_dot_direction, float roughness) |
| 65 | +{ |
| 66 | + roughness += 1; |
| 67 | + float k = (roughness * roughness) / 8; |
| 68 | + return normal_dot_direction / (normal_dot_direction * (1 - k) + k); |
| 69 | +} |
| 70 | + |
| 71 | +vec3 calculate_point_light_radiance(point_light light, vec3 view_direction, vec3 frag_position) |
| 72 | +{ |
| 73 | + float distance = length(light.position.xyz - frag_position); |
| 74 | + float attenuation = 1 / (light.constant + light.linear * distance + light.quadratic * distance * distance); |
| 75 | + |
| 76 | + return light.colour.rgb * attenuation; |
| 77 | +} |
| 78 | + |
| 79 | +vec3 calculate_directional_light_radiance(directional_light light) |
| 80 | +{ |
| 81 | + return light.colour.rgb; |
| 82 | +} |
| 83 | + |
| 84 | +vec3 calculate_reflectance(vec3 albedo, vec3 normal, vec3 view_direction, vec3 light_direction, float metallic, float roughness, vec3 base_reflectivity, vec3 radiance) |
| 85 | +{ |
| 86 | + vec3 halfway = normalize(view_direction + light_direction); |
| 87 | + float rough_sq = roughness * roughness; |
| 88 | + float rough_sq_sq = rough_sq * rough_sq; |
| 89 | + |
| 90 | + float normal_dot_halfway = max(dot(normal, halfway), 0); |
| 91 | + float normal_dot_halfway_sq = normal_dot_halfway * normal_dot_halfway; |
| 92 | + |
| 93 | + float denom = normal_dot_halfway_sq * (rough_sq_sq - 1) + 1; |
| 94 | + denom = PI * denom * denom; |
| 95 | + |
| 96 | + float normal_distribution = (rough_sq_sq / denom); |
| 97 | + |
| 98 | + float normal_dot_view_dir = max(dot(normal, view_direction), 0); |
| 99 | + float normal_dot_light_dir = max(dot(normal, light_direction), 0); |
| 100 | + |
| 101 | + float ggx_0 = geometry_ggx(normal_dot_view_dir, roughness); |
| 102 | + float ggx_1 = geometry_ggx(normal_dot_light_dir, roughness); |
| 103 | + |
| 104 | + float geo = ggx_0 * ggx_1; |
| 105 | + |
| 106 | + float cos_theta = max(dot(halfway, view_direction), 0); |
| 107 | + vec3 fresnel = base_reflectivity + (1 - base_reflectivity) * pow(clamp(1 - cos_theta, 0, 1), 5); |
| 108 | + |
| 109 | + vec3 numerator = normal_distribution * geo * fresnel; |
| 110 | + float denominator = 4 * max(dot(normal, view_direction), 0) + 0.0001; |
| 111 | + |
| 112 | + vec3 specular = numerator / denominator; |
| 113 | + vec3 refraction_diffuse = vec3(1) - fresnel; |
| 114 | + refraction_diffuse *= 1 - metallic; |
| 115 | + |
| 116 | + return (refraction_diffuse * albedo / PI + specular) * radiance * normal_distribution; |
| 117 | +} |
| 118 | + |
| 119 | +void main() { |
| 120 | + vec3 normal = in_dto.normal; |
| 121 | + vec3 tangent = in_dto.tangent.xyz; |
| 122 | + tangent = (tangent - dot(tangent, normal) * normal); |
| 123 | + |
| 124 | + vec3 bitangent = cross(in_dto.normal, in_dto.tangent.xyz); |
| 125 | + TBN = mat3(tangent, bitangent, normal); |
| 126 | + |
| 127 | + vec3 local_normal = 2 * texture(samplers[SAMP_NORMAL], in_dto.tex_coord).rgb - 1; |
| 128 | + normal = normalize(TBN * local_normal); |
| 129 | + |
| 130 | + vec4 albedo_samp = texture(samplers[SAMP_ALBEDO], in_dto.tex_coord); |
| 131 | + |
| 132 | + //Gamma correction |
| 133 | + vec3 albedo = pow(albedo_samp.rgb, vec3(2.2)); |
| 134 | + |
| 135 | + float metallic = texture(samplers[SAMP_METALLIC], in_dto.tex_coord).r; |
| 136 | + float roughness = texture(samplers[SAMP_ROUGHNESS], in_dto.tex_coord).r; |
| 137 | + float ao = texture(samplers[SAMP_AO], in_dto.tex_coord).r; |
| 138 | + |
| 139 | + vec3 base_reflectivity = vec3(0.04); |
| 140 | + base_reflectivity = mix(base_reflectivity, albedo, metallic); |
| 141 | + |
| 142 | + if (in_mode == 0 || in_mode == 1) |
| 143 | + { |
| 144 | + vec3 view_direction = in_dto.view_position - in_dto.frag_position; |
| 145 | + albedo += vec3(1) * in_mode; |
| 146 | + |
| 147 | + albedo = clamp(albedo, vec3(0), vec3(1)); |
| 148 | + |
| 149 | + vec3 total_reflectance = vec3(0); |
| 150 | + |
| 151 | + { |
| 152 | + directional_light light = object_ubo.dir_light; |
| 153 | + vec3 light_dir = normalize(-light.direction.xyz); |
| 154 | + vec3 radiance = calculate_directional_light_radiance(light); |
| 155 | + |
| 156 | + total_reflectance += calculate_reflectance(albedo, normal, view_direction, light_dir, metallic, roughness, base_reflectivity, radiance); |
| 157 | + } |
| 158 | + |
| 159 | + for (int i = 0; i < object_ubo.num_point_lights; i++) |
| 160 | + { |
| 161 | + point_light light = object_ubo.point_lights[i]; |
| 162 | + |
| 163 | + vec3 light_dir = normalize(light.position.xyz - in_dto.frag_position.xyz); |
| 164 | + |
| 165 | + vec3 radiance = calculate_point_light_radiance(light, in_dto.view_position, in_dto.frag_position); |
| 166 | + |
| 167 | + total_reflectance += calculate_reflectance(albedo, normal, view_direction, light_dir, metallic, roughness, base_reflectivity, radiance); |
| 168 | + } |
| 169 | + |
| 170 | + vec3 irradiance = texture(samplersCube[SAMP_IBL], normal).rgb; |
| 171 | + |
| 172 | + vec3 ambient = irradiance * albedo * ao; |
| 173 | + vec3 colour = ambient + total_reflectance; |
| 174 | + colour = colour / (colour + vec3(1)); |
| 175 | + colour = pow(colour, vec3(1 / 2.2)); |
| 176 | + |
| 177 | + out_colour = vec4(colour, albedo_samp.a); |
| 178 | + } |
| 179 | + else if (in_mode == 2) |
| 180 | + { |
| 181 | + out_colour = vec4(abs(normal), 1); |
| 182 | + } |
| 183 | +} |
| 184 | + |
0 commit comments