Skip to content

Instantly share code, notes, and snippets.

@riccardobl
Last active February 19, 2024 20:26
Show Gist options
  • Save riccardobl/373028cd15c6c2ccca83889baeccce61 to your computer and use it in GitHub Desktop.
Save riccardobl/373028cd15c6c2ccca83889baeccce61 to your computer and use it in GitHub Desktop.
#import "Pipeline/utils/FastMath.glsl"
#define _LIGHT_TYPE_DIRECTIONAL 0
#define _LIGHT_TYPE_POSITIONAL 1
#define _LIGHT_TYPE_SPOT 2
#ifndef PI
#define PI 3.14159265358979323846264
#endif
#ifndef Light
struct StdLight{
float invRadius;
vec3 position;
vec4 color;
vec3 spotDirection;
float spotAngleCos;
int type;
};
#define Light StdLight
#endif
#ifndef ComputedJmeLight
struct StdComputedJmeLight {
vec3 color;
vec3 position;
float type; // 0 = direction 1 = positional 2 = spot
float attenuation;
float invRange;
float spotAngleCos;
vec3 spotDirection;
float NdotL; // cos angle between normal and light direction
float NdotH; // cos angle between normal and half vector
float LdotH; // cos angle between light direction and half vector
float HdotV; // cos angle between view direction and half vector
vec3 vector;
float fallOff;
};
#define ComputedJmeLight StdComputedJmeLight
#endif
#ifndef LightsData
struct StdLightsData {
vec4 ambientLight;
int nLights;
#if MAX_LIGHTS > 0
Light lights[MAX_LIGHTS];
#endif
};
#define LightsData StdLightsData
#endif
#ifndef LightIndex
struct StdLightIndex {
int index;
};
#define LightIndex StdLightIndex
#endif
//From Frostbite PBR Course
//Distance based attenuation
// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
float _distAtt(float distSqrt, float invSqrInfluence){
float factor = distSqrt * invSqrInfluence;
float fac = clamp(1.0 - factor * factor,0.,1.);
return fac * fac;
}
void Light_computeFor(vec3 worldPos,vec3 worldNormal, vec3 viewDir, inout ComputedJmeLight light){
float posLight = step(0.5, light.type);
light.vector= light.position.xyz * sign(posLight - 0.5) - (worldPos * posLight);
// vec3 L=normalize(light.vector);
vec3 L;
float dist;
fast_lengthAndNormalize(light.vector,dist,L);
// L=vec3(0,1,0);
// dist=length(light.vector);
float invRange=light.invRange;
const float light_threshold=0.01;
if(invRange==0&&light.type==1.0){
// light.color/=10;
//Compute max light power.
vec3 nc=(light.color.rgb)/length(light.color.rgb);
float power = max(max(nc.r,nc.g),nc.b);
float energy=length(light.color);
power *= abs(energy / 100.0f);
// Compute the distance (using the inverse square law)
// at which the light power reaches the light_threshold.
invRange= fast_inversesqrt(max(1e-16, power / max(1e-16, light_threshold)));
}
light.attenuation= (1.0 -invRange * dist) / (1.0 + invRange * dist * dist);
light.attenuation = clamp( light.attenuation, 1.0 - posLight, 1.0);
if(light.type>1.){
vec3 spotdir = normalize(light.spotDirection);
float curAngleCos = dot(-L, spotdir);
float innerAngleCos = floor(light.spotAngleCos) * 0.001;
float outerAngleCos = fract(light.spotAngleCos);
float innerMinusOuter = innerAngleCos - outerAngleCos;
float falloff= pow(clamp((curAngleCos - outerAngleCos) / innerMinusOuter, 0.0, 1.0), 4.0);
light.attenuation*=falloff;
}
vec3 h=normalize(L+viewDir);
light.NdotL = max(dot(worldNormal, L), 0.0);
light.NdotH = max(dot(worldNormal, h), 0.0);
light.LdotH = max(dot(L, h), 0.0);
light.HdotV = max(dot(viewDir,h), 0.);
}
ComputedJmeLight Light_computeFor(vec3 worldPos,vec3 worldNormal, vec3 viewDir, in Light light){
ComputedJmeLight clight;
clight.type = float(light.type);
clight.position = light.position;
clight.invRange = light.invRadius;
clight.color = light.color.rgb;
clight.spotDirection = light.spotDirection;
clight.spotAngleCos = light.spotAngleCos;
Light_computeFor(worldPos,worldNormal,viewDir,clight);
return clight;
}
#ifndef PI
#define PI 3.14159265358979323846264
#endif
#define UE4_GGX
#ifndef Surface
struct PBRSurface {
vec3 normal; // normals w/ normalmap
vec3 position;
float opacity;
float metalness; // metallic value at the surface
// vec3 reflectance0; // full reflectance color (normal incidence angle)
// vec3 reflectance90; // reflectance color at grazing angle
float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2])
float roughness;
// vec3 diffuseColor; // color contribution from diffuse lighting
// vec3 specularColor; // color contribution from specular lighting
vec3 albedo;
vec3 f0;
float NdotV;
// float lightMask; // inverse of shadow map (1= light 0 =shadow)
vec3 emission;
vec3 viewDir;
vec3 reflectedVec;
float ao;
float depth;
bool frontFacing; //gl_FrontFacing
vec3 envLight;
};
void PBRSurface_calcMissing(in vec3 cameraPos,in vec3 shininess,in float minRoughness,inout PBRSurface surface){
surface.viewDir = normalize(cameraPos - surface.position);
surface.alphaRoughness = clamp(surface.roughness * surface.roughness, minRoughness, 1.0);
surface.f0=mix(shininess,surface.albedo,surface.metalness);
surface.NdotV = clamp(abs(dot(!surface.frontFacing?-surface.normal:surface.normal, surface.viewDir)), 0.001, 1.0);
surface.reflectedVec= normalize(reflect(-surface.viewDir, surface.normal));
}
void PBRSurface_toGBuffer(in PBRSurface surface, inout GBuffer gbuffer){
gbuffer.color=vec4(surface.albedo,surface.opacity);
gbuffer.emission=surface.emission;
gbuffer.ao=surface.ao;
gbuffer.worldNormal=surface.normal;
gbuffer.roughness=surface.roughness;
gbuffer.metallicness=surface.metalness;
gbuffer.depth=surface.depth;
gbuffer.worldPosition=surface.position;
gbuffer.frontFacing=surface.frontFacing;
gbuffer.envLight=surface.envLight;
}
void PBRSurface_fromGBuffer( in GBuffer gbuffer, inout PBRSurface surface){
surface.albedo=gbuffer.color.rgb;
surface.emission=gbuffer.emission;
surface.ao=gbuffer.ao;
surface.normal=gbuffer.worldNormal;
surface.roughness=gbuffer.roughness;
surface.metalness=gbuffer.metallicness;
surface.depth=gbuffer.depth;
surface.position=gbuffer.worldPosition;
surface.frontFacing=gbuffer.frontFacing;
surface.depth=gbuffer.depth;
surface.envLight=gbuffer.envLight;
surface.opacity=gbuffer.color.a;
}
#define Surface PBRSurface
#endif
vec3 fresnelSchlick(in Surface surface,in ComputedJmeLight light){
float cosTheta=light.HdotV;
vec3 F0=surface.f0;
return F0 + (1.0 - F0) * pow(max(1.0 - cosTheta,0.), 5.0);
}
// UE4 way to optimise shlick GGX Gometry shadowing term
float ue4GGX(in Surface surface,in ComputedJmeLight light){
//G Shchlick GGX Gometry shadowing term, k = alpha/2
float k = surface.alphaRoughness * 0.5;
/*
//classic Schlick ggx
float G_V = ndotv / (ndotv * (1.0 - k) + k);
float G_L = ndotl / (ndotl * (1.0 - k) + k);
float G = ( G_V * G_L );
float specular =(D* fresnel * G) /(4 * ndotv);
*/
//http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html
float G_V = surface.NdotV + sqrt( (surface.NdotV - surface.NdotV * k) * surface.NdotV + k );
float G_L = light.NdotL + sqrt( (light.NdotL - light.NdotL * k) * light.NdotL + k );
// the max here is to avoid division by 0 that may cause some small glitches.
return 1.0/max( G_V * G_L ,0.01);
}
float GeometrySchlickGGX(float NdotV, float roughness){
float r = (roughness + 1.0);
float k = (r*r) / 8.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
float GeometrySmith(in Surface surface,in ComputedJmeLight light){
#ifdef UE4_GGX
return ue4GGX(surface,light);
#else
float ggx2 = GeometrySchlickGGX(surface.NdotV, surface.roughness);
float ggx1 = GeometrySchlickGGX(light.NdotL, surface.roughness);
return ggx1 * ggx2;
#endif
}
float DistributionGGX(in Surface surface,in ComputedJmeLight light){
float alpha = surface.alphaRoughness;
//D, GGX normaal Distribution function
float alpha2 = alpha * alpha;
float nom = alpha2;
float denom = ((light.NdotH * light.NdotH) * (alpha2 - 1.0)) + 1.0;
denom = PI * denom * denom;
denom=max(denom,1e-8);
return nom / denom;
}
vec3 PBR_computeDirectLight(
inout Surface surface,
in ComputedJmeLight light
){
if(max(max(light.color.r,light.color.g),light.color.b)<0.0001)return vec3(0);
if (light.NdotL <= 0.0 || surface.NdotV <= 0.0||light.attenuation < 1e-8) return vec3(0);
vec3 pos=surface.position;
vec3 normal=surface.normal;
vec3 viewDir=surface.viewDir;
vec3 radiance = light.color * light.attenuation;
// cook-torrance brdf
float NDF = DistributionGGX(surface,light);
float G = GeometrySmith(surface,light);
vec3 F = fresnelSchlick(surface,light);
vec3 nominator = NDF * G * F;
float denominator = 4 * surface.NdotV * light.NdotL + 0.001; // 0.001 to prevent divide by zero.
vec3 specular = nominator / denominator;
specular=max(specular,0.);
// kS is equal to Fresnel
vec3 kS = F;
// for energy conservation, the diffuse and specular light can't
// be above 1.0 (unless the surface emits light); to preserve this
// relationship the diffuse component (kD) should equal 1.0 - kS.
vec3 kD = vec3(1.0) - kS;
// multiply kD by the inverse metalness such that only non-metals
// have diffuse lighting, or a linear blend if partly metal (pure metals
// have no diffuse light).
kD *= 1.0 - surface.metalness;
// kD=0;
vec3 dlight= (kD * surface.albedo / PI + specular) * radiance * light.NdotL;
// dlight= vec3( (surface.albedo / PI +specular) * radiance * light.NdotL);
// dlight=max(dlight,0);
#if defined( SHADOW_MAP) && !defined(NO_SHADOWS)
float lmask=surface.lightMask;
#ifndef POINT_LIGHT_SHADOWS
lmask=mix(lmask,.9,light.type==1.0);
#endif
#ifndef SPOT_LIGHT_SHADOWS
lmask=mix(lmask,.9,light.type==2.0);
#endif
dlight*=lmask;
#endif
return dlight;
}
// from Sebastien Lagarde https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf page 69
vec3 getSpecularDominantDir(const in vec3 N, const in vec3 R, const in float realRoughness){
vec3 dominant;
float smoothness = 1.0 - realRoughness;
float lerpFactor = smoothness * (sqrt(smoothness) + realRoughness);
// The result is not normalized as we fetch in a cubemap
dominant = mix(N, R, lerpFactor);
return dominant;
}
vec3 integrateBRDFApprox( const in vec3 specular, float roughness, float NoV ){
const vec4 c0 = vec4( -1, -0.0275, -0.572, 0.022 );
const vec4 c1 = vec4( 1, 0.0425, 1.04, -0.04 );
vec4 r = roughness * c0 + c1;
float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
return specular * AB.x + AB.y;
}
vec3 sphericalHarmonics( const in vec3 normal, const vec3 sph[9] ){
float x = normal.x;
float y = normal.y;
float z = normal.z;
vec3 result = (
sph[0] +
sph[1] * y +
sph[2] * z +
sph[3] * x +
sph[4] * y * x +
sph[5] * y * z +
sph[6] * (3.0 * z * z - 1.0) +
sph[7] * (z * x) +
sph[8] * (x*x - y*y)
);
return max(result, vec3(0.0));
}
vec3 ApproximateSpecularIBLPolynomial(samplerCube envMap, vec3 SpecularColor , float Roughness, float ndotv, vec3 refVec, float nbMipMaps){
float Lod = sqrt( Roughness ) * (nbMipMaps - 1.0);
vec3 PrefilteredColor = textureLod(envMap, refVec.xyz, Lod).rgb;
return PrefilteredColor * integrateBRDFApprox(SpecularColor, Roughness, ndotv);
}
// vec3 PBR_computeIBLContribution(in samplerCube prefEnv,
// in samplerCube irrMap,
// in mat4 lightProbeData,
// Surface surface
// ) {
// vec4 probePos = lightProbeData[3];
// float invRadius = fract( probePos.w);
// vec3 rv = surface.reflectedVec;
// vec3 direction = surface.position - probePos.xyz;
// rv = invRadius * direction + rv;
// // ambient lighting (we now use IBL as the ambient term)
// vec3 F = fresnelSchlickRoughness(surface.NdotV, surface.f0,surface.roughness);
// vec3 kS = F;
// vec3 kD = 1.0 - kS;
// kD *= 1.0 - surface.metalness;
// float mipCount = probePos.w - invRadius;
// float lod = (surface.roughness * (mipCount));
// // vec3 dominantR ;//= getSpecularDominantDir( surface.normal, rv.xyz, surface.alphaRoughness);
// // dominantR=rv.xyz;
// vec3 dominantR =getSpecularDominantDir( surface.normal, rv.xyz, surface.alphaRoughness);
// #ifdef BRDF
// vec2 brdfcoord=vec2(surface.NdotV, 1.0 - surface.roughness);
// vec3 brdf = texture(g_BrdfLUT,brdfcoord).xyz;
// #else
// vec3 brdf=vec3(1,1,1);
// #endif
// vec3 irradiance = textureCube(irrMap, surface.normal).rgb;
// vec3 prefilteredColor = textureCubeLod(prefEnv, dominantR, lod).rgb;
// vec3 diffuse = irradiance * surface.albedo;
// vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);
// vec3 ambient= (kD * diffuse + specular) * surface.ao ;
// // #if defined( SHADOW_MAP) && !defined(NO_SHADOWS)
// // ambient*=surface.lightMask;
// // #endif
// // #if defined( SHADOW_MAP) && !defined(NO_SHADOWS)
// // // specular*=shadow;
// // diffuse=mix(diffuse,diffuse*shadow,.4);
// // specular=mix(specular,specular*shadow,.4);
// // // diffuse=diffuse*2;
// // #endif
// return ambient;
// }
void PBR_computeIBLContribution(
in samplerCube prefEnvMap,
in vec3 shCoeffs[9],
in mat4 lightProbeData,
in Surface surface,
in vec3 geoNormal,
in vec3 specularColor,
out float outNdf,
out vec3 outColor
) {
// lightProbeData is a mat4 with this layout
// 3x3 rot mat|
// 0 1 2 | 3
// 0 | ax bx cx | px | )
// 1 | ay by cy | py | probe position
// 2 | az bz cz | pz | )
// --|----------|
// 3 | sx sy sz sp | -> 1/probe radius + nbMipMaps
// --scale--
// parallax fix for spherical / obb bounds and probe blending from
// from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
vec3 rv = reflect(-surface.viewDir, surface.normal);
vec4 probePos = lightProbeData[3];
float invRadius = fract( probePos.w);
float nbMipMaps = probePos.w - invRadius;
vec3 direction = surface.position - probePos.xyz;
float ndf = 0.0;
if(lightProbeData[0][3] != 0.0){
// oriented box probe
mat3 wToLocalRot = inverse(mat3(lightProbeData));
vec3 scale = vec3(lightProbeData[0][3], lightProbeData[1][3], lightProbeData[2][3]);
// probe blending
// compute fragment position in probe local space
vec3 localPos = wToLocalRot * surface.position;
localPos -= probePos.xyz;
// compute normalized distance field
vec3 localDir = abs(localPos);
localDir /= scale;
ndf = max(max(localDir.x, localDir.y), localDir.z);
// parallax fix
vec3 rayLs = wToLocalRot * rv;
rayLs /= scale;
vec3 positionLs = surface.position - probePos.xyz;
positionLs = wToLocalRot * positionLs;
positionLs /= scale;
vec3 unit = vec3(1.0);
vec3 firstPlaneIntersect = (unit - positionLs) / rayLs;
vec3 secondPlaneIntersect = (-unit - positionLs) / rayLs;
vec3 furthestPlane = max(firstPlaneIntersect, secondPlaneIntersect);
float dist = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z);
vec3 intersectPositionWs = surface.position + rv * dist;
rv = intersectPositionWs - probePos.xyz;
} else {
// spherical probe
// parallax fix
rv = invRadius * direction + rv;
// probe blending
float dist = sqrt(dot(direction, direction));
ndf = dist * invRadius;
}
vec3 indirectDiffuse = vec3(0.0);
vec3 indirectSpecular = vec3(0.0);
indirectDiffuse = sphericalHarmonics(surface.normal, shCoeffs) * surface.albedo.rgb;
vec3 dominantR = getSpecularDominantDir( surface.normal, rv.xyz, surface.alphaRoughness);
indirectSpecular = ApproximateSpecularIBLPolynomial(prefEnvMap, specularColor.rgb, surface.roughness, surface.NdotV, dominantR, nbMipMaps);
#ifdef HORIZON_FADE
//horizon fade from http://marmosetco.tumblr.com/post/81245981087
float horiz = dot(rv, geoNormal);
float horizFadePower = 1.0 - Roughness;
horiz = clamp( 1.0 + horizFadePower * horiz, 0.0, 1.0 );
horiz *= horiz;
indirectSpecular *= vec3(horiz);
#endif
vec3 indirectLighting = (indirectDiffuse + indirectSpecular) * surface.ao;
outNdf = ndf;
outColor = indirectLighting * step( 0.0, probePos.w);
}
#extension GL_ARB_explicit_attrib_location : enable
#define SHININESS 0.04
#define MIN_ROUGHNESS 0.005
#import "Pipeline/utils/Utils.glsl"
#import "Pipeline/utils/GBufferF.glsl"
#import "Pipeline/utils/Light.glsl"
#import "Pipeline/utils/PBR.glsl"
#import "Pipeline/utils/WorldParams.glsl"
#define BIG_STRUCT uniform
#ifdef UPGRADE_BIG_STRUCT_TO_SSBO
#undef BIG_STRUCT
#define BIG_STRUCT buffer
#endif
layout (std140) uniform m_Camera {
Camera bo_Camera;
};
#ifdef IS_DEFERRED
layout(location=0) out vec4 outData1;
layout(location=1) out vec4 outData2;
layout(location=2) out vec4 outData3;
#else
layout(location=0) out vec4 outColor;
layout (std140) BIG_STRUCT m_LightsData {
LightsData bo_LightsData;
};
// layout (std140) BIG_STRUCT m_LightsData {
// LightIndex bo_LightsIndices[MAX_LIGHTS_PER_GEOM];
// };
uniform int m_LightsIndices[MAX_LIGHTS_PER_GEOM];
uniform int m_NLightsPerGeo;
#endif
#for i=0..3 ( #if defined(PROBE_$i) $0 #endif )
uniform samplerCube m_PrefilteredEnvMap$i;
uniform vec3 m_ShCoeff$i[9];
uniform mat4 m_ProbeData$i;
#endfor
in vec2 TexCoord;
in vec3 WorldPos;
in vec3 WorldNormal;
#if defined(NORMALMAP) ||defined(PARALLAXMAP)
in vec3 WorldBinormal;
in vec3 WorldTangent;
#endif
// Base color
uniform vec4 m_BaseColor;
#ifdef BASECOLORMAP
uniform sampler2D m_BaseColorMap;
#endif
// Surface
uniform float m_Metallic;
uniform float m_Roughness;
#ifdef AO_ROUGHNESS_METALLIC_MAP
uniform sampler2D m_AORoughnessMetallicMap;
#endif
#if defined(NORMALMAP)
uniform sampler2D m_NormalMap;
#endif
#if defined(PARALLAXMAP)
uniform sampler2D m_ParallaxMap;
#endif
// Glow
#ifdef EMISSIVE
uniform vec4 m_Emissive;
#endif
#ifdef EMISSIVEMAP
uniform sampler2D m_EmissiveMap;
#endif
#if defined(EMISSIVE) || defined(EMISSIVEMAP)
uniform float m_EmissiveIntensity;
uniform float m_EmissivePower;
#endif
// Alpha
#ifdef DISCARD_ALPHA
uniform float m_AlphaDiscardThreshold;
#endif
void main(){
#if defined(NORMALMAP) ||defined(PARALLAXMAP)
mat3 TBN=mat3(WorldTangent,WorldBinormal,WorldNormal);
#endif
PBRSurface surface;
// Parallax?
{
}
// Base color & alpha
{
vec4 baseColor=m_BaseColor;
#ifdef BASECOLORMAP
baseColor*=texture(m_BaseColorMap,TexCoord);
#endif
#ifdef DISCARD_ALPHA
if(baseColor.a < m_AlphaDiscardThreshold){
discard;
return;
}
#endif
surface.albedo=baseColor.rgb;
surface.opacity=baseColor.a;
}
// Glow
{
#ifdef EMISSIVEMAP
vec4 emission=texture(m_EmissiveMap,TexCoord).rgba;
#ifdef EMISSIVE
emission*=m_Emissive;
#endif
surface.emission= (emission * pow(emission.a, m_EmissivePower) * m_EmissiveIntensity).rgb;
#elif defined(EMISSIVE)
vec4 emission=m_Emissive;
surface.emission=(emission * pow(emission.a, m_EmissivePower) * m_EmissiveIntensity).rgb;
#else
surface.emission=vec3(0);
#endif
}
// AO Rough Metallic
{
surface.ao=1.0;
surface.roughness=max(m_Roughness,1e-4);
surface.metalness=max(m_Metallic,0.0);
#ifdef AO_ROUGHNESS_METALLIC_MAP
vec4 gbufferMap=texture(m_AORoughnessMetallicMap,TexCoord);
surface.ao*=gbufferMap.r;
surface.roughness*=gbufferMap.g;
surface.metalness*=gbufferMap.b;
#endif
}
// Normals
{
#if defined(NORMALMAP)
surface.normal=texture(m_NormalMap,TexCoord).rgb;
#ifdef OPENGL_NORMALMAP
surface.normal = normalize((surface.normal.xyz * vec3(2.,-2.,2.) - vec3(1.,-1.,1.)));
#else
surface.normal = normalize((surface.normal.xyz * vec3(2.,2.,2.) - vec3(1.,1.,1.)));
#endif
surface.normal=TBN*surface.normal;
#else
surface.normal=WorldNormal;
#endif
}
// Depth
{
surface.depth=gl_FragCoord.z;
}
// // ViewDir
// {
// surface.viewDir=viewDir;
// }
// Position
{
surface.position=WorldPos;
}
// gl_FrontFacing
{
surface.frontFacing=gl_FrontFacing;
}
PBRSurface_calcMissing(bo_Camera.cameraPosition,vec3(SHININESS),MIN_ROUGHNESS,surface);
// surface.alphaRoughness = clamp(surface.roughness * surface.roughness, MIN_ROUGHNESS, 1.0);
// surface.f0=mix(vec3(SHININESS),surface.albedo,surface.metalness);
// surface.NdotV = clamp(abs(dot(!gl_FrontFacing?-surface.normal:surface.normal, surface.viewDir)), 0.001, 1.0);
// surface.reflectedVec= normalize(reflect(-surface.viewDir, surface.normal));
// surface.albedo=gbuffer.color.rgb;
// surface.opacity=gbuffer.color.a;
// surface.metalness=gbuffer.metallicness;
// surface.roughness=gbuffer.roughness;
// surface.normal=gbuffer.worldNormal;
// surface.position=gbuffer.worldPosition;
// surface.ao=gbuffer.ao;
// surface.emission=gbuffer.emission;
// surface.viewDir=viewDir;
// surface.alphaRoughness = clamp(surface.roughness * surface.roughness, MIN_ROUGHNESS, 1.0);
// surface.f0=mix(vec3(SHININESS),surface.albedo,surface.metalness);
// surface.NdotV = clamp(abs(dot(!gl_FrontFacing?-surface.normal:surface.normal, surface.viewDir)), 0.001, 1.0);
// surface.reflectedVec= normalize(reflect(-surface.viewDir, surface.normal));
// GBuffer gbuffer;
// Base color
// gbuffer.color=m_BaseColor;
// #ifdef BASECOLORMAP
// gbuffer.color*=texture(m_BaseColorMap,TexCoord);
// #endif
// // Glow
// #ifdef EMISSIVEMAP
// vec4 emission=texture(m_EmissiveMap,TexCoord).rgba;
// #ifdef EMISSIVE
// emission*=m_Emissive;
// #endif
// gbuffer.emission= (emission * pow(emission.a, m_EmissivePower) * m_EmissiveIntensity).rgb;
// #elif defined(EMISSIVE)
// vec4 emission=m_Emissive;
// gbuffer.emission=(emission * pow(emission.a, m_EmissivePower) * m_EmissiveIntensity).rgb;
// #else
// gbuffer.emission=vec3(0);
// #endif
// Surface
// gbuffer.ao=1.0;
// gbuffer.roughness=max(m_Roughness,1e-4);
// gbuffer.metallicness=max(m_Metallic,0.0);
// #ifdef AO_ROUGHNESS_METALLIC_MAP
// vec4 gbufferMap=texture(m_AORoughnessMetallicMap,TexCoord);
// gbuffer.ao*=gbufferMap.r;
// gbuffer.roughness*=gbufferMap.g;
// gbuffer.metallicness*=gbufferMap.b;
// #endif
// Normals
// #if defined(NORMALMAP)
// gbuffer.worldNormal=texture(m_NormalMap,TexCoord).rgb;
// #ifdef OPENGL_NORMALMAP
// gbuffer.worldNormal = normalize((gbuffer.worldNormal.xyz * vec3(2.,-2.,2.) - vec3(1.,-1.,1.)));
// #else
// gbuffer.worldNormal = normalize((gbuffer.worldNormal.xyz * vec3(2.,2.,2.) - vec3(1.,1.,1.)));
// #endif
// gbuffer.worldNormal=TBN*gbuffer.worldNormal;
// #else
// gbuffer.worldNormal=WorldNormal;
// #endif
// gbuffer.depth=gl_FragCoord.z;
// Position
// gbuffer.worldPosition=WorldPos.xyz;
// gbuffer.depth=gl_FragCoord.z;
// EnvLight
{
#if NUM_PROBES > 0
float probeNdfSum=0;
float invProbeNdfSum=0;
float probeWeightSum=0;
float specular = 0.5;
float nonMetalSpec = 0.08 * specular;
vec3 specularColor = (nonMetalSpec - nonMetalSpec * surface.metalness) + surface.albedo * surface.metalness;
vec3 envReflection=vec3(0);
#for i=0..3 ( #ifdef PROBE_$i $0 #endif )
vec3 probeColor$i;
float probeNdf$i;
float probeInvNdf$i = max(1.0 - probeNdf$i,0.0);
PBR_computeIBLContribution(m_PrefilteredEnvMap$i,m_ShCoeff$i,m_ProbeData$i,surface,WorldNormal, specularColor, probeNdf$i, probeColor$i);
probeNdfSum += probeNdf$i;
invProbeNdfSum += max(1. - probeNdf$i, 0.0);
#endfor
#if NUM_PROBES > 1
float probeWeightSum=0;
#for i=0..3 ( #ifdef PROBE_$i $0 #endif )
float probeWeight$i = ((1.0 - (probeNdf$i / probeNdfSum)) / (NUM_PROBES - 1)) * ( probeInvNdf$i / invProbeNdfSum);
probeWeightSum += probeWeight$i;
#endfor
#for i=0..3 ( #ifdef PROBE_$i $0 #endif )
envReflection.rgb += probeColor$i * clamp( probeWeight$i / probeWeightSum, 0., 1.);
#endfor
#elif NUM_PROBES > 0
envReflection.rgb += probeColor0;
#endif
surface.envLight=envReflection.rgb;
#else
surface.envLight=vec3(0);
#endif
}
#ifdef IS_DEFERRED
// Write to gbuffer
GBuffer gbuffer;
PBRSurface_toGBuffer(surface,gbuffer); // convert to gbuffer
packGBuffer(gbuffer,outData1, outData2,outData3); // compress and output
#else
// Compute lights
#if MAX_LIGHTS > 0
vec3 dlightSum=vec3(0);
for(int i=0;i<MAX_LIGHTS_PER_GEOM;i++){
if(i>=bo_LightsData.nLights||i>=m_NLightsPerGeo)break;
int lightIndex=m_LightsIndices[i];
Light light=bo_LightsData.lights[lightIndex];
ComputedJmeLight clight=Light_computeFor(surface.position, surface.normal, surface.viewDir, light);
vec3 lightResult = PBR_computeDirectLight(surface,clight);
dlightSum += lightResult;
}
outColor.rgb+=dlightSum;
#endif
outColor.rgb += surface.envLight;
outColor.rgb += surface.emission;
outColor.rgb*=vec3(surface.ao);
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment