deferred-shading-mainpass.frag 1.92 KB
#version 300 es

precision mediump float;

const int kMaxLights = 32;

const float kAttenuationConst = .05f;
const float kAttenuationLinear = .1f;
const float kAttenuationQuadratic = .15f;

// G-buffer
uniform sampler2D uTextureNormal;
uniform sampler2D uTexturePosition;
uniform sampler2D uTextureColor;

uniform mat4 uInvProjection;
uniform vec3 uDepth_InvDepth_Near;

#define DEPTH uDepth_InvDepth_Near.x
#define INV_DEPTH uDepth_InvDepth_Near.y
#define NEAR uDepth_InvDepth_Near.z

// Light source uniforms
struct Light
{
  vec3 position;    // view space
  float radius;
  vec3 color;
};

uniform Light uLights[kMaxLights];

in vec2 vUv;
out vec4 oColor;

vec4 Unmap(vec4 m)  // texture -> projection
{
  m.w = m.w * DEPTH + NEAR;
  m.xyz = (m.xyz - vec3(.5)) * (2.f * m.w);
  return m;
}

vec3 CalculateLighting(vec3 pos, vec3 normal)
{
  vec3 viewDir = normalize(pos);
  vec3 viewDirRefl = -reflect(viewDir, normal);

  vec3 light = vec3(0.04f); // fake ambient term
  for (int i = 0; i < kMaxLights; ++i)
  {
    vec3 rel = pos - uLights[i].position;
    float distance = length(rel);
    rel /= distance;

    float a = uLights[i].radius / (kAttenuationConst + kAttenuationLinear * distance +
      kAttenuationQuadratic * distance * distance);     // attenuation

    float l = max(0.f, dot(normal, rel));   // lambertian
    float s = pow(max(0.f, dot(viewDirRefl, rel)), 256.f);  // specular

    light += (uLights[i].color * (l + s)) * a;
  }

  return light;
}

void main()
{
  vec3 normSample = texture(uTextureNormal, vUv).xyz;
  if (dot(normSample, normSample) == 0.f)
  {
    discard;  // if we didn't write this texel, don't bother lighting it.
  }

  vec3 normal = normalize(normSample - .5f);

  vec4 posSample = texture(uTexturePosition, vUv);
  vec3 pos = (uInvProjection * Unmap(posSample)).xyz;

  vec3 color = texture(uTextureColor, vUv).rgb;
  vec3 finalColor = color * CalculateLighting(pos, normal);

  oColor = vec4(finalColor, 1.f);
}