Initial commit: Minecraft 光追着色器包(从零实现的 path tracing)

This commit is contained in:
WpyQwq
2026-09-19 12:06:22 +08:00
commit 59e30822f8
314 changed files with 9259 additions and 0 deletions
+213
View File
@@ -0,0 +1,213 @@
#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