Initial commit: Minecraft 光追着色器包(从零实现的 path tracing)
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user