213 lines
5.3 KiB
GLSL
213 lines
5.3 KiB
GLSL
#include "/Lib/Settings.glsl"
|
|
// MinecraftPT — Utilities
|
|
// Math helpers, noise functions, packing/unpacking, color space conversions
|
|
|
|
#ifndef UTILITIES_GLSL
|
|
#define UTILITIES_GLSL
|
|
|
|
// --- Math helpers ---
|
|
#define saturate(x) clamp(x, 0.0, 1.0)
|
|
#define maxVec2(v) max(v.x, v.y)
|
|
#define maxVec3(v) max(max(v.x, v.y), v.z)
|
|
#define minVec3(v) min(min(v.x, v.y), v.z)
|
|
#define fsign(x) ((x) >= 0.0 ? 1.0 : -1.0)
|
|
#define sq(x) ((x) * (x))
|
|
#define cube(x) ((x) * (x) * (x))
|
|
|
|
// Gamma correction
|
|
vec3 LinearToGamma(vec3 linear){
|
|
return pow(linear, vec3(1.0 / 2.2));
|
|
}
|
|
|
|
vec3 GammaToLinear(vec3 gamma){
|
|
return pow(gamma, vec3(2.2));
|
|
}
|
|
|
|
float LinearToGamma(float linear){
|
|
return pow(linear, 1.0 / 2.2);
|
|
}
|
|
|
|
float GammaToLinear(float gamma){
|
|
return pow(gamma, 2.2);
|
|
}
|
|
|
|
// Normal packing (octahedral encoding)
|
|
vec2 EncodeNormal(vec3 n){
|
|
n /= abs(n.x) + abs(n.y) + abs(n.z);
|
|
n.xy = n.z >= 0.0 ? n.xy : (1.0 - abs(n.yx)) * fsign(n.xy);
|
|
return n.xy * 0.5 + 0.5;
|
|
}
|
|
|
|
vec3 DecodeNormal(vec2 e){
|
|
e = e * 2.0 - 1.0;
|
|
vec3 n = vec3(e.x, e.y, 1.0 - abs(e.x) - abs(e.y));
|
|
float t = max(-n.z, 0.0);
|
|
n.x += t * fsign(n.x);
|
|
n.y += t * fsign(n.y);
|
|
return normalize(n);
|
|
}
|
|
|
|
// Pack two 8-bit values into a 16-bit uint
|
|
float Pack2xU8_to_U16(vec2 v){
|
|
v = floor(v * 255.0 + 0.5);
|
|
return v.x * 256.0 + v.y;
|
|
}
|
|
|
|
vec2 Unpack2xU8_from_U16(float v){
|
|
return vec2(floor(v / 256.0), mod(v, 256.0)) / 255.0;
|
|
}
|
|
|
|
// Pack two 8-bit values with ID (8-bit + 8-bit) into float
|
|
vec2 Unpack2xU8_ID_from_U16(float v){
|
|
return vec2(mod(v, 9362.0) / 9361.0, floor(v / 9362.0) / 10.0);
|
|
}
|
|
|
|
float Unpack2xU8_ID_Y_from_U16(float v){
|
|
return floor(v / 9362.0) / 10.0;
|
|
}
|
|
|
|
// Luminance
|
|
float luminance(vec3 color){
|
|
return dot(color, vec3(0.2126, 0.7152, 0.0722));
|
|
}
|
|
|
|
// Hash functions
|
|
float hash1(vec2 p){
|
|
p = fract(p * vec2(443.8975, 397.2973));
|
|
p += dot(p, p + 19.19);
|
|
return fract(p.x * p.y);
|
|
}
|
|
|
|
float hash1(vec3 p){
|
|
p = fract(p * vec3(443.8975, 397.2973, 491.1871));
|
|
p += dot(p, p + 19.19);
|
|
return fract(p.x * p.y);
|
|
}
|
|
|
|
vec2 hash2(vec2 p){
|
|
vec3 p3 = fract(vec3(p.xyx) * vec3(443.8975, 397.2973, 491.1871));
|
|
p3 += dot(p3, p3.yxz + 19.19);
|
|
return fract(p3.xy);
|
|
}
|
|
|
|
vec2 hash2(vec3 p){
|
|
vec3 p3 = fract(p * vec3(443.8975, 397.2973, 491.1871));
|
|
p3 += dot(p3, p3.yxz + 19.19);
|
|
return fract(p3.xy);
|
|
}
|
|
|
|
vec3 hash3(vec2 p){
|
|
vec3 p3 = fract(vec3(p.xyx) * vec3(443.8975, 397.2973, 491.1871));
|
|
p3 += dot(p3, p3.yxz + 19.19);
|
|
return fract(p3);
|
|
}
|
|
|
|
// Interleaved gradient noise (temporal)
|
|
float InterleavedGradientNoise(vec2 pos, float index){
|
|
vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189);
|
|
return fract(magic.z * fract(dot(pos, magic.xy)) + index * 0.03125);
|
|
}
|
|
|
|
// Blue noise temporal (from noise.png)
|
|
// Used as dithering / ray offset
|
|
float BlueNoiseTemporal(vec2 screenPos, float frame){
|
|
vec2 coord = (screenPos + 0.5) / vec2(viewWidth, viewHeight);
|
|
coord = fract(coord * vec2(128.0, 128.0) + 0.5);
|
|
vec2 texel = coord * vec2(127.0 / 128.0) + vec2(0.5 / 128.0);
|
|
float noise = textureLod(noisetex, texel, 0.0).r;
|
|
// Temporal interleaving
|
|
return fract(noise + frame * 0.03125);
|
|
}
|
|
|
|
// Sky lightmap curve (vanilla sky light attenuation)
|
|
float SkyLightmapCurve(float skylight){
|
|
return skylight * skylight * (3.0 - 2.0 * skylight);
|
|
}
|
|
|
|
// Packing a ray for DDA traversal
|
|
struct Ray{
|
|
vec3 ori;
|
|
vec3 dir;
|
|
vec3 rdir;
|
|
vec3 sdir;
|
|
};
|
|
|
|
Ray PackRay(vec3 origin, vec3 direction){
|
|
Ray ray;
|
|
ray.ori = origin;
|
|
ray.dir = direction;
|
|
ray.rdir = 1.0 / direction;
|
|
ray.sdir = fsign(direction);
|
|
return ray;
|
|
}
|
|
|
|
// Smooth min/max
|
|
float smoothMin(float a, float b, float k){
|
|
float h = max(k - abs(a - b), 0.0) / k;
|
|
return min(a, b) - h * h * h * k * (1.0 / 6.0);
|
|
}
|
|
|
|
// Curve function for smooth transitions
|
|
float curve(float x){
|
|
return x * x * (3.0 - 2.0 * x);
|
|
}
|
|
|
|
// Fresnel Schlick
|
|
float FresnelSchlick(float cosTheta, float f0){
|
|
return f0 + (1.0 - f0) * pow(1.0 - cosTheta, 5.0);
|
|
}
|
|
|
|
vec3 FresnelSchlick(vec3 cosTheta, vec3 f0){
|
|
return f0 + (1.0 - f0) * pow(1.0 - cosTheta, vec3(5.0));
|
|
}
|
|
|
|
// GGX normal distribution
|
|
float GGX_D(float NdotH, float roughness){
|
|
float a = roughness * roughness;
|
|
float a2 = a * a;
|
|
float denom = NdotH * NdotH * (a2 - 1.0) + 1.0;
|
|
return a2 / (3.14159 * denom * denom);
|
|
}
|
|
|
|
// Smith geometry (GGX)
|
|
float Smith_G(float NdotV, float NdotL, float roughness){
|
|
float a = roughness * roughness;
|
|
float k = a * 0.5;
|
|
float g1 = NdotV / (NdotV * (1.0 - k) + k);
|
|
float g2 = NdotL / (NdotL * (1.0 - k) + k);
|
|
return g1 * g2;
|
|
}
|
|
|
|
// Importance sample GGX
|
|
vec3 ImportanceSampleGGX(vec2 uv, vec3 N, float roughness){
|
|
float a = roughness * roughness;
|
|
float phi = uv.x * 6.283185;
|
|
float cosTheta = sqrt((1.0 - uv.y) / (1.0 + (a * a - 1.0) * uv.y));
|
|
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
|
|
|
|
vec3 H = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
|
|
|
|
// Tangent space to world
|
|
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
|
vec3 T = normalize(cross(up, N));
|
|
vec3 B = cross(N, T);
|
|
|
|
return normalize(T * H.x + B * H.y + N * H.z);
|
|
}
|
|
|
|
// Cosine-weighted hemisphere sampling (for diffuse)
|
|
vec3 SampleHemisphere(vec2 uv, vec3 N){
|
|
float phi = uv.x * 6.283185;
|
|
float cosTheta = sqrt(uv.y);
|
|
float sinTheta = sqrt(1.0 - uv.y);
|
|
|
|
vec3 dir = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
|
|
|
|
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
|
vec3 T = normalize(cross(up, N));
|
|
vec3 B = cross(N, T);
|
|
|
|
return normalize(T * dir.x + B * dir.y + N * dir.z);
|
|
}
|
|
|
|
#endif |