Newer
Older
ForwardPlusRenderer / shaders / FragmentShader.frag
#version 450

const int light_count = 4098;
struct PointLight
{
	vec3 color;
  float luminance;
	vec3 position;
};

layout(location = 0) in vec3 in_color;
layout(location = 1) in vec2 in_uv;
layout(location = 2) in vec3 in_normal;
layout(location = 3) in vec3 in_position;
layout(location = 4) in vec3 in_tangent;

layout(location = 5) in vec3 in_bitangent;
layout(early_fragment_tests) in;
layout(binding = 0) uniform CameraUBO
{
  mat4 projection;
  mat4 view;
  vec3 position;
} camera;

layout(push_constant) uniform ViewportConstants
{
  vec4 ambient_light;
  ivec2 viewport_size;
	ivec2 tile_size;
	uint horizontal_tile_count;
	uint vertical_tile_count;
	uint max_lights_per_tile;
	uint max_lights;

} viewport_constants;


layout(set = 2, binding = 0) uniform sampler2D texture_sampler;

struct LightCullingData
{
  uint visible_light_indices[1024];
  uint total_visible_lights;
};

layout(set = 3, binding = 0) buffer PointLightSSBO
{
	PointLight lights[light_count];
} point_light_SSBO;

layout(set = 3, binding = 1) buffer readonly VisibleLights
{
	LightCullingData visible_lights[];
};
layout(location = 0) out vec4 out_color;
void main()
{
  //Get the tile based on current fragment.
  ivec2 tile = ivec2(gl_FragCoord.xy / viewport_constants.tile_size);
  uint tile_index = tile.y * viewport_constants.horizontal_tile_count + tile.x;

   //Base color and base illuminance from texture and ambient light.
	  vec4 diffuse_map = texture(texture_sampler, in_uv);
    vec3 base_illuminance =   diffuse_map.rgb * (viewport_constants.ambient_light.rgb * viewport_constants.ambient_light.a);
    vec3 illuminance = base_illuminance;

    //Iterate through the visible lights in the current tile.
    for(int i = 0; i < visible_lights[tile_index].total_visible_lights; ++i)
    {
     //Extract the light based on the compute shader culled storage buffer.
      PointLight light = point_light_SSBO.lights[visible_lights[tile_index].visible_light_indices[i]];
    	vec3 light_direction = normalize(light.position - in_position);
      
      //If the light points away, fragment not  affected.
      float lambertian = max(dot(light_direction, in_normal), 0.0);
      if(lambertian > 0.0f)
      {
       //if the distance to light  is smaller than light radius, fragment not affected.
        float light_distance = distance(light.position, in_position);
        if (light_distance < light.luminance)
        {
          //Fake specular
          vec3 camera_direction = normalize(camera.position - in_position);
          vec3 H = normalize(light_direction + camera_direction);
          float theta = max(dot(H, in_normal), 0.0);
          float specular = pow(theta, 256.0f); 
          float attenuation = clamp(1.0 - light_distance * light_distance / (light.luminance * light.luminance), 0.0, 1.0);
          illuminance += light.color * attenuation * (lambertian * diffuse_map.rgb + specular);
        }
      }
    }
  out_color = vec4(illuminance, 1.0f);
}