// DDA-Voxel-Raycast (Amanatides & Woo). Liefert ersten getroffenen, soliden // (nicht Luft, nicht Wasser) Block sowie die Eintrittsnormale (face). import { BLOCK } from './constants.js'; export function raycastVoxel(getBlock, originX, originY, originZ, dirX, dirY, dirZ, maxDist) { let x = Math.floor(originX); let y = Math.floor(originY); let z = Math.floor(originZ); const stepX = dirX > 0 ? 1 : dirX < 0 ? -1 : 0; const stepY = dirY > 0 ? 1 : dirY < 0 ? -1 : 0; const stepZ = dirZ > 0 ? 1 : dirZ < 0 ? -1 : 0; const tDeltaX = stepX !== 0 ? Math.abs(1 / dirX) : Infinity; const tDeltaY = stepY !== 0 ? Math.abs(1 / dirY) : Infinity; const tDeltaZ = stepZ !== 0 ? Math.abs(1 / dirZ) : Infinity; let tMaxX = stepX > 0 ? (x + 1 - originX) * tDeltaX : stepX < 0 ? (originX - x) * tDeltaX : Infinity; let tMaxY = stepY > 0 ? (y + 1 - originY) * tDeltaY : stepY < 0 ? (originY - y) * tDeltaY : Infinity; let tMaxZ = stepZ > 0 ? (z + 1 - originZ) * tDeltaZ : stepZ < 0 ? (originZ - z) * tDeltaZ : Infinity; let nx = 0, ny = 0, nz = 0; let t = 0; // Start-Voxel pruefen let b = getBlock(x, y, z); if (b !== BLOCK.AIR && b !== BLOCK.WATER) { return { x, y, z, block: b, nx: 0, ny: 0, nz: 0 }; } const maxSteps = 128; for (let i = 0; i < maxSteps; i++) { if (tMaxX < tMaxY && tMaxX < tMaxZ) { x += stepX; t = tMaxX; tMaxX += tDeltaX; nx = -stepX; ny = 0; nz = 0; } else if (tMaxY < tMaxZ) { y += stepY; t = tMaxY; tMaxY += tDeltaY; nx = 0; ny = -stepY; nz = 0; } else { z += stepZ; t = tMaxZ; tMaxZ += tDeltaZ; nx = 0; ny = 0; nz = -stepZ; } if (t > maxDist) break; b = getBlock(x, y, z); if (b !== BLOCK.AIR && b !== BLOCK.WATER) { return { x, y, z, block: b, nx, ny, nz }; } } return null; }