This repository has been archived on 2025-06-21. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
raylib-python-cffi/examples/models/resources/shaders/brdf.fs
Richard Smith a703659c9d initial
2019-05-21 10:56:31 +01:00

140 lines
4 KiB
GLSL

/*******************************************************************************************
*
* rPBR [shader] - Bidirectional reflectance distribution function fragment shader
*
* Copyright (c) 2017 Victor Fisac
*
**********************************************************************************************/
#version 330
#define MAX_SAMPLES 1024u
# Input vertex attributes (from vertex shader)
in vec2 fragTexCoord
# Constant values
const float PI = 3.14159265359
# Output fragment color
out vec4 finalColor
float DistributionGGX(vec3 N, vec3 H, float roughness)
float RadicalInverse_VdC(uint bits)
vec2 Hammersley(uint i, uint N)
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
float GeometrySchlickGGX(float NdotV, float roughness)
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
vec2 IntegrateBRDF(float NdotV, float roughness)
float DistributionGGX(vec3 N, vec3 H, float roughness)
[
float a = roughness*roughness
float a2 = a*a
float NdotH = max(dot(N, H), 0.0)
float NdotH2 = NdotH*NdotH
float nom = a2
float denom = (NdotH2*(a2 - 1.0) + 1.0)
denom = PI*denom*denom
return nom/denom
]
float RadicalInverse_VdC(uint bits)
[
bits = (bits << 16u) | (bits >> 16u)
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u)
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u)
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u)
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u)
return float(bits) * 2.3283064365386963e-10 # / 0x100000000
]
vec2 Hammersley(uint i, uint N)
[
return vec2(float(i)/float(N), RadicalInverse_VdC(i))
]
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
[
float a = roughness*roughness
float phi = 2.0 * PI * Xi.x
float cosTheta = sqrt((1.0 - Xi.y)/(1.0 + (a*a - 1.0)*Xi.y))
float sinTheta = sqrt(1.0 - cosTheta*cosTheta)
# Transform from spherical coordinates to cartesian coordinates (halfway vector)
vec3 H = vec3(cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta)
# Transform from tangent space H vector to world space sample vector
vec3 up = ((abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0))
vec3 tangent = normalize(cross(up, N))
vec3 bitangent = cross(N, tangent)
vec3 sampleVec = tangent*H.x + bitangent*H.y + N*H.z
return normalize(sampleVec)
]
float GeometrySchlickGGX(float NdotV, float roughness)
[
# For IBL k is calculated different
float k = (roughness*roughness)/2.0
float nom = NdotV
float denom = NdotV*(1.0 - k) + k
return nom/denom
]
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
[
float NdotV = max(dot(N, V), 0.0)
float NdotL = max(dot(N, L), 0.0)
float ggx2 = GeometrySchlickGGX(NdotV, roughness)
float ggx1 = GeometrySchlickGGX(NdotL, roughness)
return ggx1*ggx2
]
vec2 IntegrateBRDF(float NdotV, float roughness)
[
vec3 V = vec3(sqrt(1.0 - NdotV*NdotV), 0.0, NdotV)
float A = 0.0
float B = 0.0
vec3 N = vec3(0.0, 0.0, 1.0)
for(uint i = 0u i < MAX_SAMPLES i++)
[
# Generate a sample vector that's biased towards the preferred alignment direction (importance sampling)
vec2 Xi = Hammersley(i, MAX_SAMPLES)
vec3 H = ImportanceSampleGGX(Xi, N, roughness)
vec3 L = normalize(2.0*dot(V, H)*H - V)
float NdotL = max(L.z, 0.0)
float NdotH = max(H.z, 0.0)
float VdotH = max(dot(V, H), 0.0)
if (NdotL > 0.0)
[
float G = GeometrySmith(N, V, L, roughness)
float G_Vis = (G*VdotH)/(NdotH*NdotV)
float Fc = pow(1.0 - VdotH, 5.0)
A += (1.0 - Fc)*G_Vis
B += Fc*G_Vis
]
]
# Calculate brdf average sample
A /= float(MAX_SAMPLES)
B /= float(MAX_SAMPLES)
return vec2(A, B)
]
void main()
[
# Calculate brdf based on texture coordinates
vec2 brdf = IntegrateBRDF(fragTexCoord.x, fragTexCoord.y)
# Calculate final fragment color
finalColor = vec4(brdf.r, brdf.g, 0.0, 1.0)
]