raylib-go/examples/shaders/pbr/glsl330/pbr.fs
2025-01-26 21:57:23 +03:30

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;
}