Initial commit: Minecraft 光追着色器包(从零实现的 path tracing)
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
// MinecraftPT — Block Light
|
||||
// Maps vanilla block light level to physical light, with per-block colors.
|
||||
|
||||
#ifndef BLOCKLIGHT_GLSL
|
||||
#define BLOCKLIGHT_GLSL
|
||||
|
||||
// Convert lightmap blocklight (0-1) to physical light intensity
|
||||
float BlocklightFromLightmap(float blocklight){
|
||||
return pow(blocklight, 2.0) * BLOCKLIGHT_BRIGHTNESS;
|
||||
}
|
||||
|
||||
// Get the block light color for a material
|
||||
vec3 BlocklightColor(float materialID){
|
||||
// Warm torch color by default
|
||||
vec3 color = pow(vec3(COLOR_TORCH_R, COLOR_TORCH_G, COLOR_TORCH_B), vec3(2.2));
|
||||
|
||||
if (materialID == MATID_SOULTORCH || materialID == MATID_COPPER_LANTERN){
|
||||
color = pow(vec3(COLOR_SOULTORCH_R, COLOR_SOULTORCH_G, COLOR_SOULTORCH_B), vec3(2.2));
|
||||
}else if (materialID == MATID_AMETHYST){
|
||||
color = pow(vec3(COLOR_AMETHYST_R, COLOR_AMETHYST_G, COLOR_AMETHYST_B), vec3(2.2));
|
||||
}else if (materialID == MATID_FIRE){
|
||||
color = pow(vec3(COLOR_FIRE_R, COLOR_FIRE_G, COLOR_FIRE_B), vec3(2.2));
|
||||
}else if (materialID == MATID_ENDROD){
|
||||
color = pow(vec3(COLOR_ENDROD_R, COLOR_ENDROD_G, COLOR_ENDROD_B), vec3(2.2));
|
||||
}
|
||||
|
||||
return color * BlocklightFromLightmap(0.5);
|
||||
}
|
||||
|
||||
// Physical block light for a lightmap value
|
||||
vec3 Blocklight(vec2 lightmap){
|
||||
// Blocklight color temperature
|
||||
vec3 warmColor = pow(vec3(COLOR_TORCH_R, COLOR_TORCH_G, COLOR_TORCH_B), vec3(2.2));
|
||||
return warmColor * pow(lightmap.x, 2.0) * BLOCKLIGHT_BRIGHTNESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
// MinecraftPT — Held Light
|
||||
// Torch in hand / flashlight illumination.
|
||||
|
||||
#ifndef HELDLIGHT_GLSL
|
||||
#define HELDLIGHT_GLSL
|
||||
|
||||
// Physical held light: torches held in hand or flashlight
|
||||
vec3 GetHeldLight(vec3 worldPos, vec3 worldNormal, out float heldLightShadow){
|
||||
vec3 result = vec3(0.0);
|
||||
heldLightShadow = 1.0;
|
||||
|
||||
#ifdef HELDLIGHT_MODE
|
||||
#if HELDLIGHT_MODE >= 1
|
||||
// Torch in hand position (roughly 0.4, -0.4, 0.6 relative to camera)
|
||||
vec3 heldPos = gbufferModelViewInverse[3].xyz + cameraPosition;
|
||||
vec3 toLight = heldPos - worldPos;
|
||||
float dist = length(toLight);
|
||||
vec3 dir = toLight / max(dist, 1e-4);
|
||||
|
||||
float intensity = exp(-dist * dist * HELDLIGHT_FALLOFF) * HELDLIGHT_BRIGHTNESS;
|
||||
float NdotL = max(dot(worldNormal, dir), 0.0);
|
||||
|
||||
vec3 color = pow(vec3(COLOR_TORCH_R, COLOR_TORCH_G, COLOR_TORCH_B), vec3(2.2));
|
||||
|
||||
result = color * intensity * NdotL;
|
||||
|
||||
#ifdef HELDLIGHT_SHADOW
|
||||
// Simple ray shadow for held light (short distance)
|
||||
heldLightShadow = SimpleShadowTracing(WorldToVoxel(worldPos + worldNormal * 0.1), dir);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — Lighting Constants
|
||||
// Per-frame lighting values computed inline (no SSBO dependency).
|
||||
// These are cheap functions of the sun angle and camera position; computed
|
||||
// per-pass instead of via a shared buffer for maximum loader compatibility.
|
||||
|
||||
#ifndef LIGHTING_CONSTANTS_GLSL
|
||||
#define LIGHTING_CONSTANTS_GLSL
|
||||
|
||||
#include "/Lib/BasicFunctions/PrecomputedAtmosphere.glsl"
|
||||
|
||||
// Sun direction in world space (matches the shadow camera direction)
|
||||
vec3 GetSunDirWorld(){
|
||||
#ifndef DIMENSION_NETHER
|
||||
#ifndef DIMENSION_END
|
||||
return normalize(shadowModelViewInverse2);
|
||||
#else
|
||||
return normalize(shadowModelViewInverse2) * fsign(0.5 - sunAngle);
|
||||
#endif
|
||||
#else
|
||||
return normalize(shadowModelViewInverse2) * fsign(0.5 - sunAngle);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Atmosphere camera position (scaled Earth radius + camera altitude)
|
||||
vec3 GetAtmoCamera(){
|
||||
return vec3(0.0, max(cameraPosition.y, 63.0) * 0.001 + atmosphereModel_bottom_radius, 0.0);
|
||||
}
|
||||
|
||||
// Sun irradiance (direct light color/intensity)
|
||||
vec3 GetSunIrradiance(){
|
||||
vec3 sunDir = GetSunDirWorld();
|
||||
vec3 moon, sunSky, moonSky;
|
||||
return GetSunAndSkyIrradiance(GetAtmoCamera(), sunDir, -sunDir, moon, sunSky, moonSky);
|
||||
}
|
||||
|
||||
vec3 GetMoonIrradiance(){
|
||||
vec3 sunDir = GetSunDirWorld();
|
||||
vec3 moon, sunSky, moonSky;
|
||||
GetSunAndSkyIrradiance(GetAtmoCamera(), sunDir, -sunDir, moon, sunSky, moonSky);
|
||||
return moon;
|
||||
}
|
||||
|
||||
vec3 GetCelestialIrradiance(){
|
||||
return GetSunIrradiance() + GetMoonIrradiance();
|
||||
}
|
||||
|
||||
vec3 GetAtmoIrradiance(){
|
||||
vec3 sunDir = GetSunDirWorld();
|
||||
vec3 moon, sunSky, moonSky;
|
||||
GetSunAndSkyIrradiance(GetAtmoCamera(), sunDir, -sunDir, moon, sunSky, moonSky);
|
||||
return sunSky + moonSky;
|
||||
}
|
||||
|
||||
// Cloud-altitude irradiances
|
||||
vec3 GetCloudSunIrradiance(){
|
||||
vec3 sunDir = GetSunDirWorld();
|
||||
vec3 atmoCamera = vec3(0.0, mix(CLOUD_CLEAR_ALTITUDE, CLOUD_RAIN_ALTITUDE, wetness) * 0.001 + atmosphereModel_bottom_radius, 0.0);
|
||||
vec3 moon, sunSky, moonSky;
|
||||
return GetSunAndSkyIrradiance(atmoCamera, sunDir, -sunDir, moon, sunSky, moonSky);
|
||||
}
|
||||
|
||||
vec3 GetCloudAtmoIrradiance(){
|
||||
vec3 sunDir = GetSunDirWorld();
|
||||
vec3 atmoCamera = vec3(0.0, mix(CLOUD_CLEAR_ALTITUDE, CLOUD_RAIN_ALTITUDE, wetness) * 0.001 + atmosphereModel_bottom_radius, 0.0);
|
||||
vec3 moon, sunSky, moonSky;
|
||||
GetSunAndSkyIrradiance(atmoCamera, sunDir, -sunDir, moon, sunSky, moonSky);
|
||||
return sunSky + moonSky;
|
||||
}
|
||||
|
||||
// Moon/sun phase for fog time factor
|
||||
vec2 GetFogTimeFactor(){
|
||||
vec3 sunDir = GetSunDirWorld();
|
||||
float timeNoon = pow(1.0 - (clamp(sunDir.y, 0.2, 0.99) - 0.2) / 0.8, 6.0);
|
||||
float moonlightStrength = curve(saturate(sunDir.y * -5.0));
|
||||
return vec2(timeNoon, moonlightStrength);
|
||||
}
|
||||
|
||||
// Dimension-aware irradiance override
|
||||
vec3 GetDimensionAmbient(){
|
||||
#ifdef DIMENSION_NETHER
|
||||
return vec3(0.08, 0.02, 0.01) * NETHER_BRIGHTNESS;
|
||||
#elif defined DIMENSION_END
|
||||
return vec3(0.02, 0.02, 0.04);
|
||||
#else
|
||||
return GetAtmoIrradiance();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
// MinecraftPT — Nether Color
|
||||
// Dimension-specific color and lighting adjustments.
|
||||
|
||||
#ifndef NETHER_COLOR_GLSL
|
||||
#define NETHER_COLOR_GLSL
|
||||
|
||||
vec3 GetDimensionSkylight(vec3 skyColor){
|
||||
#ifdef DIMENSION_NETHER
|
||||
return skyColor * 0.4;
|
||||
#elif defined DIMENSION_END
|
||||
return skyColor * 0.2;
|
||||
#else
|
||||
return skyColor;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,150 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — Precomputed Atmosphere (analytic)
|
||||
// A compact analytic Rayleigh/Mie sky model with precomputed transmittance.
|
||||
// Provides sun/sky irradiance for the scene and sky radiance for the panorama.
|
||||
|
||||
#ifndef PRECOMPUTED_ATMOSPHERE_GLSL
|
||||
#define PRECOMPUTED_ATMOSPHERE_GLSL
|
||||
|
||||
// Earth-like atmosphere constants (scaled)
|
||||
const float atmosphereModel_bottom_radius = 6360.0;
|
||||
const float atmosphereModel_top_radius = 6420.0;
|
||||
|
||||
const vec3 wavelengths = vec3(680.0, 550.0, 440.0); // nm
|
||||
const vec3 betaRayleigh = vec3(5.802, 13.558, 33.1) * 1e-6;
|
||||
const float betaMie = 3.996e-6;
|
||||
const float mieG = 0.8;
|
||||
|
||||
vec3 RayleighPhase(float cosTheta){
|
||||
return 3.0 / (16.0 * 3.14159265) * (1.0 + cosTheta * cosTheta);
|
||||
}
|
||||
|
||||
vec3 MiePhase(float cosTheta){
|
||||
float g = mieG;
|
||||
float g2 = g * g;
|
||||
return 3.0 / (8.0 * 3.14159265) * ((1.0 - g2) * (1.0 + cosTheta * cosTheta)) /
|
||||
((2.0 + g2) * pow(1.0 + g2 - 2.0 * g * cosTheta, 1.5));
|
||||
}
|
||||
|
||||
// Ground intersection for ray from camera
|
||||
float GroundIntersection(vec3 pos, vec3 dir){
|
||||
float b = dot(pos, dir);
|
||||
float c = dot(pos, pos) - atmosphereModel_bottom_radius * atmosphereModel_bottom_radius;
|
||||
float h = b * b - c;
|
||||
if (h > 0.0){
|
||||
float t = -b - sqrt(h);
|
||||
if (t > 0.0) return t;
|
||||
}
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
float AtmosphereIntersection(vec3 pos, vec3 dir){
|
||||
float b = dot(pos, dir);
|
||||
float c = dot(pos, pos) - atmosphereModel_top_radius * atmosphereModel_top_radius;
|
||||
float h = b * b - c;
|
||||
if (h > 0.0){
|
||||
float t = -b + sqrt(h);
|
||||
if (t > 0.0) return t;
|
||||
}
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
// Optical depth to space (transmittance approximation)
|
||||
vec3 OpticalDepthToSpace(vec3 pos, vec3 dir){
|
||||
float tMax = AtmosphereIntersection(pos, dir);
|
||||
if (tMax < 0.0) return vec3(1e10);
|
||||
|
||||
const int steps = 16;
|
||||
float dt = tMax / float(steps);
|
||||
vec3 opticalDepth = vec3(0.0);
|
||||
|
||||
vec3 p = pos;
|
||||
for (int i = 0; i < steps; i++){
|
||||
float h = length(p) - atmosphereModel_bottom_radius;
|
||||
vec3 density = exp(-h / 8.0) * betaRayleigh + exp(-h / 1.2) * betaMie;
|
||||
opticalDepth += density * dt;
|
||||
p += dir * dt;
|
||||
}
|
||||
|
||||
return opticalDepth;
|
||||
}
|
||||
|
||||
// Sun/sky irradiance at a camera position (simplified single scattering)
|
||||
void GetSunAndSkyIrradiance(vec3 camera, vec3 sunDir, vec3 moonDir,
|
||||
out vec3 colorSunlight, out vec3 colorMoonlight,
|
||||
out vec3 colorSunSkylight, out vec3 colorMoonSkylight){
|
||||
|
||||
vec3 sunColor = vec3(1.0, 0.98, 0.92);
|
||||
vec3 moonColor = vec3(0.5, 0.6, 0.8) * 0.1;
|
||||
|
||||
float sunElevation = sunDir.y;
|
||||
float moonElevation = moonDir.y;
|
||||
|
||||
float sunStrength = curve(saturate(sunElevation * 15.0 + 0.5));
|
||||
float moonStrength = curve(saturate(-sunElevation * 5.0 + 0.5));
|
||||
|
||||
// Sun disk color by elevation (sunset tint)
|
||||
vec3 sunsetTint = mix(vec3(1.0, 0.3, 0.1), vec3(1.0), curve(saturate(sunElevation * 3.0)));
|
||||
sunColor *= sunsetTint;
|
||||
|
||||
colorSunlight = sunColor * sunStrength * SUNLIGHT_INTENSITY;
|
||||
colorMoonlight = moonColor * moonStrength;
|
||||
|
||||
// Sky irradiance: ambient hemisphere light
|
||||
vec3 skyColorDay = vec3(0.55, 0.75, 1.0) * sunStrength * 0.8;
|
||||
vec3 skyColorNight = vec3(0.05, 0.08, 0.15) * 0.3;
|
||||
vec3 skyColorSunset = vec3(1.0, 0.5, 0.3) * curve(saturate(1.0 - abs(sunElevation) * 4.0)) * 0.3;
|
||||
|
||||
colorSunSkylight = skyColorDay + skyColorSunset;
|
||||
colorMoonSkylight = skyColorNight;
|
||||
}
|
||||
|
||||
// Sky radiance for a direction (used for the sky panorama and reflections)
|
||||
vec3 GetSkyRadiance(vec3 dir, vec3 sunDir){
|
||||
dir = normalize(dir);
|
||||
sunDir = normalize(sunDir);
|
||||
|
||||
float cosTheta = dot(dir, sunDir);
|
||||
|
||||
// Horizon / elevation response
|
||||
float elevation = dir.y;
|
||||
|
||||
// Day sky
|
||||
vec3 skyDay = vec3(0.4, 0.62, 0.9) * 0.6;
|
||||
skyDay = mix(skyDay, vec3(0.9, 0.95, 1.0), pow(saturate(elevation), 0.6));
|
||||
skyDay *= 1.0 - exp(-max(elevation, 0.0) * 3.0);
|
||||
|
||||
// Rayleigh scattering glow around sun
|
||||
vec3 rayleigh = RayleighPhase(cosTheta) * betaRayleigh * 1.2;
|
||||
|
||||
// Mie scattering (sun disk)
|
||||
float mie = MiePhase(cosTheta) * betaMie * 20.0;
|
||||
|
||||
// Sun disk itself
|
||||
float sunDisk = exp(-(1.0 - cosTheta) / (2.0 * SUN_ANGULAR_RADIUS * SUN_ANGULAR_RADIUS));
|
||||
|
||||
vec3 sunColor = vec3(1.0, 0.97, 0.9) * SUNLIGHT_INTENSITY;
|
||||
|
||||
// Sunset tint
|
||||
float sunElevation = sunDir.y;
|
||||
sunColor *= mix(vec3(1.0, 0.3, 0.1), vec3(1.0), curve(saturate(sunElevation * 3.0)));
|
||||
|
||||
float sunVisible = curve(saturate(sunElevation * 15.0 + 0.5));
|
||||
|
||||
vec3 radiance = skyDay;
|
||||
radiance += sunColor * (rayleigh + mie) * sunVisible;
|
||||
radiance += sunColor * sunDisk * sunVisible * 80.0;
|
||||
|
||||
// Night sky
|
||||
float night = 1.0 - curve(saturate(sunElevation * 10.0 + 0.5));
|
||||
radiance += vec3(0.02, 0.03, 0.06) * night;
|
||||
|
||||
// Horizon haze
|
||||
float horizon = exp(-abs(elevation) * 4.0);
|
||||
radiance += vec3(0.9, 0.7, 0.5) * horizon * sunVisible * 0.1;
|
||||
|
||||
return radiance;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
// MinecraftPT — Sunlight & Shadow
|
||||
// Direct sunlight with RTWSM warped shadow map sampling and voxel shadow tracing.
|
||||
|
||||
#ifndef SUNLIGHT_SHADOW_GLSL
|
||||
#define SUNLIGHT_SHADOW_GLSL
|
||||
|
||||
#include "/Lib/RTWSM/SampleWarp.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
|
||||
// Sample the warped shadow map
|
||||
float SampleShadowMap(vec3 shadowPos){
|
||||
vec2 shadowCoord = shadowPos.xy * 0.5 + 0.5;
|
||||
vec3 shadowUv = vec3(UnshiftShadowScreenPos(shadowCoord), shadowPos.z * 0.5 + 0.5);
|
||||
|
||||
float shadow = 0.0;
|
||||
float depth = shadowUv.z;
|
||||
|
||||
#ifdef SHADOW_QUALITY
|
||||
#if SHADOW_QUALITY >= 2
|
||||
// 3x3 PCF
|
||||
for (int i = -1; i <= 1; i++){
|
||||
for (int j = -1; j <= 1; j++){
|
||||
vec2 sampleCoord = shadowUv.xy + vec2(i, j) * shadowPixelSize;
|
||||
shadow += step(texelFetch(shadowcolor0, ivec2(sampleCoord * shadowSize), 0).a, depth) * (1.0 / 9.0);
|
||||
}}
|
||||
#else
|
||||
shadow = step(texelFetch(shadowcolor0, ivec2(shadowUv.xy * shadowSize), 0).a, depth);
|
||||
#endif
|
||||
#else
|
||||
shadow = step(texelFetch(shadowcolor0, ivec2(shadowUv.xy * shadowSize), 0).a, depth);
|
||||
#endif
|
||||
|
||||
return shadow;
|
||||
}
|
||||
|
||||
// Full sunlight evaluation: shadow map + optional voxel shadow tracing
|
||||
float GetSunShadow(vec3 viewPos, vec3 worldPos, vec3 vertexNormal, float lightmap){
|
||||
float shadow = 1.0;
|
||||
|
||||
#ifdef PT_SHADOW
|
||||
vec3 shadowDir = normalize(shadowModelViewInverse2);
|
||||
shadow = ShadowTracing(viewPos, worldPos, vertexNormal, shadowDir, lightmap);
|
||||
#else
|
||||
// Shadow map path
|
||||
vec4 shadowPos = shadowProjection * shadowModelView * vec4(worldPos, 1.0);
|
||||
if (shadowPos.w > 0.0){
|
||||
vec3 shadowNdc = shadowPos.xyz / shadowPos.w;
|
||||
if (all(lessThan(abs(shadowNdc.xy), vec2(1.0)))){
|
||||
shadow = SampleShadowMap(shadowNdc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return shadow;
|
||||
}
|
||||
|
||||
// Direct sun light for a surface
|
||||
vec3 GetSunlight(vec3 viewPos, vec3 worldPos, vec3 vertexNormal, vec3 worldNormal, float lightmap){
|
||||
float shadow = GetSunShadow(viewPos, worldPos, vertexNormal, lightmap);
|
||||
float NdotL = max(dot(worldNormal, GetSunDirWorld()), 0.0);
|
||||
|
||||
vec3 sunColor = GetSunIrradiance();
|
||||
#ifdef COLORED_SHADOWS
|
||||
// Sample shadow albedo for colored shadows (subtle)
|
||||
vec3 shadowAlbedo = vec3(0.0);
|
||||
sunColor *= 1.0 - shadowAlbedo * 0.3;
|
||||
#endif
|
||||
|
||||
return sunColor * shadow * NdotL;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
// MinecraftPT — Temporal Noise
|
||||
// Blue noise sampling with temporal interleaving, used for dithering and ray offsets.
|
||||
|
||||
#ifndef TEMPORAL_NOISE_GLSL
|
||||
#define TEMPORAL_NOISE_GLSL
|
||||
|
||||
float BlueNoiseTemporal(){
|
||||
vec2 coord = (gl_FragCoord.xy + 0.5) / screenSize;
|
||||
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;
|
||||
return fract(noise + frameCounter * 0.03125);
|
||||
}
|
||||
|
||||
vec2 BlueNoiseTemporal2(){
|
||||
vec2 coord = (gl_FragCoord.xy + 0.5) / screenSize;
|
||||
coord = fract(coord * vec2(128.0, 128.0) + 0.5);
|
||||
vec2 texel = coord * vec2(127.0 / 128.0) + vec2(0.5 / 128.0);
|
||||
vec2 noise = textureLod(noisetex, texel, 0.0).rg;
|
||||
return fract(noise + frameCounter * 0.03125);
|
||||
}
|
||||
|
||||
// Interleaved gradient noise
|
||||
float InterleavedNoise(vec2 pos){
|
||||
vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189);
|
||||
return fract(magic.z * fract(dot(pos, magic.xy)));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
// MinecraftPT — Vanilla Composite helpers
|
||||
// Sky/cloud colors approximating vanilla for transitions and fog.
|
||||
|
||||
#ifndef VANILLA_COMPOSITE_GLSL
|
||||
#define VANILLA_COMPOSITE_GLSL
|
||||
|
||||
vec3 GetVanillaSkyColor(vec3 dir){
|
||||
vec3 skyColor = vec3(0.6, 0.8, 1.0);
|
||||
float horizon = exp(-max(dir.y, 0.0) * 3.0);
|
||||
return mix(skyColor * 0.3, skyColor, 1.0 - horizon);
|
||||
}
|
||||
|
||||
vec3 GetVanillaFogColor(vec3 skyColor, float nightFactor){
|
||||
return mix(skyColor, skyColor * vec3(0.2, 0.25, 0.4), nightFactor);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,221 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — GbufferData structures
|
||||
|
||||
#ifndef GBUFFER_DATA_GLSL
|
||||
#define GBUFFER_DATA_GLSL
|
||||
|
||||
struct Material{
|
||||
float roughness;
|
||||
float metalness;
|
||||
float emissiveness;
|
||||
float scattering;
|
||||
float reflectionStrength;
|
||||
};
|
||||
|
||||
struct GbufferData{
|
||||
vec3 albedo;
|
||||
float albedoAlpha;
|
||||
vec3 worldNormal;
|
||||
vec3 vertexNormal;
|
||||
vec2 lightmap;
|
||||
float materialID;
|
||||
float parallaxShadow;
|
||||
Material material;
|
||||
};
|
||||
|
||||
// Standard material defaults
|
||||
#define material_air Material(1.0, 0.0, 0.0, 0.0, 0.0);
|
||||
#define material_water Material(0.0, 0.018, 0.0, 0.0, 1.0);
|
||||
#define material_glass Material(0.0, 0.04, 0.0, 0.0, 1.0);
|
||||
|
||||
// Material IDs (written to GBuffer)
|
||||
#define MATID_DEFAULT 0.0
|
||||
#define MATID_WATER 1.0
|
||||
#define MATID_STAINEDGLASS 2.0
|
||||
#define MATID_LEAVES 3.0
|
||||
#define MATID_GRASS 4.0 // cross plant
|
||||
#define MATID_HAND 5.0
|
||||
#define MATID_ENTITIES 6.0
|
||||
#define MATID_ENTITIES_PLAYER 7.0
|
||||
#define MATID_ENTITIES_SNOW 8.0
|
||||
#define MATID_LIGHTNING 9.0
|
||||
#define MATID_SKY 10.0
|
||||
#define MATID_TORCH 11.0
|
||||
#define MATID_FIRE 12.0
|
||||
#define MATID_ENDROD 13.0
|
||||
#define MATID_AMETHYST 14.0
|
||||
#define MATID_SOULTORCH 15.0
|
||||
#define MATID_REDSTONE_TORCH 16.0
|
||||
#define MATID_PARTICLE 17.0
|
||||
#define MATID_END_PORTAL 18.0
|
||||
#define MATID_SELECTION 19.0
|
||||
#define MATID_COPPER_LANTERN 20.0
|
||||
#define MATID_BEACON_BEAM 21.0
|
||||
|
||||
// Material from specular texture (LAB PBR)
|
||||
Material MaterialFromTex(vec4 specTex){
|
||||
Material material;
|
||||
|
||||
material.roughness = 1.0 - specTex.r;
|
||||
material.roughness = material.roughness * material.roughness;
|
||||
|
||||
material.metalness = specTex.g;
|
||||
|
||||
material.reflectionStrength = saturate(material.roughness < 0.1 ? 1.0 : pow(specTex.r, 0.2));
|
||||
material.reflectionStrength = saturate(material.reflectionStrength + material.metalness);
|
||||
material.metalness = max(material.metalness, 0.04);
|
||||
|
||||
material.emissiveness = specTex.a;
|
||||
material.scattering = 0.0;
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
// Predefined metal F0 values (from LAB PBR spec)
|
||||
vec3 PredefinedMetalF0(float index){
|
||||
vec3 f0 = vec3(0.0);
|
||||
|
||||
if (abs(index - 230.0 / 255.0) < 2e-4){
|
||||
f0 = vec3(0.56, 0.58, 0.58); // Iron
|
||||
}else if (abs(index - 231.0 / 255.0) < 2e-4){
|
||||
f0 = vec3(1.00, 0.69, 0.28); // Gold
|
||||
}else if (abs(index - 232.0 / 255.0) < 2e-4){
|
||||
f0 = vec3(0.81, 0.82, 0.83); // Aluminum
|
||||
}else if (abs(index - 233.0 / 255.0) < 2e-4){
|
||||
f0 = vec3(0.50, 0.49, 0.49); // Chromium
|
||||
}else if (abs(index - 234.0 / 255.0) < 2e-4){
|
||||
f0 = vec3(0.95, 0.52, 0.35); // Copper
|
||||
}else if (abs(index - 235.0 / 255.0) < 2e-4){
|
||||
f0 = vec3(0.81, 0.83, 0.87); // Lead
|
||||
}else if (abs(index - 236.0 / 255.0) < 2e-4){
|
||||
f0 = vec3(0.66, 0.63, 0.58); // Platinum
|
||||
}else if (abs(index - 237.0 / 255.0) < 2e-4){
|
||||
f0 = vec3(0.95, 0.91, 0.81); // Silver
|
||||
}
|
||||
|
||||
return f0;
|
||||
}
|
||||
|
||||
// Read solid GBuffer data
|
||||
GbufferData GetGbufferDataSoild(ivec2 texelCoord){
|
||||
GbufferData data;
|
||||
|
||||
vec4 gbuffer2 = texelFetch(colortex2, texelCoord, 0);
|
||||
vec4 gbuffer3 = texelFetch(colortex3, texelCoord, 0);
|
||||
|
||||
data.albedo = GammaToLinear(texelFetch(colortex0, texelCoord, 0).rgb);
|
||||
data.albedoAlpha = 1.0;
|
||||
data.worldNormal = DecodeNormal(texelFetch(colortex1, texelCoord, 0).xy);
|
||||
data.vertexNormal = DecodeNormal(texelFetch(colortex1, texelCoord, 0).zw);
|
||||
data.lightmap = gbuffer3.xy;
|
||||
data.materialID = gbuffer2.a;
|
||||
data.parallaxShadow = gbuffer3.b;
|
||||
|
||||
vec4 specTex = vec4(gbuffer2.r, gbuffer2.g, gbuffer2.b, 0.0);
|
||||
data.material = MaterialFromTex(specTex);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Read translucent GBuffer data
|
||||
GbufferData GetGbufferDataTranslucent(ivec2 texelCoord, out bool isSmooth){
|
||||
GbufferData data;
|
||||
|
||||
vec4 gbuffer5 = texelFetch(colortex5, texelCoord, 0);
|
||||
vec4 gbuffer6 = texelFetch(colortex6, texelCoord, 0);
|
||||
|
||||
data.worldNormal = DecodeNormal(gbuffer6.xy);
|
||||
data.vertexNormal = DecodeNormal(gbuffer6.zw);
|
||||
data.lightmap = texelFetch(colortex7, texelCoord, 0).xy;
|
||||
data.materialID = gbuffer6.a;
|
||||
data.parallaxShadow = 1.0;
|
||||
|
||||
isSmooth = false;
|
||||
|
||||
if (data.materialID == MATID_WATER){
|
||||
data.albedo = GammaToLinear(gbuffer5.rgb);
|
||||
data.albedoAlpha = gbuffer5.a;
|
||||
data.material = material_water;
|
||||
isSmooth = true;
|
||||
|
||||
}else if (data.materialID == MATID_STAINEDGLASS){
|
||||
data.albedo = GammaToLinear(gbuffer5.rgb);
|
||||
data.albedoAlpha = gbuffer5.a;
|
||||
data.material = material_glass;
|
||||
isSmooth = true;
|
||||
|
||||
}else if (data.materialID == MATID_PARTICLE){
|
||||
data.albedo = GammaToLinear(gbuffer5.rgb);
|
||||
data.albedoAlpha = gbuffer5.a;
|
||||
data.material = material_air;
|
||||
|
||||
}else{
|
||||
data.albedo = GammaToLinear(texelFetch(colortex0, texelCoord, 0).rgb);
|
||||
data.albedoAlpha = 1.0;
|
||||
vec4 specTex = vec4(gbuffer2.r, gbuffer2.g, gbuffer2.b, 0.0);
|
||||
data.material = MaterialFromTex(specTex);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Material mask utilities
|
||||
struct MaterialMask{
|
||||
float sky;
|
||||
float grass;
|
||||
float leaves;
|
||||
float hand;
|
||||
float entityPlayer;
|
||||
float water;
|
||||
float stainedGlass;
|
||||
float lightning;
|
||||
float entitiesSnow;
|
||||
float endrod;
|
||||
float fire;
|
||||
float torch;
|
||||
float lightSource;
|
||||
float redstoneTorch;
|
||||
float soulTorch;
|
||||
float amethyst;
|
||||
float particle;
|
||||
float endPortal;
|
||||
float selection;
|
||||
};
|
||||
|
||||
MaterialMask CalculateMasks(float materialIDs){
|
||||
MaterialMask mask;
|
||||
|
||||
mask.sky = float(materialIDs == MATID_SKY);
|
||||
mask.grass = float(materialIDs == MATID_GRASS || materialIDs == MATID_BEACON_BEAM);
|
||||
mask.leaves = float(materialIDs == MATID_LEAVES);
|
||||
mask.hand = float(materialIDs == MATID_HAND);
|
||||
mask.water = float(materialIDs == MATID_WATER);
|
||||
mask.stainedGlass = float(materialIDs == MATID_STAINEDGLASS);
|
||||
mask.entityPlayer = float(materialIDs == MATID_ENTITIES_PLAYER);
|
||||
mask.entitiesSnow = float(materialIDs == MATID_ENTITIES_SNOW || materialIDs == MATID_BEACON_BEAM);
|
||||
mask.lightning = float(materialIDs == MATID_LIGHTNING);
|
||||
mask.endrod = float(materialIDs == MATID_ENDROD);
|
||||
mask.fire = float(materialIDs == MATID_FIRE);
|
||||
mask.torch = float(materialIDs == MATID_TORCH);
|
||||
mask.redstoneTorch = float(materialIDs == MATID_REDSTONE_TORCH);
|
||||
mask.amethyst = float(materialIDs == MATID_AMETHYST);
|
||||
mask.soulTorch = float(materialIDs == MATID_SOULTORCH || materialIDs == MATID_COPPER_LANTERN);
|
||||
mask.particle = float(materialIDs == MATID_PARTICLE);
|
||||
mask.endPortal = float(materialIDs == MATID_END_PORTAL);
|
||||
mask.selection = float(materialIDs == MATID_SELECTION);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
void ApplyMaterial(inout Material material, in MaterialMask materialMask, inout bool isSmooth){
|
||||
if (materialMask.water > 0.5){
|
||||
material = material_water;
|
||||
isSmooth = true;
|
||||
}else if (materialMask.stainedGlass > 0.5){
|
||||
material = material_glass;
|
||||
isSmooth = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
// MinecraftPT — Bloom CS (SIG)
|
||||
// Bloom sprite / glare generation (compute shader utility).
|
||||
|
||||
#ifndef BLOOM_CS_SIG_GLSL
|
||||
#define BLOOM_CS_SIG_GLSL
|
||||
|
||||
// Bloom glare from bright pixels
|
||||
void EmitBloomGlare(ivec2 texel, vec3 color, float intensity){
|
||||
// Simple bloom spike (cross pattern)
|
||||
// This is a placeholder — actual implementation samples and adds to bloom buffer
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
// MinecraftPT — Cloud Shadow
|
||||
// Cloud shadow projection onto the ground from the cloud layer.
|
||||
|
||||
#ifndef CLOUD_SHADOW_GLSL
|
||||
uniform sampler3D CloudNoise3D;
|
||||
#define CLOUD_SHADOW_GLSL
|
||||
|
||||
float GetCloudShadow(vec3 worldPos){
|
||||
float cloudAlt = mix(CLOUD_CLEAR_ALTITUDE, CLOUD_RAIN_ALTITUDE, wetness);
|
||||
float cloudDensity = mix(CLOUD_CLEAR_DENSITY, CLOUD_RAIN_DENSITY, wetness);
|
||||
|
||||
// Project ground position onto cloud layer
|
||||
vec3 shadowDir = normalize(GetSunDirWorld());
|
||||
vec3 cloudPos = worldPos + shadowDir * (cloudAlt - worldPos.y) / shadowDir.y;
|
||||
|
||||
// Sample cloud density at that position
|
||||
vec2 p = cloudPos.xz * CLOUD_BASE_NOISE_SCALE + frameTimeCounter * 0.001 * CLOUD_SPEED;
|
||||
float n = textureLod(CloudNoise3D, vec3(p, 0.2), 0.0).r;
|
||||
|
||||
float shadow = 1.0 - saturate((n - 0.5) * cloudDensity * 2.0 * CLOUD_SHADOW);
|
||||
|
||||
return shadow;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
// MinecraftPT — Depth of Field
|
||||
// Circle of confusion computation and bokeh blur.
|
||||
|
||||
#ifndef DOF_GLSL
|
||||
#define DOF_GLSL
|
||||
|
||||
// Compute CoC (circle of confusion) for a fragment
|
||||
float GetCoC(float depth, float focalDepth){
|
||||
float focus = focalDepth;
|
||||
float aperture = DOF_BLUR;
|
||||
float coc = abs(depth - focus) / focus * aperture * DOF_MAX_COC;
|
||||
return clamp(coc, 0.0, DOF_MAX_COC);
|
||||
}
|
||||
|
||||
// Simple bokeh blur (gather)
|
||||
vec3 DofBlur(vec2 texelCoord, float coc){
|
||||
vec3 color = vec3(0.0);
|
||||
float weight = 0.0;
|
||||
|
||||
int radius = int(min(coc, 8.0)) + 1;
|
||||
for (int i = -radius; i <= radius; i++){
|
||||
for (int j = -radius; j <= radius; j++){
|
||||
float dist = length(vec2(i, j));
|
||||
if (dist > coc) continue;
|
||||
|
||||
vec2 coord = texelCoord + vec2(i, j);
|
||||
vec3 sampleColor = texelFetch(colortex12, ivec2(coord), 0).rgb;
|
||||
float w = max(0.0, 1.0 - dist / coc);
|
||||
|
||||
color += sampleColor * w;
|
||||
weight += w;
|
||||
}}
|
||||
|
||||
return weight > 0.0 ? color / weight : color;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — End Sky
|
||||
// End dimension sky: stars, planet, accretion disc around black hole.
|
||||
|
||||
#ifndef END_SKY_GLSL
|
||||
#define END_SKY_GLSL
|
||||
|
||||
vec3 GetEndSky(vec3 dir, vec3 sunDir){
|
||||
dir = normalize(dir);
|
||||
|
||||
// Dark base
|
||||
vec3 color = vec3(0.01, 0.01, 0.02);
|
||||
|
||||
// Stars (hash-based)
|
||||
float stars = 0.0;
|
||||
vec3 starDir = dir;
|
||||
for (int i = 0; i < 32; i++){
|
||||
vec3 seed = vec3(i * 0.1, 0.5, 0.7);
|
||||
vec3 starPos = normalize(hash3(seed.xy) - 0.5);
|
||||
float star = exp(-(1.0 - dot(dir, starPos)) * 1000.0);
|
||||
stars += star * hash1(seed.xy);
|
||||
}
|
||||
color += stars * 0.5;
|
||||
|
||||
// Planet (distant body)
|
||||
vec3 planetDir = normalize(vec3(0.5, 0.3, 0.0));
|
||||
float planet = exp(-(1.0 - dot(dir, planetDir)) * 200.0);
|
||||
color += vec3(0.3, 0.4, 0.6) * planet * 0.8;
|
||||
|
||||
// Accretion disc (around planet)
|
||||
float disc = exp(-abs(dot(normalize(dir.xz), normalize(planetDir.xz))) * 50.0);
|
||||
disc *= step(abs(dir.y), 0.1);
|
||||
color += vec3(1.0, 0.6, 0.2) * disc * 0.5;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
// MinecraftPT — Parallax Occlusion Mapping
|
||||
// Steep parallax mapping with PCF soft shadows.
|
||||
|
||||
#ifndef PARALLAX_GLSL
|
||||
#define PARALLAX_GLSL
|
||||
|
||||
// Steep parallax mapping
|
||||
vec2 ParallaxMapping(vec2 texcoord, vec3 viewDir){
|
||||
float height = texture(tex, texcoord).a;
|
||||
vec2 delta = viewDir.xy / viewDir.z * PARALLAX_DEPTH;
|
||||
|
||||
int numLayers = max(1, int(PARALLAX_QUALITY));
|
||||
float layerDepth = 1.0 / float(numLayers);
|
||||
float currentDepth = 0.0;
|
||||
vec2 currentCoord = texcoord;
|
||||
|
||||
for (int i = 0; i < numLayers; i++){
|
||||
currentCoord -= delta * layerDepth;
|
||||
height = texture(tex, currentCoord).a;
|
||||
currentDepth += layerDepth;
|
||||
if (height < currentDepth) break;
|
||||
}
|
||||
|
||||
// Parallax shadow
|
||||
float shadow = 1.0;
|
||||
#ifdef PARALLAX_SHADOW
|
||||
// PCF shadow
|
||||
for (int i = 0; i < PARALLAX_SHADOW_QUALITY; i++){
|
||||
vec2 shadowCoord = currentCoord + delta * float(i) / float(PARALLAX_SHADOW_QUALITY);
|
||||
shadow *= step(currentDepth - layerDepth * float(i) / float(PARALLAX_SHADOW_QUALITY), texture(tex, shadowCoord).a);
|
||||
}
|
||||
#endif
|
||||
|
||||
return currentCoord;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
// MinecraftPT — Planar Clouds
|
||||
// Simple 2D cloud layer rendered as a plane at altitude.
|
||||
|
||||
#ifndef PLANAR_CLOUDS_GLSL
|
||||
#define PLANAR_CLOUDS_GLSL
|
||||
|
||||
// Sample cloud density at a world XZ position (2D noise + coverage)
|
||||
float GetPlanarCloudDensity(vec2 xz, float time, out vec3 cloudColor){
|
||||
// Coverage by weather
|
||||
float coverage = mix(PC_CLEAR_COVERAGE, PC_RAIN_COVERAGE, wetness);
|
||||
float density = mix(PC_CLEAR_DENSITY, PC_RAIN_DENSITY, wetness);
|
||||
float sunlighting = mix(PC_CLEAR_SUNLIGHTING, PC_RAIN_SUNLIGHTING, wetness);
|
||||
float skylighting = mix(PC_CLEAR_SKYLIGHTING, PC_RAIN_SKYLIGHTING, wetness);
|
||||
|
||||
// FBM noise
|
||||
vec2 p = xz * PC_NOISE_SCALE + vec2(time * 0.01, 0.0);
|
||||
float n = 0.0;
|
||||
float amp = 0.5;
|
||||
for (int i = 0; i < 3; i++){
|
||||
n += textureLod(CloudNoise3D, vec3(p, 0.5), 0.0).r * amp;
|
||||
p *= 2.0;
|
||||
amp *= 0.5;
|
||||
}
|
||||
|
||||
float clouds = saturate((n - (1.0 - coverage)) * (1.0 / max(coverage, 0.01)));
|
||||
|
||||
// Cloud color: lit by sun and sky
|
||||
float sunFactor = sunlighting;
|
||||
cloudColor = mix(GetCloudAtmoIrradiance(), GetCloudSunIrradiance(), sunFactor) * clouds
|
||||
+ vec3(1.0) * skylighting * clouds;
|
||||
|
||||
return clouds * density;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
// MinecraftPT — Ripple
|
||||
// Rain-induced ripple normal map for water surfaces.
|
||||
|
||||
#ifndef RIPPLE_GLSL
|
||||
uniform sampler2D ripple2D;
|
||||
#define RIPPLE_GLSL
|
||||
|
||||
vec2 GetRippleNormal(vec3 worldPos, float time){
|
||||
vec2 coord = worldPos.xz * 0.1;
|
||||
vec2 ripple = textureLod(ripple2D, fract(coord + time * 0.02), 0.0).rg;
|
||||
return ripple * 2.0 - 1.0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
// MinecraftPT — Volumetric Fog
|
||||
// Height-based volumetric fog with 3D noise, ray marched in the volumetric pass.
|
||||
|
||||
#ifndef VOLUMETRIC_FOG_GLSL
|
||||
uniform sampler3D CloudNoise3D;
|
||||
#define VOLUMETRIC_FOG_GLSL
|
||||
|
||||
// Fog density at a world position (height + noise)
|
||||
float GetVolumetricFogDensity(vec3 worldPos, float time){
|
||||
float height = worldPos.y;
|
||||
|
||||
// Two-layer height fog
|
||||
float density = VFOG_DENSITY_BASE;
|
||||
density += exp(-(height - VFOG_HEIGHT) * VFOG_FALLOFF) * VFOG_DENSITY;
|
||||
density += exp(-(height - VFOG_HEIGHT_2) * VFOG_FALLOFF * 2.0) * VFOG_DENSITY * 0.5;
|
||||
|
||||
// Noise variation
|
||||
#ifdef VFOG_NOISE_TYPE
|
||||
if (VFOG_NOISE_TYPE > 0){
|
||||
vec3 p = worldPos * vec3(VFOG_NOISE_HORIZONTAL_SCALE, VFOG_NOISE_VERTICAL_SCALE, VFOG_NOISE_HORIZONTAL_SCALE) + vec3(time * 0.01, 0.0, time * 0.008);
|
||||
float n = 0.0;
|
||||
float amp = 0.5;
|
||||
for (int i = 0; i < VFOG_NOISE_OCTAVE; i++){
|
||||
n += textureLod(CloudNoise3D, fract(p), 0.0).r * amp;
|
||||
p *= 2.0;
|
||||
amp *= 0.5;
|
||||
}
|
||||
density *= 1.0 + (n - 0.5) * VFOG_NOISE_COVERAGE * 2.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Rain fog boost
|
||||
density *= 1.0 + wetness * VFOG_RAIN_DENSITY_MUL;
|
||||
|
||||
return max(density, 0.0);
|
||||
}
|
||||
|
||||
// In-scattering color for fog (sun + sky)
|
||||
vec3 GetFogColor(vec3 worldPos, vec3 sunDir){
|
||||
vec3 sunColor = GetSunIrradiance() * VFOG_SUNLIGHT_DENSITY;
|
||||
vec3 skyColor = GetAtmoIrradiance();
|
||||
|
||||
return skyColor + sunColor * 0.5;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
// MinecraftPT — Water Fog
|
||||
// Underwater volumetric fog with scattering colors.
|
||||
|
||||
#ifndef WATER_FOG_GLSL
|
||||
#define WATER_FOG_GLSL
|
||||
|
||||
vec3 GetWaterFogColor(vec3 worldPos){
|
||||
return vec3(WATER_SCATTERING_R, WATER_SCATTERING_G, WATER_SCATTERING_B) * WATER_SCATTERING_DENSITY;
|
||||
}
|
||||
|
||||
float GetWaterFogDensity(vec3 worldPos){
|
||||
return WATER_SCATTERING_DENSITY;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
// MinecraftPT — Water Waves
|
||||
// Gerstner-style water wave normals with multi-octave detail.
|
||||
|
||||
#ifndef WATER_WAVES_GLSL
|
||||
#define WATER_WAVES_GLSL
|
||||
|
||||
vec3 GetWaveNormal(vec3 worldPos, float lightmap){
|
||||
vec2 pos = worldPos.xz;
|
||||
|
||||
float time = frameTimeCounter * 0.05 * WAVE_SPEED;
|
||||
|
||||
// Multi-octave sine waves
|
||||
float wave1 = sin(pos.x * 0.1 * WAVE_SCALE + time) * cos(pos.y * 0.08 * WAVE_SCALE + time * 0.7);
|
||||
float wave2 = sin(pos.x * 0.2 * WAVE_SCALE + time * 1.3) * cos(pos.y * 0.15 * WAVE_SCALE - time * 0.9);
|
||||
float wave3 = sin((pos.x + pos.y) * 0.35 * WAVE_SCALE + time * 1.7) * 0.5;
|
||||
|
||||
// Height field derivatives for normal
|
||||
float dx = cos(pos.x * 0.1 * WAVE_SCALE + time) * 0.1 * WAVE_SCALE * 0.5 * 0.05
|
||||
+ cos(pos.x * 0.2 * WAVE_SCALE + time * 1.3) * 0.2 * WAVE_SCALE * 0.5 * 0.04;
|
||||
float dz = -sin(pos.x * 0.1 * WAVE_SCALE + time) * sin(pos.y * 0.08 * WAVE_SCALE + time * 0.7) * 0.08 * WAVE_SCALE * 0.5 * 0.05
|
||||
- sin(pos.x * 0.2 * WAVE_SCALE + time * 1.3) * sin(pos.y * 0.15 * WAVE_SCALE - time * 0.9) * 0.15 * WAVE_SCALE * 0.5 * 0.04;
|
||||
|
||||
vec3 normal = normalize(vec3(-dx, 1.0, -dz) * WAVE_NORMAL_STRENGTH + vec3(0.0, 1.0 - WAVE_NORMAL_STRENGTH, 0.0));
|
||||
|
||||
return normal;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — Waving Plants
|
||||
// Wind animation for grass, plants, leaves.
|
||||
|
||||
#ifndef WAVING_PLANTS_GLSL
|
||||
#define WAVING_PLANTS_GLSL
|
||||
|
||||
void WavingPlants(inout vec4 worldPos, float lightLevel){
|
||||
float time = frameTimeCounter * 0.05 * WAVING_SPEED;
|
||||
|
||||
// Wind direction
|
||||
vec2 wind = vec2(0.5, 0.3) * sin(time) + vec2(0.2);
|
||||
|
||||
// Amplitude by plant type
|
||||
float amplitude = GRASS_AMPLITUDE;
|
||||
#ifdef IS_LEAVES
|
||||
amplitude = LEAVES_AMPLITUDE;
|
||||
#endif
|
||||
|
||||
float dist = length(worldPos.xyz - gbufferModelViewInverse[3].xyz);
|
||||
float fade = 1.0 - saturate(dist / WAVING_RANGE);
|
||||
|
||||
vec3 vertexPos = worldPos.xyz;
|
||||
|
||||
// Vertex-based wave
|
||||
vec3 offset = vec3(wind * sin(vertexPos.x * 0.3 + vertexPos.z * 0.2 + time * 2.0), 0.0);
|
||||
offset *= vertexPos.y * amplitude * fade;
|
||||
|
||||
// Random per-vertex jitter (height-based)
|
||||
float heightFactor = vertexPos.y;
|
||||
float noise = sin(vertexPos.x * 12.9898 + vertexPos.z * 78.233 + time) * 0.5 + 0.5;
|
||||
offset.x += noise * amplitude * 0.5 * heightFactor * fade;
|
||||
offset.z += noise * amplitude * 0.3 * heightFactor * fade;
|
||||
|
||||
worldPos.xyz += offset;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — Diffuse Spatial Filter
|
||||
// Edge-avoiding A-trous wavelet spatial filter. Multi-pass (detail levels).
|
||||
|
||||
#ifndef DIFFUSE_SPATIAL_FILTER_GLSL
|
||||
#define DIFFUSE_SPATIAL_FILTER_GLSL
|
||||
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
// Single A-trous pass at the given step size
|
||||
vec3 DiffuseSpatialPass(vec3 center, vec2 texelCoord, int step){
|
||||
vec3 result = center * 0.25;
|
||||
|
||||
// Center depth and normal for edge detection
|
||||
float depth = texelFetch(depthtex0, texelCoord * 2.0, 0).r;
|
||||
vec3 normal = DecodeNormal(texelFetch(colortex1, texelCoord * 2.0, 0).xy);
|
||||
vec3 centerAlbedo = texelFetch(colortex0, texelCoord * 2.0, 0).rgb;
|
||||
|
||||
// Reconstruct view position for depth edge weight
|
||||
vec4 viewPos = gbufferProjectionInverse * vec4(texelCoord * 2.0 / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||
viewPos.xyz /= viewPos.w;
|
||||
|
||||
float weightSum = 0.25;
|
||||
|
||||
vec2 offsets[4] = vec2[4](vec2(1.0, 0.0), vec2(-1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, -1.0));
|
||||
|
||||
for (int i = 0; i < 4; i++){
|
||||
vec2 coord = texelCoord + offsets[i] * float(step);
|
||||
vec3 sampleColor = texelFetch(colortex7, ivec2(coord), 0).rgb;
|
||||
|
||||
float sampleDepth = texelFetch(depthtex0, coord * 2.0, 0).r;
|
||||
vec3 sampleNormal = DecodeNormal(texelFetch(colortex1, coord * 2.0, 0).xy);
|
||||
|
||||
// Edge-avoiding weights
|
||||
float depthWeight = exp(-abs(depth - sampleDepth) * PT_DIFFUSE_SPATIAL_FILTER_DEPTH_WEIGHT * 100.0);
|
||||
float normalWeight = pow(max(dot(normal, sampleNormal), 0.0), 8.0 * PT_DIFFUSE_SPATIAL_FILTER_NORMAL_WEIGHT + 1.0);
|
||||
float luminanceWeight = exp(-abs(luminance(center) - luminance(sampleColor)) * PT_DIFFUSE_SPATIAL_FILTER_LUMINANCE_WEIGHT * 10.0);
|
||||
|
||||
float weight = depthWeight * normalWeight * luminanceWeight;
|
||||
|
||||
result += sampleColor * weight;
|
||||
weightSum += weight;
|
||||
}
|
||||
|
||||
return result / weightSum;
|
||||
}
|
||||
|
||||
// Run the spatial filter chain (detail levels)
|
||||
vec3 DiffuseSpatialFilter(vec2 texelCoord){
|
||||
vec3 color = texelFetch(colortex7, ivec2(texelCoord), 0).rgb;
|
||||
|
||||
int levels = 1 + int(PT_DIFFUSE_SPATIAL_FILTER_DETAIL);
|
||||
|
||||
int step = 1;
|
||||
for (int i = 0; i < levels; i++){
|
||||
color = DiffuseSpatialPass(color, texelCoord, step);
|
||||
step *= 2;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
// MinecraftPT — Diffuse Temporal Filter
|
||||
// Reprojects the previous frame's denoised diffuse result using motion vectors
|
||||
// and accumulates with the current noisy frame.
|
||||
|
||||
#ifndef DIFFUSE_TEMPORAL_FILTER_GLSL
|
||||
#define DIFFUSE_TEMPORAL_FILTER_GLSL
|
||||
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
vec3 DiffuseTemporalAccumulate(vec3 current, vec2 texelCoord, vec3 prevColor){
|
||||
vec2 motionVec = texelFetch(colortex10, ivec2(texelCoord), 0).xy;
|
||||
vec2 prevCoord = (texelCoord + 0.5) - motionVec;
|
||||
|
||||
// Validate reprojection: depth comparison
|
||||
float depth = texelFetch(depthtex0, texelCoord * 2.0, 0).r;
|
||||
float prevDepth = textureLod(prevDepth2D, prevCoord / (screenSize * 0.5), 0.0).r;
|
||||
|
||||
float depthValid = step(abs(depth - prevDepth), 0.05 * depth + 0.001);
|
||||
|
||||
// History confidence based on accumulation count
|
||||
float accum = 1.0 / float(PT_DIFFUSE_TEMPORAL_MAX_ACCUM);
|
||||
|
||||
// Sample previous
|
||||
vec3 history = textureLod(colortex7, prevCoord / (screenSize * 0.5), 0.0).rgb;
|
||||
|
||||
// Neighborhood clamp to reduce ghosting
|
||||
vec3 minColor = history;
|
||||
vec3 maxColor = history;
|
||||
for (int i = -1; i <= 1; i++){
|
||||
for (int j = -1; j <= 1; j++){
|
||||
vec3 c = textureLod(colortex7, (prevCoord + vec2(i, j)) / (screenSize * 0.5), 0.0).rgb;
|
||||
minColor = min(minColor, c);
|
||||
maxColor = max(maxColor, c);
|
||||
}}
|
||||
history = clamp(history, minColor, maxColor);
|
||||
|
||||
float blend = mix(accum, 1.0, depthValid * PT_DIFFUSE_TEMPORAL_HISTORY_FIX * 0.5);
|
||||
|
||||
return mix(current, history, blend * (1.0 - accum));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — Diffuse Variance Estimation
|
||||
// Computes luminance moments to drive temporal accumulation and firefly rejection.
|
||||
|
||||
#ifndef DIFFUSE_VARIANCE_ESTIMATION_GLSL
|
||||
#define DIFFUSE_VARIANCE_ESTIMATION_GLSL
|
||||
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
vec2 DiffuseEstimateVariance(vec3 color, vec2 texelCoord){
|
||||
float lum = luminance(color);
|
||||
float lum2 = lum * lum;
|
||||
|
||||
// Local variance from neighbors (5-tap)
|
||||
float variance = 0.0;
|
||||
for (int i = -1; i <= 1; i++){
|
||||
for (int j = -1; j <= 1; j++){
|
||||
if (i == 0 && j == 0) continue;
|
||||
vec3 c = texelFetch(colortex7, ivec2(texelCoord) + ivec2(i, j), 0).rgb;
|
||||
float l = luminance(c);
|
||||
variance += (l - lum) * (l - lum);
|
||||
}}
|
||||
variance /= 8.0;
|
||||
|
||||
// Clamp fireflies
|
||||
float firefly = step(1.0, lum / max(variance * 4.0, 0.001));
|
||||
|
||||
return vec2(lum, firefly);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — Specular Spatial Filter
|
||||
// Edge-avoiding spatial filter for specular reflections (fewer passes than diffuse).
|
||||
|
||||
#ifndef SPECULAR_SPATIAL_FILTER_GLSL
|
||||
#define SPECULAR_SPATIAL_FILTER_GLSL
|
||||
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
vec3 SpecularSpatialPass(vec3 center, vec2 texelCoord, int step){
|
||||
vec3 result = center * 0.25;
|
||||
|
||||
float depth = texelFetch(depthtex0, texelCoord * 2.0, 0).r;
|
||||
vec3 normal = DecodeNormal(texelFetch(colortex1, texelCoord * 2.0, 0).xy);
|
||||
|
||||
float weightSum = 0.25;
|
||||
|
||||
vec2 offsets[4] = vec2[4](vec2(1.0, 0.0), vec2(-1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, -1.0));
|
||||
|
||||
for (int i = 0; i < 4; i++){
|
||||
vec2 coord = texelCoord + offsets[i] * float(step);
|
||||
vec3 sampleColor = texelFetch(colortex11, ivec2(coord), 0).rgb;
|
||||
|
||||
float sampleDepth = texelFetch(depthtex0, coord * 2.0, 0).r;
|
||||
vec3 sampleNormal = DecodeNormal(texelFetch(colortex1, coord * 2.0, 0).xy);
|
||||
|
||||
float depthWeight = exp(-abs(depth - sampleDepth) * PT_DIFFUSE_SPATIAL_FILTER_DEPTH_WEIGHT * 100.0);
|
||||
float normalWeight = pow(max(dot(normal, sampleNormal), 0.0), 8.0 * PT_DIFFUSE_SPATIAL_FILTER_NORMAL_WEIGHT + 1.0);
|
||||
float luminanceWeight = exp(-abs(luminance(center) - luminance(sampleColor)) * PT_DIFFUSE_SPATIAL_FILTER_LUMINANCE_WEIGHT * 10.0);
|
||||
|
||||
float weight = depthWeight * normalWeight * luminanceWeight;
|
||||
|
||||
result += sampleColor * weight;
|
||||
weightSum += weight;
|
||||
}
|
||||
|
||||
return result / weightSum;
|
||||
}
|
||||
|
||||
vec3 SpecularSpatialFilter(vec2 texelCoord){
|
||||
vec3 color = texelFetch(colortex11, ivec2(texelCoord), 0).rgb;
|
||||
|
||||
int levels = 1 + int(PT_DIFFUSE_SPATIAL_FILTER_DETAIL) / 2;
|
||||
|
||||
int step = 1;
|
||||
for (int i = 0; i < levels; i++){
|
||||
color = SpecularSpatialPass(color, texelCoord, step);
|
||||
step *= 2;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
// MinecraftPT — Specular Temporal Filter
|
||||
// Temporal accumulation for specular reflections with reprojection.
|
||||
|
||||
#ifndef SPECULAR_TEMPORAL_FILTER_GLSL
|
||||
#define SPECULAR_TEMPORAL_FILTER_GLSL
|
||||
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
vec3 SpecularTemporalAccumulate(vec3 current, vec2 texelCoord){
|
||||
vec2 motionVec = texelFetch(colortex10, ivec2(texelCoord), 0).xy;
|
||||
vec2 prevCoord = (texelCoord + 0.5) - motionVec;
|
||||
|
||||
float depth = texelFetch(depthtex0, texelCoord * 2.0, 0).r;
|
||||
float prevDepth = textureLod(prevDepth2D, prevCoord / (screenSize * 0.5), 0.0).r;
|
||||
|
||||
float depthValid = step(abs(depth - prevDepth), 0.05 * depth + 0.001);
|
||||
|
||||
float accum = 1.0 / float(PT_DIFFUSE_TEMPORAL_MAX_ACCUM);
|
||||
|
||||
vec3 history = textureLod(colortex11, prevCoord / (screenSize * 0.5), 0.0).rgb;
|
||||
|
||||
// Neighborhood clamp
|
||||
vec3 minColor = history;
|
||||
vec3 maxColor = history;
|
||||
for (int i = -1; i <= 1; i++){
|
||||
for (int j = -1; j <= 1; j++){
|
||||
vec3 c = textureLod(colortex11, (prevCoord + vec2(i, j)) / (screenSize * 0.5), 0.0).rgb;
|
||||
minColor = min(minColor, c);
|
||||
maxColor = max(maxColor, c);
|
||||
}}
|
||||
history = clamp(history, minColor, maxColor);
|
||||
|
||||
float blend = mix(accum, 1.0, depthValid * PT_DIFFUSE_TEMPORAL_HISTORY_FIX * 0.5);
|
||||
|
||||
return mix(current, history, blend * (1.0 - accum));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
// MinecraftPT — SampleIRC
|
||||
// Sampling the irradiance cache: a 3D grid of pre-computed diffuse irradiance
|
||||
// used to cheaply evaluate indirect diffuse light.
|
||||
|
||||
#ifndef SAMPLE_IRC_GLSL
|
||||
#define SAMPLE_IRC_GLSL
|
||||
|
||||
// Sample irradiance cache at a world position (trilinear)
|
||||
vec3 SampleIRC(vec3 worldPos){
|
||||
vec3 voxelPos = WorldToVoxel(worldPos);
|
||||
|
||||
vec3 coord = voxelPos / float(ircResolution);
|
||||
|
||||
if (clamp(coord, vec3(0.0), vec3(1.0)) == coord){
|
||||
coord *= float(ircResolution) - 1.0;
|
||||
|
||||
vec3 base = floor(coord);
|
||||
vec3 frac = coord - base;
|
||||
ivec3 i0 = ivec3(base);
|
||||
ivec3 i1 = min(i0 + 1, ivec3(ircResolution - 1));
|
||||
|
||||
vec3 c000 = texelFetch(irradianceCache3D, i0, 0).rgb;
|
||||
vec3 c100 = texelFetch(irradianceCache3D, ivec3(i1.x, i0.y, i0.z), 0).rgb;
|
||||
vec3 c010 = texelFetch(irradianceCache3D, ivec3(i0.x, i1.y, i0.z), 0).rgb;
|
||||
vec3 c110 = texelFetch(irradianceCache3D, ivec3(i1.x, i1.y, i0.z), 0).rgb;
|
||||
vec3 c001 = texelFetch(irradianceCache3D, ivec3(i0.x, i0.y, i1.z), 0).rgb;
|
||||
vec3 c101 = texelFetch(irradianceCache3D, ivec3(i1.x, i0.y, i1.z), 0).rgb;
|
||||
vec3 c011 = texelFetch(irradianceCache3D, ivec3(i0.x, i1.y, i1.z), 0).rgb;
|
||||
vec3 c111 = texelFetch(irradianceCache3D, i1, 0).rgb;
|
||||
|
||||
vec3 x00 = mix(c000, c100, frac.x);
|
||||
vec3 x10 = mix(c010, c110, frac.x);
|
||||
vec3 x01 = mix(c001, c101, frac.x);
|
||||
vec3 x11 = mix(c011, c111, frac.x);
|
||||
vec3 y0 = mix(x00, x10, frac.y);
|
||||
vec3 y1 = mix(x01, x11, frac.y);
|
||||
|
||||
return mix(y0, y1, frac.z);
|
||||
}
|
||||
|
||||
// Outside the cache — fall back to sky ambient
|
||||
return GetCelestialIrradiance() + GetAtmoIrradiance();
|
||||
}
|
||||
|
||||
// Normal-aware IRC sampling (bias by surface normal facing)
|
||||
vec3 SampleIRCNormal(vec3 worldPos, vec3 normal){
|
||||
vec3 irc = SampleIRC(worldPos);
|
||||
// Simple hemisphere shading via normal alignment with up
|
||||
float upFactor = normal.y * 0.5 + 0.5;
|
||||
return irc * (0.5 + 0.5 * upFactor);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — Shadow Tracing
|
||||
// Direct sunlight shadow rays: march from surface toward the sun through the
|
||||
// voxel grid. Soft penumbra via distance-weighted ray length.
|
||||
|
||||
#ifndef SHADOW_TRACING_GLSL
|
||||
#define SHADOW_TRACING_GLSL
|
||||
|
||||
#include "/Lib/PathTracing/Tracer/TracingUtilities.glsl"
|
||||
|
||||
float ShadowTracing(vec3 viewPos, vec3 worldPos, vec3 vertexNormal, vec3 lightVector, float lightMap){
|
||||
float shadow = 1.0;
|
||||
|
||||
vec3 voxelPos = WorldToVoxel(worldPos);
|
||||
voxelPos += vertexNormal * (-viewPos.z * 0.0003);
|
||||
|
||||
if (clamp(voxelPos, vec3(0.0), vec3(voxelResolution)) == voxelPos){
|
||||
lightMap = saturate(1.0 - lightMap * 2.0);
|
||||
vec2 shadowWeight = vec2(
|
||||
4.0 - 2.0 * saturate(lightMap - viewPos.z * 0.01),
|
||||
0.2 + 0.5 * saturate(lightMap - viewPos.z * 0.01)
|
||||
);
|
||||
|
||||
Ray ray = PackRay(voxelPos, lightVector);
|
||||
|
||||
vec3 voxelCoord = floor(ray.ori);
|
||||
vec3 totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
|
||||
float rayLength = 0.0;
|
||||
vec3 tracingNext;
|
||||
|
||||
bool hit = false;
|
||||
|
||||
for (int i = 0; i < 64; i++){
|
||||
if (clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 0.5)) != voxelCoord) break;
|
||||
|
||||
vec4 voxelData = texelFetch(voxelData3D, ivec3(voxelCoord), 0);
|
||||
float voxelID = DecodeVoxelID(voxelData.z);
|
||||
|
||||
// Full block or cutout shape
|
||||
if (voxelID >= 999.0){
|
||||
hit = rayLength > 0.0;
|
||||
}else if (voxelID < 1000.0 && voxelID > 1.0){
|
||||
float rawID = 1000.0 - voxelID;
|
||||
rayLength = minVec3(totalStep);
|
||||
hit = HitShape_Lite(ray, voxelCoord, rawID, rayLength);
|
||||
}
|
||||
|
||||
if (hit){
|
||||
shadow = saturate((rayLength - shadowWeight.y) * shadowWeight.x);
|
||||
break;
|
||||
}
|
||||
|
||||
// Sparse skip
|
||||
float marker = voxelData.z;
|
||||
if (marker > 0.60 && marker < 0.92){
|
||||
float skipSize = marker > 0.90 ? 8.0 : (marker > 0.70 ? 4.0 : 2.0);
|
||||
vec3 nextBoundary = floor((voxelCoord + 1.0) / skipSize) * skipSize;
|
||||
vec3 distToBoundary = (nextBoundary - voxelCoord) * abs(ray.rdir);
|
||||
float tSkip = minVec3(distToBoundary) + 1e-4;
|
||||
rayLength += tSkip;
|
||||
vec3 stepVec = ray.sdir * abs(ray.rdir) * tSkip;
|
||||
ray.ori += stepVec;
|
||||
voxelCoord = floor(ray.ori);
|
||||
totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
|
||||
continue;
|
||||
}
|
||||
|
||||
rayLength = minVec3(totalStep);
|
||||
tracingNext = step(totalStep, vec3(rayLength));
|
||||
voxelCoord += tracingNext * ray.sdir;
|
||||
totalStep += tracingNext * abs(ray.rdir);
|
||||
}
|
||||
}
|
||||
|
||||
return shadow;
|
||||
}
|
||||
|
||||
// Simplified version for IRC / light sampling (no soft penumbra)
|
||||
float SimpleShadowTracing(vec3 voxelPos, vec3 lightVector){
|
||||
Ray ray = PackRay(voxelPos, lightVector);
|
||||
|
||||
vec3 voxelCoord = floor(ray.ori);
|
||||
vec3 totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
|
||||
float rayLength = 0.0;
|
||||
vec3 tracingNext;
|
||||
|
||||
bool hit = false;
|
||||
|
||||
for (int i = 0; i < 64; i++){
|
||||
if (clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 0.5)) != voxelCoord) break;
|
||||
|
||||
vec4 voxelData = texelFetch(voxelData3D, ivec3(voxelCoord), 0);
|
||||
float voxelID = DecodeVoxelID(voxelData.z);
|
||||
|
||||
if (voxelID >= 999.0){
|
||||
hit = rayLength > 0.0;
|
||||
}else if (voxelID < 1000.0 && voxelID > 1.0){
|
||||
float rawID = 1000.0 - voxelID;
|
||||
rayLength = minVec3(totalStep);
|
||||
hit = HitShape_Lite(ray, voxelCoord, rawID, rayLength);
|
||||
}
|
||||
|
||||
if (hit) break;
|
||||
|
||||
// Sparse skip
|
||||
float marker = voxelData.z;
|
||||
if (marker > 0.60 && marker < 0.92){
|
||||
float skipSize = marker > 0.90 ? 8.0 : (marker > 0.70 ? 4.0 : 2.0);
|
||||
vec3 nextBoundary = floor((voxelCoord + 1.0) / skipSize) * skipSize;
|
||||
vec3 distToBoundary = (nextBoundary - voxelCoord) * abs(ray.rdir);
|
||||
float tSkip = minVec3(distToBoundary) + 1e-4;
|
||||
rayLength += tSkip;
|
||||
vec3 stepVec = ray.sdir * abs(ray.rdir) * tSkip;
|
||||
ray.ori += stepVec;
|
||||
voxelCoord = floor(ray.ori);
|
||||
totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
|
||||
continue;
|
||||
}
|
||||
|
||||
rayLength = minVec3(totalStep);
|
||||
tracingNext = step(totalStep, vec3(rayLength));
|
||||
voxelCoord += tracingNext * ray.sdir;
|
||||
totalStep += tracingNext * abs(ray.rdir);
|
||||
}
|
||||
|
||||
return float(!hit);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,149 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — Specular Tracer
|
||||
// Traces GGX-sampled reflection/refraction rays through the voxel grid and
|
||||
// accumulates the reflected radiance (incl. light sphere contributions).
|
||||
|
||||
#ifndef SPECULAR_TRACER_GLSL
|
||||
#define SPECULAR_TRACER_GLSL
|
||||
|
||||
#include "/Lib/PathTracing/Tracer/TracingUtilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/ShadowTracing.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/SampleIRC.glsl"
|
||||
|
||||
// Panorama: 3:2 cubemap cross. Map direction to face UV.
|
||||
float absX = abs(dir.x), absY = abs(dir.y), absZ = abs(dir.z);
|
||||
float maxAxis = max(absX, max(absY, absZ));
|
||||
|
||||
vec2 uv;
|
||||
vec3 tdir = dir / maxAxis;
|
||||
|
||||
if (maxAxis == absX){
|
||||
uv = vec2(tdir.y * 0.5 + 0.5, tdir.z * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(0.0, 0.5) * vec2(1.0/3.0, 1.0/2.0);
|
||||
if (tdir.x > 0.0){
|
||||
uv = vec2(tdir.y * 0.5 + 0.5, tdir.z * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(1.0/3.0, 0.5/2.0);
|
||||
}
|
||||
}else if (maxAxis == absY){
|
||||
uv = vec2(tdir.x * 0.5 + 0.5, tdir.z * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(2.0/3.0, 0.5/2.0);
|
||||
if (tdir.y > 0.0){
|
||||
uv = vec2(tdir.x * 0.5 + 0.5, tdir.z * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(1.0/3.0, 0.5/2.0);
|
||||
}
|
||||
}else{
|
||||
uv = vec2(tdir.x * 0.5 + 0.5, tdir.y * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(2.0/3.0, 1.5/2.0);
|
||||
if (tdir.z > 0.0){
|
||||
uv = vec2(tdir.x * 0.5 + 0.5, tdir.y * 0.5 + 0.5) / vec2(3.0, 2.0) + vec2(1.0/3.0, 1.5/2.0);
|
||||
}
|
||||
}
|
||||
|
||||
return textureLod(skyBox2D, uv, 0.0).rgb;
|
||||
}
|
||||
|
||||
// Trace a single specular ray and accumulate radiance.
|
||||
// origin: world pos (voxel space handled inside), dir: normalized direction
|
||||
vec3 SpecularTrace(vec3 voxelPos, vec3 dir, float maxDist, vec2 noise){
|
||||
vec3 result = vec3(0.0);
|
||||
|
||||
Ray ray = PackRay(voxelPos, dir);
|
||||
|
||||
vec3 voxelCoord = floor(ray.ori);
|
||||
vec3 totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
|
||||
float rayLength = 0.0;
|
||||
vec3 tracingNext;
|
||||
|
||||
bool hit = false;
|
||||
|
||||
for (int i = 0; i < 128; i++){
|
||||
if (clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 0.5)) != voxelCoord){
|
||||
// Escaped the voxel grid — sample sky
|
||||
result = SampleSkyBox(dir);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rayLength > maxDist){
|
||||
result = SampleSkyBox(dir);
|
||||
break;
|
||||
}
|
||||
|
||||
vec4 voxelData = texelFetch(voxelData3D, ivec3(voxelCoord), 0);
|
||||
float voxelID = DecodeVoxelID(voxelData.z);
|
||||
|
||||
// Light source: accumulate sphere light
|
||||
if (IsLightSphere(voxelID)){
|
||||
result += HitLightShpereReflection(ray, voxelCoord, voxelID, rayLength);
|
||||
rayLength = minVec3(totalStep);
|
||||
tracingNext = step(totalStep, vec3(rayLength));
|
||||
voxelCoord += tracingNext * ray.sdir;
|
||||
totalStep += tracingNext * abs(ray.rdir);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (voxelID >= 999.0){ // Full block
|
||||
// Shade the hit point: sample albedo from atlas, apply lighting
|
||||
vec3 hitPos = ray.ori + ray.dir * rayLength;
|
||||
vec3 hitNormal = -step(vec3(rayLength), totalStep - abs(ray.rdir)) * ray.sdir;
|
||||
vec2 midCoord = voxelData.xy;
|
||||
vec3 albedo = SampleVoxelAlbedo(midCoord, hitPos, hitNormal);
|
||||
|
||||
// Direct light from sun
|
||||
vec3 sunColor = GetSunIrradiance();
|
||||
float sunShadow = SimpleShadowTracing(hitPos + hitNormal * 0.01, GetSunDirWorld());
|
||||
vec3 direct = albedo * sunColor * sunShadow * max(dot(hitNormal, GetSunDirWorld()), 0.0);
|
||||
|
||||
// Sky ambient from IRC
|
||||
vec3 irc = SampleIRC(hitPos);
|
||||
result += direct + irc * albedo * 0.5;
|
||||
|
||||
hit = true;
|
||||
break;
|
||||
}else if (voxelID < 1000.0 && voxelID > 1.0){
|
||||
// Cutout shape
|
||||
float rawID = 1000.0 - voxelID;
|
||||
rayLength = minVec3(totalStep);
|
||||
vec3 n;
|
||||
if (HitShape(ray, voxelCoord, rawID, rayLength, n)){
|
||||
vec3 hitPos = ray.ori + ray.dir * rayLength;
|
||||
vec2 midCoord = voxelData.xy;
|
||||
vec3 albedo = SampleVoxelAlbedo(midCoord, hitPos, n);
|
||||
|
||||
vec3 sunColor = GetSunIrradiance();
|
||||
float sunShadow = SimpleShadowTracing(hitPos + n * 0.01, GetSunDirWorld());
|
||||
vec3 direct = albedo * sunColor * sunShadow * max(dot(n, GetSunDirWorld()), 0.0);
|
||||
|
||||
vec3 irc = SampleIRC(hitPos);
|
||||
result += direct + irc * albedo * 0.5;
|
||||
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Sparse skip
|
||||
float marker = voxelData.z;
|
||||
if (marker > 0.60 && marker < 0.92){
|
||||
float skipSize = marker > 0.90 ? 8.0 : (marker > 0.70 ? 4.0 : 2.0);
|
||||
vec3 nextBoundary = floor((voxelCoord + 1.0) / skipSize) * skipSize;
|
||||
vec3 distToBoundary = (nextBoundary - voxelCoord) * abs(ray.rdir);
|
||||
float tSkip = minVec3(distToBoundary) + 1e-4;
|
||||
rayLength += tSkip;
|
||||
vec3 stepVec = ray.sdir * abs(ray.rdir) * tSkip;
|
||||
ray.ori += stepVec;
|
||||
voxelCoord = floor(ray.ori);
|
||||
totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
|
||||
continue;
|
||||
}
|
||||
|
||||
rayLength = minVec3(totalStep);
|
||||
tracingNext = step(totalStep, vec3(rayLength));
|
||||
voxelCoord += tracingNext * ray.sdir;
|
||||
totalStep += tracingNext * abs(ray.rdir);
|
||||
}
|
||||
|
||||
if (!hit){
|
||||
result = SampleSkyBox(dir);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
// MinecraftPT — Tracing Noise
|
||||
// Noise functions for ray tracing (hash-based, temporally stable).
|
||||
|
||||
#ifndef TRACING_NOISE_GLSL
|
||||
#define TRACING_NOISE_GLSL
|
||||
|
||||
// Per-pixel temporal noise, stable across frames
|
||||
float GetTracingNoise(vec2 screenPos, int frame, int offset){
|
||||
// Blue noise from texture + temporal interleave
|
||||
vec2 coord = (screenPos + 0.5) / screenSize;
|
||||
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;
|
||||
return fract(noise + (frame + offset) * 0.03125);
|
||||
}
|
||||
|
||||
vec2 GetTracingNoise2(vec2 screenPos, int frame, int offset){
|
||||
// 2D noise for ray directions
|
||||
vec2 coord = (screenPos + 0.5) / screenSize;
|
||||
coord = fract(coord * vec2(128.0, 128.0) + 0.5);
|
||||
vec2 texel = coord * vec2(127.0 / 128.0) + vec2(0.5 / 128.0);
|
||||
vec2 noise = textureLod(noisetex, texel, 0.0).rg;
|
||||
return fract(noise + (frame + offset) * 0.03125);
|
||||
}
|
||||
|
||||
// Golden-ratio based sample rotation (for progressive sampling)
|
||||
vec2 RotateNoise(vec2 uv, int sampleIndex, int totalSamples){
|
||||
float angle = 6.28318 * float(sampleIndex) / float(totalSamples);
|
||||
mat2 rot = mat2(cos(angle), sin(angle), -sin(angle), cos(angle));
|
||||
return rot * uv;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,187 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — Tracing Utilities
|
||||
// Core voxel ray marching helpers used by all tracers.
|
||||
|
||||
// Custom resource declarations (bound via shaders.properties)
|
||||
uniform sampler2D atlas2D;
|
||||
uniform sampler3D voxelData3D;
|
||||
uniform sampler2D skyBox2D;
|
||||
|
||||
// Sample the sky box panorama for a direction (for reflections / sky miss).
|
||||
// Layout must match SkyImage_CS: 3x2 tiles:
|
||||
// row 0: +X -X +Y row 1: -Y +Z -Z
|
||||
vec3 SampleSkyBox(vec3 dir){
|
||||
dir = normalize(dir);
|
||||
|
||||
float absX = abs(dir.x), absY = abs(dir.y), absZ = abs(dir.z);
|
||||
float maxAxis = max(absX, max(absY, absZ));
|
||||
|
||||
vec3 tdir = dir / maxAxis;
|
||||
|
||||
vec2 uv;
|
||||
vec2 tileOrigin;
|
||||
vec2 tile = vec2(1.0 / 3.0, 1.0 / 2.0);
|
||||
|
||||
if (maxAxis == absX){
|
||||
// +X (col 0) or -X (col 1), row 0
|
||||
tileOrigin = vec2(dir.x > 0.0 ? 0.0 : 1.0, 0.0);
|
||||
uv = vec2(tdir.y * 0.5 + 0.5, tdir.z * 0.5 + 0.5);
|
||||
}else if (maxAxis == absY){
|
||||
// +Y (col 2, row 0) or -Y (col 0, row 1)
|
||||
tileOrigin = dir.y > 0.0 ? vec2(2.0, 0.0) : vec2(0.0, 1.0);
|
||||
uv = vec2(tdir.x * 0.5 + 0.5, tdir.z * 0.5 + 0.5);
|
||||
}else{
|
||||
// +Z (col 1, row 1) or -Z (col 2, row 1)
|
||||
tileOrigin = vec2(dir.z > 0.0 ? 1.0 : 2.0, 1.0);
|
||||
uv = vec2(tdir.x * 0.5 + 0.5, tdir.y * 0.5 + 0.5);
|
||||
}
|
||||
|
||||
uv = uv * tile + tileOrigin * tile;
|
||||
|
||||
return textureLod(skyBox2D, uv, 0.0).rgb;
|
||||
}
|
||||
|
||||
|
||||
#ifndef TRACING_UTILITIES_GLSL
|
||||
#define TRACING_UTILITIES_GLSL
|
||||
|
||||
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
|
||||
#include "/Lib/PathTracing/Voxelizer/BlockShape.glsl"
|
||||
|
||||
// Convert world position to voxel grid coordinates
|
||||
vec3 WorldToVoxel(vec3 worldPos){
|
||||
return worldPos + cameraPositionFract + (voxelResolution * 0.5);
|
||||
}
|
||||
|
||||
// Sample the atlas for a hit voxel, returns albedo
|
||||
vec3 SampleVoxelAlbedo(vec2 midCoord, vec3 hitVoxelPos, vec3 hitNormal){
|
||||
// Reconstruct the face UV from hit position within voxel
|
||||
vec3 local = fract(hitVoxelPos);
|
||||
vec2 uv;
|
||||
if (abs(hitNormal.x) > 0.5){
|
||||
uv = vec2(local.z, local.y);
|
||||
}else if (abs(hitNormal.y) > 0.5){
|
||||
uv = vec2(local.x, local.z);
|
||||
}else{
|
||||
uv = vec2(local.x, local.y);
|
||||
}
|
||||
|
||||
// midCoord is the tile-aligned center UV; reconstruct pixel within tile
|
||||
vec2 tileCoord = midCoord;
|
||||
vec2 atlasSizeF = vec2(atlasSize);
|
||||
float tileW = 1.0 / atlasSizeF.x; // approximate; resolved via textureResolution
|
||||
vec2 pixelUV = tileCoord + (uv - 0.5) * tileW * 4.0;
|
||||
|
||||
return textureLod(atlas2D, pixelUV, 0.0).rgb;
|
||||
}
|
||||
|
||||
// Read a voxel's data
|
||||
vec4 ReadVoxel(ivec3 voxelCoord){
|
||||
return texelFetch(voxelData3D, voxelCoord, 0);
|
||||
}
|
||||
|
||||
// Test whether a voxel is empty (air or empty marker)
|
||||
bool IsVoxelEmpty(vec4 voxelData){
|
||||
float voxelID = DecodeVoxelID(voxelData.z);
|
||||
return voxelID <= 1.0;
|
||||
}
|
||||
|
||||
// Test whether a voxel is a light source (sphere light)
|
||||
bool IsLightSphere(float voxelID){
|
||||
return voxelID >= 239.0 && voxelID <= 290.0;
|
||||
}
|
||||
|
||||
// Core 3D-DDA march. Calls the callback-style inline logic via return.
|
||||
// Returns: 0 = no hit, 1 = hit, 2 = hit light
|
||||
int TraceRay(Ray ray, float maxDist, out float rayLength, out ivec3 hitVoxel, out float voxelID, out vec3 hitNormal){
|
||||
vec3 voxelPos = ray.ori;
|
||||
vec3 voxelCoord = floor(voxelPos);
|
||||
vec3 totalStep = (ray.sdir * (voxelCoord - voxelPos + 0.5) + 0.5) * abs(ray.rdir);
|
||||
rayLength = 0.0;
|
||||
vec3 tracingNext;
|
||||
hitNormal = vec3(0.0);
|
||||
|
||||
int result = 0;
|
||||
vec3 prevCoord = voxelCoord;
|
||||
|
||||
for (int i = 0; i < 128; i++){
|
||||
if (clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 0.5)) != voxelCoord) break;
|
||||
|
||||
vec4 voxelData = texelFetch(voxelData3D, ivec3(voxelCoord), 0);
|
||||
float id = DecodeVoxelID(voxelData.z);
|
||||
|
||||
if (id <= 1.0){
|
||||
// empty or full-block marker
|
||||
if (id >= 0.99 && id <= 1.0){
|
||||
// Full block
|
||||
if (rayLength > 0.0){
|
||||
hitVoxel = ivec3(voxelCoord);
|
||||
voxelID = 1.0;
|
||||
hitNormal = -step(vec3(rayLength), totalStep - abs(ray.rdir)) * ray.sdir;
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if (id >= 1000.0){
|
||||
// Encoded as full block: id = rawID + 1000
|
||||
float rawID = id - 1000.0;
|
||||
if (rawID <= 1.0){
|
||||
hitVoxel = ivec3(voxelCoord);
|
||||
voxelID = rawID;
|
||||
hitNormal = -step(vec3(rayLength), totalStep - abs(ray.rdir)) * ray.sdir;
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}else if (id > 1.0 && id < 1000.0){
|
||||
// Cutout shape: id = 1000 - rawID
|
||||
float rawID = 1000.0 - id;
|
||||
float t = minVec3(totalStep);
|
||||
rayLength = t;
|
||||
vec3 n;
|
||||
if (HitShape(ray, voxelCoord, rawID, rayLength, n)){
|
||||
hitVoxel = ivec3(voxelCoord);
|
||||
voxelID = rawID;
|
||||
hitNormal = n;
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}else if (id >= 200.0 && id <= 290.0){
|
||||
// Light source — contribute and continue
|
||||
// (handled by caller; here just note it)
|
||||
hitVoxel = ivec3(voxelCoord);
|
||||
voxelID = id;
|
||||
result = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
// Sparse tracing: skip empty markers
|
||||
float marker = voxelData.z;
|
||||
if (marker > 0.60 && marker < 0.92){
|
||||
// Hierarchical skip — approximate by stepping over the block size
|
||||
float skipSize = marker > 0.90 ? 8.0 : (marker > 0.70 ? 4.0 : 2.0);
|
||||
// find next boundary
|
||||
vec3 nextBoundary = floor((voxelCoord + 1.0) / skipSize) * skipSize;
|
||||
vec3 distToBoundary = (nextBoundary - voxelCoord) * abs(ray.rdir);
|
||||
float tSkip = minVec3(distToBoundary) + 1e-4;
|
||||
rayLength += tSkip;
|
||||
vec3 stepVec = ray.sdir * abs(ray.rdir) * tSkip;
|
||||
voxelPos += stepVec;
|
||||
voxelCoord = floor(voxelPos);
|
||||
totalStep = (ray.sdir * (voxelCoord - voxelPos + 0.5) + 0.5) * abs(ray.rdir);
|
||||
if (rayLength > maxDist) break;
|
||||
continue;
|
||||
}
|
||||
|
||||
rayLength = minVec3(totalStep);
|
||||
tracingNext = step(totalStep, vec3(rayLength));
|
||||
voxelCoord += tracingNext * ray.sdir;
|
||||
totalStep += tracingNext * abs(ray.rdir);
|
||||
|
||||
if (rayLength > maxDist) break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,223 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — Block Shape reconstruction
|
||||
// Exact AABB-based shapes for non-full-block voxel IDs, used during ray marching.
|
||||
|
||||
#ifndef BLOCK_SHAPE_GLSL
|
||||
#define BLOCK_SHAPE_GLSL
|
||||
|
||||
float SphereIntersectionLength(Ray ray, vec3 blockOrigin, vec3 sphereOrigin, float sphereRadius){
|
||||
sphereOrigin = -blockOrigin - sphereOrigin;
|
||||
|
||||
float b = dot(ray.dir, sphereOrigin);
|
||||
float c = dot(sphereOrigin, sphereOrigin) - sphereRadius * sphereRadius;
|
||||
float d = b * b - c;
|
||||
|
||||
float intersectionLength = 0.0;
|
||||
|
||||
if (d > 0.0){
|
||||
d = sqrt(d);
|
||||
intersectionLength = saturate(min(-b + d, d * 2.0));
|
||||
}
|
||||
|
||||
return intersectionLength;
|
||||
}
|
||||
|
||||
float BoxIntersectionLength(Ray ray, vec3 blockOrigin){
|
||||
vec3 boxMax = blockOrigin + 1.0;
|
||||
|
||||
vec3 t1 = ray.rdir * blockOrigin;
|
||||
vec3 t2 = ray.rdir * boxMax;
|
||||
|
||||
vec3 tMin = min(t1, t2);
|
||||
vec3 tMax = max(t1, t2);
|
||||
|
||||
float tEnter = maxVec3(tMin);
|
||||
float tExit = minVec3(tMax);
|
||||
|
||||
return max(tExit - tEnter, 0.0);
|
||||
}
|
||||
|
||||
// Light sphere colors for emissive blocks (IDs 200-270 range)
|
||||
vec3 LightShpereColor(float voxelID){
|
||||
const vec3 torchColor = pow(vec3(COLOR_TORCH_R, COLOR_TORCH_G, COLOR_TORCH_B), vec3(2.2)) * BRIGHTNESS_TORCH * SPHERELIGHT_BRIGHTNESS;
|
||||
const vec3 fireColor = pow(vec3(COLOR_FIRE_R, COLOR_FIRE_G, COLOR_FIRE_B), vec3(2.2)) * BRIGHTNESS_FIRE * SPHERELIGHT_BRIGHTNESS;
|
||||
const vec3 redstoneTorchColor = pow(vec3(COLOR_REDSTONETORCH_R, COLOR_REDSTONETORCH_G, COLOR_REDSTONETORCH_B), vec3(2.2)) * BRIGHTNESS_REDSTONETORCH * SPHERELIGHT_BRIGHTNESS;
|
||||
const vec3 amethystColor = pow(vec3(COLOR_AMETHYST_R, COLOR_AMETHYST_G, COLOR_AMETHYST_B), vec3(2.2)) * BRIGHTNESS_AMETHYST * SPHERELIGHT_BRIGHTNESS;
|
||||
const vec3 soultorchColor = pow(vec3(COLOR_SOULTORCH_R, COLOR_SOULTORCH_G, COLOR_SOULTORCH_B), vec3(2.2)) * BRIGHTNESS_SOULTORCH * SPHERELIGHT_BRIGHTNESS;
|
||||
const vec3 lightblockColor = pow(vec3(COLOR_LIGHTBLOCK_R, COLOR_LIGHTBLOCK_G, COLOR_LIGHTBLOCK_B), vec3(2.2)) * BRIGHTNESS_LIGHTBLOCK * SPHERELIGHT_BRIGHTNESS;
|
||||
const vec3 endrodColor = pow(vec3(COLOR_ENDROD_R, COLOR_ENDROD_G, COLOR_ENDROD_B), vec3(2.2)) * BRIGHTNESS_ENDROD * SPHERELIGHT_BRIGHTNESS;
|
||||
|
||||
vec3 shpereColor = vec3(0.0);
|
||||
|
||||
if (voxelID <= 244.0){
|
||||
if (voxelID == 242.0){ // Torch
|
||||
shpereColor = torchColor;
|
||||
}else if (voxelID == 243.0){ // Redstone Torch
|
||||
shpereColor = redstoneTorchColor;
|
||||
}else if (abs(voxelID - 240.0) < 1.5){ // Campfire 239 240
|
||||
shpereColor = fireColor;
|
||||
}else{
|
||||
shpereColor = soultorchColor;
|
||||
}
|
||||
|
||||
}else{
|
||||
if (voxelID == 245.0){ // Amethyst Cluster
|
||||
shpereColor = amethystColor;
|
||||
}else if (voxelID == 246.0){ // Soul Torch
|
||||
shpereColor = soultorchColor;
|
||||
}else if (voxelID == 247.0){ // Copper Lantern
|
||||
shpereColor = torchColor;
|
||||
}else if (abs(voxelID - 250.5) < 2.0){ // Candle & Sea Pickle
|
||||
shpereColor = torchColor * 0.8;
|
||||
}else if (abs(voxelID - 263.0) < 7.5){ // Light Block
|
||||
shpereColor = lightblockColor * (voxelID * (1.0 / 15.0) - (255.0 / 15.0));
|
||||
}else if (abs(voxelID - 280.0) < 1.5){ // End Rod
|
||||
shpereColor = endrodColor;
|
||||
}else{
|
||||
// Generic emissive (from vanilla light level blocks)
|
||||
shpereColor = torchColor * 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
return shpereColor;
|
||||
}
|
||||
|
||||
vec3 HitLightShpere(Ray ray, vec3 voxelCoord, float voxelID, float rayLength){
|
||||
vec3 shpereLighting = vec3(0.0);
|
||||
|
||||
vec3 blockOrigin = voxelCoord - ray.ori;
|
||||
float intersectionLength = SphereIntersectionLength(ray, blockOrigin, vec3(0.5), 0.5);
|
||||
|
||||
if (intersectionLength > 0.0)
|
||||
intersectionLength = intersectionLength * intersectionLength;
|
||||
shpereLighting = LightShpereColor(voxelID) * (intersectionLength * BLOCKLIGHT_BRIGHTNESS);
|
||||
|
||||
return shpereLighting;
|
||||
}
|
||||
|
||||
vec3 HitLightShpereReflection(Ray ray, vec3 voxelCoord, float voxelID, float rayLength){
|
||||
vec3 shpereLighting = vec3(0.0);
|
||||
|
||||
vec3 blockOrigin = voxelCoord - ray.ori;
|
||||
float intersectionLength = SphereIntersectionLength(ray, blockOrigin, vec3(0.5), 0.25);
|
||||
|
||||
if (intersectionLength > 0.0)
|
||||
intersectionLength = intersectionLength * intersectionLength;
|
||||
intersectionLength = intersectionLength * intersectionLength * 50.0;
|
||||
shpereLighting = LightShpereColor(voxelID) * (intersectionLength * BLOCKLIGHT_BRIGHTNESS);
|
||||
|
||||
return shpereLighting;
|
||||
}
|
||||
|
||||
bool IsHitBox(Ray ray, vec3 blockOrigin, vec3 boxOrigin, vec3 boxSize, inout float rayLength, inout vec3 hitNormal){
|
||||
vec3 boxMin = blockOrigin + boxOrigin;
|
||||
vec3 boxMax = boxMin + boxSize;
|
||||
|
||||
vec3 t1 = ray.rdir * boxMin;
|
||||
vec3 t2 = ray.rdir * boxMax;
|
||||
|
||||
vec3 tMin = min(t1, t2);
|
||||
vec3 tMax = max(t1, t2);
|
||||
|
||||
float tEnter = maxVec3(tMin);
|
||||
float tExit = minVec3(tMax);
|
||||
|
||||
bool hit = min(rayLength, tExit) >= tEnter && tExit >= 0.0;
|
||||
|
||||
if (hit){
|
||||
hitNormal = -step(vec3(tEnter), tMin) * ray.sdir;
|
||||
rayLength = tEnter;
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
// Full shape reconstruction for cutout blocks. voxelID here is the raw block ID
|
||||
// from block.properties (0-100 range).
|
||||
bool HitShape(Ray ray, vec3 voxelCoord, float voxelID, inout float rayLength, out vec3 hitNormal){
|
||||
vec3 blockOrigin = voxelCoord - ray.ori;
|
||||
hitNormal = vec3(0.0);
|
||||
|
||||
bool hit = false;
|
||||
|
||||
const float rotIndex[8] = float[8](1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, -1.0);
|
||||
|
||||
if (voxelID == 2.0){ // Leaves — full block
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.0), vec3(1.0), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 4.0){ // Cross plant (X shape)
|
||||
vec3 ori0 = vec3(0.5);
|
||||
vec3 size0 = vec3(-1.0, 1.0, 0.25 / 16.0);
|
||||
vec3 ori1 = vec3(0.5);
|
||||
vec3 size1 = vec3(0.25 / 16.0, 1.0, -1.0);
|
||||
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(ori0.x, 0.0, ori0.z), vec3(size0.x, 1.0, size0.z), rayLength, hitNormal);
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(ori1.x, 0.0, ori1.z), vec3(size1.x, 1.0, size1.z), rayLength, hitNormal) || hit;
|
||||
|
||||
}else if (voxelID == 5.0){ // Torch
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.4375, 0.0, 0.4375), vec3(0.125, 0.5625, 0.125), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 6.0){ // Lantern
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.25, 0.1875, 0.25), vec3(0.5, 0.5625, 0.5), rayLength, hitNormal);
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.4375, 0.0, 0.4375), vec3(0.125, 0.1875, 0.125), rayLength, hitNormal) || hit;
|
||||
|
||||
}else if (voxelID == 10.0 || voxelID == 11.0){ // Glass pane / Iron bars
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(7.0 / 16.0, 0.0, 7.0 / 16.0), vec3(2.0 / 16.0, 1.0, 2.0 / 16.0), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID >= 12.0 && voxelID <= 13.0){ // Stairs & slabs simplified as full-ish
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.0), vec3(1.0), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID >= 14.0 && voxelID <= 16.0){ // Walls, fences, fence gates
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.25, 0.0, 0.25), vec3(0.5, 1.0, 0.5), rayLength, hitNormal);
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.0, 0.375, 0.0), vec3(1.0, 0.25, 1.0), rayLength, hitNormal) || hit;
|
||||
|
||||
}else if (voxelID == 17.0){ // Door
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.0, 0.0, 13.0 / 16.0), vec3(1.0, 1.0, 3.0 / 16.0), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 20.0){ // End rod
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.4375, 0.0, 0.4375), vec3(0.125, 1.0, 0.125), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 21.0){ // Chain
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.4375, 0.0, 0.4375), vec3(0.125, 1.0, 0.125), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 22.0){ // Amethyst cluster
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.25, 0.0, 0.25), vec3(0.5, 0.5, 0.5), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 27.0){ // Ladder
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 28.0 || voxelID == 29.0 || voxelID == 31.0){ // Sugar cane / Bamboo / Chorus
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.375, 0.0, 0.375), vec3(0.25, 1.0, 0.25), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 32.0){ // Coral
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.25, 0.0, 0.25), vec3(0.5, 0.625, 0.5), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 33.0){ // Pointed dripstone
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.375, 0.0, 0.375), vec3(0.25, 1.0, 0.25), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 35.0){ // Lightning rod
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.375, 0.0, 0.375), vec3(0.25, 1.0, 0.25), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 37.0){ // Snow layers
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.0, 0.0, 0.0), vec3(1.0, 0.125, 1.0), rayLength, hitNormal);
|
||||
|
||||
}else if (voxelID == 80.0){ // Cobweb
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.0), vec3(1.0), rayLength, hitNormal);
|
||||
|
||||
}else{
|
||||
// Default: full block
|
||||
hit = IsHitBox(ray, blockOrigin, vec3(0.0), vec3(1.0), rayLength, hitNormal);
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
// Lightweight hit test (no normal) for shadow rays
|
||||
bool HitShape_Lite(Ray ray, vec3 voxelCoord, float voxelID, float rayLength){
|
||||
vec3 blockOrigin = voxelCoord - ray.ori;
|
||||
vec3 unused = vec3(0.0);
|
||||
return HitShape(ray, voxelCoord, voxelID, rayLength, unused);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,338 @@
|
||||
// MinecraftPT — Shadow + Voxelization pass
|
||||
// Renders the RTWSM shadow map (shadowcolor0) AND the voxel atlas (shadowcolor1),
|
||||
// which is then copied into the 3D voxel texture by VoxelData_Copy_CS.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
|
||||
#include "/Lib/RTWSM/SampleWarp.glsl"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Vertex Shader
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef PROGRAM_VSH
|
||||
|
||||
uniform mat4 shadowModelViewInverse;
|
||||
uniform mat4 shadowProjection;
|
||||
uniform vec3 cameraPositionFract;
|
||||
uniform float frameTimeCounter;
|
||||
uniform float wetness;
|
||||
|
||||
uniform sampler2D noisetex;
|
||||
|
||||
in vec4 mc_Entity;
|
||||
in vec4 at_midBlock;
|
||||
in vec2 mc_midTexCoord;
|
||||
|
||||
out vec3 g_color;
|
||||
out vec3 g_worldPos;
|
||||
out vec2 g_texcoord;
|
||||
|
||||
#ifdef PROGRAM_VOXEL
|
||||
flat out float g_voxelID;
|
||||
out float g_mcLightLevel;
|
||||
out vec3 g_voxelCoord;
|
||||
out float g_notInVoxel;
|
||||
out float g_normalInvalid;
|
||||
#endif
|
||||
|
||||
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
|
||||
#include "/Lib/RTWSM/SampleWarp.glsl"
|
||||
|
||||
#ifdef WAVING_PLANTS
|
||||
#include "/Lib/IndividualFunctions/WavingPlants.glsl"
|
||||
#endif
|
||||
|
||||
void main(){
|
||||
vec4 worldPos = shadowModelViewInverse * gl_ModelViewMatrix * gl_Vertex;
|
||||
|
||||
float skylightmap = saturate(float(gl_MultiTexCoord1.y - 8) / 232.0);
|
||||
|
||||
#ifdef WAVING_PLANTS
|
||||
#ifdef SHADOW_WAVING_PLANTS
|
||||
WavingPlants(worldPos, skylightmap);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
g_worldPos = worldPos.xyz;
|
||||
g_color = gl_Color.rgb;
|
||||
g_texcoord.xy = mat2(gl_TextureMatrix[0]) * gl_MultiTexCoord0.xy + gl_TextureMatrix[0][3].xy;
|
||||
|
||||
#ifdef PROGRAM_VOXEL
|
||||
vec3 worldNormal = mat3(shadowModelViewInverse) * normalize(gl_NormalMatrix * gl_Normal);
|
||||
|
||||
g_voxelID = mc_Entity.x;
|
||||
g_mcLightLevel = skylightmap;
|
||||
g_notInVoxel = step(5999.5, g_voxelID);
|
||||
g_notInVoxel += step(g_voxelID, 0.5);
|
||||
g_notInVoxel *= float(abs(g_voxelID - 8400.0) > 400.5);
|
||||
g_normalInvalid = step(maxVec3(abs(worldNormal)), 0.99);
|
||||
|
||||
g_voxelCoord = vec3(-2.0);
|
||||
|
||||
if (g_notInVoxel < 0.5){
|
||||
// Full block detection: verify vertices are on the block grid
|
||||
if (g_voxelID <= 1.0){
|
||||
vec3 vertexPos = gl_Vertex.xyz + cameraPositionFract;
|
||||
vertexPos = abs(vertexPos - round(vertexPos));
|
||||
float posInvalid = vertexPos.x + vertexPos.y + vertexPos.z;
|
||||
posInvalid = step(0.001, posInvalid);
|
||||
g_notInVoxel = posInvalid + g_normalInvalid;
|
||||
}
|
||||
|
||||
#ifdef PT_MIDBLOCK_TEMPFIX
|
||||
g_voxelCoord = g_worldPos + cameraPositionFract + (voxelResolution * 0.5) - worldNormal * 0.01;
|
||||
#else
|
||||
g_voxelCoord = g_worldPos + cameraPositionFract + (voxelResolution * 0.5) + at_midBlock.xyz * 0.015625;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
gl_Position = vec4(1.0); // set by geometry shader
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Geometry Shader
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef PROGRAM_GSH
|
||||
|
||||
layout(triangles) in;
|
||||
layout(triangle_strip, max_vertices = 6) out;
|
||||
|
||||
uniform mat4 shadowProjection;
|
||||
uniform ivec2 atlasSize;
|
||||
uniform int renderStage;
|
||||
|
||||
in vec3 g_color[];
|
||||
in vec3 g_worldPos[];
|
||||
in vec2 g_texcoord[];
|
||||
|
||||
#ifdef PROGRAM_VOXEL
|
||||
flat in float g_voxelID[];
|
||||
in float g_mcLightLevel[];
|
||||
in vec3 g_voxelCoord[];
|
||||
in float g_notInVoxel[];
|
||||
in float g_normalInvalid[];
|
||||
#endif
|
||||
|
||||
out vec3 v_color;
|
||||
out vec4 v_worldPos_voxelData_isWater_isVoxel;
|
||||
out vec2 v_texcoord_mcLightLevel;
|
||||
flat out vec2 v_midTexCoord;
|
||||
|
||||
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
|
||||
|
||||
void main(){
|
||||
v_midTexCoord = vec2(0.0);
|
||||
|
||||
vec3 posDiff = vec3(
|
||||
distance(g_worldPos[0], g_worldPos[1]),
|
||||
distance(g_worldPos[1], g_worldPos[2]),
|
||||
distance(g_worldPos[2], g_worldPos[0])
|
||||
);
|
||||
|
||||
// Emit the shadow map triangle (for RTWSM shadow sampling)
|
||||
{
|
||||
float bias = saturate(maxVec3(posDiff) * 0.5 - 1.0) * shadowProjection[0][0] * 0.3;
|
||||
|
||||
for (int i = 0; i < 3; i++){
|
||||
vec4 worldPos = shadowModelViewInverse * gl_in[i].gl_Position;
|
||||
gl_Position = gl_in[i].gl_Position;
|
||||
gl_Position.z += bias;
|
||||
|
||||
// Shift into the right square shadow region, then apply warp
|
||||
ShiftShadowNdcPos(gl_Position.xy);
|
||||
gl_Position.xy += SampleRTWWarpSmooth(gl_Position.xy * 0.5 + 0.5) * 2.0;
|
||||
|
||||
v_color = g_color[i];
|
||||
v_worldPos_voxelData_isWater_isVoxel = vec4(g_worldPos[i], 0.0);
|
||||
v_texcoord_mcLightLevel = g_texcoord[i];
|
||||
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
#ifdef PROGRAM_VOXEL
|
||||
|
||||
vec3 voxelCoord = floor(g_voxelCoord[0] * 0.33333333 + g_voxelCoord[1] * 0.33333333 + g_voxelCoord[2] * 0.33333333);
|
||||
|
||||
if (all(bvec3(
|
||||
clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 1.0)) == voxelCoord,
|
||||
g_notInVoxel[0] + g_notInVoxel[1] + g_notInVoxel[2] < 0.5,
|
||||
renderStage == MC_RENDER_STAGE_TERRAIN_SOLID || renderStage == MC_RENDER_STAGE_TERRAIN_TRANSLUCENT
|
||||
))){
|
||||
|
||||
vec2 atlasResolution = vec2(atlasSize);
|
||||
|
||||
vec2 maxTexCoord = max(g_texcoord[0].xy, max(g_texcoord[1].xy, g_texcoord[2].xy));
|
||||
vec2 minTexCoord = min(g_texcoord[0].xy, min(g_texcoord[1].xy, g_texcoord[2].xy));
|
||||
|
||||
v_midTexCoord = (maxTexCoord + minTexCoord) * 0.5;
|
||||
|
||||
vec2 coordSize = (maxTexCoord - minTexCoord) * atlasResolution;
|
||||
|
||||
#if TEXTURE_RESOLUTION == 0
|
||||
float coordMaxSize = maxVec3(vec3(
|
||||
maxVec2(abs(g_texcoord[0].xy - g_texcoord[1].xy) * atlasResolution) / max(posDiff.x, 1e-4),
|
||||
maxVec2(abs(g_texcoord[1].xy - g_texcoord[2].xy) * atlasResolution) / max(posDiff.y, 1e-4),
|
||||
maxVec2(abs(g_texcoord[0].xy - g_texcoord[2].xy) * atlasResolution) / max(posDiff.z, 1e-4)
|
||||
));
|
||||
|
||||
float textureResolution = floor(coordMaxSize + 0.5);
|
||||
#else
|
||||
float textureResolution = TEXTURE_RESOLUTION;
|
||||
#endif
|
||||
|
||||
float voxelID = g_voxelID[0];
|
||||
|
||||
float roundedResolution = round(log2(textureResolution));
|
||||
|
||||
vec2 atlasTiles = vec2(atlasSize) * exp2(-roundedResolution);
|
||||
|
||||
// Tile-aligned texel sampling for accurate atlas UV
|
||||
v_midTexCoord = (floor(v_midTexCoord * atlasTiles) + 0.5) / atlasTiles;
|
||||
|
||||
float skylight = saturate(SkyLightmapCurve(g_mcLightLevel[0] * 0.33333333 + g_mcLightLevel[1] * 0.33333333 + g_mcLightLevel[2] * 0.33333333));
|
||||
|
||||
float zOffset = g_normalInvalid[0] + g_normalInvalid[1] + g_normalInvalid[2];
|
||||
|
||||
coordSize /= textureResolution;
|
||||
|
||||
zOffset += saturate(coordSize.x * coordSize.y) * -0.2;
|
||||
|
||||
bool isCutout = voxelID == 2.0;
|
||||
|
||||
// Light blocks (8000-8400): encode block light level
|
||||
if (abs(voxelID - 8400.0) < 400.5){
|
||||
voxelID -= 8000.0;
|
||||
|
||||
if (voxelID > 499.5){
|
||||
// hardcoded light level block
|
||||
voxelID = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Encode: cutout shapes get 1000 - id, full blocks get id + 1000
|
||||
bool isShape = bool(
|
||||
uint(voxelID == 2.0) | // leaves
|
||||
uint(voxelID == 4.0) | // cross plants
|
||||
uint(voxelID == 5.0) | // torch
|
||||
uint(voxelID == 6.0) | // lantern
|
||||
uint(voxelID == 10.0) | // glass pane
|
||||
uint(voxelID == 11.0) | // iron bars
|
||||
uint(voxelID == 12.0) | // stairs
|
||||
uint(voxelID == 13.0) | // slabs
|
||||
uint(voxelID == 14.0) | // walls
|
||||
uint(voxelID == 15.0) | // fences
|
||||
uint(voxelID == 16.0) | // fence gates
|
||||
uint(voxelID == 17.0) | // doors
|
||||
uint(voxelID == 20.0) | // end rod
|
||||
uint(voxelID == 21.0) | // chain
|
||||
uint(voxelID == 22.0) | // amethyst
|
||||
uint(voxelID == 27.0) | // ladder
|
||||
uint(voxelID == 28.0) | // sugar cane
|
||||
uint(voxelID == 29.0) | // bamboo
|
||||
uint(voxelID == 31.0) | // chorus
|
||||
uint(voxelID == 32.0) | // coral
|
||||
uint(voxelID == 33.0) | // dripstone
|
||||
uint(voxelID == 35.0) | // lightning rod
|
||||
uint(voxelID == 36.0) | // pot
|
||||
uint(voxelID == 37.0) | // snow layers
|
||||
uint(voxelID == 80.0) // cobweb
|
||||
);
|
||||
|
||||
voxelID = isShape ? 1000.0 - voxelID : voxelID + 1000.0;
|
||||
|
||||
#ifdef PT_FULLBLOCK_VERIFICATION
|
||||
if (voxelID == 1001.0){
|
||||
if (abs(posDiff.x + posDiff.y + posDiff.z - 3.41421356) > 0.001){
|
||||
voxelID = 65536.0;
|
||||
zOffset = -0.49;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
vec2 voxelTexel = VoxelTexel_From_VoxelCoord(voxelCoord);
|
||||
const vec2[3] vertexOffset = vec2[3](vec2(0.0, 0.0), vec2(1.0, 0.0), vec2(0.5, 1.0));
|
||||
|
||||
for (int i = 0; i < 3; i++){
|
||||
gl_Position = vec4((voxelTexel + vertexOffset[i]) * shadowPixelSize * 2.0 - 1.0, zOffset * 0.5 - 0.75, 1.0);
|
||||
|
||||
v_color = g_color[i];
|
||||
v_worldPos_voxelData_isWater_isVoxel = vec4(voxelID, roundedResolution, 0.0, 1.0);
|
||||
v_texcoord_mcLightLevel = vec2(skylight, 0.0);
|
||||
|
||||
EmitVertex();
|
||||
}
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Fragment Shader
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef PROGRAM_FSH
|
||||
|
||||
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
|
||||
|
||||
layout(location = 0) out vec4 shadowbuffer0;
|
||||
layout(location = 1) out vec4 shadowbuffer1;
|
||||
|
||||
uniform mat4 shadowModelViewInverse;
|
||||
uniform vec3 cameraPosition;
|
||||
uniform ivec2 atlasSize;
|
||||
uniform int isEyeInWater;
|
||||
uniform vec2 screenSize;
|
||||
uniform vec2 pixelSize;
|
||||
uniform int frameCounter;
|
||||
uniform int renderStage;
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform sampler2D noisetex;
|
||||
uniform sampler2D pixelData2D;
|
||||
|
||||
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
|
||||
#include "/Lib/RTWSM/SampleWarp.glsl"
|
||||
|
||||
in vec3 v_color;
|
||||
in vec4 v_worldPos_voxelData_isWater_isVoxel;
|
||||
in vec2 v_texcoord_mcLightLevel;
|
||||
flat in vec2 v_midTexCoord;
|
||||
|
||||
void main(){
|
||||
// Shadow map fragment
|
||||
if (v_worldPos_voxelData_isWater_isVoxel.w < 0.5){
|
||||
vec4 albedoTex = textureLod(tex, v_texcoord_mcLightLevel.xy, 0.0);
|
||||
|
||||
// Keep shadow fragments only in the right square region [W, 2W] x [0, W]
|
||||
if (gl_FragCoord.x < float(voxelWidth) || gl_FragCoord.x >= shadowSize || gl_FragCoord.y >= float(voxelWidth)
|
||||
|| albedoTex.a < 0.004) discard;
|
||||
|
||||
albedoTex.rgb *= v_color;
|
||||
|
||||
shadowbuffer0 = vec4(albedoTex);
|
||||
shadowbuffer1 = vec4(0.0);
|
||||
}
|
||||
|
||||
// Voxel atlas fragment
|
||||
if (v_worldPos_voxelData_isWater_isVoxel.w > 0.2){
|
||||
shadowbuffer0 = vec4(v_color.rgb, v_texcoord_mcLightLevel.x);
|
||||
|
||||
vec2 midCoord = saturate(v_midTexCoord * (65536.0 / 65535.0));
|
||||
float voxelID = saturate(v_worldPos_voxelData_isWater_isVoxel.x / 65535.0);
|
||||
float textureResolution = saturate(v_worldPos_voxelData_isWater_isVoxel.y / 255.0);
|
||||
float skylight = saturate(SkyLightmapCurve(v_texcoord_mcLightLevel.x * 1.07));
|
||||
|
||||
shadowbuffer1 = vec4(midCoord, voxelID, Pack2xU8_to_U16(vec2(textureResolution, skylight)));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,139 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — Voxel Profile
|
||||
// Voxel grid parameters derived from settings.
|
||||
//
|
||||
// The shadow framebuffer (shadowcolor0/1) is square, size S x S, and holds:
|
||||
// - the VOXEL ATLAS in the bottom-left region: texels [0, W) x [0, H)
|
||||
// where W = voxelWidth and H = ceil(N / W), N = Rx*Ry*Rz voxels.
|
||||
// Each voxel is one texel; linear packing: n = x + y*Rx + z*Rx*Ry.
|
||||
// - the SHADOW MAP in the right square region: texels [W, 2W) x [0, W).
|
||||
// The shadow camera NDC is shifted into this region (square -> square,
|
||||
// no aspect distortion). Effective shadow resolution = W.
|
||||
|
||||
#ifndef VOXEL_PROFILE_GLSL
|
||||
#define VOXEL_PROFILE_GLSL
|
||||
|
||||
// Shadow render distance -> shadow coverage
|
||||
#if SHADOW_RENDER_DISTANCE == 4
|
||||
const float shadowDistance = 64.1;
|
||||
#elif SHADOW_RENDER_DISTANCE == 6
|
||||
const float shadowDistance = 96.1;
|
||||
#elif SHADOW_RENDER_DISTANCE == 8
|
||||
const float shadowDistance = 128.1;
|
||||
#elif SHADOW_RENDER_DISTANCE == 12
|
||||
const float shadowDistance = 192.1;
|
||||
#elif SHADOW_RENDER_DISTANCE == 16
|
||||
const float shadowDistance = 256.1;
|
||||
#elif SHADOW_RENDER_DISTANCE == 24
|
||||
const float shadowDistance = 384.1;
|
||||
#elif SHADOW_RENDER_DISTANCE == 32
|
||||
const float shadowDistance = 512.1;
|
||||
#elif SHADOW_RENDER_DISTANCE == 48
|
||||
const float shadowDistance = 768.1;
|
||||
#elif SHADOW_RENDER_DISTANCE == 64
|
||||
const float shadowDistance = 1024.1;
|
||||
#elif SHADOW_RENDER_DISTANCE == 96
|
||||
const float shadowDistance = 1536.1;
|
||||
#elif SHADOW_RENDER_DISTANCE == 128
|
||||
const float shadowDistance = 2048.1;
|
||||
#else
|
||||
const float shadowDistance = 256.1;
|
||||
#endif
|
||||
|
||||
// Voxel grid resolution and coverage (blocks)
|
||||
#if PT_VOXEL_RESOLUTION == 4004
|
||||
const ivec3 voxelResolutionInt = ivec3(128);
|
||||
const float voxelDistance = 64.0;
|
||||
const int voxelWidth = 2048;
|
||||
#elif PT_VOXEL_RESOLUTION == 6004
|
||||
const ivec3 voxelResolutionInt = ivec3(192, 128, 192);
|
||||
const float voxelDistance = 96.0;
|
||||
const int voxelWidth = 2048;
|
||||
#elif PT_VOXEL_RESOLUTION == 8004
|
||||
const ivec3 voxelResolutionInt = ivec3(256, 128, 256);
|
||||
const float voxelDistance = 128.0;
|
||||
const int voxelWidth = 2048;
|
||||
#elif PT_VOXEL_RESOLUTION == 8006
|
||||
const ivec3 voxelResolutionInt = ivec3(256, 192, 256);
|
||||
const float voxelDistance = 128.0;
|
||||
const int voxelWidth = 4096;
|
||||
#elif PT_VOXEL_RESOLUTION == 8008
|
||||
const ivec3 voxelResolutionInt = ivec3(256);
|
||||
const float voxelDistance = 128.0;
|
||||
const int voxelWidth = 4096;
|
||||
#elif PT_VOXEL_RESOLUTION == 12004
|
||||
const ivec3 voxelResolutionInt = ivec3(384, 128, 384);
|
||||
const float voxelDistance = 192.0;
|
||||
const int voxelWidth = 4096;
|
||||
#elif PT_VOXEL_RESOLUTION == 12006
|
||||
const ivec3 voxelResolutionInt = ivec3(384, 192, 384);
|
||||
const float voxelDistance = 192.0;
|
||||
const int voxelWidth = 4096;
|
||||
#elif PT_VOXEL_RESOLUTION == 12008
|
||||
const ivec3 voxelResolutionInt = ivec3(384, 256, 384);
|
||||
const float voxelDistance = 192.0;
|
||||
const int voxelWidth = 6144;
|
||||
#elif PT_VOXEL_RESOLUTION == 16004
|
||||
const ivec3 voxelResolutionInt = ivec3(512, 128, 512);
|
||||
const float voxelDistance = 256.0;
|
||||
const int voxelWidth = 6144;
|
||||
#elif PT_VOXEL_RESOLUTION == 16008
|
||||
const ivec3 voxelResolutionInt = ivec3(512, 256, 512);
|
||||
const float voxelDistance = 256.0;
|
||||
const int voxelWidth = 6144;
|
||||
#elif PT_VOXEL_RESOLUTION == 16016
|
||||
const ivec3 voxelResolutionInt = ivec3(512);
|
||||
const float voxelDistance = 256.0;
|
||||
const int voxelWidth = 8192;
|
||||
#else
|
||||
const ivec3 voxelResolutionInt = ivec3(256, 192, 256);
|
||||
const float voxelDistance = 128.0;
|
||||
const int voxelWidth = 4096;
|
||||
#endif
|
||||
|
||||
const vec3 voxelResolution = vec3(voxelResolutionInt);
|
||||
|
||||
// Irradiance cache resolution (clamped to voxel grid)
|
||||
const int ircResolution = min(PT_IRC_RESOLUTION, voxelResolutionInt.x);
|
||||
|
||||
// Shadow framebuffer size (square)
|
||||
const int shadowMapResolution = voxelWidth * 2;
|
||||
const float shadowSize = float(shadowMapResolution);
|
||||
const float shadowPixelSize = 1.0 / shadowSize;
|
||||
const float shadowRatio = 0.5; // W / S
|
||||
|
||||
// Map 3D voxel coordinate to 2D atlas texel (linear packing)
|
||||
vec2 VoxelTexel_From_VoxelCoord(vec3 voxelCoord){
|
||||
float n = voxelCoord.x + voxelCoord.y * voxelResolution.x + voxelCoord.z * voxelResolution.x * voxelResolution.y;
|
||||
return vec2(mod(n, float(voxelWidth)), floor(n / float(voxelWidth)));
|
||||
}
|
||||
|
||||
// Shift shadow map NDC into the right square region [W, 2W] x [0, W]
|
||||
void ShiftShadowNdcPos(inout vec2 coord){
|
||||
coord = coord * shadowRatio + vec2(1.0 - shadowRatio, shadowRatio - 1.0);
|
||||
}
|
||||
|
||||
// Shift shadow map screen uv into the right square region
|
||||
void ShiftShadowScreenPos(inout vec2 coord){
|
||||
coord = coord * shadowRatio + vec2(1.0 - shadowRatio, 0.0);
|
||||
}
|
||||
|
||||
// Shift back from shadow region uv to standard shadow uv
|
||||
vec2 UnshiftShadowScreenPos(vec2 coord){
|
||||
return (coord - vec2(1.0 - shadowRatio, 0.0)) / shadowRatio;
|
||||
}
|
||||
|
||||
// Block ID encoding (16-bit range)
|
||||
// Full block: voxelID + 1000
|
||||
// Cutout shape: 1000 - voxelID
|
||||
// Empty markers: 0.91 (8^3), 0.71 (4^3), 0.61 (2^3)
|
||||
float EncodeVoxelID(float voxelID){
|
||||
return saturate((voxelID + 1000.0) / 65535.0);
|
||||
}
|
||||
|
||||
float DecodeVoxelID(float encoded){
|
||||
return abs(floor(encoded * 65535.0 - 999.9));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
// MinecraftPT — CausticsTex_CS
|
||||
// Generates a caustics normal field texture (pixelData2D) used by water voxels.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
const ivec3 workGroups = ivec3(16, 16, 1);
|
||||
layout (local_size_x = 32, local_size_y = 32) in;
|
||||
|
||||
layout (rg16f) uniform writeonly image2D img_pixelData2D;
|
||||
|
||||
void main(){
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
vec2 uv = (vec2(texel) + 0.5) / vec2(512.0, 513.0);
|
||||
|
||||
float time = frameTimeCounter * 0.05;
|
||||
|
||||
// Analytic caustics field (sum of moving sine waves)
|
||||
vec2 coord = uv * 32.0;
|
||||
float n1 = sin(coord.x * 2.0 + time * 3.0) * cos(coord.y * 1.7 - time * 2.0);
|
||||
float n2 = sin(coord.x * 1.3 - time * 1.5) * cos(coord.y * 2.4 + time * 2.5);
|
||||
float n3 = sin((coord.x + coord.y) * 3.1 + time * 4.0) * 0.5;
|
||||
|
||||
float field = n1 * 0.5 + n2 * 0.3 + n3 * 0.2;
|
||||
|
||||
// Normal from field gradient
|
||||
float eps = 0.01;
|
||||
float fx = sin((coord.x + eps) * 2.0 + time * 3.0) * cos(coord.y * 1.7 - time * 2.0);
|
||||
float fxx = sin((coord.x - eps) * 2.0 + time * 3.0) * cos(coord.y * 1.7 - time * 2.0);
|
||||
float fy = sin(coord.x * 2.0 + time * 3.0) * cos((coord.y + eps) * 1.7 - time * 2.0);
|
||||
float fyy = sin(coord.x * 2.0 + time * 3.0) * cos((coord.y - eps) * 1.7 - time * 2.0);
|
||||
|
||||
vec2 normal = vec2((fx - fxx) * 0.5 / eps, (fy - fyy) * 0.5 / eps) * 0.2;
|
||||
normal = tanh(normal);
|
||||
|
||||
imageStore(img_pixelData2D, texel, vec4(normal * 0.5 + 0.5, 0.0, 0.0));
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
// MinecraftPT — Bloom_CS
|
||||
// Bloom compute passes: two downsample levels + axial blur X/Y.
|
||||
// Uses two alternating images (bloomA/bloomB) to avoid read-write conflicts.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
const ivec3 workGroups = ivec3(int(ceil(viewWidth * 0.03125)), int(ceil(viewHeight * 0.03125)), 1);
|
||||
layout (local_size_x = 8, local_size_y = 8) in;
|
||||
|
||||
layout (rgba16f) uniform writeonly image2D img_bloomA;
|
||||
layout (rgba16f) uniform writeonly image2D img_bloomB;
|
||||
|
||||
uniform sampler2D colortex12;
|
||||
uniform sampler2D bloomA;
|
||||
uniform sampler2D bloomB;
|
||||
|
||||
// Downsample pass
|
||||
#ifdef PROGRAM_BLOOM_DOWNSAMPLE
|
||||
void main(){
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
vec3 color = vec3(0.0);
|
||||
|
||||
#if PROGRAM_BLOOM_DOWNSAMPLE_LEVEL == 1
|
||||
// Level 1: 2x2 box from the HDR scene -> bloomA
|
||||
for (int i = 0; i < 2; i++){
|
||||
for (int j = 0; j < 2; j++){
|
||||
color += texelFetch(colortex12, texel * 2 + ivec2(i, j), 0).rgb;
|
||||
}}
|
||||
color *= 0.25;
|
||||
|
||||
float brightness = luminance(color);
|
||||
color *= saturate(brightness * BLOOM_CLAMP_STRENGTH);
|
||||
|
||||
ivec2 imgSize = imageSize(img_bloomA);
|
||||
if (all(lessThan(texel, imgSize))){
|
||||
imageStore(img_bloomA, texel, vec4(color, 1.0));
|
||||
}
|
||||
|
||||
#else
|
||||
// Level 2: 2x2 box from bloomA -> bloomB
|
||||
for (int i = 0; i < 2; i++){
|
||||
for (int j = 0; j < 2; j++){
|
||||
color += texelFetch(bloomA, texel * 2 + ivec2(i, j), 0).rgb;
|
||||
}}
|
||||
color *= 0.25;
|
||||
|
||||
float brightness = luminance(color);
|
||||
color *= saturate(brightness * BLOOM_CLAMP_STRENGTH);
|
||||
|
||||
ivec2 imgSize = imageSize(img_bloomB);
|
||||
if (all(lessThan(texel, imgSize))){
|
||||
imageStore(img_bloomB, texel, vec4(color, 1.0));
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// Axial blur pass (X or Y depending on defines)
|
||||
#ifdef PROGRAM_BLOOM_AXIALBLUR
|
||||
void main(){
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
ivec2 imgSize = imageSize(img_bloomA);
|
||||
if (any(greaterThanEqual(texel, imgSize))) return;
|
||||
|
||||
vec2 uv = (vec2(texel) + 0.5) / vec2(imgSize);
|
||||
|
||||
// Which buffer to read (BLOOM_AXIAL_READ_A defined for the pass reading bloomA)
|
||||
#ifdef BLOOM_AXIAL_READ_A
|
||||
sampler2D src = bloomA;
|
||||
#else
|
||||
sampler2D src = bloomB;
|
||||
#endif
|
||||
|
||||
#ifdef PROGRAM_BLOOM_AXIALBLUR_X
|
||||
vec2 axis = vec2(1.0, 0.0);
|
||||
#else
|
||||
vec2 axis = vec2(0.0, 1.0);
|
||||
#endif
|
||||
|
||||
vec3 color = vec3(0.0);
|
||||
float weightSum = 0.0;
|
||||
|
||||
for (int i = -8; i <= 8; i++){
|
||||
vec2 coord = uv + axis * float(i) / vec2(imgSize);
|
||||
float w = exp(-float(i * i) * 0.05);
|
||||
color += textureLod(src, coord, 0.0).rgb * w;
|
||||
weightSum += w;
|
||||
}
|
||||
|
||||
// Write to the opposite buffer of the read source
|
||||
#ifdef BLOOM_AXIAL_READ_A
|
||||
imageStore(img_bloomB, texel, vec4(color / weightSum, 1.0));
|
||||
#else
|
||||
imageStore(img_bloomA, texel, vec4(color / weightSum, 1.0));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
// MinecraftPT — Bloom_FS
|
||||
// Final bloom composite onto the scene.
|
||||
// bloomB is a fixed 1024x1024 image; the valid bloom region for this screen
|
||||
// is its top-left (viewWidth/4 x viewHeight/4) texels, so UV = screen / 4096.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
uniform sampler2D colortex12;
|
||||
uniform sampler2D bloomB;
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
vec2 texelCoord = gl_FragCoord.xy;
|
||||
|
||||
vec3 scene = texelFetch(colortex12, ivec2(texelCoord), 0).rgb;
|
||||
vec3 bloom = textureLod(bloomB, clamp(texelCoord / 4096.0, vec2(0.0), vec2(1.0)), 0.0).rgb;
|
||||
|
||||
vec3 color = scene + bloom * BLOOM_AMOUNT;
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// MinecraftPT — DepthCopy_CS
|
||||
// Copies the current frame depth to prevDepth2D at the end of the frame,
|
||||
// so temporal filters in the next frame have the previous depth for
|
||||
// reprojection validation.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
const ivec3 workGroups = ivec3(int(ceil(viewWidth * 0.0625)), int(ceil(viewHeight * 0.0625)), 1);
|
||||
layout (local_size_x = 8, local_size_y = 8) in;
|
||||
|
||||
layout (r32f) uniform writeonly image2D img_prevDepth2D;
|
||||
|
||||
uniform sampler2D depthtex0;
|
||||
|
||||
void main(){
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
imageStore(img_prevDepth2D, texel, vec4(texelFetch(depthtex0, texel * 2, 0).r));
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// MinecraftPT — DiffuseSpatial (single pass, step parameterized by composite index)
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/PathTracing/Denoiser/DiffuseSpatialFilter.glsl"
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
vec2 texelCoord = gl_FragCoord.xy;
|
||||
vec3 color = texelFetch(colortex7, ivec2(texelCoord), 0).rgb;
|
||||
|
||||
// Step size determined by whic composite pass we are
|
||||
int step = 1;
|
||||
#ifdef SPATIAL_STEP_2
|
||||
step = 2;
|
||||
#elif defined SPATIAL_STEP_4
|
||||
step = 4;
|
||||
#elif defined SPATIAL_STEP_8
|
||||
step = 8;
|
||||
#endif
|
||||
|
||||
color = DiffuseSpatialPass(color, texelCoord, step);
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// MinecraftPT — DiffuseTemporal_FS
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/PathTracing/Denoiser/DiffuseTemporalFilter.glsl"
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
vec2 texelCoord = gl_FragCoord.xy;
|
||||
vec3 current = texelFetch(colortex6, ivec2(texelCoord), 0).rgb;
|
||||
vec3 prev = texelFetch(colortex7, ivec2(texelCoord), 0).rgb;
|
||||
|
||||
vec3 result = DiffuseTemporalAccumulate(current, texelCoord, prev);
|
||||
|
||||
colorOut = vec4(result, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
// MinecraftPT — DiffuseTracing_FS
|
||||
// One diffuse path-tracing ray per pixel at half resolution.
|
||||
// Output: colortex6 = noisy diffuse irradiance, colortex10 = motion vectors.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
#include "/Lib/GbufferData.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/TracingNoise.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/TracingUtilities.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/ShadowTracing.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/SampleIRC.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/SpecularTracer.glsl"
|
||||
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
|
||||
|
||||
uniform sampler2D colortex0; // albedo
|
||||
uniform sampler2D colortex1; // normals
|
||||
uniform sampler2D colortex3; // lightmap
|
||||
|
||||
layout(location = 0) out vec4 diffuseOut; // colortex6
|
||||
layout(location = 1) out vec4 motionOut; // colortex10
|
||||
|
||||
vec3 TraceDiffuseRay(vec3 origin, vec3 dir, float maxDist){
|
||||
vec3 result = vec3(0.0);
|
||||
|
||||
Ray ray = PackRay(origin, dir);
|
||||
vec3 voxelCoord = floor(ray.ori);
|
||||
vec3 totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
|
||||
float rayLength = 0.0;
|
||||
vec3 tracingNext;
|
||||
|
||||
for (int i = 0; i < 128; i++){
|
||||
if (clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 0.5)) != voxelCoord){
|
||||
// Miss: sample sky
|
||||
result += SampleSkyBox(dir) * (1.0 / 3.14159265);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rayLength > maxDist){
|
||||
result += SampleSkyBox(dir) * (1.0 / 3.14159265);
|
||||
break;
|
||||
}
|
||||
|
||||
vec4 voxelData = texelFetch(voxelData3D, ivec3(voxelCoord), 0);
|
||||
float voxelID = DecodeVoxelID(voxelData.z);
|
||||
|
||||
// Light sphere contribution
|
||||
if (IsLightSphere(voxelID)){
|
||||
result += HitLightShpere(ray, voxelCoord, voxelID, rayLength);
|
||||
rayLength = minVec3(totalStep);
|
||||
tracingNext = step(totalStep, vec3(rayLength));
|
||||
voxelCoord += tracingNext * ray.sdir;
|
||||
totalStep += tracingNext * abs(ray.rdir);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool hit = false;
|
||||
vec3 hitNormal = vec3(0.0);
|
||||
|
||||
if (voxelID >= 999.0){
|
||||
hit = rayLength > 0.0;
|
||||
hitNormal = -step(vec3(rayLength), totalStep - abs(ray.rdir)) * ray.sdir;
|
||||
}else if (voxelID < 1000.0 && voxelID > 1.0){
|
||||
float rawID = 1000.0 - voxelID;
|
||||
rayLength = minVec3(totalStep);
|
||||
hit = HitShape(ray, voxelCoord, rawID, rayLength, hitNormal);
|
||||
}
|
||||
|
||||
if (hit){
|
||||
vec3 hitPos = ray.ori + ray.dir * rayLength;
|
||||
vec2 midCoord = voxelData.xy;
|
||||
vec3 albedo = SampleVoxelAlbedo(midCoord, hitPos, hitNormal);
|
||||
float skylight = Unpack2xU8_Y_from_U16(voxelData.w);
|
||||
|
||||
// Direct sun at hit point
|
||||
vec3 sun = GetSunIrradiance();
|
||||
float shadow = SimpleShadowTracing(hitPos + hitNormal * 0.01, GetSunDirWorld());
|
||||
float NdotL = max(dot(hitNormal, GetSunDirWorld()), 0.0);
|
||||
|
||||
result += albedo * sun * shadow * NdotL;
|
||||
|
||||
// Sky light at hit point (from voxel skylight)
|
||||
result += albedo * GetAtmoIrradiance() * skylight * 0.5;
|
||||
|
||||
// One-bounce: sample IRC
|
||||
result += albedo * SampleIRC(hitPos) * 0.5;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Sparse skip
|
||||
float marker = voxelData.z;
|
||||
if (marker > 0.60 && marker < 0.92){
|
||||
float skipSize = marker > 0.90 ? 8.0 : (marker > 0.70 ? 4.0 : 2.0);
|
||||
vec3 nextBoundary = floor((voxelCoord + 1.0) / skipSize) * skipSize;
|
||||
vec3 distToBoundary = (nextBoundary - voxelCoord) * abs(ray.rdir);
|
||||
float tSkip = minVec3(distToBoundary) + 1e-4;
|
||||
rayLength += tSkip;
|
||||
vec3 stepVec = ray.sdir * abs(ray.rdir) * tSkip;
|
||||
ray.ori += stepVec;
|
||||
voxelCoord = floor(ray.ori);
|
||||
totalStep = (ray.sdir * (voxelCoord - ray.ori + 0.5) + 0.5) * abs(ray.rdir);
|
||||
continue;
|
||||
}
|
||||
|
||||
rayLength = minVec3(totalStep);
|
||||
tracingNext = step(totalStep, vec3(rayLength));
|
||||
voxelCoord += tracingNext * ray.sdir;
|
||||
totalStep += tracingNext * abs(ray.rdir);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void main(){
|
||||
// Half resolution texel
|
||||
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
|
||||
ivec2 fullCoord = texelCoord * 2;
|
||||
|
||||
// Skip sky
|
||||
float depth = texelFetch(depthtex0, fullCoord, 0).r;
|
||||
if (depth >= 1.0){
|
||||
diffuseOut = vec4(0.0);
|
||||
motionOut = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 albedoData = texelFetch(colortex0, fullCoord, 0);
|
||||
vec4 normalData = texelFetch(colortex1, fullCoord, 0);
|
||||
|
||||
vec3 worldNormal = DecodeNormal(normalData.xy);
|
||||
vec3 viewNormal = mat3(gbufferModelView) * worldNormal;
|
||||
|
||||
// Reconstruct view position
|
||||
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(fullCoord) / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||
viewPos.xyz /= viewPos.w;
|
||||
|
||||
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
|
||||
|
||||
vec2 noise = GetTracingNoise2(vec2(texelCoord), frameCounter, 0);
|
||||
|
||||
// Cosine-weighted hemisphere sampling
|
||||
vec3 dir = SampleHemisphere(noise, worldNormal);
|
||||
|
||||
// Only trace if there's anything to bounce (skip pure black)
|
||||
vec3 traceResult = TraceDiffuseRay(WorldToVoxel(worldPos + worldNormal * 0.05), dir, PT_DIFFUSE_TRACING_DISTANCE);
|
||||
|
||||
diffuseOut = vec4(traceResult, 1.0);
|
||||
|
||||
// Motion vectors (full res reprojection)
|
||||
vec4 prevViewPos = gbufferPreviousProjection * gbufferPreviousModelView * vec4(worldPos, 1.0);
|
||||
prevViewPos.xyz /= prevViewPos.w;
|
||||
vec2 prevScreen = (prevViewPos.xy * 0.5 + 0.5) * screenSize;
|
||||
|
||||
vec2 motion = vec2(texelCoord) - prevScreen * 0.5;
|
||||
|
||||
motionOut = vec4(motion, 0.0, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// MinecraftPT — DiffuseVariance_FS
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/PathTracing/Denoiser/DiffuseVarianceEstimation.glsl"
|
||||
|
||||
layout(location = 0) out vec4 varOut;
|
||||
|
||||
void main(){
|
||||
vec2 texelCoord = gl_FragCoord.xy;
|
||||
vec3 color = texelFetch(colortex7, ivec2(texelCoord), 0).rgb;
|
||||
vec2 variance = DiffuseEstimateVariance(color, texelCoord);
|
||||
|
||||
varOut = vec4(variance, 0.0, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// MinecraftPT — Dof_FS
|
||||
// Depth of field with circle of confusion bokeh.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/IndividualFunctions/DOF.glsl"
|
||||
|
||||
uniform sampler2D colortex12;
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
vec2 texelCoord = gl_FragCoord.xy;
|
||||
|
||||
vec3 color = texelFetch(colortex12, ivec2(texelCoord), 0).rgb;
|
||||
|
||||
#ifdef DOF
|
||||
if (DOF > 0){
|
||||
float depth = texelFetch(depthtex0, ivec2(texelCoord), 0).r;
|
||||
|
||||
// Focal distance (from center depth or manual)
|
||||
float focalDepth = CAMERA_FOCAL_POINT;
|
||||
#ifdef CAMERA_FOCUS_MODE
|
||||
if (CAMERA_FOCUS_MODE == 1){
|
||||
vec2 center = screenSize * 0.5;
|
||||
focalDepth = texelFetch(depthtex0, ivec2(center), 0).r;
|
||||
}
|
||||
#endif
|
||||
|
||||
float coc = GetCoC(depth, focalDepth);
|
||||
|
||||
#ifdef DISABLE_HAND_DOF
|
||||
// Skip hand (close depth)
|
||||
if (depth < 0.1) coc = 0.0;
|
||||
#endif
|
||||
|
||||
if (coc > 0.5){
|
||||
color = DofBlur(texelCoord, coc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// MinecraftPT — Exposure_CS
|
||||
// Computes the average scene luminance and smooths the exposure over time.
|
||||
// Writes the result into a 1x1 R16F image (exposureTex) read by the final pass.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
const ivec3 workGroups = ivec3(8, 8, 1);
|
||||
layout (local_size_x = 16, local_size_y = 16) in;
|
||||
|
||||
layout (r16f) uniform writeonly image2D img_exposureTex;
|
||||
|
||||
uniform sampler2D colortex12;
|
||||
|
||||
shared float luminanceSum[256];
|
||||
|
||||
void main(){
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
// Downsample luminance from the HDR scene
|
||||
float lum = 0.0;
|
||||
vec2 base = vec2(texel * 4);
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
vec3 color = texelFetch(colortex12, ivec2(base + vec2(i, j)), 0).rgb;
|
||||
lum += luminance(color);
|
||||
}}
|
||||
lum /= 16.0;
|
||||
|
||||
// Shared reduction
|
||||
uint local = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 16u;
|
||||
luminanceSum[local] = lum;
|
||||
barrier();
|
||||
|
||||
if (local == 0u){
|
||||
float avg = 0.0;
|
||||
for (uint i = 0u; i < 256u; i++){
|
||||
avg += luminanceSum[i];
|
||||
}
|
||||
avg /= 256.0;
|
||||
|
||||
// Target exposure (inverse of average luminance)
|
||||
float targetExposure = 1.0 / max(avg, 0.001);
|
||||
|
||||
// Read previous exposure for temporal smoothing (single thread)
|
||||
float prevExposure = imageLoad(img_exposureTex, ivec2(0, 0)).r;
|
||||
if (prevExposure <= 0.0) prevExposure = 1.0;
|
||||
|
||||
float adapted = mix(prevExposure, targetExposure, SMOOTH_EXPOSURE);
|
||||
adapted = clamp(adapted, 0.01, 100.0);
|
||||
|
||||
imageStore(img_exposureTex, ivec2(0, 0), vec4(adapted));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// MinecraftPT — IRC_CS (Irradiance Cache Update)
|
||||
// Updates the 3D irradiance cache: traces a few rays per cell toward the sky,
|
||||
// stores ambient + direct light contributions, blends over time.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/ShadowTracing.glsl"
|
||||
#include "/Lib/BasicFunctions/PrecomputedAtmosphere.glsl"
|
||||
|
||||
#ifdef PT_IRC
|
||||
|
||||
|
||||
const ivec3 workGroups = ivec3(int(ceil(float(ircResolution) / 4.0)));
|
||||
layout (local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
|
||||
|
||||
layout (rgba16f) uniform writeonly image3D img_irradianceCache3D;
|
||||
layout (rgba16f) uniform readonly image3D img_irradianceCache3D_Alt;
|
||||
|
||||
uniform sampler3D voxelData3D;
|
||||
|
||||
void main(){
|
||||
ivec3 texel = ivec3(gl_GlobalInvocationID.xyz);
|
||||
|
||||
if (any(greaterThanEqual(texel, ivec3(ircResolution)))){
|
||||
return;
|
||||
}
|
||||
|
||||
// World position of this cache cell
|
||||
vec3 cellPos = (vec3(texel) + 0.5) / float(ircResolution);
|
||||
vec3 worldPos = (cellPos - 0.5) * voxelDistance + cameraPosition;
|
||||
|
||||
// Voxel occupancy check — don't cache inside solid blocks
|
||||
vec3 voxelCoord = cellPos * voxelResolution;
|
||||
vec4 voxelData = texelFetch(voxelData3D, ivec3(clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 1.0))), 0);
|
||||
float voxelID = DecodeVoxelID(voxelData.z);
|
||||
|
||||
if (voxelID > 1.0 && voxelID < 999.0){
|
||||
// Solid — keep old value
|
||||
return;
|
||||
}
|
||||
|
||||
// Sample sky irradiance from multiple directions (hemisphere)
|
||||
vec3 irradiance = vec3(0.0);
|
||||
|
||||
for (int i = 0; i < PT_IRC_SPP; i++){
|
||||
// Deterministic sample directions over hemisphere
|
||||
float phi = 6.28318 * hash1(vec3(texel) + float(i) * 1.7);
|
||||
float cosTheta = hash1(vec3(texel) * 2.0 + float(i) * 3.1);
|
||||
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
|
||||
|
||||
vec3 dir = vec3(cos(phi) * sinTheta, cosTheta, sin(phi) * sinTheta);
|
||||
|
||||
// Trace toward sky — if not blocked, add sky light
|
||||
vec3 voxelPos = WorldToVoxel(worldPos) + dir * 0.5;
|
||||
float visibility = SimpleShadowTracing(voxelPos, dir);
|
||||
|
||||
// Sky radiance in this direction (analytic)
|
||||
vec3 skyRadiance = GetSkyRadiance(dir, GetSunDirWorld());
|
||||
|
||||
irradiance += skyRadiance * visibility;
|
||||
}
|
||||
|
||||
irradiance /= float(PT_IRC_SPP);
|
||||
|
||||
// Sun contribution (direct)
|
||||
vec3 sunDir = GetSunDirWorld();
|
||||
float sunVis = SimpleShadowTracing(WorldToVoxel(worldPos), sunDir);
|
||||
irradiance += GetSunIrradiance() * sunVis * max(sunDir.y, 0.0);
|
||||
|
||||
// Blend with previous (temporal smoothing), ping-pong by frame parity
|
||||
bool evenFrame = (frameCounter % 2) == 0;
|
||||
vec3 prev = evenFrame
|
||||
? texelFetch(img_irradianceCache3D_Alt, texel, 0).rgb
|
||||
: texelFetch(img_irradianceCache3D, texel, 0).rgb;
|
||||
irradiance = mix(prev, irradiance, PT_IRC_BLENDWEIGHT);
|
||||
|
||||
if (evenFrame){
|
||||
imageStore(img_irradianceCache3D, texel, vec4(irradiance, 1.0));
|
||||
}else{
|
||||
imageStore(img_irradianceCache3D_Alt, texel, vec4(irradiance, 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
// MinecraftPT — MotionBlur_FS
|
||||
// Per-pixel camera motion blur using motion vectors.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
|
||||
|
||||
uniform sampler2D colortex12;
|
||||
uniform sampler2D colortex10;
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
vec2 texelCoord = gl_FragCoord.xy;
|
||||
|
||||
vec3 color = texelFetch(colortex12, ivec2(texelCoord), 0).rgb;
|
||||
|
||||
#ifdef MOTION_BLUR
|
||||
if (MOTION_BLUR > 0){
|
||||
vec2 motion = texelFetch(colortex10, ivec2(texelCoord * 0.5), 0).xy * 2.0;
|
||||
float speed = length(motion);
|
||||
|
||||
if (speed > 0.5){
|
||||
// Shutter angle sampling
|
||||
float shutterAngle = mix(90.0, 360.0, MOTION_BLUR_SUTTER_SPEED);
|
||||
float samples = float(MOTION_BLUR_QUALITY);
|
||||
float dither = BlueNoiseTemporal();
|
||||
|
||||
vec2 dir = normalize(motion);
|
||||
float length = min(speed, 32.0) * 0.5;
|
||||
|
||||
vec3 acc = vec3(0.0);
|
||||
for (int i = 0; i < MOTION_BLUR_QUALITY; i++){
|
||||
float t = (float(i) + dither) / samples - 0.5;
|
||||
vec2 sampleCoord = texelCoord + dir * length * t;
|
||||
acc += textureLod(colortex12, sampleCoord / screenSize, 0.0).rgb;
|
||||
}
|
||||
|
||||
color = acc / samples;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// MinecraftPT — SH_Tracing_CS
|
||||
// Low-order spherical-harmonics sky tracing: evaluates sky radiance on a small
|
||||
// SH basis and stores it for ambient light estimation (used by IRC seeding).
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
#include "/Lib/BasicFunctions/PrecomputedAtmosphere.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/ShadowTracing.glsl"
|
||||
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
|
||||
|
||||
#ifdef PT_IRC
|
||||
|
||||
|
||||
const ivec3 workGroups = ivec3(int(ceil(float(ircResolution) / 4.0)));
|
||||
layout (local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
|
||||
|
||||
layout (rgba16f) uniform writeonly image3D img_irradianceCache3D;
|
||||
layout (rgba16f) uniform readonly image3D img_irradianceCache3D_Alt;
|
||||
|
||||
uniform sampler3D voxelData3D;
|
||||
|
||||
// SH basis Y1 (linear, 3 components) coefficients for sky radiance at a cell
|
||||
void main(){
|
||||
ivec3 texel = ivec3(gl_GlobalInvocationID.xyz);
|
||||
|
||||
if (any(greaterThanEqual(texel, ivec3(ircResolution)))){
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 cellPos = (vec3(texel) + 0.5) / float(ircResolution);
|
||||
vec3 worldPos = (cellPos - 0.5) * voxelDistance + cameraPosition;
|
||||
|
||||
vec3 voxelCoord = cellPos * voxelResolution;
|
||||
vec4 voxelData = texelFetch(voxelData3D, ivec3(clamp(voxelCoord, vec3(0.0), vec3(voxelResolution - 1.0))), 0);
|
||||
float voxelID = DecodeVoxelID(voxelData.z);
|
||||
|
||||
if (voxelID > 1.0 && voxelID < 999.0){
|
||||
return;
|
||||
}
|
||||
|
||||
// Trace N directions, accumulate SH coefficients
|
||||
vec3 sh = vec3(0.0);
|
||||
|
||||
for (int i = 0; i < 6; i++){
|
||||
float phi = 6.28318 * hash1(vec3(texel) * 1.3 + float(i) * 0.7);
|
||||
float cosTheta = hash1(vec3(texel) * 0.7 + float(i) * 1.9);
|
||||
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
|
||||
|
||||
vec3 dir = vec3(cos(phi) * sinTheta, cosTheta, sin(phi) * sinTheta);
|
||||
|
||||
float visibility = SimpleShadowTracing(WorldToVoxel(worldPos) + dir * 0.5, dir);
|
||||
|
||||
vec3 radiance = GetSkyRadiance(dir, GetSunDirWorld());
|
||||
|
||||
sh += radiance * visibility * cosTheta; // cos-weighted
|
||||
}
|
||||
|
||||
sh /= 6.0;
|
||||
|
||||
imageStore(img_irradianceCache3D, texel, vec4(sh, 1.0));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,76 @@
|
||||
// MinecraftPT — SkyImage_CS
|
||||
// Precomputes the sky panorama (skyBox2D, 3:2 cubemap cross) using the analytic
|
||||
// atmosphere model, for sampling by the path tracer and reflections.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
#include "/Lib/BasicFunctions/PrecomputedAtmosphere.glsl"
|
||||
#include "/Lib/IndividualFunctions/EndSky.glsl"
|
||||
#include "/Lib/IndividualFunctions/PlanarClouds.glsl"
|
||||
|
||||
const ivec3 workGroups = ivec3(int(ceil(float(SKYBOX_RESOLUTION_X) / 8.0)), int(ceil(float(SKYBOX_RESOLUTION_Y) / 8.0)), 1);
|
||||
layout (local_size_x = 8, local_size_y = 8) in;
|
||||
|
||||
layout (rgba16f) uniform writeonly image2D img_skyBox2D;
|
||||
|
||||
void main(){
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
// Panorama layout: 3:2 cross (like a cubemap cross folded)
|
||||
vec2 resolution = vec2(SKYBOX_RESOLUTION_X, SKYBOX_RESOLUTION_Y);
|
||||
vec2 uv = (vec2(texel) + 0.5) / resolution;
|
||||
|
||||
// Determine face and local UV
|
||||
float tileX = SKYBOX_RESOLUTION / resolution.x; // 1/3
|
||||
float tileY = SKYBOX_RESOLUTION / resolution.y; // 1/2
|
||||
|
||||
int face = int(floor(uv.x / tileX));
|
||||
vec2 faceUV = vec2(
|
||||
(uv.x - float(face) * tileX) / tileX,
|
||||
(uv.y - float(face < 3 ? 0 : 1) * tileY) / tileY
|
||||
);
|
||||
faceUV = faceUV * 2.0 - 1.0;
|
||||
|
||||
// Cubemap cross mapping (Standard OpenGL cross layout, 4x3 grid):
|
||||
// faces: 0=+X, 1=-X, 2=+Y, 3=-Y, 4=+Z, 5=-Z (top row: +X -X +Y; bottom row: -Y +Z -Z)
|
||||
// This panorama is a 3x2 layout, so: top row = +X, -X, +Y; bottom row = -Y, +Z, -Z
|
||||
vec3 dir;
|
||||
if (face == 0){ // +X
|
||||
dir = vec3(1.0, -faceUV.y, -faceUV.x);
|
||||
}else if (face == 1){ // -X
|
||||
dir = vec3(-1.0, -faceUV.y, faceUV.x);
|
||||
}else if (face == 2){ // +Y
|
||||
dir = vec3(faceUV.x, 1.0, -faceUV.y);
|
||||
}else if (face == 3){ // -Y
|
||||
dir = vec3(faceUV.x, -1.0, faceUV.y);
|
||||
}else if (face == 4){ // +Z
|
||||
dir = vec3(faceUV.x, -faceUV.y, 1.0);
|
||||
}else{ // -Z
|
||||
dir = vec3(-faceUV.x, -faceUV.y, -1.0);
|
||||
}
|
||||
|
||||
dir = normalize(dir);
|
||||
|
||||
vec3 sunDir = GetSunDirWorld();
|
||||
|
||||
// Sky radiance from analytic atmosphere
|
||||
vec3 color = GetSkyRadiance(dir, sunDir);
|
||||
|
||||
// Stars at night
|
||||
float night = 1.0 - curve(saturate(sunDir.y * 10.0 + 0.5));
|
||||
if (night > 0.5){
|
||||
float stars = 0.0;
|
||||
vec3 starSeed = floor(dir * 64.0);
|
||||
float star = hash1(starSeed);
|
||||
stars = step(0.998, star) * 2.0;
|
||||
color += vec3(1.0, 1.0, 1.0) * stars * night;
|
||||
}
|
||||
|
||||
// End dimension sky
|
||||
#ifdef DIMENSION_END
|
||||
color = GetEndSky(dir, sunDir);
|
||||
#endif
|
||||
|
||||
imageStore(img_skyBox2D, texel, vec4(color, 0.0));
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// MinecraftPT — Sky_End_FS
|
||||
// End dimension sky rendering pass.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/IndividualFunctions/EndSky.glsl"
|
||||
|
||||
uniform sampler2D depthtex0;
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
|
||||
|
||||
float depth = texelFetch(depthtex0, texelCoord, 0).r;
|
||||
if (depth < 1.0){
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(texelCoord) / screenSize * 2.0 - 1.0, 1.0, 1.0);
|
||||
vec3 viewDir = normalize(viewPos.xyz / viewPos.w);
|
||||
vec3 worldDir = normalize(mat3(gbufferModelViewInverse) * viewDir);
|
||||
|
||||
vec3 color = GetEndSky(worldDir, GetSunDirWorld());
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// MinecraftPT — Sky_Overworld_FS
|
||||
// Renders the sky into the background (colortex12) where no geometry was drawn.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
#include "/Lib/BasicFunctions/PrecomputedAtmosphere.glsl"
|
||||
#include "/Lib/IndividualFunctions/EndSky.glsl"
|
||||
#include "/Lib/IndividualFunctions/PlanarClouds.glsl"
|
||||
#include "/Lib/IndividualFunctions/CloudShadow.glsl"
|
||||
|
||||
uniform sampler2D depthtex0;
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
|
||||
|
||||
float depth = texelFetch(depthtex0, texelCoord, 0).r;
|
||||
if (depth < 1.0){
|
||||
// Not sky — preserve scene
|
||||
discard;
|
||||
}
|
||||
|
||||
// Reconstruct view ray
|
||||
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(texelCoord) / screenSize * 2.0 - 1.0, 1.0, 1.0);
|
||||
vec3 viewDir = normalize(viewPos.xyz / viewPos.w);
|
||||
vec3 worldDir = normalize(mat3(gbufferModelViewInverse) * viewDir);
|
||||
|
||||
vec3 sunDir = GetSunDirWorld();
|
||||
|
||||
// Sky radiance
|
||||
vec3 color = GetSkyRadiance(worldDir, sunDir);
|
||||
|
||||
#ifdef DIMENSION_END
|
||||
color = GetEndSky(worldDir, sunDir);
|
||||
#elif defined DIMENSION_NETHER
|
||||
// Nether: dark smoky red-brown atmosphere
|
||||
color = vec3(0.18, 0.06, 0.03) * 1.2;
|
||||
color += vec3(0.5, 0.2, 0.1) * 0.3 * (1.0 - abs(worldDir.y) * 0.5);
|
||||
#endif
|
||||
|
||||
// Planar clouds
|
||||
#ifdef PLANAR_CLOUDS
|
||||
if (PLANAR_CLOUDS > 0){
|
||||
// Ray-plane intersection with cloud layer
|
||||
float cloudAlt = mix(PC_ALTITUDE, CLOUD_CLEAR_ALTITUDE, wetness * 0.5);
|
||||
if (worldDir.y > 0.001){
|
||||
float t = (cloudAlt - cameraPosition.y) / worldDir.y;
|
||||
if (t > 0.0){
|
||||
vec3 cloudPos = cameraPosition + worldDir * t;
|
||||
vec3 cloudColor;
|
||||
float cloudDensity = GetPlanarCloudDensity(cloudPos.xz, frameTimeCounter * CLOUD_SPEED, cloudColor);
|
||||
|
||||
if (cloudDensity > 0.01){
|
||||
// Soft cloud edge
|
||||
vec3 cloudLight = mix(GetCloudAtmoIrradiance(), GetCloudSunIrradiance(), 0.8);
|
||||
color = mix(color, cloudLight, cloudDensity * 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// MinecraftPT — Soild_FS (Main Lighting Composite)
|
||||
// Combines GBuffer data with path-traced diffuse + specular, direct sun,
|
||||
// held light, emission, and ambient to produce the final HDR scene.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
#include "/Lib/GbufferData.glsl"
|
||||
#include "/Lib/BasicFunctions/Blocklight.glsl"
|
||||
#include "/Lib/BasicFunctions/HeldLight.glsl"
|
||||
#include "/Lib/BasicFunctions/Sunlight_Shadow.glsl"
|
||||
#include "/Lib/BasicFunctions/NetherColor.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/SampleIRC.glsl"
|
||||
|
||||
uniform sampler2D colortex7; // diffuse PT (denoised)
|
||||
uniform sampler2D colortex11; // specular PT (denoised)
|
||||
uniform sampler2D colortex8; // previous diffuse (for blending)
|
||||
uniform sampler2D colortex12; // combined HDR (for historical blend)
|
||||
|
||||
layout(location = 0) out vec4 colorOut; // colortex12
|
||||
|
||||
void main(){
|
||||
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
|
||||
|
||||
// Skip sky — sky was written by composite20 (Sky_Overworld_FS) into colortex12
|
||||
float depth = texelFetch(depthtex0, texelCoord, 0).r;
|
||||
if (depth >= 1.0){
|
||||
discard;
|
||||
}
|
||||
|
||||
// Read GBuffer
|
||||
GbufferData gbuffer = GetGbufferDataSoild(texelCoord);
|
||||
MaterialMask mask = CalculateMasks(gbuffer.materialID);
|
||||
|
||||
vec3 worldNormal = gbuffer.worldNormal;
|
||||
vec3 vertexNormal = gbuffer.vertexNormal;
|
||||
vec3 albedo = gbuffer.albedo;
|
||||
vec2 lightmap = gbuffer.lightmap;
|
||||
|
||||
// Reconstruct world position
|
||||
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(texelCoord) / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||
viewPos.xyz /= viewPos.w;
|
||||
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
|
||||
|
||||
// Path-traced diffuse (from half-res colortex6, sampled at full res)
|
||||
vec2 halfCoord = vec2(texelCoord) * 0.5;
|
||||
vec3 diffusePT = textureLod(colortex7, halfCoord / (screenSize * 0.5), 0.0).rgb;
|
||||
|
||||
// Path-traced specular
|
||||
vec3 specularPT = textureLod(colortex11, halfCoord / (screenSize * 0.5), 0.0).rgb;
|
||||
|
||||
// Direct sunlight
|
||||
vec3 sunLight = GetSunlight(viewPos.xyz, worldPos, vertexNormal, worldNormal, lightmap.x);
|
||||
|
||||
// Block light
|
||||
vec3 blockLight = Blocklight(lightmap) * gbuffer.material.emissiveness;
|
||||
|
||||
// Emission from GBuffer
|
||||
vec3 emission = vec3(0.0);
|
||||
emission = texelFetch(colortex0, texelCoord, 0).a * 2.0;
|
||||
|
||||
// Held light
|
||||
float heldShadow = 1.0;
|
||||
vec3 heldLight = GetHeldLight(worldPos, worldNormal, heldShadow);
|
||||
|
||||
// IRC ambient
|
||||
vec3 irc = SampleIRC(worldPos) * 0.3;
|
||||
|
||||
// Combine:
|
||||
// diffuse = albedo * (sun + block + irc + held) + diffusePT
|
||||
// specular = specularPT
|
||||
// emission = emission
|
||||
// HDR output
|
||||
|
||||
vec3 color = vec3(0.0);
|
||||
|
||||
// Diffuse
|
||||
color += albedo * (sunLight + blockLight + irc) * (1.0 - gbuffer.material.metalness);
|
||||
color += albedo * heldLight * heldShadow * gbuffer.material.roughness;
|
||||
|
||||
// Path-traced diffuse contribution (indirect GI)
|
||||
color += diffusePT * albedo * 0.5;
|
||||
|
||||
// Specular
|
||||
color += specularPT * gbuffer.material.reflectionStrength;
|
||||
|
||||
// Emission
|
||||
color += emission;
|
||||
|
||||
// Fresnel-based specular from direct light
|
||||
float NdotV = max(dot(worldNormal, normalize(-viewPos.xyz)), 0.0);
|
||||
float F0 = gbuffer.material.metalness;
|
||||
vec3 fresnel = FresnelSchlick(NdotV, vec3(F0));
|
||||
|
||||
// Direct specular (sun)
|
||||
float NdotL = max(dot(worldNormal, GetSunDirWorld()), 0.0);
|
||||
if (NdotL > 0.0){
|
||||
float roughness = gbuffer.material.roughness;
|
||||
vec3 halfVec = normalize(GetSunDirWorld() + normalize(-viewPos.xyz));
|
||||
float NdotH = max(dot(worldNormal, halfVec), 0.0);
|
||||
float D = GGX_D(NdotH, roughness);
|
||||
float G = Smith_G(NdotV, NdotL, roughness);
|
||||
vec3 specular = fresnel * D * G / (4.0 * NdotV * NdotL + 0.0001);
|
||||
color += GetSunIrradiance() * specular * NdotL * 0.5;
|
||||
}
|
||||
|
||||
// Apply parallax shadow
|
||||
color *= gbuffer.parallaxShadow;
|
||||
|
||||
// Sky mask: if sky, output 0
|
||||
if (mask.sky > 0.5) color = vec3(0.0);
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// MinecraftPT — SpecularSpatial_FS
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/PathTracing/Denoiser/SpecularSpatialFilter.glsl"
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
vec2 texelCoord = gl_FragCoord.xy;
|
||||
vec3 color = texelFetch(colortex11, ivec2(texelCoord), 0).rgb;
|
||||
|
||||
int step = 1;
|
||||
#ifdef SPATIAL_STEP_2
|
||||
step = 2;
|
||||
#elif defined SPATIAL_STEP_4
|
||||
step = 4;
|
||||
#endif
|
||||
|
||||
color = SpecularSpatialPass(color, texelCoord, step);
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// MinecraftPT — SpecularTemporal_FS
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/PathTracing/Denoiser/SpecularTemporalFilter.glsl"
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
vec2 texelCoord = gl_FragCoord.xy;
|
||||
vec3 current = texelFetch(colortex9, ivec2(texelCoord), 0).rgb;
|
||||
vec3 prev = texelFetch(colortex11, ivec2(texelCoord), 0).rgb;
|
||||
|
||||
vec3 result = SpecularTemporalAccumulate(current, texelCoord);
|
||||
|
||||
colorOut = vec4(result, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// MinecraftPT — SpecularTracing_FS
|
||||
// Specular reflection path tracing at half resolution.
|
||||
// Output: colortex9 = noisy specular, colortex11 = history (ping-pong)
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
#include "/Lib/GbufferData.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/TracingNoise.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/TracingUtilities.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/SpecularTracer.glsl"
|
||||
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
|
||||
|
||||
layout(location = 0) out vec4 specularOut;
|
||||
|
||||
void main(){
|
||||
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
|
||||
ivec2 fullCoord = texelCoord * 2;
|
||||
|
||||
float depth = texelFetch(depthtex0, fullCoord, 0).r;
|
||||
if (depth >= 1.0){
|
||||
specularOut = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 normalData = texelFetch(colortex1, fullCoord, 0);
|
||||
vec3 worldNormal = DecodeNormal(normalData.xy);
|
||||
vec4 materialData = texelFetch(colortex2, fullCoord, 0);
|
||||
|
||||
float roughness = 1.0 - materialData.r;
|
||||
roughness = roughness * roughness;
|
||||
float metalness = materialData.g;
|
||||
|
||||
// Skip rough non-metal surfaces when rough specular is disabled
|
||||
#if ENABLE_ROUGH_SPECULAR == 0
|
||||
if (roughness > 0.5 && metalness < 0.04){
|
||||
specularOut = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Reconstruct view position
|
||||
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(fullCoord) / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||
viewPos.xyz /= viewPos.w;
|
||||
|
||||
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
|
||||
vec3 viewDir = normalize(-viewPos.xyz);
|
||||
|
||||
vec2 noise = GetTracingNoise2(vec2(texelCoord), frameCounter, 1);
|
||||
|
||||
// Importance-sample GGX reflection direction
|
||||
vec3 reflDir = ImportanceSampleGGX(noise, worldNormal, roughness);
|
||||
|
||||
// Or use pure reflection for smooth surfaces
|
||||
if (roughness < 0.05){
|
||||
reflDir = reflect(-viewDir, worldNormal);
|
||||
}
|
||||
|
||||
// Trace the specular ray
|
||||
vec3 result = SpecularTrace(WorldToVoxel(worldPos + worldNormal * 0.02), reflDir, PT_SPECULAR_TRACING_DISTANCE, noise);
|
||||
|
||||
specularOut = vec4(result, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// MinecraftPT — TAA
|
||||
// Temporal anti-aliasing with jittered accumulation and neighborhood clamping.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
|
||||
|
||||
uniform sampler2D colortex12; // HDR scene (current)
|
||||
uniform sampler2D colortex13; // previous frame HDR
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
layout(location = 1) out vec4 historyOut; // same result, stored for next frame
|
||||
|
||||
void main(){
|
||||
vec2 texelCoord = gl_FragCoord.xy;
|
||||
|
||||
vec3 current = texelFetch(colortex12, ivec2(texelCoord), 0).rgb;
|
||||
|
||||
// Motion vector
|
||||
vec2 motion = texelFetch(colortex10, ivec2(texelCoord * 0.5), 0).xy * 2.0;
|
||||
vec2 prevCoord = texelCoord + motion;
|
||||
|
||||
// Sample previous
|
||||
vec3 history = textureLod(colortex13, prevCoord / screenSize, 0.0).rgb;
|
||||
|
||||
// Neighborhood clamp
|
||||
vec3 minColor = history;
|
||||
vec3 maxColor = history;
|
||||
for (int i = -1; i <= 1; i++){
|
||||
for (int j = -1; j <= 1; j++){
|
||||
vec3 c = textureLod(colortex13, (prevCoord + vec2(i, j)) / screenSize, 0.0).rgb;
|
||||
minColor = min(minColor, c);
|
||||
maxColor = max(maxColor, c);
|
||||
}}
|
||||
history = clamp(history, minColor, maxColor);
|
||||
|
||||
// Subpixel sharpening
|
||||
float sharpening = TAA_SUBPIXEL_SHARPNING;
|
||||
current = current + (current - history) * sharpening * TAA_AGGRESSION;
|
||||
|
||||
float blend = TAA_BLENDWEIGHT;
|
||||
vec3 color = mix(current, history, blend);
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
historyOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// MinecraftPT — Translucent_FS
|
||||
// Composites translucent geometry (water, glass, particles) on top of solid.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
#include "/Lib/GbufferData.glsl"
|
||||
#include "/Lib/BasicFunctions/Sunlight_Shadow.glsl"
|
||||
#include "/Lib/BasicFunctions/Blocklight.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/SampleIRC.glsl"
|
||||
#include "/Lib/PathTracing/Tracer/ShadowTracing.glsl"
|
||||
|
||||
uniform sampler2D colortex12; // combined HDR solid scene
|
||||
uniform sampler2D colortex4; // translucent albedo
|
||||
uniform sampler2D colortex5; // translucent normal
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
|
||||
|
||||
float depth = texelFetch(depthtex0, texelCoord, 0).r;
|
||||
if (depth >= 1.0){
|
||||
colorOut = texelFetch(colortex12, texelCoord, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if there is translucent data
|
||||
vec4 gbuffer5 = texelFetch(colortex5, texelCoord, 0);
|
||||
float matID = gbuffer5.a * 255.0;
|
||||
|
||||
if (matID < 0.5){
|
||||
colorOut = texelFetch(colortex12, texelCoord, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isSmooth;
|
||||
GbufferData gbuffer = GetGbufferDataTranslucent(texelCoord, isSmooth);
|
||||
|
||||
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(texelCoord) / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||
viewPos.xyz /= viewPos.w;
|
||||
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
|
||||
|
||||
vec3 solidColor = texelFetch(colortex12, texelCoord, 0).rgb;
|
||||
|
||||
// Water: blend with refraction
|
||||
vec3 color = solidColor;
|
||||
|
||||
if (matID == MATID_WATER){
|
||||
vec3 waterColor = gbuffer.albedo;
|
||||
float alpha = gbuffer.albedoAlpha;
|
||||
|
||||
// Fresnel
|
||||
vec3 viewDir = normalize(-viewPos.xyz);
|
||||
float NdotV = max(dot(gbuffer.worldNormal, viewDir), 0.0);
|
||||
float fresnel = 0.02 + 0.98 * pow(1.0 - NdotV, 5.0);
|
||||
|
||||
// Light contribution (sun + sky) on water
|
||||
vec3 sunLight = GetSunlight(viewPos.xyz, worldPos, gbuffer.vertexNormal, gbuffer.worldNormal, gbuffer.lightmap.x);
|
||||
vec3 waterLight = waterColor * (sunLight + Blocklight(gbuffer.lightmap) * 0.5);
|
||||
|
||||
// Water tint / depth color
|
||||
vec3 deepColor = waterColor * 0.3;
|
||||
|
||||
color = mix(solidColor, waterLight + deepColor, fresnel * 0.8 + 0.2);
|
||||
|
||||
}else if (matID == MATID_STAINEDGLASS){
|
||||
vec3 glassColor = gbuffer.albedo;
|
||||
float alpha = gbuffer.albedoAlpha;
|
||||
|
||||
vec3 viewDir = normalize(-viewPos.xyz);
|
||||
float NdotV = max(dot(gbuffer.worldNormal, viewDir), 0.0);
|
||||
float fresnel = 0.04 + 0.96 * pow(1.0 - NdotV, 5.0);
|
||||
|
||||
color = mix(solidColor, solidColor * glassColor, fresnel);
|
||||
color += glassColor * 0.1;
|
||||
|
||||
}else{
|
||||
// Particles etc — additively blend
|
||||
color = solidColor + gbuffer.albedo * gbuffer.albedoAlpha * 0.5;
|
||||
}
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// MinecraftPT — Volumetric_FS
|
||||
// Volumetric fog + volumetric clouds ray marched per-pixel and composited.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/LightingConstants.glsl"
|
||||
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
|
||||
#include "/Lib/IndividualFunctions/VolumetricFog.glsl"
|
||||
#include "/Lib/IndividualFunctions/WaterFog.glsl"
|
||||
#include "/Lib/IndividualFunctions/PlanarClouds.glsl"
|
||||
#include "/Lib/IndividualFunctions/CloudShadow.glsl"
|
||||
|
||||
uniform sampler2D colortex12; // HDR scene
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
vec2 texelCoord = gl_FragCoord.xy;
|
||||
vec3 sceneColor = texelFetch(colortex12, ivec2(texelCoord), 0).rgb;
|
||||
|
||||
float depth = texelFetch(depthtex0, ivec2(texelCoord), 0).r;
|
||||
|
||||
// Reconstruct view position
|
||||
vec4 viewPos = gbufferProjectionInverse * vec4(texelCoord / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||
viewPos.xyz /= viewPos.w;
|
||||
|
||||
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
|
||||
|
||||
// Dithering for the ray march
|
||||
float dither = BlueNoiseTemporal();
|
||||
|
||||
// Volumetric fog accumulation
|
||||
vec3 fogColor = vec3(0.0);
|
||||
float transmittance = 1.0;
|
||||
|
||||
// Ray march toward the surface
|
||||
int steps = VFOG_QUALITY;
|
||||
float dist = length(viewPos.xyz);
|
||||
float stepSize = dist / float(steps);
|
||||
|
||||
vec3 rayDir = normalize(viewPos.xyz);
|
||||
vec3 marchPos = worldPos;
|
||||
|
||||
float time = frameTimeCounter * 0.05;
|
||||
|
||||
for (int i = 0; i < steps; i++){
|
||||
float t = (float(i) + dither) * stepSize;
|
||||
vec3 samplePos = marchPos - rayDir * t;
|
||||
|
||||
float density = GetVolumetricFogDensity(samplePos, time);
|
||||
density *= stepSize;
|
||||
|
||||
// Sun scattering
|
||||
float phase = 0.5 + 0.5 * dot(normalize(GetSunDirWorld()), -rayDir);
|
||||
|
||||
vec3 inscatter = GetFogColor(samplePos, GetSunDirWorld()) * density * phase;
|
||||
|
||||
fogColor += transmittance * inscatter;
|
||||
transmittance *= exp(-density);
|
||||
}
|
||||
|
||||
// Cloud shadow on fog
|
||||
#ifdef VFOG_CLOUD_SHADOW
|
||||
float cloudShadow = GetCloudShadow(worldPos);
|
||||
fogColor *= cloudShadow;
|
||||
#endif
|
||||
|
||||
// Combine
|
||||
vec3 finalColor = sceneColor * transmittance + fogColor;
|
||||
|
||||
// Water fog (underwater)
|
||||
#ifdef UNDERWATER_VFOG
|
||||
if (isEyeInWater > 0){
|
||||
vec3 waterColor = GetWaterFogColor(worldPos);
|
||||
float waterFog = 1.0 - exp(-dist * GetWaterFogDensity(worldPos) * UNDERWATER_VFOG_DENSITY);
|
||||
finalColor = mix(finalColor, waterColor * 3.0, waterFog);
|
||||
}
|
||||
#endif
|
||||
|
||||
colorOut = vec4(finalColor, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// MinecraftPT — VoxelData_Copy compute shader
|
||||
// Copies the 2D voxel atlas (shadowcolor1) into the 3D voxel texture,
|
||||
// computing sparse-tracing empty markers for hierarchical ray skipping.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
|
||||
|
||||
#if PT_VOXEL_RESOLUTION == 4004
|
||||
const ivec3 workGroups = ivec3(16, 16, 16);
|
||||
#elif PT_VOXEL_RESOLUTION == 6004
|
||||
const ivec3 workGroups = ivec3(24, 16, 24);
|
||||
#elif PT_VOXEL_RESOLUTION == 8004
|
||||
const ivec3 workGroups = ivec3(32, 16, 32);
|
||||
#elif PT_VOXEL_RESOLUTION == 8006
|
||||
const ivec3 workGroups = ivec3(32, 24, 32);
|
||||
#elif PT_VOXEL_RESOLUTION == 8008
|
||||
const ivec3 workGroups = ivec3(32, 32, 32);
|
||||
#elif PT_VOXEL_RESOLUTION == 12004
|
||||
const ivec3 workGroups = ivec3(48, 16, 48);
|
||||
#elif PT_VOXEL_RESOLUTION == 12006
|
||||
const ivec3 workGroups = ivec3(48, 24, 48);
|
||||
#elif PT_VOXEL_RESOLUTION == 12008
|
||||
const ivec3 workGroups = ivec3(48, 32, 48);
|
||||
#elif PT_VOXEL_RESOLUTION == 16004
|
||||
const ivec3 workGroups = ivec3(64, 16, 64);
|
||||
#elif PT_VOXEL_RESOLUTION == 16008
|
||||
const ivec3 workGroups = ivec3(64, 32, 64);
|
||||
#elif PT_VOXEL_RESOLUTION == 16016
|
||||
const ivec3 workGroups = ivec3(64, 64, 64);
|
||||
#else
|
||||
const ivec3 workGroups = ivec3(32, 24, 32);
|
||||
#endif
|
||||
|
||||
layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
|
||||
|
||||
layout (rgba16) uniform writeonly image3D img_voxelData3D;
|
||||
|
||||
#ifdef PT_SPARE_TRACING
|
||||
shared uint isOccupied_8;
|
||||
shared uint isOccupied_4[8];
|
||||
shared uint isOccupied_2[64];
|
||||
#endif
|
||||
|
||||
uniform sampler2D shadowcolor1;
|
||||
|
||||
void main(){
|
||||
#ifdef PT_SPARE_TRACING
|
||||
int id_4 = int((gl_LocalInvocationID.x >> 2u) + (gl_LocalInvocationID.y >> 2u) * 2u + (gl_LocalInvocationID.z >> 2u) * 4u);
|
||||
int id_2 = int((gl_LocalInvocationID.x >> 1u) + (gl_LocalInvocationID.y >> 1u) * 4u + (gl_LocalInvocationID.z >> 2u) * 16u);
|
||||
|
||||
isOccupied_8 = 0u;
|
||||
isOccupied_4[id_4] = 0u;
|
||||
isOccupied_2[id_2] = 0u;
|
||||
|
||||
barrier();
|
||||
#endif
|
||||
|
||||
ivec3 drawTexel = ivec3(gl_GlobalInvocationID.xyz);
|
||||
ivec2 voxelTexel = ivec2(VoxelTexel_From_VoxelCoord(vec3(drawTexel)));
|
||||
|
||||
vec4 voxelData = texelFetch(shadowcolor1, voxelTexel, 0);
|
||||
|
||||
// A texel with z >= 1.0 is empty (clear color)
|
||||
if (voxelData.z >= 1.0){
|
||||
voxelData = vec4(0.0, 0.0, 1.0, 1.0); // empty voxel: encoded ID = 1.0 (air)
|
||||
}
|
||||
|
||||
#ifdef PT_SPARE_TRACING
|
||||
uint occupied = uint(voxelData.z < 0.999);
|
||||
|
||||
atomicMax(isOccupied_8, occupied);
|
||||
barrier();
|
||||
|
||||
if (isOccupied_8 == 0u){
|
||||
voxelData.z = 0.91; // 8^3 empty marker
|
||||
}else{
|
||||
atomicMax(isOccupied_4[id_4], occupied);
|
||||
barrier();
|
||||
if (isOccupied_4[id_4] == 0u){
|
||||
voxelData.z = 0.71; // 4^3 empty marker
|
||||
}else{
|
||||
atomicMax(isOccupied_2[id_2], occupied);
|
||||
barrier();
|
||||
if (isOccupied_2[id_2] == 0u)
|
||||
voxelData.z = 0.61; // 2^3 empty marker
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
imageStore(img_voxelData3D, drawTexel, voxelData);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// MinecraftPT — WaterRefraction_FS
|
||||
// Water refraction pass: sample the solid scene with wave-based offset.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/GbufferData.glsl"
|
||||
#include "/Lib/IndividualFunctions/WaterWaves.glsl"
|
||||
|
||||
uniform sampler2D colortex12; // solid scene
|
||||
uniform sampler2D colortex4; // translucent albedo
|
||||
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
|
||||
void main(){
|
||||
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
|
||||
|
||||
float depth = texelFetch(depthtex0, texelCoord, 0).r;
|
||||
if (depth >= 1.0){
|
||||
colorOut = texelFetch(colortex12, texelCoord, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 gbuffer5 = texelFetch(colortex5, texelCoord, 0);
|
||||
float matID = gbuffer5.a * 255.0;
|
||||
|
||||
if (matID != MATID_WATER){
|
||||
colorOut = texelFetch(colortex12, texelCoord, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reconstruct world position
|
||||
vec4 viewPos = gbufferProjectionInverse * vec4(vec2(texelCoord) / screenSize * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||
viewPos.xyz /= viewPos.w;
|
||||
vec3 worldPos = gbufferModelViewInverse[3].xyz + viewPos.xyz;
|
||||
|
||||
// Wave normal-based refraction offset
|
||||
vec3 waveNormal = GetWaveNormal(worldPos, 0.5);
|
||||
vec3 viewDir = normalize(-viewPos.xyz);
|
||||
vec3 refracted = refract(viewDir, waveNormal, 0.75);
|
||||
|
||||
// Sample the solid scene with the refraction offset
|
||||
vec3 refractedDir = mat3(gbufferModelView) * refracted;
|
||||
vec2 refractedCoord = viewPos.xy / viewPos.z * refractedDir.xy / refractedDir.z * 0.5 + 0.5;
|
||||
vec2 sampleCoord = refractedCoord * screenSize;
|
||||
|
||||
vec3 color = textureLod(colortex12, sampleCoord / screenSize, 0.0).rgb;
|
||||
|
||||
// Water depth color fade
|
||||
vec3 waterColor = texelFetch(colortex4, texelCoord, 0).rgb;
|
||||
color = mix(color, waterColor, 0.3);
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// MinecraftPT — Final_FS
|
||||
// HDR tonemapping, color grading, dithering, and output to screen.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
|
||||
|
||||
uniform sampler2D exposureTex;
|
||||
|
||||
#if defined PROGRAM_FINAL_0
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
#elif defined PROGRAM_FINAL_1
|
||||
layout(location = 0) out vec4 colorOut;
|
||||
#endif
|
||||
|
||||
// Tonemapping operators
|
||||
vec3 TonemapACES(vec3 color){
|
||||
// ACES filmic
|
||||
float a = 2.51;
|
||||
float b = 0.03;
|
||||
float c = 2.43;
|
||||
float d = 0.59;
|
||||
float e = 0.14;
|
||||
return saturate((color * (a * color + b)) / (color * (c * color + d) + e));
|
||||
}
|
||||
|
||||
vec3 TonemapAGX(vec3 color){
|
||||
// AGX-inspired: log-shaping curve
|
||||
vec3 logColor = log2(max(color, 1e-6));
|
||||
vec3 mid = vec3(AGX_HDR_MIDGREY);
|
||||
vec3 shaped = logColor - mid;
|
||||
shaped = tanh(shaped * 0.5) * 0.5 + 0.5;
|
||||
vec3 result = exp2(shaped + mid);
|
||||
return result;
|
||||
}
|
||||
|
||||
vec3 TonemapFilmic(vec3 color){
|
||||
// Uncharted 2 filmic
|
||||
vec3 x = max(color, 0.0);
|
||||
return (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06);
|
||||
}
|
||||
|
||||
// Color grading
|
||||
vec3 ApplyColorGrading(vec3 color){
|
||||
// White/black point
|
||||
color = (color - BLACK_POINT) / (WHITE_POINT - BLACK_POINT + 1e-6);
|
||||
|
||||
// Saturation
|
||||
float lum = luminance(color);
|
||||
color = mix(vec3(lum), color, SATURATION);
|
||||
|
||||
// Gamma
|
||||
color = pow(color, vec3(GAMMA));
|
||||
|
||||
// Hue shifts (simplified)
|
||||
#ifdef ADVANCED_COLOR
|
||||
vec3 midtone = color * MIDTONE_HUE * MIDTONE_STRENGTH;
|
||||
vec3 highlight = color * HIGHLIGHT_HUE * HIGHLIGHT_STRENGTH;
|
||||
vec3 shadow = color * SHADOW_HUE * SHADOW_STRENGTH;
|
||||
color += midtone + highlight + shadow;
|
||||
#endif
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void main(){
|
||||
vec3 color = texelFetch(colortex12, ivec2(gl_FragCoord.xy), 0).rgb;
|
||||
|
||||
// Exposure
|
||||
#ifdef MANUAL_EXPOSURE
|
||||
float exposure = MANUAL_EXPOSURE * pow(2.0, EV_VALUE);
|
||||
#else
|
||||
float exposure = textureLod(exposureTex, vec2(0.5), 0.0).r;
|
||||
#endif
|
||||
color *= exposure;
|
||||
|
||||
// Bloom composite
|
||||
#ifdef BLOOM
|
||||
vec3 bloom = vec3(0.0);
|
||||
// Simple bloom: sample from bloom buffer
|
||||
bloom = textureLod(colortex15, gl_FragCoord.xy / screenSize, 0.0).rgb;
|
||||
color += bloom * BLOOM_AMOUNT;
|
||||
#endif
|
||||
|
||||
// Tonemapping
|
||||
#if TONEMAP_OPERATOR == 0
|
||||
color = TonemapACES(color);
|
||||
#elif TONEMAP_OPERATOR == 1
|
||||
color = TonemapAGX(color);
|
||||
#elif TONEMAP_OPERATOR == 2
|
||||
color = TonemapFilmic(color);
|
||||
#else
|
||||
// Vanilla-like: Reinhard
|
||||
color = color / (color + 1.0);
|
||||
#endif
|
||||
|
||||
// Color grading
|
||||
color = ApplyColorGrading(color);
|
||||
|
||||
// Dithering
|
||||
vec2 noise = BlueNoiseTemporal2();
|
||||
color += (noise - 0.5) / 255.0;
|
||||
|
||||
// Gamma correction
|
||||
color = LinearToGamma(color);
|
||||
|
||||
colorOut = vec4(color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// MinecraftPT — Armor Glint Fragment Shader (enchanted armor shimmer)
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec3 worldPos;
|
||||
in vec3 worldNormal;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 color;
|
||||
in vec2 lightmap;
|
||||
|
||||
layout(location = 0) out vec4 colortex0Out;
|
||||
layout(location = 1) out vec4 colortex1Out;
|
||||
layout(location = 2) out vec4 colortex2Out;
|
||||
layout(location = 3) out vec4 colortex3Out;
|
||||
layout(location = 4) out vec4 colortex4Out;
|
||||
layout(location = 5) out vec4 colortex5Out;
|
||||
|
||||
void main(){
|
||||
vec4 albedo = texture(tex, texcoord) * color;
|
||||
|
||||
if (albedo.a < 0.004) discard;
|
||||
|
||||
// Glint is additive-ish; store with high specular
|
||||
colortex0Out = vec4(albedo.rgb, 0.0);
|
||||
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
|
||||
colortex2Out = vec4(0.0, 0.0, 0.0, 6.0 / 255.0);
|
||||
colortex3Out = vec4(lightmap, 1.0, 1.0);
|
||||
|
||||
colortex4Out = vec4(0.0);
|
||||
colortex5Out = vec4(0.0);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// MinecraftPT — Basic Fragment Shader (untextured geometry, e.g. clouds, selection)
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec3 worldPos;
|
||||
in vec3 worldNormal;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 color;
|
||||
in vec2 lightmap;
|
||||
flat in int blockId;
|
||||
|
||||
layout(location = 0) out vec4 colortex0Out;
|
||||
layout(location = 1) out vec4 colortex1Out;
|
||||
layout(location = 2) out vec4 colortex2Out;
|
||||
layout(location = 3) out vec4 colortex3Out;
|
||||
layout(location = 4) out vec4 colortex4Out;
|
||||
layout(location = 5) out vec4 colortex5Out;
|
||||
|
||||
void main(){
|
||||
vec4 albedo = color;
|
||||
|
||||
#ifdef IS_SELECTION
|
||||
float matID = 19.0 / 255.0; // MATID_SELECTION
|
||||
#else
|
||||
float matID = 0.0;
|
||||
#endif
|
||||
|
||||
colortex0Out = vec4(albedo.rgb, 0.0);
|
||||
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
|
||||
colortex2Out = vec4(0.0, 0.0, 0.0, matID);
|
||||
colortex3Out = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
colortex4Out = vec4(0.0);
|
||||
colortex5Out = vec4(0.0);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// MinecraftPT — Beacon Beam Fragment Shader (emissive beam)
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec3 worldPos;
|
||||
in vec3 worldNormal;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 color;
|
||||
in vec2 lightmap;
|
||||
|
||||
layout(location = 0) out vec4 colortex0Out;
|
||||
layout(location = 1) out vec4 colortex1Out;
|
||||
layout(location = 2) out vec4 colortex2Out;
|
||||
layout(location = 3) out vec4 colortex3Out;
|
||||
layout(location = 4) out vec4 colortex4Out;
|
||||
layout(location = 5) out vec4 colortex5Out;
|
||||
|
||||
void main(){
|
||||
vec4 albedo = texture(tex, texcoord) * color;
|
||||
|
||||
if (albedo.a < 0.004) discard;
|
||||
|
||||
colortex0Out = vec4(albedo.rgb, 1.0); // fully emissive
|
||||
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
|
||||
colortex2Out = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
colortex3Out = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
colortex4Out = vec4(0.0);
|
||||
colortex5Out = vec4(0.0);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// MinecraftPT — Composite_Copy_CS
|
||||
// Copies the full-res GBuffer into the half-res working buffers used by the
|
||||
// path tracing passes (simplified: keeps full-res, pass-through for layout parity).
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
layout (local_size_x = 8, local_size_y = 8) in;
|
||||
|
||||
uniform sampler2D colortex0;
|
||||
uniform sampler2D colortex1;
|
||||
uniform sampler2D colortex3;
|
||||
|
||||
void main(){
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
// Pass-through (identity copy for pipeline parity)
|
||||
// In a full implementation this would downsample to half-res buffers.
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// MinecraftPT — Damaged Block Fragment Shader
|
||||
// Handles block damage cracks — same as terrain but with damage texture overlay
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/Programs/Gbuffers/Terrain_FS.glsl"
|
||||
@@ -0,0 +1,60 @@
|
||||
// MinecraftPT — Entities Fragment Shader
|
||||
// Handles entities (players, mobs), hands are in Hand_FS
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec3 worldPos;
|
||||
in vec3 worldNormal;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 color;
|
||||
in vec2 lightmap;
|
||||
flat in int blockId;
|
||||
flat in float blockLightLevel;
|
||||
|
||||
layout(location = 0) out vec4 colortex0Out;
|
||||
layout(location = 1) out vec4 colortex1Out;
|
||||
layout(location = 2) out vec4 colortex2Out;
|
||||
layout(location = 3) out vec4 colortex3Out;
|
||||
layout(location = 4) out vec4 colortex4Out;
|
||||
layout(location = 5) out vec4 colortex5Out;
|
||||
|
||||
uniform bool isPlayer;
|
||||
|
||||
void main(){
|
||||
vec4 albedo = texture(tex, texcoord) * color;
|
||||
|
||||
if (albedo.a < 0.004) discard;
|
||||
|
||||
// Entity material ID — default entity
|
||||
float matID = 6.0; // MATID_ENTITIES
|
||||
|
||||
// Player special handling (OptiFine provides isPlayer uniform in entities pass)
|
||||
if (isPlayer){
|
||||
matID = 7.0; // MATID_ENTITIES_PLAYER
|
||||
}
|
||||
|
||||
vec4 specTex = vec4(0.0);
|
||||
#ifdef TEXTURE_PBR_FORMAT
|
||||
if (TEXTURE_PBR_FORMAT >= 1){
|
||||
specTex = texture(atlasSpecular2D, texcoord);
|
||||
}
|
||||
#endif
|
||||
|
||||
vec2 lm = lightmap;
|
||||
lm.y = SkyLightmapCurve(lightmap.y);
|
||||
|
||||
float emissive = 0.0;
|
||||
#ifdef VANILLA_EMISSIVE
|
||||
emissive = step(13.5, blockLightLevel) * blockLightLevel / 15.0;
|
||||
#endif
|
||||
|
||||
colortex0Out = vec4(albedo.rgb, emissive);
|
||||
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
|
||||
colortex2Out = vec4(specTex.r, specTex.g, specTex.b, matID / 255.0);
|
||||
colortex3Out = vec4(lm, 1.0, 1.0);
|
||||
|
||||
colortex4Out = vec4(0.0);
|
||||
colortex5Out = vec4(0.0);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// MinecraftPT — Entities Vertex Shader
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
out vec2 texcoord;
|
||||
out vec3 worldPos;
|
||||
out vec3 worldNormal;
|
||||
out vec3 vertexNormal;
|
||||
out vec4 color;
|
||||
out vec2 lightmap;
|
||||
flat out int blockId;
|
||||
flat out float blockLightLevel;
|
||||
|
||||
void main(){
|
||||
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
|
||||
vec4 wPos = gbufferModelViewInverse * viewPos;
|
||||
worldPos = wPos.xyz;
|
||||
|
||||
vertexNormal = normalize(gl_NormalMatrix * gl_Normal);
|
||||
worldNormal = normalize(mat3(gbufferModelViewInverse) * vertexNormal);
|
||||
|
||||
lightmap = gl_MultiTexCoord1.xy / 240.0;
|
||||
lightmap = saturate(lightmap);
|
||||
|
||||
blockId = int(mc_Entity.x + 0.5);
|
||||
blockLightLevel = at_midBlock.w;
|
||||
|
||||
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
|
||||
color = gl_Color;
|
||||
|
||||
gl_Position = gl_ProjectionMatrix * viewPos;
|
||||
gl_Position.xy += taaJitter * gl_Position.w;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// MinecraftPT — Generic Vertex Shader (entities, textured, line, weather, glints)
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
out vec2 texcoord;
|
||||
out vec3 worldPos;
|
||||
out vec3 worldNormal;
|
||||
out vec3 vertexNormal;
|
||||
out vec4 color;
|
||||
out vec2 lightmap;
|
||||
flat out int blockId;
|
||||
flat out float blockLightLevel;
|
||||
|
||||
void main(){
|
||||
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
|
||||
vec4 wPos = gbufferModelViewInverse * viewPos;
|
||||
worldPos = wPos.xyz;
|
||||
|
||||
vertexNormal = normalize(gl_NormalMatrix * gl_Normal);
|
||||
worldNormal = normalize(mat3(gbufferModelViewInverse) * vertexNormal);
|
||||
|
||||
lightmap = gl_MultiTexCoord1.xy / 240.0;
|
||||
lightmap = saturate(lightmap);
|
||||
|
||||
blockId = int(mc_Entity.x + 0.5);
|
||||
blockLightLevel = at_midBlock.w;
|
||||
|
||||
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
|
||||
color = gl_Color;
|
||||
|
||||
gl_Position = gl_ProjectionMatrix * viewPos;
|
||||
gl_Position.xy += taaJitter * gl_Position.w;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// MinecraftPT — Water Hand Vertex Shader (hand when submerged)
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
out vec2 texcoord;
|
||||
out vec3 worldPos;
|
||||
out vec3 worldNormal;
|
||||
out vec3 vertexNormal;
|
||||
out vec4 color;
|
||||
out vec2 lightmap;
|
||||
|
||||
void main(){
|
||||
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
|
||||
vec4 wPos = gbufferModelViewInverse * viewPos;
|
||||
worldPos = wPos.xyz;
|
||||
|
||||
vertexNormal = normalize(gl_NormalMatrix * gl_Normal);
|
||||
worldNormal = normalize(mat3(gbufferModelViewInverse) * vertexNormal);
|
||||
|
||||
lightmap = gl_MultiTexCoord1.xy / 240.0;
|
||||
lightmap = saturate(lightmap);
|
||||
|
||||
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
|
||||
color = gl_Color;
|
||||
|
||||
gl_Position = gl_ProjectionMatrix * viewPos;
|
||||
gl_Position.xy += taaJitter * gl_Position.w;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// MinecraftPT — Line Fragment Shader (debug lines, selection box)
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec3 worldPos;
|
||||
in vec3 worldNormal;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 color;
|
||||
in vec2 lightmap;
|
||||
flat in int blockId;
|
||||
|
||||
layout(location = 0) out vec4 colortex0Out;
|
||||
layout(location = 1) out vec4 colortex1Out;
|
||||
layout(location = 2) out vec4 colortex2Out;
|
||||
layout(location = 3) out vec4 colortex3Out;
|
||||
layout(location = 4) out vec4 colortex4Out;
|
||||
layout(location = 5) out vec4 colortex5Out;
|
||||
|
||||
void main(){
|
||||
colortex0Out = vec4(color.rgb, 0.0);
|
||||
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
|
||||
colortex2Out = vec4(0.0, 0.0, 0.0, 19.0 / 255.0); // MATID_SELECTION
|
||||
colortex3Out = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
colortex4Out = vec4(0.0);
|
||||
colortex5Out = vec4(0.0);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// MinecraftPT — Sky Vertex Shader
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
out vec2 texcoord;
|
||||
out vec3 worldPos;
|
||||
out vec4 color;
|
||||
|
||||
void main(){
|
||||
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
|
||||
vec4 wPos = gbufferModelViewInverse * viewPos;
|
||||
worldPos = wPos.xyz;
|
||||
|
||||
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
|
||||
color = gl_Color;
|
||||
|
||||
gl_Position = gl_ProjectionMatrix * viewPos;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// MinecraftPT — Sky Fragment Shader
|
||||
// Writes sky color into GBuffer with MATID_SKY so composite can identify it.
|
||||
// Custom sky is drawn in composite20 (Sky_Overworld_FS) over this.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec3 worldPos;
|
||||
in vec4 color;
|
||||
|
||||
layout(location = 0) out vec4 colortex0Out;
|
||||
layout(location = 1) out vec4 colortex1Out;
|
||||
layout(location = 2) out vec4 colortex2Out;
|
||||
layout(location = 3) out vec4 colortex3Out;
|
||||
layout(location = 4) out vec4 colortex4Out;
|
||||
layout(location = 5) out vec4 colortex5Out;
|
||||
|
||||
void main(){
|
||||
vec4 albedo = texture(tex, texcoord) * color;
|
||||
|
||||
// Sky: mark with MATID_SKY
|
||||
colortex0Out = vec4(albedo.rgb, 0.0);
|
||||
colortex1Out = vec4(0.5);
|
||||
colortex2Out = vec4(0.0, 0.0, 0.0, 10.0 / 255.0); // MATID_SKY
|
||||
colortex3Out = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
colortex4Out = vec4(0.0);
|
||||
colortex5Out = vec4(0.0);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// MinecraftPT — Spider Eyes Fragment Shader (emissive eyes)
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec3 worldPos;
|
||||
in vec3 worldNormal;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 color;
|
||||
in vec2 lightmap;
|
||||
|
||||
layout(location = 0) out vec4 colortex0Out;
|
||||
layout(location = 1) out vec4 colortex1Out;
|
||||
layout(location = 2) out vec4 colortex2Out;
|
||||
layout(location = 3) out vec4 colortex3Out;
|
||||
layout(location = 4) out vec4 colortex4Out;
|
||||
layout(location = 5) out vec4 colortex5Out;
|
||||
|
||||
void main(){
|
||||
vec4 albedo = texture(tex, texcoord) * color;
|
||||
|
||||
if (albedo.a < 0.004) discard;
|
||||
|
||||
colortex0Out = vec4(albedo.rgb, albedo.r > 0.5 ? 1.0 : 0.0);
|
||||
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
|
||||
colortex2Out = vec4(0.0, 0.0, 0.0, 6.0 / 255.0);
|
||||
colortex3Out = vec4(lightmap, 1.0, 1.0);
|
||||
|
||||
colortex4Out = vec4(0.0);
|
||||
colortex5Out = vec4(0.0);
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
// MinecraftPT — Terrain Fragment Shader
|
||||
// Writes the solid and translucent GBuffer
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec3 worldPos;
|
||||
in vec3 worldNormal;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 color;
|
||||
in vec2 lightmap;
|
||||
flat in int blockId;
|
||||
flat in float blockLightLevel;
|
||||
|
||||
layout(location = 0) out vec4 colortex0Out; // albedo + emissive
|
||||
layout(location = 1) out vec4 colortex1Out; // normals
|
||||
layout(location = 2) out vec4 colortex2Out; // spec + matID
|
||||
layout(location = 3) out vec4 colortex3Out; // lightmap
|
||||
layout(location = 4) out vec4 colortex4Out; // translucent albedo + alpha
|
||||
layout(location = 5) out vec4 colortex5Out; // translucent normal + matID
|
||||
|
||||
// Material IDs from block.properties
|
||||
#define BLOCK_LEAVES 1
|
||||
#define BLOCK_TRANSLUCENT 2
|
||||
#define BLOCK_WATER 3
|
||||
#define BLOCK_CROSS 4
|
||||
#define BLOCK_TORCH 5
|
||||
#define BLOCK_LANTERN 6
|
||||
#define BLOCK_FIRE 7
|
||||
#define BLOCK_CAMPFIRE 8
|
||||
#define BLOCK_LAVA 9
|
||||
#define BLOCK_GLASS_PANE 10
|
||||
#define BLOCK_IRON_BARS 11
|
||||
#define BLOCK_STAIRS 12
|
||||
#define BLOCK_SLAB 13
|
||||
#define BLOCK_WALL 14
|
||||
#define BLOCK_FENCE 15
|
||||
#define BLOCK_FENCE_GATE 16
|
||||
#define BLOCK_DOOR 17
|
||||
#define BLOCK_RAIL 18
|
||||
#define BLOCK_REDSTONE 19
|
||||
#define BLOCK_ENDROD 20
|
||||
#define BLOCK_CHAIN 21
|
||||
#define BLOCK_AMETHYST 22
|
||||
#define BLOCK_CANDLE 23
|
||||
#define BLOCK_GLOWSTONE 24
|
||||
#define BLOCK_LIGHT 25
|
||||
#define BLOCK_PORTAL 26
|
||||
#define BLOCK_LADDER 27
|
||||
#define BLOCK_SUGARCANE 28
|
||||
#define BLOCK_BAMBOO 29
|
||||
#define BLOCK_CACTUS 30
|
||||
#define BLOCK_CHORUS 31
|
||||
#define BLOCK_CORAL 32
|
||||
#define BLOCK_DRIPSTONE 33
|
||||
#define BLOCK_CONDUIT 34
|
||||
#define BLOCK_LIGHTNING_ROD 35
|
||||
#define BLOCK_POT 36
|
||||
#define BLOCK_SNOW_LAYERS 37
|
||||
#define BLOCK_COBWEB 80
|
||||
|
||||
void main(){
|
||||
vec4 albedo = texture(tex, texcoord) * color;
|
||||
|
||||
// Cutout (alpha test)
|
||||
if (albedo.a < 0.004) discard;
|
||||
|
||||
// Material ID determination
|
||||
float matID = 0.0; // MATID_DEFAULT
|
||||
#ifdef IS_HAND
|
||||
matID = 5.0; // MATID_HAND
|
||||
#endif
|
||||
bool isTranslucent = false;
|
||||
|
||||
if (blockId == BLOCK_LEAVES){
|
||||
matID = 3.0; // MATID_LEAVES
|
||||
}else if (blockId == BLOCK_TRANSLUCENT){
|
||||
matID = 2.0; // MATID_STAINEDGLASS
|
||||
isTranslucent = true;
|
||||
}else if (blockId == BLOCK_WATER){
|
||||
matID = 1.0; // MATID_WATER (should be handled by gbuffers_water)
|
||||
isTranslucent = true;
|
||||
}else if (blockId == BLOCK_CROSS){
|
||||
matID = 4.0; // MATID_GRASS
|
||||
}else if (blockId == BLOCK_TORCH){
|
||||
matID = 11.0; // MATID_TORCH
|
||||
}else if (blockId == BLOCK_LANTERN){
|
||||
matID = 20.0; // MATID_COPPER_LANTERN
|
||||
}else if (blockId == BLOCK_FIRE || blockId == BLOCK_CAMPFIRE){
|
||||
matID = 12.0; // MATID_FIRE
|
||||
}else if (blockId == BLOCK_LAVA){
|
||||
matID = 12.0;
|
||||
}else if (blockId == BLOCK_GLASS_PANE){
|
||||
matID = 2.0; // MATID_STAINEDGLASS
|
||||
isTranslucent = true;
|
||||
}else if (blockId == BLOCK_ENDROD){
|
||||
matID = 13.0; // MATID_ENDROD
|
||||
}else if (blockId == BLOCK_AMETHYST){
|
||||
matID = 14.0; // MATID_AMETHYST
|
||||
}else if (blockId == BLOCK_PORTAL){
|
||||
matID = 18.0; // MATID_END_PORTAL
|
||||
}else if (blockId == BLOCK_COBWEB){
|
||||
matID = 17.0; // MATID_PARTICLE-like
|
||||
isTranslucent = true;
|
||||
}
|
||||
|
||||
// Emissive detection
|
||||
float emissive = 0.0;
|
||||
#ifdef HARDCODED_EMISSIVENESS_MODE
|
||||
if (blockId == BLOCK_LAVA || blockId == BLOCK_FIRE || blockId == BLOCK_CAMPFIRE ||
|
||||
blockId == BLOCK_GLOWSTONE || blockId == BLOCK_ENDROD || blockId == BLOCK_LANTERN ||
|
||||
blockId == BLOCK_AMETHYST || blockId == BLOCK_TORCH || blockId == BLOCK_CANDLE ||
|
||||
blockId == BLOCK_LIGHT || blockId == BLOCK_CONDUIT){
|
||||
emissive = 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VANILLA_EMISSIVE
|
||||
// Emissive blocks from vanilla light level (at_midBlock.w = 0-15)
|
||||
emissive = max(emissive, step(13.5, blockLightLevel) * blockLightLevel / 15.0);
|
||||
#endif
|
||||
|
||||
// LAB PBR specular
|
||||
vec4 specTex = vec4(0.0);
|
||||
#ifdef TEXTURE_PBR_FORMAT
|
||||
if (TEXTURE_PBR_FORMAT >= 1 && blockId != BLOCK_WATER){
|
||||
specTex = texture(atlasSpecular2D, texcoord);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Lightmap
|
||||
vec2 lm = lightmap;
|
||||
lm.y = SkyLightmapCurve(lightmap.y);
|
||||
|
||||
// Parallax shadow (POM)
|
||||
float parallaxShadow = 1.0;
|
||||
|
||||
// Encode normals (octahedral)
|
||||
vec2 worldNormalEnc = EncodeNormal(worldNormal);
|
||||
vec2 vertexNormalEnc = EncodeNormal(vertexNormal);
|
||||
|
||||
// Solid write
|
||||
colortex0Out = vec4(albedo.rgb, emissive);
|
||||
colortex1Out = vec4(worldNormalEnc, vertexNormalEnc);
|
||||
colortex2Out = vec4(specTex.r, specTex.g, specTex.b, matID / 255.0);
|
||||
colortex3Out = vec4(lm, parallaxShadow, 1.0);
|
||||
|
||||
// Translucent write (glass, panes, cobweb)
|
||||
if (isTranslucent){
|
||||
colortex4Out = vec4(albedo.rgb, albedo.a);
|
||||
colortex5Out = vec4(worldNormalEnc, matID / 255.0, specTex.r);
|
||||
}else{
|
||||
colortex4Out = vec4(0.0);
|
||||
colortex5Out = vec4(0.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// MinecraftPT — Terrain Vertex Shader
|
||||
// Handles terrain, block entities, damaged blocks
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
out vec2 texcoord;
|
||||
out vec3 worldPos;
|
||||
out vec3 worldNormal;
|
||||
out vec3 vertexNormal;
|
||||
out vec4 color;
|
||||
out vec2 lightmap;
|
||||
flat out int blockId;
|
||||
flat out float blockLightLevel;
|
||||
|
||||
#ifdef WAVING_PLANTS
|
||||
#include "/Lib/IndividualFunctions/WavingPlants.glsl"
|
||||
#endif
|
||||
|
||||
void main(){
|
||||
// World position
|
||||
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
|
||||
vec4 wPos = gbufferModelViewInverse * viewPos;
|
||||
worldPos = wPos.xyz;
|
||||
|
||||
// Normals
|
||||
vertexNormal = normalize(gl_NormalMatrix * gl_Normal);
|
||||
worldNormal = normalize(mat3(gbufferModelViewInverse) * vertexNormal);
|
||||
worldNormal = normalize(worldNormal);
|
||||
|
||||
// Lightmap (blocklight, skylight)
|
||||
lightmap = gl_MultiTexCoord1.xy / 240.0;
|
||||
lightmap = saturate(lightmap);
|
||||
|
||||
// Block ID from mc_Entity
|
||||
blockId = int(mc_Entity.x + 0.5);
|
||||
blockLightLevel = at_midBlock.w;
|
||||
|
||||
// Waving plants
|
||||
#ifdef WAVING_PLANTS
|
||||
if (blockId == 4){
|
||||
WavingPlants(wPos, lightmap.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
|
||||
color = gl_Color;
|
||||
|
||||
gl_Position = gl_ProjectionMatrix * viewPos;
|
||||
gl_Position.xy += taaJitter * gl_Position.w;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// MinecraftPT — Textured Fragment Shader (textured non-terrain geometry)
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec3 worldPos;
|
||||
in vec3 worldNormal;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 color;
|
||||
in vec2 lightmap;
|
||||
flat in int blockId;
|
||||
|
||||
layout(location = 0) out vec4 colortex0Out;
|
||||
layout(location = 1) out vec4 colortex1Out;
|
||||
layout(location = 2) out vec4 colortex2Out;
|
||||
layout(location = 3) out vec4 colortex3Out;
|
||||
layout(location = 4) out vec4 colortex4Out;
|
||||
layout(location = 5) out vec4 colortex5Out;
|
||||
|
||||
void main(){
|
||||
vec4 albedo = texture(tex, texcoord) * color;
|
||||
|
||||
if (albedo.a < 0.004) discard;
|
||||
|
||||
vec2 lm = lightmap;
|
||||
lm.y = SkyLightmapCurve(lightmap.y);
|
||||
|
||||
colortex0Out = vec4(albedo.rgb, 0.0);
|
||||
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
|
||||
colortex2Out = vec4(0.0, 0.0, 0.0, 6.0 / 255.0); // MATID_ENTITIES
|
||||
colortex3Out = vec4(lm, 1.0, 1.0);
|
||||
|
||||
colortex4Out = vec4(0.0);
|
||||
colortex5Out = vec4(0.0);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// MinecraftPT — Water Fragment Shader
|
||||
// Writes the water GBuffer with waves, caustics data
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec3 worldPos;
|
||||
in vec3 worldNormal;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 color;
|
||||
in vec2 lightmap;
|
||||
|
||||
layout(location = 0) out vec4 colortex0Out; // albedo + emissive
|
||||
layout(location = 1) out vec4 colortex1Out; // normals
|
||||
layout(location = 2) out vec4 colortex2Out; // spec + matID
|
||||
layout(location = 3) out vec4 colortex3Out; // lightmap
|
||||
layout(location = 4) out vec4 colortex4Out; // translucent albedo + alpha
|
||||
layout(location = 5) out vec4 colortex5Out; // translucent normal + matID
|
||||
|
||||
#include "/Lib/IndividualFunctions/WaterWaves.glsl"
|
||||
|
||||
void main(){
|
||||
vec4 albedo = texture(tex, texcoord) * color;
|
||||
|
||||
// Water surface height / waves
|
||||
vec3 wPos = worldPos;
|
||||
#ifdef WAVE_PARALLAX
|
||||
vec3 waveNormal = GetWaveNormal(wPos, lightmap.y);
|
||||
#else
|
||||
vec3 waveNormal = GetWaveNormal(wPos, lightmap.y);
|
||||
#endif
|
||||
|
||||
// Water color — deep water tint
|
||||
vec3 waterColor = mix(vec3(0.05, 0.15, 0.2), vec3(0.1, 0.3, 0.4), wetness * 0.5);
|
||||
|
||||
// Water lightmap
|
||||
vec2 lm = lightmap;
|
||||
lm.y = SkyLightmapCurve(lightmap.y);
|
||||
|
||||
// Water is translucent
|
||||
colortex0Out = vec4(waterColor, 0.0);
|
||||
colortex1Out = vec4(EncodeNormal(waveNormal), EncodeNormal(vertexNormal));
|
||||
colortex2Out = vec4(0.0, 0.018, 0.0, 1.0 / 255.0); // matID = MATID_WATER
|
||||
colortex3Out = vec4(lm, 1.0, 1.0);
|
||||
|
||||
// Translucent buffer: water albedo is mostly transparent, we store depth tint
|
||||
colortex4Out = vec4(waterColor, 0.6);
|
||||
colortex5Out = vec4(EncodeNormal(waveNormal), 1.0 / 255.0, 0.0);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// MinecraftPT — Water Vertex Shader
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
out vec2 texcoord;
|
||||
out vec3 worldPos;
|
||||
out vec3 worldNormal;
|
||||
out vec3 vertexNormal;
|
||||
out vec4 color;
|
||||
out vec2 lightmap;
|
||||
|
||||
void main(){
|
||||
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
|
||||
vec4 wPos = gbufferModelViewInverse * viewPos;
|
||||
worldPos = wPos.xyz;
|
||||
|
||||
vertexNormal = normalize(gl_NormalMatrix * gl_Normal);
|
||||
worldNormal = normalize(mat3(gbufferModelViewInverse) * vertexNormal);
|
||||
|
||||
lightmap = gl_MultiTexCoord1.xy / 240.0;
|
||||
lightmap = saturate(lightmap);
|
||||
|
||||
texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
|
||||
color = gl_Color;
|
||||
|
||||
gl_Position = gl_ProjectionMatrix * viewPos;
|
||||
gl_Position.xy += taaJitter * gl_Position.w;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// MinecraftPT — Weather Fragment Shader (rain/snow)
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
in vec2 texcoord;
|
||||
in vec3 worldPos;
|
||||
in vec3 worldNormal;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 color;
|
||||
in vec2 lightmap;
|
||||
flat in int blockId;
|
||||
|
||||
layout(location = 0) out vec4 colortex0Out;
|
||||
layout(location = 1) out vec4 colortex1Out;
|
||||
layout(location = 2) out vec4 colortex2Out;
|
||||
layout(location = 3) out vec4 colortex3Out;
|
||||
layout(location = 4) out vec4 colortex4Out;
|
||||
layout(location = 5) out vec4 colortex5Out;
|
||||
|
||||
void main(){
|
||||
vec4 albedo = texture(tex, texcoord) * color;
|
||||
|
||||
if (albedo.a < 0.004) discard;
|
||||
|
||||
// Weather drops are thin — mark as particle-ish translucent
|
||||
colortex0Out = vec4(albedo.rgb, 0.0);
|
||||
colortex1Out = vec4(EncodeNormal(worldNormal), EncodeNormal(vertexNormal));
|
||||
colortex2Out = vec4(0.0, 0.0, 0.0, 17.0 / 255.0); // MATID_PARTICLE
|
||||
colortex3Out = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
colortex4Out = vec4(0.0);
|
||||
colortex5Out = vec4(0.0);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// MinecraftPT — Post_VS
|
||||
// Fullscreen triangle vertex shader for composite passes.
|
||||
|
||||
void main(){
|
||||
// Fullscreen triangle
|
||||
vec2 pos = vec2(
|
||||
gl_VertexID == 0 ? -1.0 : (gl_VertexID == 1 ? 3.0 : -1.0),
|
||||
gl_VertexID == 0 ? -1.0 : (gl_VertexID == 1 ? -1.0 : 3.0)
|
||||
);
|
||||
|
||||
gl_Position = vec4(pos, 1.0, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// MinecraftPT — RTWSM Backward Analysis
|
||||
// Computes the importance map from the shadow map depth: which shadow map texels
|
||||
// need more resolution (near-field geometry, steep normals).
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
|
||||
|
||||
const ivec3 workGroups = ivec3(32, 16, 1);
|
||||
layout (local_size_x = 32, local_size_y = 32) in;
|
||||
|
||||
layout (r32f) uniform writeonly image2D img_rtwImportance2D;
|
||||
|
||||
uniform sampler2D shadowcolor0;
|
||||
|
||||
void main(){
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
vec2 uv = (vec2(texel) + 0.5) / vec2(RTW_RESOLUTION, RTW_RESOLUTION_Y);
|
||||
|
||||
// Sample shadow map depth (in the shadow region)
|
||||
vec2 shadowUv = vec2(uv.x * 0.5 + 0.5, uv.y * 0.5); // map to right region
|
||||
vec2 shadowTexel = shadowUv * shadowSize;
|
||||
|
||||
vec4 shadowData = texelFetch(shadowcolor0, ivec2(shadowTexel), 0);
|
||||
|
||||
float depth = shadowData.a;
|
||||
float importance = 0.0;
|
||||
|
||||
if (depth < 1.0){
|
||||
// Depth-based importance: closer = more important
|
||||
float dist = 1.0 - depth;
|
||||
importance = pow(dist, 2.0) * RTW_BACKWARD_DIST_FACTOR;
|
||||
|
||||
// Depth gradient importance (edges)
|
||||
float dLeft = texelFetch(shadowcolor0, ivec2(shadowTexel) + ivec2(-1, 0), 0).a;
|
||||
float dRight = texelFetch(shadowcolor0, ivec2(shadowTexel) + ivec2(1, 0), 0).a;
|
||||
float dUp = texelFetch(shadowcolor0, ivec2(shadowTexel) + ivec2(0, -1), 0).a;
|
||||
float dDown = texelFetch(shadowcolor0, ivec2(shadowTexel) + ivec2(0, 1), 0).a;
|
||||
|
||||
float gradient = abs(dLeft - dRight) + abs(dUp - dDown);
|
||||
importance += gradient * 0.5 * RTW_BACKWARD_NORMAL_FACTOR;
|
||||
}
|
||||
|
||||
imageStore(img_rtwImportance2D, texel, vec4(importance));
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// MinecraftPT — RTWSM Blur Importance
|
||||
// Gaussian-blurs the importance map to make the warp smooth.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
const ivec3 workGroups = ivec3(32, 16, 1);
|
||||
layout (local_size_x = 32, local_size_y = 32) in;
|
||||
|
||||
layout (r32f) uniform writeonly image2D img_rtwImportance2D;
|
||||
|
||||
uniform sampler2D rtwImportance2D;
|
||||
|
||||
void main(){
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
float importance = 0.0;
|
||||
float weightSum = 0.0;
|
||||
|
||||
int radius = int(RTW_BLUR_FACTOR);
|
||||
|
||||
for (int i = -radius; i <= radius; i++){
|
||||
for (int j = -radius; j <= radius; j++){
|
||||
vec2 coord = vec2(texel + ivec2(i, j)) / vec2(RTW_RESOLUTION, RTW_RESOLUTION_Y);
|
||||
float w = exp(-(i * i + j * j) / (2.0 * RTW_BLUR_FACTOR * RTW_BLUR_FACTOR));
|
||||
importance += textureLod(rtwImportance2D, coord, 0.0).r * w;
|
||||
weightSum += w;
|
||||
}}
|
||||
|
||||
imageStore(img_rtwImportance2D, texel, vec4(importance / weightSum));
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// MinecraftPT — RTWSM Building Warp
|
||||
// Builds the final warp curve (cumulative importance) from the importance map.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
const ivec3 workGroups = ivec3(32, 1, 1);
|
||||
layout (local_size_x = 32) in;
|
||||
|
||||
layout (rg16) uniform writeonly image2D img_rtwWarp1D;
|
||||
|
||||
uniform sampler2D rtwImportance2D;
|
||||
|
||||
void main(){
|
||||
int y = int(gl_GlobalInvocationID.y);
|
||||
|
||||
// Compute the cumulative importance curve for this row
|
||||
float total = 0.0;
|
||||
for (int x = 0; x < RTW_RESOLUTION; x++){
|
||||
total += textureLod(rtwImportance2D, vec2(float(x) / float(RTW_RESOLUTION), float(y) / float(RTW_RESOLUTION_Y)), 0.0).r;
|
||||
}
|
||||
|
||||
// Write warp curve: row 0 = cumulative, row 1 = inverse
|
||||
if (total > 0.0){
|
||||
float cum = 0.0;
|
||||
for (int x = 0; x < RTW_RESOLUTION; x++){
|
||||
cum += textureLod(rtwImportance2D, vec2(float(x) / float(RTW_RESOLUTION), float(y) / float(RTW_RESOLUTION_Y)), 0.0).r;
|
||||
imageStore(img_rtwWarp1D, ivec2(x, 0), vec4(cum / total, 0.0, 0.0, 0.0));
|
||||
}
|
||||
|
||||
// Inverse: for each output position find input position
|
||||
for (int x = 0; x < RTW_RESOLUTION; x++){
|
||||
float target = float(x) / float(RTW_RESOLUTION - 1);
|
||||
int lo = 0;
|
||||
int hi = RTW_RESOLUTION - 1;
|
||||
for (int i = 0; i < 10; i++){
|
||||
int mid = (lo + hi) / 2;
|
||||
float v = textureLod(rtwImportance2D, vec2(float(mid) / float(RTW_RESOLUTION), float(y) / float(RTW_RESOLUTION_Y)), 0.0).r;
|
||||
if (v < target) lo = mid; else hi = mid;
|
||||
}
|
||||
float inv = float(lo) / float(RTW_RESOLUTION);
|
||||
imageStore(img_rtwWarp1D, ivec2(x, 1), vec4(inv, 0.0, 0.0, 0.0));
|
||||
}
|
||||
}else{
|
||||
// Identity warp
|
||||
for (int x = 0; x < RTW_RESOLUTION; x++){
|
||||
float v = float(x) / float(RTW_RESOLUTION);
|
||||
imageStore(img_rtwWarp1D, ivec2(x, 0), vec4(v, 0.0, 0.0, 0.0));
|
||||
imageStore(img_rtwWarp1D, ivec2(x, 1), vec4(v, 0.0, 0.0, 0.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// MinecraftPT — RTWSM Collapse Importance
|
||||
// Collapses the 2D importance map into a 1D cumulative curve per row.
|
||||
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
|
||||
const ivec3 workGroups = ivec3(RTW_RESOLUTION, 1, 1);
|
||||
layout (local_size_x = 1) in;
|
||||
|
||||
layout (r32f) uniform writeonly image2D img_rtwImportance2D;
|
||||
layout (rg16) uniform writeonly image2D img_rtwWarp1D;
|
||||
|
||||
uniform sampler2D rtwImportance2D;
|
||||
|
||||
void main(){
|
||||
int y = int(gl_GlobalInvocationID.y);
|
||||
|
||||
// Sum importance across rows -> 1D profile
|
||||
float sum = 0.0;
|
||||
for (int x = 0; x < RTW_RESOLUTION; x++){
|
||||
sum += textureLod(rtwImportance2D, vec2(float(x) / float(RTW_RESOLUTION), float(y) / float(RTW_RESOLUTION_Y)), 0.0).r;
|
||||
}
|
||||
|
||||
// Build cumulative distribution
|
||||
float cumulative = 0.0;
|
||||
for (int x = 0; x < RTW_RESOLUTION; x++){
|
||||
float imp = textureLod(rtwImportance2D, vec2(float(x) / float(RTW_RESOLUTION), float(y) / float(RTW_RESOLUTION_Y)), 0.0).r;
|
||||
cumulative += imp;
|
||||
float normalized = sum > 0.0 ? cumulative / sum : float(x) / float(RTW_RESOLUTION);
|
||||
|
||||
imageStore(img_rtwWarp1D, ivec2(x, y), vec4(normalized, 1.0 - normalized, 0.0, 0.0));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "/Lib/Settings.glsl"
|
||||
#include "/Lib/Utilities.glsl"
|
||||
// MinecraftPT — RTWSM SampleWarp
|
||||
// Samples the warp map to redistribute shadow map coordinates.
|
||||
|
||||
#ifndef SAMPLE_WARP_GLSL
|
||||
uniform sampler2D rtwWarp1D;
|
||||
#define SAMPLE_WARP_GLSL
|
||||
|
||||
// Warp curve sampling: rtwWarp1D is a RG16 texture, RTW_RESOLUTION x 2
|
||||
// Row 0: warp curve (cumulative importance), Row 1: inverse warp curve
|
||||
vec2 SampleWarp(float value){
|
||||
vec2 coord = vec2(value * (RTW_RESOLUTION - 1.0) + 0.5, 0.5) / vec2(RTW_RESOLUTION, 2.0);
|
||||
return textureLod(rtwWarp1D, coord, 0.0).rg;
|
||||
}
|
||||
|
||||
// Smooth warp sampling with lerp
|
||||
vec2 SampleRTWWarpSmooth(vec2 shadowScreenPos){
|
||||
// The warp is 1D along the shadow map's X axis (sun direction)
|
||||
float u = saturate(shadowScreenPos.x);
|
||||
|
||||
// Sample warp curve
|
||||
vec2 warp = SampleWarp(u);
|
||||
|
||||
// Apply warp: remap x based on cumulative importance
|
||||
float warpedX = warp.x;
|
||||
|
||||
// Also apply to y for 2D warping (using second channel)
|
||||
float warpedY = warp.y;
|
||||
|
||||
return vec2(warpedX - u, warpedY - shadowScreenPos.y);
|
||||
}
|
||||
|
||||
// Full warp application for shadow map sampling
|
||||
vec2 WarpShadowCoord(vec2 shadowScreenPos){
|
||||
float u = saturate(shadowScreenPos.x);
|
||||
vec2 warp = SampleWarp(u);
|
||||
|
||||
vec2 warped = vec2(warp.x, warp.y);
|
||||
|
||||
// The warp curve maps [0,1] -> [0,1] cumulative
|
||||
// Inverse: sample with the inverse curve
|
||||
return warped;
|
||||
}
|
||||
|
||||
// Unwarp (for reconstructing world positions)
|
||||
vec2 UnwarpShadowCoord(vec2 warpedCoord){
|
||||
// Binary search on the warp curve (forward map)
|
||||
float low = 0.0;
|
||||
float high = 1.0;
|
||||
|
||||
for (int i = 0; i < 8; i++){
|
||||
float mid = (low + high) * 0.5;
|
||||
vec2 sample = SampleWarp(mid);
|
||||
if (sample.x < warpedCoord.x){
|
||||
low = mid;
|
||||
}else{
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return vec2((low + high) * 0.5, warpedCoord.y);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,390 @@
|
||||
// MinecraftPT — Settings
|
||||
// All configurable options. Change values here or via the in-game GUI.
|
||||
|
||||
#ifndef SETTINGS_GLSL
|
||||
#define SETTINGS_GLSL
|
||||
|
||||
// =============================== Path Tracing: Voxel ===============================
|
||||
// Voxelization resolution (width x height x width)
|
||||
// 4004=128³, 6004=192x128x192, 8004=256x128x256, 8006=256x192x256, 8008=256³
|
||||
// 12004=384x128x384, 12006=384x192x384, 12008=384x256x384, 16004=512x128x512, 16008=512x256x512, 16016=512³
|
||||
#define PT_VOXEL_RESOLUTION 8006
|
||||
|
||||
// Full block verification (more accurate, slightly slower)
|
||||
#define PT_FULLBLOCK_VERIFICATION 0
|
||||
// Full block detection from geometry (helps modded blocks)
|
||||
#define PT_FULLBLOCK_DETECTION 0
|
||||
// Sparse tracing — hierarchical empty-voxel skipping (much faster, recommended)
|
||||
#define PT_SPARE_TRACING 1
|
||||
// Detect emissive blocks from vanilla light level
|
||||
#define VANILLA_EMISSIVE 1
|
||||
// Trace through alpha pixels of blocks
|
||||
#define PT_TRACING_ALPHA 0
|
||||
|
||||
// =============================== Path Tracing: Diffuse ===============================
|
||||
// Max tracing distance for diffuse rays (blocks)
|
||||
#define PT_DIFFUSE_TRACING_DISTANCE 32.0
|
||||
// Samples per pixel for diffuse tracing (1 = 1 ray)
|
||||
#define PT_DIFFUSE_SPP 1
|
||||
// Screen space tracing for diffuse (SST) — helps short-range detail
|
||||
#define PT_DIFFUSE_SST 1
|
||||
// Diffuse refraction through translucent blocks
|
||||
#define PT_DIFFUSE_REFRACTION 1
|
||||
#define PT_DIFFUSE_REFRACTION_IOR 1.3
|
||||
|
||||
// ---- Diffuse denoiser ----
|
||||
// Max temporal accumulation (frames)
|
||||
#define PT_DIFFUSE_TEMPORAL_MAX_ACCUM 8
|
||||
// Spatial filter detail (0=low,1=medium,2=high,3=ultra)
|
||||
#define PT_DIFFUSE_SPATIAL_FILTER_DETAIL 2
|
||||
#define PT_DIFFUSE_SPATIAL_FILTER_LUMINANCE_WEIGHT 0.4
|
||||
#define PT_DIFFUSE_SPATIAL_FILTER_DEPTH_WEIGHT 0.8
|
||||
#define PT_DIFFUSE_SPATIAL_FILTER_NORMAL_WEIGHT 0.4
|
||||
// Fix history bleeding (0=off,1=on)
|
||||
#define PT_DIFFUSE_TEMPORAL_HISTORY_FIX 1
|
||||
|
||||
// =============================== Path Tracing: Specular ===============================
|
||||
// Enable rough specular (GGX) reflections
|
||||
#define ENABLE_ROUGH_SPECULAR 1
|
||||
// Clamp minimum roughness
|
||||
#define ROUGHNESS_CLAMP 0
|
||||
// Max tracing distance for specular rays
|
||||
#define PT_SPECULAR_TRACING_DISTANCE 64.0
|
||||
// Screen space reflection mode (0=off,1=combined,2=only screen space)
|
||||
#define PT_SSR_MODE 1
|
||||
// SSR quality (steps)
|
||||
#define PT_SSR_QUALITY 32
|
||||
// Reuse screen-space data in specular tracing
|
||||
#define PT_SPECULAR_SCREEN_REUSE 1
|
||||
// Smooth IRC specular
|
||||
#define PT_SPECULAR_IRC_SMOOTH 0
|
||||
// Skybox resolution for reflections (32/48/64/96/128)
|
||||
#define SKYBOX_RESOLUTION 64
|
||||
|
||||
// =============================== Path Tracing: IRC ===============================
|
||||
// Irradiance cache resolution (16/32/48/64)
|
||||
#define PT_IRC_RESOLUTION 32
|
||||
// Samples per IRC update
|
||||
#define PT_IRC_SPP 8
|
||||
// IRC blend weight (0-1)
|
||||
#define PT_IRC_BLENDWEIGHT 0.5
|
||||
// Self-bounce attenuation
|
||||
#define PT_IRC_SELFBOUNCE_ATTENUATION 1.0
|
||||
|
||||
// =============================== Lighting ===============================
|
||||
#define BLOCKLIGHT_BRIGHTNESS 1.0
|
||||
#define SPHERELIGHT_BRIGHTNESS 1.0
|
||||
#define BLOCKLIGHT_TEMPERATURE 1.5
|
||||
#define PARTICLELIGHT_BRIGHTNESS 1.0
|
||||
#define NOLIGHT_BRIGHTNESS 0.05
|
||||
#define NIGHT_BRIGHTNESS 0.35
|
||||
#define NETHER_BRIGHTNESS 1.0
|
||||
#define COLD_MOONLIGHT 1
|
||||
#define SUNRISE_ROTATION 0.0
|
||||
#define SUN_ANGULAR_RADIUS 0.00465
|
||||
#define SUNLIGHT_INTENSITY 1.0
|
||||
|
||||
// Light colors
|
||||
#define BRIGHTNESS_TORCH 1.0
|
||||
#define COLOR_TORCH_R 1.0
|
||||
#define COLOR_TORCH_G 0.64
|
||||
#define COLOR_TORCH_B 0.32
|
||||
#define BRIGHTNESS_ENDROD 1.0
|
||||
#define COLOR_ENDROD_R 1.0
|
||||
#define COLOR_ENDROD_G 0.75
|
||||
#define COLOR_ENDROD_B 0.6
|
||||
#define BRIGHTNESS_FIRE 1.8
|
||||
#define COLOR_FIRE_R 1.0
|
||||
#define COLOR_FIRE_G 0.45
|
||||
#define COLOR_FIRE_B 0.13
|
||||
#define BRIGHTNESS_LIGHTBLOCK 1.0
|
||||
#define COLOR_LIGHTBLOCK_R 1.0
|
||||
#define COLOR_LIGHTBLOCK_G 1.0
|
||||
#define COLOR_LIGHTBLOCK_B 1.0
|
||||
#define BRIGHTNESS_SOULTORCH 0.4
|
||||
#define COLOR_SOULTORCH_R 0.4
|
||||
#define COLOR_SOULTORCH_G 0.98
|
||||
#define COLOR_SOULTORCH_B 1.0
|
||||
#define BRIGHTNESS_AMETHYST 0.3
|
||||
#define COLOR_AMETHYST_R 0.84
|
||||
#define COLOR_AMETHYST_G 0.52
|
||||
#define COLOR_AMETHYST_B 1.28
|
||||
#define BRIGHTNESS_REDSTONETORCH 0.1
|
||||
#define COLOR_REDSTONETORCH_R 1.0
|
||||
#define COLOR_REDSTONETORCH_G 0.48
|
||||
#define COLOR_REDSTONETORCH_B 0.39
|
||||
|
||||
// Held light (torch in hand)
|
||||
#define HELDLIGHT_BRIGHTNESS 1.0
|
||||
#define HELDLIGHT_MODE 1
|
||||
#define HELDLIGHT_FALLOFF 0.2
|
||||
#define HELDLIGHT_COLOR_TEMPERATURE 1.5
|
||||
#define SPECULAR_HELDLIGHT 0
|
||||
#define HELDLIGHT_SHADOW 1
|
||||
|
||||
// =============================== Shadows ===============================
|
||||
// Shadow map render distance (4/6/8/12/16/24/32/48/64/96/128)
|
||||
#define SHADOW_RENDER_DISTANCE 16
|
||||
// Variable penumbra shadows
|
||||
#define VARIABLE_PENUMBRA_SHADOWS 1
|
||||
#define VPS_SPREAD 1.0
|
||||
// Shadow map quality (1/2/3)
|
||||
#define SHADOW_QUALITY 2
|
||||
#define SHADOW_BASIC_BLUR 0.0
|
||||
// Use voxel shadow tracing instead of shadow map
|
||||
#define PT_SHADOW 1
|
||||
// Screen space shadows
|
||||
#define SCREEN_SPACE_SHADOWS 1
|
||||
// Colored shadows (from shadow map albedo)
|
||||
#define COLORED_SHADOWS 1
|
||||
#define HAND_SCREEN_SHADOW 1
|
||||
// Prevent light leaking at sun-grazing angles
|
||||
#define SUNLIGHT_LEAK_FIX 1
|
||||
|
||||
// RTWSM (warped shadow map)
|
||||
#define RTW_RESOLUTION 512
|
||||
#define RTW_BACKWARD_DIST_FACTOR 1.0
|
||||
#define RTW_BACKWARD_NORMAL_FACTOR 0.8
|
||||
#define RTW_BLUR_FACTOR 2.0
|
||||
|
||||
// =============================== Surface ===============================
|
||||
// Block atlas texture resolution (0=auto)
|
||||
#define TEXTURE_RESOLUTION 0
|
||||
// LAB PBR texture format (0=legacy,1=LAB-PBR 1.3,2=LAB-PBR 1.4)
|
||||
#define TEXTURE_PBR_FORMAT 1
|
||||
// Emissiveness from LAB PBR
|
||||
#define LABPBR_EMISSIVENESS 1
|
||||
// Hardcoded emissive blocks
|
||||
#define HARDCODED_EMISSIVENESS_MODE 1
|
||||
// Subsurface scattering
|
||||
#define LABPBR_SSS 1
|
||||
#define SSS_QUALITY 4
|
||||
#define SSS_STRENGTH 0.4
|
||||
#define SSS_STRENGTH_OFFSET 0.0
|
||||
#define SSS_BRIGHTNESS 1.0
|
||||
// Porosity (wetness)
|
||||
#define LABPBR_POROSITY 1
|
||||
#define TEXTURE_DEFAULT_POROSITY 0.2
|
||||
#define POROSITY_ABSORPTION 0.3
|
||||
#define SURFACE_WETNESS 0.5
|
||||
// Predefined metals
|
||||
#define LABPBR_PREDEFINED_METAL 1
|
||||
#define METAL_MINIMAL_F0 0.04
|
||||
#define METAL_ORIGIN_COLOR 1.0
|
||||
#define METALMASK_STRENGTH 1.0
|
||||
|
||||
// Parallax occlusion mapping
|
||||
#define PARALLAX_MODE 0
|
||||
#define ENTITIES_PARALLAX 0
|
||||
#define PARALLAX_DEPTH 0.08
|
||||
#define PARALLAX_QUALITY 6
|
||||
|
||||
// Waving plants
|
||||
#define WAVING_PLANTS 1
|
||||
#define SHADOW_WAVING_PLANTS 0
|
||||
#define WAVING_RANGE 24.0
|
||||
#define WAVING_SPEED 1.0
|
||||
#define GRASS_AMPLITUDE 0.05
|
||||
#define LEAVES_AMPLITUDE 0.08
|
||||
|
||||
// =============================== Water ===============================
|
||||
#define WAVE_SCALE 8.0
|
||||
#define WAVE_SPEED 1.0
|
||||
#define WAVE_NORMAL_STRENGTH 0.4
|
||||
#define WAVE_PARALLAX 1
|
||||
#define WAVE_PARALLAX_DEPTH 0.4
|
||||
#define WATER_FOG 1
|
||||
#define WATER_SCATTERING_DENSITY 0.3
|
||||
#define WATER_SCATTERING_R 0.3
|
||||
#define WATER_SCATTERING_G 0.6
|
||||
#define WATER_SCATTERING_B 0.8
|
||||
#define WATER_ATTENUATION_R 0.6
|
||||
#define WATER_ATTENUATION_G 0.4
|
||||
#define WATER_ATTENUATION_B 0.3
|
||||
#define UNDERWATER_VFOG 1
|
||||
#define UNDERWATER_VFOG_QUALITY 8
|
||||
#define UNDERWATER_VFOG_DENSITY 1.0
|
||||
|
||||
// Rain / wetness
|
||||
#define drynessHalflife 0.25
|
||||
#define wetnessHalflife 2.0
|
||||
#define RAIN_SHADOW 0.98
|
||||
#define RAIN_VISIBILITY 1.0
|
||||
#define RAIN_SPLASH_EFFECT 1
|
||||
#define RAIN_SPLASH_SPEED 1.0
|
||||
#define RAIN_SPLASH_STRENGTH 1.0
|
||||
#define RAIN_SPLASH_SCALE 1.0
|
||||
#define RAIN_WIND_X 1.0
|
||||
#define RAIN_WIND_Z 1.0
|
||||
#define RAIN_DISTURBANCE 1.0
|
||||
#define DISABLE_LOCAL_PRECIPITATION 0
|
||||
|
||||
// =============================== Sky / Atmosphere ===============================
|
||||
#define ATMO_HORIZON 1
|
||||
#define ATMO_REFLECTION_HORIZON 1
|
||||
#define SKY_TEXTURE_BRIGHTNESS 1.0
|
||||
#define HASHSTARS_BRIGHTNESS 1.0
|
||||
#define STAR_TYPE 0
|
||||
#define MOON_TEXTURE 1
|
||||
#define BILINEAR_MOON_TEXTURE 1
|
||||
#define END_PLANET_CYCLE 0
|
||||
#define ACCRETIONDISC_ANGLE 0.0
|
||||
#define BLACKHOLE_LQ 0
|
||||
|
||||
// =============================== Clouds ===============================
|
||||
#define PLANAR_CLOUDS 1
|
||||
#define VOLUMETRIC_CLOUDS 1
|
||||
#define PC_ALTITUDE 128.0
|
||||
#define PC_NOISE_SCALE 0.001
|
||||
#define PC_CLEAR_COVERAGE 0.4
|
||||
#define PC_CLEAR_DENSITY 0.5
|
||||
#define PC_CLEAR_SUNLIGHTING 1.0
|
||||
#define PC_CLEAR_SKYLIGHTING 0.6
|
||||
#define PC_RAIN_COVERAGE 0.9
|
||||
#define PC_RAIN_DENSITY 0.8
|
||||
#define PC_RAIN_SUNLIGHTING 1.0
|
||||
#define PC_RAIN_SKYLIGHTING 0.3
|
||||
|
||||
#define CLOUD_QUALITY 4
|
||||
#define CLOUD_DETAILED_NOISE_STRENGTH 0.5
|
||||
#define CLOUD_BASE_NOISE_SCALE 0.004
|
||||
#define CLOUD_DETAILED_NOISE_SCALE 0.016
|
||||
#define CLOUD_COVERAGE_NOISE_OFFSET 0.5
|
||||
#define CLOUD_FADE 0.2
|
||||
#define CLOUD_BOTTOM_BRIGHTNESS 0.6
|
||||
#define CLOUD_OUTSCATTER_FACTOR 0.4
|
||||
#define CLOUD_SHADOW 1
|
||||
#define CLOUD_SPEED 1.0
|
||||
#define CLOUD_CLEAR_ALTITUDE 192.0
|
||||
#define CLOUD_CLEAR_THICKNESS 64.0
|
||||
#define CLOUD_CLEAR_COVERY 0.5
|
||||
#define CLOUD_CLEAR_DENSITY 0.35
|
||||
#define CLOUD_CLEAR_SUNLIGHTING 1.0
|
||||
#define CLOUD_CLEAR_SKYLIGHTING 0.7
|
||||
#define CLOUD_CLEAR_SCALE 1.0
|
||||
|
||||
// =============================== Volumetric fog ===============================
|
||||
#define VFOG 1
|
||||
#define VFOG_REFLECTION 1
|
||||
#define VFOG_REFRACTION 1
|
||||
#define VFOG_HEIGHT 160.0
|
||||
#define VFOG_HEIGHT_2 40.0
|
||||
#define VFOG_FALLOFF 0.002
|
||||
#define VFOG_DENSITY 1.0
|
||||
#define VFOG_DENSITY_BASE 0.001
|
||||
#define VFOG_QUALITY 24
|
||||
#define VFOG_IGNORE_WORLDTIME 0
|
||||
#define VFOG_SUNLIGHT_ABSORPTION 1.0
|
||||
#define VFOG_RAIN_DENSITY_MUL 1.0
|
||||
#define VFOG_SUNLIGHT_DENSITY 1.0
|
||||
#define VFOG_STAINED 1
|
||||
#define VFOG_FOG_DENSITY 0.05
|
||||
#define VFOG_CLOUD_SHADOW 1
|
||||
#define VFOG_NOISE_TYPE 1
|
||||
#define VFOG_NOISE_OCTAVE 3
|
||||
#define VFOG_NOISE_COVERAGE 0.3
|
||||
#define VFOG_NOISE_HORIZONTAL_SCALE 0.004
|
||||
#define VFOG_NOISE_VERTICAL_SCALE 0.01
|
||||
#define LANDSCATTERING 1
|
||||
#define LANDSCATTERING_STRENGTH 1.0
|
||||
#define LANDSCATTERING_SHADOW 1
|
||||
#define LANDSCATTERING_SHADOW_QUALITY 8
|
||||
#define LANDSCATTERING_REFLECTION 1
|
||||
#define LANDSCATTERING_REFRACTION 1
|
||||
#define INDOOR_FOG 0
|
||||
#define CAVE_FOG 1
|
||||
#define CAVE_FOG_BRIGHTNESS 0.8
|
||||
#define NETHERFOG_DENSITY 1.0
|
||||
|
||||
// =============================== Post-processing ===============================
|
||||
// TAA
|
||||
#define TAA_BLENDWEIGHT 0.9
|
||||
#define TAA_AGGRESSION 0.05
|
||||
#define TAA_SUBPIXEL_SHARPNING 0.8
|
||||
|
||||
// DOF
|
||||
#define DOF 1
|
||||
#define DISABLE_HAND_DOF 1
|
||||
#define DOF_BLUR 0.5
|
||||
#define DOF_QUALITY 12
|
||||
#define DOF_COCSPREAD_QUALITY 12
|
||||
#define DOF_MAX_COC 12.0
|
||||
#define DOF_CATSEYE 0
|
||||
#define DOF_CATSEYE_STRENGTH 1.0
|
||||
#define DOF_CATSEYE_MIDPOINT 0.5
|
||||
#define CAMERA_FOCUS_MODE 0
|
||||
#define CAMERA_FOCAL_POINT 50.0
|
||||
#define DOF_DEPTH_SMMOOTH_HALFLIFE 0.1
|
||||
#define DOF_FOCUS_IGNORE_HAND_PARTICLE 0
|
||||
|
||||
// Exposure
|
||||
#define AE_MODE 0
|
||||
#define SMOOTH_EXPOSURE 0.3
|
||||
#define AE_CURVE 0.6
|
||||
#define AE_OFFSET 0.0
|
||||
#define EXPOSURE_TIME 0.1
|
||||
#define MANUAL_EXPOSURE 1.0
|
||||
#define LUMINANCE_WEIGHT_MODE 0
|
||||
#define LUMINANCE_WEIGHT_STRENGTH 1.0
|
||||
#define EV_VALUE 0.0
|
||||
|
||||
// Motion blur
|
||||
#define MOTION_BLUR 1
|
||||
#define MOTION_BLUR_DITHER 1
|
||||
#define MOTION_BLUR_QUALITY 8
|
||||
#define MOTION_BLUR_SUTTER_MODE 0
|
||||
#define MOTION_BLUR_SUTTER_ANGLE 0.0
|
||||
#define MOTION_BLUR_SUTTER_SPEED 1.0
|
||||
|
||||
// Vignette
|
||||
#define VIGNETTE 0
|
||||
#define VIGNETTE_FALLOFF 1.0
|
||||
#define VIGNETTE_ROUNDNESS 1.0
|
||||
#define SNEAKING_VIGNETTE 1
|
||||
|
||||
// Bloom
|
||||
#define BLOOM 1
|
||||
#define BLOOM_AMOUNT 0.3
|
||||
#define BLOOM_CLAMP_STRENGTH 1.0
|
||||
#define NETHER_END_BLOOM_BOOST 1.0
|
||||
|
||||
// Color
|
||||
#define TONEMAP_OPERATOR 0 // 0=ACES, 1=AGX, 2=filmic, 3=Vanilla
|
||||
#define AGX_EV 0.0
|
||||
#define AGX_HDR_EV 0.0
|
||||
#define ABNEY_EFFECT_CORRECTION 1
|
||||
#define AGX_HDR_MIDGREY 0.18
|
||||
#define ADVANCED_COLOR 1
|
||||
#define HIGHLIGHT_CURVE 1.0
|
||||
#define SHADOW_CURVE 1.0
|
||||
#define WHITE_POINT 1.0
|
||||
#define BLACK_POINT 0.0
|
||||
#define MIDTONE_HUE 0.0
|
||||
#define MIDTONE_STRENGTH 0.0
|
||||
#define HIGHLIGHT_HUE 0.0
|
||||
#define HIGHLIGHT_STRENGTH 0.0
|
||||
#define SHADOW_HUE 0.0
|
||||
#define SHADOW_STRENGTH 0.0
|
||||
#define KEEP_LUMINANCE 0
|
||||
#define SATURATION 1.0
|
||||
#define GAMMA 1.0
|
||||
|
||||
// =============================== Misc ===============================
|
||||
#define CAVE_MODE 0
|
||||
#define PT_HALF_RES 1
|
||||
#define DEBUG_COUNTER 0
|
||||
#define DEBUG_IRC 0
|
||||
#define DISABLE_NIGHTVISION 0
|
||||
#define DISABLE_BLINDNESS_DARKNESS 0
|
||||
#define WHITE_DEBUG_WORLD 0
|
||||
|
||||
// RTWSM resolution
|
||||
#if RTW_RESOLUTION == 256
|
||||
#define RTW_RESOLUTION_Y 258
|
||||
#elif RTW_RESOLUTION == 512
|
||||
#define RTW_RESOLUTION_Y 514
|
||||
#elif RTW_RESOLUTION == 1024
|
||||
#define RTW_RESOLUTION_Y 1026
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
// MinecraftPT — Custom resource declarations
|
||||
// The shader loader auto-declares standard uniforms, colortex/depthtex/shadowcolor
|
||||
// samplers, noisetex and tex. This file only declares CUSTOM samplers and images
|
||||
// (bound via shaders.properties customTexture / image declarations).
|
||||
|
||||
#ifndef UNIFORM_DECLARE_GLSL
|
||||
#define UNIFORM_DECLARE_GLSL
|
||||
|
||||
// Custom textures (from customTexture.* in shaders.properties)
|
||||
uniform sampler2D atlas2D;
|
||||
uniform sampler2D atlasSpecular2D;
|
||||
uniform sampler3D CloudNoise3D;
|
||||
uniform sampler3D CloudDetailedNoise3D;
|
||||
uniform sampler2D ripple2D;
|
||||
|
||||
// Custom image samplers (from image.img_* in shaders.properties)
|
||||
uniform sampler3D voxelData3D;
|
||||
uniform sampler2D skyBox2D;
|
||||
uniform sampler2D prevDepth2D;
|
||||
uniform sampler2D rtwImportance2D;
|
||||
uniform sampler2D rtwWarp1D;
|
||||
uniform sampler2D pixelData2D;
|
||||
|
||||
// Custom image bindings (write access)
|
||||
layout(rgba16) uniform writeonly image3D img_voxelData3D;
|
||||
layout(rgba16f) uniform writeonly image3D img_irradianceCache3D;
|
||||
layout(rgba16f) uniform writeonly image3D img_irradianceCache3D_Alt;
|
||||
layout(rgba16f) uniform writeonly image2D img_skyBox2D;
|
||||
layout(r32f) uniform writeonly image2D img_prevDepth2D;
|
||||
layout(r32f) uniform writeonly image2D img_rtwImportance2D;
|
||||
layout(rg16) uniform writeonly image2D img_rtwWarp1D;
|
||||
layout(rg16f) uniform writeonly image2D img_pixelData2D;
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user