296 lines
10 KiB
GLSL
296 lines
10 KiB
GLSL
#version 330
|
|
|
|
#define MAX_LIGHTS 4
|
|
#define LIGHT_DIRECTIONAL 0
|
|
#define LIGHT_POINT 1
|
|
#define LIGHT_SPOT 2
|
|
#define PI 3.14159265358979323846
|
|
|
|
struct Light{
|
|
int enabled;
|
|
int type;
|
|
float enargy;
|
|
float cutOff ;
|
|
float outerCutOff;
|
|
float constant;
|
|
float linear ;
|
|
float quadratic ;
|
|
float shiny ;
|
|
float specularStr;
|
|
vec3 position;
|
|
vec3 direction;
|
|
vec3 lightColor;
|
|
};
|
|
|
|
// Input vertex attributes (from vertex shader)
|
|
in vec3 fragPosition;
|
|
in vec2 fragTexCoord;
|
|
in vec4 fragColor;
|
|
in vec3 fragNormal;
|
|
in vec4 shadowPos;
|
|
in mat3 TBN;
|
|
|
|
// Output fragment color
|
|
out vec4 finalColor;
|
|
// mask
|
|
uniform sampler2D mask;
|
|
uniform int frame;
|
|
// Input uniform values
|
|
uniform int numOfLights = 4;
|
|
uniform sampler2D albedoMap;
|
|
uniform sampler2D mraMap;
|
|
uniform sampler2D normalMap;
|
|
uniform sampler2D emissiveMap; // r: Hight g:emissive
|
|
// Input uniform values
|
|
uniform sampler2D texture0;
|
|
uniform sampler2D texture1;
|
|
uniform sampler2D flashlight;
|
|
|
|
uniform vec4 colDiffuse;
|
|
|
|
uniform vec2 tiling = vec2(0.5);
|
|
uniform vec2 offset ;
|
|
uniform vec2 tilingFlashlight = vec2(0.5);
|
|
uniform vec2 offsetFlashlight ;
|
|
|
|
uniform int useTexAlbedo =1;
|
|
uniform int useTexNormal = 0;
|
|
uniform int useTexMRA =1;
|
|
uniform int useTexEmissive =1;
|
|
|
|
uniform vec4 albedoColor ;
|
|
uniform vec4 emissiveColor ;
|
|
uniform float normalValue =0.5;
|
|
uniform float metallicValue =0.4;
|
|
uniform float roughnessValue =0;
|
|
uniform float aoValue =0.8;
|
|
uniform float emissivePower ;
|
|
|
|
// Input lighting values
|
|
uniform Light lights[MAX_LIGHTS];
|
|
uniform vec3 viewPos;
|
|
|
|
uniform vec3 ambientColor = vec3(1,1,1);
|
|
uniform float ambientStrength = 0.2;
|
|
uniform float ambient = 0.03;
|
|
uniform float fogDensity;
|
|
|
|
vec3 CalcDirLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic);
|
|
vec3 CalcPointLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic);
|
|
vec3 CalcSpotLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic);
|
|
|
|
// Reflectivity in range 0.0 to 1.0
|
|
// NOTE: Reflectivity is increased when surface view at larger angle
|
|
vec3 SchlickFresnel(float hDotV,vec3 refl)
|
|
{
|
|
return refl + (1.0 - refl)*pow(1.0 - hDotV, 5.0);
|
|
}
|
|
|
|
float GgxDistribution(float nDotH,float roughness)
|
|
{
|
|
float a = roughness * roughness * roughness * roughness;
|
|
float d = nDotH * nDotH * (a - 1.0) + 1.0;
|
|
d = PI * d * d;
|
|
return a / max(d,0.0000001);
|
|
}
|
|
|
|
float GeomSmith(float nDotV,float nDotL,float roughness)
|
|
{
|
|
float r = roughness + 1.0;
|
|
float k = r*r / 8.0;
|
|
float ik = 1.0 - k;
|
|
float ggx1 = nDotV/(nDotV*ik + k);
|
|
float ggx2 = nDotL/(nDotL*ik + k);
|
|
return ggx1*ggx2;
|
|
}
|
|
|
|
vec3 ComputePBR()
|
|
{
|
|
vec3 albedo = texture(albedoMap,vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb;
|
|
albedo = vec3(albedoColor.x*albedo.x, albedoColor.y*albedo.y, albedoColor.z*albedo.z);
|
|
|
|
float metallic = clamp(metallicValue, 0.0, 1.0);
|
|
float roughness = clamp(roughnessValue, 0.0, 1.0);
|
|
float ao = clamp(aoValue, 0.0, 1.0);
|
|
|
|
if (useTexMRA == 1)
|
|
{
|
|
vec4 mra = texture(mraMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y))*useTexMRA;
|
|
metallic = clamp(mra.r + metallicValue, 0.04, 1.0);
|
|
roughness = clamp(mra.g + roughnessValue, 0.04, 1.0);
|
|
ao = (mra.b + aoValue)*0.5;
|
|
}
|
|
|
|
vec3 N = normalize(fragNormal);
|
|
if (useTexNormal == 1)
|
|
{
|
|
N = texture(normalMap, vec2(fragTexCoord.x*tiling.x + offset.y, fragTexCoord.y*tiling.y + offset.y)).rgb;
|
|
N = normalize(N*2.0 - 1.0);
|
|
N = normalize(N*TBN);
|
|
}
|
|
|
|
vec3 V = normalize(viewPos - fragPosition);
|
|
|
|
vec3 emissive = vec3(0);
|
|
emissive = (texture(emissiveMap, vec2(fragTexCoord.x*tiling.x+offset.x, fragTexCoord.y*tiling.y+offset.y)).rgb).g * emissiveColor.rgb*emissivePower * useTexEmissive;
|
|
|
|
// return N;//vec3(metallic,metallic,metallic);
|
|
// if dia-electric use base reflectivity of 0.04 otherwise ut is a metal use albedo as base reflectivity
|
|
vec3 baseRefl = mix(vec3(0.04), albedo.rgb, metallic);
|
|
vec3 lightAccum = vec3(0.0); // Acumulate lighting lum
|
|
|
|
vec3 norm=N;
|
|
vec3 viewDir=V;
|
|
vec3 result = vec3(0.0);
|
|
|
|
for (int i = 0; i < MAX_LIGHTS; i++){
|
|
|
|
if(lights[i].enabled == 1){
|
|
|
|
if(lights[i].type == LIGHT_DIRECTIONAL){
|
|
result += CalcDirLight(lights[i],norm,viewDir,albedo,baseRefl,roughness,metallic);
|
|
}
|
|
|
|
if(lights[i].type == LIGHT_POINT){
|
|
result += CalcPointLight(lights[i],norm,viewDir,albedo,baseRefl,roughness,metallic);
|
|
}
|
|
|
|
if(lights[i].type == LIGHT_SPOT){
|
|
result += CalcSpotLight(lights[i],norm,viewDir,albedo,baseRefl,roughness,metallic);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vec3 ambientFinal = (ambientColor + albedo)*ambient*0.5;
|
|
|
|
return ambientFinal+result*ao + emissive;
|
|
|
|
}
|
|
|
|
|
|
void main()
|
|
{
|
|
vec3 color = ComputePBR();
|
|
|
|
// HDR tonemapping
|
|
color = pow(color, color + vec3(1.0));
|
|
|
|
// // Gamma correction
|
|
// color = pow(color, vec3(1.0/2.5));
|
|
|
|
// Fog calculation
|
|
float dist = length(viewPos - fragPosition);
|
|
|
|
// these could be parameters...
|
|
const vec4 fogColor = vec4(0.5, 0.5, 0.5, 1.0);
|
|
|
|
|
|
// Exponential fog
|
|
float fogFactor = 1.0/exp((dist*fogDensity)*(dist*fogDensity));
|
|
|
|
|
|
fogFactor = clamp(fogFactor, 0.0, 1.0);
|
|
|
|
finalColor = mix(fogColor,vec4(color,1.0), fogFactor);
|
|
}
|
|
|
|
|
|
|
|
vec3 CalcDirLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic)
|
|
{
|
|
|
|
vec3 L = normalize(-light.direction);
|
|
float diff=max(dot(normal,L),0.0);
|
|
vec3 diffuse=light.lightColor*diff*vec3(texture(texture0,fragTexCoord));
|
|
vec3 H = normalize(diffuse + L);
|
|
|
|
// Cook-Torrance BRDF distribution function
|
|
float nDotV = max(dot(normal,viewDir), 0.0000001);
|
|
float nDotL = max(dot(normal,L), 0.0000001);
|
|
float hDotV = max(dot(H,viewDir), 0.0);
|
|
float nDotH = max(dot(normal,H), 0.0);
|
|
float D = GgxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H
|
|
float G = GeomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow
|
|
vec3 F = SchlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance
|
|
|
|
vec3 spec = (D*G*F)/(4.0*nDotV*nDotL);
|
|
|
|
// Difuse and spec light can't be above 1.0
|
|
// kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent
|
|
vec3 kD = vec3(1.0) - F;
|
|
// Mult kD by the inverse of metallnes, only non-metals should have diffuse light
|
|
kD *= 1.0 - metallic;
|
|
// Angle of light has impact on result
|
|
return ((kD*albedo.rgb/PI + spec)*nDotL)*light.enabled;
|
|
|
|
}
|
|
|
|
vec3 CalcPointLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic)
|
|
{
|
|
|
|
vec3 L = normalize(light.position - fragPosition);
|
|
vec3 H = normalize(viewDir + L);
|
|
float distance=length(light.position-fragPosition);
|
|
float attenuation=light.enargy/(light.constant+light.linear*distance+light.quadratic*(distance*distance));
|
|
vec3 radiance = light.lightColor.rgb*light.enargy*attenuation;
|
|
|
|
// Cook-Torrance BRDF distribution function
|
|
float nDotV = max(dot(normal,viewDir), 0.0000001);
|
|
float nDotL = max(dot(normal,L), 0.0000001);
|
|
float hDotV = max(dot(H,viewDir), 0.0);
|
|
float nDotH = max(dot(normal,H), 0.0);
|
|
float D = GgxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H
|
|
float G = GeomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow
|
|
vec3 F = SchlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance
|
|
|
|
vec3 spec = (D*G*F)/(4.0*nDotV*nDotL);
|
|
|
|
// Difuse and spec light can't be above 1.0
|
|
// kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent
|
|
vec3 kD = vec3(1.0) - F;
|
|
// Mult kD by the inverse of metallnes, only non-metals should have diffuse light
|
|
kD *= 1.0 - metallic;
|
|
// Angle of light has impact on result
|
|
return ((kD*albedo.rgb/PI + spec)*radiance*nDotL)*light.enabled ;
|
|
}
|
|
|
|
vec3 CalcSpotLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic){
|
|
|
|
vec3 L = normalize(light.position - fragPosition);
|
|
|
|
float theta=dot(L,normalize(-light.direction));
|
|
float epsilon=cos(radians(light.cutOff))-cos(radians(light.outerCutOff));
|
|
float intensity=smoothstep(0.0,1.0,(theta-cos(radians(light.outerCutOff)))/epsilon);//clamp((theta-cos(radians(light.outerCutOff)))/epsilon,0.0,1.0);
|
|
intensity*= length(vec3(texture(flashlight,vec2(fragTexCoord.x*tilingFlashlight.x + offsetFlashlight.y, fragTexCoord.y*tilingFlashlight.y + offsetFlashlight.y)).rgb));
|
|
|
|
float diff=max(dot(normal,L),0.0);
|
|
vec3 H = light.lightColor*diff*vec3(texture(texture0,fragTexCoord));
|
|
float distance=length(light.position-fragPosition);
|
|
float attenuation=light.enargy/(light.constant+light.linear*distance+light.quadratic*(distance*distance));
|
|
vec3 radiance = light.lightColor.rgb*light.enargy*attenuation;
|
|
H*=intensity;
|
|
|
|
// Cook-Torrance BRDF distribution function
|
|
float nDotV = max(dot(normal,viewDir), 0.0000001);
|
|
float nDotL = max(dot(normal,L), 0.0000001);
|
|
float hDotV = max(dot(H,viewDir), 0.0);
|
|
float nDotH = max(dot(normal,H), 0.0);
|
|
float D = GgxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H
|
|
float G = GeomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow
|
|
vec3 F = SchlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance
|
|
|
|
vec3 spec = (D*G*F)/(4.0*nDotV*nDotL);
|
|
spec*=intensity;
|
|
|
|
|
|
// Difuse and spec light can't be above 1.0
|
|
// kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent
|
|
vec3 kD = vec3(1.0) - F;
|
|
// Mult kD by the inverse of metallnes, only non-metals should have diffuse light
|
|
kD *= 1.0 - metallic;
|
|
// Angle of light has impact on result
|
|
return ((kD*albedo.rgb/PI + spec)*radiance*nDotL)*light.enabled;
|
|
}
|
|
|