Files

88 lines
3.1 KiB
GLSL

#ifndef IBL_COMMON_GLSL
#define IBL_COMMON_GLSL
/*
** Physical based render code, develop by engineer: qiutanguu.
*/
#include "LightingCommon.glsl"
// https://www.mathematik.uni-marburg.de/~thormae/lectures/graphics1/code/ImportanceSampling/importance_sampling_notes.pdf
// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf
// https://bruop.github.io/ibl/
vec3 importanceSampleGGX(vec2 Xi, float alphaRoughness, vec3 normal)
{
// Maps a 2D point to a hemisphere with spread based on roughness.
float alpha = alphaRoughness * alphaRoughness;
// Sample in spherical coordinates.
float phi = 2.0 * kPI * Xi.x;
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha * alpha - 1.0) * Xi.y));
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
// Construct tangent space sample vector.
vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
// Tangent space
vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 tangentX = normalize(cross(up, normal));
vec3 tangentY = normalize(cross(normal, tangentX));
// Convert to world Space
return normalize(tangentX * H.x + tangentY * H.y + normal * H.z);
}
// http://jcgt.org/published/0007/04/01/paper.pdf by Eric Heitz
// Input Ve: view direction
// Input alpha_x, alpha_y: roughness parameters
// Input U1, U2: uniform random numbers
// Output Ne: normal sampled with PDF D_Ve(Ne) = G1(Ve) * max(0, dot(Ve, Ne)) * D(Ne) / Ve.z
vec3 importanceSampleGGXVNDF(vec3 Ve, float alpha_x, float alpha_y, float U1, float U2)
{
// Section 3.2: transforming the view direction to the hemisphere configuration
vec3 Vh = normalize(vec3(alpha_x * Ve.x, alpha_y * Ve.y, Ve.z));
// Section 4.1: orthonormal basis (with special case if cross product is zero)
float lensq = Vh.x * Vh.x + Vh.y * Vh.y;
vec3 T1 = lensq > 0 ? vec3(-Vh.y, Vh.x, 0) * inversesqrt(lensq) : vec3(1, 0, 0);
vec3 T2 = cross(Vh, T1);
// Section 4.2: parameterization of the projected area
float r = sqrt(U1);
float phi = 2.0 * kPI * U2;
float t1 = r * cos(phi);
float t2 = r * sin(phi);
float s = 0.5 * (1.0 + Vh.z);
t2 = (1.0 - s) * sqrt(1.0 - t1 * t1) + s * t2;
// Section 4.3: reprojection onto hemisphere
vec3 Nh = t1 * T1 + t2 * T2 + sqrt(max(0.0, 1.0 - t1 * t1 - t2 * t2)) * Vh;
// Section 3.4: transforming the normal back to the ellipsoid configuration
vec3 Ne = normalize(vec3(alpha_x * Nh.x, alpha_y * Nh.y, max(0.0, Nh.z)));
return Ne;
}
// Importance sample use cosine weight.
vec3 importanceSampleCosine(vec2 xi, vec3 N)
{
float phi = 2.f * kPI * xi.y;
float cosTheta = sqrt(xi.x);
float sinTheta = sqrt(1 - xi.x);
vec3 sampleHemisphere = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
//orient sample into world space
vec3 up = abs(N.z) < 0.999 ? vec3(0.f, 0.f, 1.f) : vec3(1.f, 0.f, 0.f);
vec3 tangent = normalize(cross(up, N));
vec3 bitangent = cross(N, tangent);
vec3 sampleWorld = vec3(0);
sampleWorld += sampleHemisphere.x * tangent;
sampleWorld += sampleHemisphere.y * bitangent;
sampleWorld += sampleHemisphere.z * N;
return sampleWorld;
}
#endif