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