Object Occlusion Culling

This commit is contained in:
2026-10-15 02:41:03 -07:00
parent 3273054766
commit 612a3d0a09
33 changed files with 3629 additions and 84 deletions

View File

@ -0,0 +1,171 @@
package iron.culling;
class HiZPyramid {
public var width: Int;
public var height: Int;
public var mipLevels: Int;
public var mipBuffers: Array<kha.arrays.Float32Array>;
public var mipWidths: Array<Int>;
public var mipHeights: Array<Int>;
public var depthEps: Float;
var mipShifts: Array<Int>;
public function new(width: Int, height: Int) {
this.width = width;
this.height = height;
mipBuffers = [];
mipWidths = [];
mipHeights = [];
depthEps = CullSystem.depthEps;
var w = width;
var h = height;
mipLevels = 0;
while (w > 1 || h > 1) {
mipWidths.push(w);
mipHeights.push(h);
mipBuffers.push(new kha.arrays.Float32Array(w * h));
mipLevels++;
w = (w + 1) >> 1;
h = (h + 1) >> 1;
}
mipWidths.push(1);
mipHeights.push(1);
mipBuffers.push(new kha.arrays.Float32Array(1));
mipLevels++;
mipShifts = [0, 1, 2, 3, 4, 5, 6];
while (mipShifts.length < mipLevels) mipShifts.push(mipShifts.length);
}
public function clear(farDepth: Float = 1e20) {
var buf = mipBuffers[0];
for (i in 0...buf.length) buf[i] = farDepth;
}
public inline function writeDepth(x: Int, y: Int, depth: Float) {
var idx = y * width + x;
if (x >= 0 && x < width && y >= 0 && y < height) {
if (depth < mipBuffers[0][idx]) {
mipBuffers[0][idx] = depth;
}
}
}
public function buildPyramid() {
for (mip in 1...mipLevels) {
var prev = mipBuffers[mip - 1];
var cur = mipBuffers[mip];
var pw = mipWidths[mip - 1];
var ph = mipHeights[mip - 1];
var cw = mipWidths[mip];
var ch = mipHeights[mip];
for (y in 0...ch) {
for (x in 0...cw) {
var sx = x * 2;
var sy = y * 2;
var d00 = prev[sy * pw + sx];
var d10 = (sx + 1 < pw) ? prev[sy * pw + sx + 1] : d00;
var d01 = (sy + 1 < ph) ? prev[(sy + 1) * pw + sx] : d00;
var d11 = (sx + 1 < pw && sy + 1 < ph) ? prev[(sy + 1) * pw + sx + 1] : d00;
var maxD = d00;
if (d10 > maxD) maxD = d10;
if (d01 > maxD) maxD = d01;
if (d11 > maxD) maxD = d11;
cur[y * cw + x] = maxD;
}
}
}
}
public inline function sample(x: Int, y: Int, mip: Int): Float {
var mw = mipWidths[mip];
var mh = mipHeights[mip];
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x >= mw) x = mw - 1;
if (y >= mh) y = mh - 1;
return mipBuffers[mip][y * mw + x];
}
public static function mipForSize(rectW: Float, rectH: Float, maxMip: Int): Int {
var maxDim = Math.max(rectW, rectH);
if (maxDim <= 2.0) return 0;
var mip = Std.int(Math.floor(Math.log(maxDim) / Math.log(2))) - 1;
if (mip < 0) mip = 0;
if (mip > maxMip) mip = maxMip;
return mip;
}
public function isOccluded(
minX: Float, minY: Float, minZ: Float,
maxX: Float, maxY: Float, maxZ: Float,
vp: iron.math.Mat4,
_screenW: Int, _screenH: Int
): Bool {
var minSx = 1e20, minSy = 1e20;
var maxSx = -1e20, maxSy = -1e20;
var minDepth = 1e20;
var m00 = vp._00, m10 = vp._10, m20 = vp._20, m30 = vp._30;
var m01 = vp._01, m11 = vp._11, m21 = vp._21, m31 = vp._31;
var m02 = vp._02, m12 = vp._12, m22 = vp._22, m32 = vp._32;
var m03 = vp._03, m13 = vp._13, m23 = vp._23, m33 = vp._33;
for (c in 0...8) {
var x = (c & 1) != 0 ? maxX : minX;
var y = (c & 2) != 0 ? maxY : minY;
var z = (c & 4) != 0 ? maxZ : minZ;
var w = m03 * x + m13 * y + m23 * z + m33;
if (w <= 0) return false;
var invW = SimdOps.reciprocal(w);
var ndcZ = (m02 * x + m12 * y + m22 * z + m32) * invW;
if (ndcZ < -1.0) ndcZ = -1.0; else if (ndcZ > 1.0) ndcZ = 1.0;
var sx = ((m00 * x + m10 * y + m20 * z + m30) * invW * 0.5 + 0.5) * width;
var sy = ((m01 * x + m11 * y + m21 * z + m31) * invW * 0.5 + 0.5) * height;
if (sx < minSx) minSx = sx;
if (sy < minSy) minSy = sy;
if (sx > maxSx) maxSx = sx;
if (sy > maxSy) maxSy = sy;
if (ndcZ < minDepth) minDepth = ndcZ;
}
var ix0 = Std.int(Math.max(0, minSx));
var iy0 = Std.int(Math.max(0, minSy));
var ix1 = Std.int(Math.min(width - 1, maxSx));
var iy1 = Std.int(Math.min(height - 1, maxSy));
if (ix0 > ix1 || iy0 > iy1) return false;
if (ix0 > 0) ix0--;
if (iy0 > 0) iy0--;
if (ix1 < width - 1) ix1++;
if (iy1 < height - 1) iy1++;
var rectW = ix1 - ix0 + 1;
var rectH = iy1 - iy0 + 1;
var mip = mipForSize(rectW, rectH, mipLevels - 1);
var mw = mipWidths[mip];
var mh = mipHeights[mip];
var shift = mipShifts[mip];
var tx0 = Std.int(Math.min(mw - 1, ix0 >> shift));
var ty0 = Std.int(Math.min(mh - 1, iy0 >> shift));
var tx1 = Std.int(Math.min(mw - 1, ix1 >> shift));
var ty1 = Std.int(Math.min(mh - 1, iy1 >> shift));
var buf = mipBuffers[mip];
var limit = minDepth - depthEps;
for (ty in ty0...ty1 + 1) {
var rowOff = ty * mw;
for (tx in tx0...tx1 + 1) {
if (buf[rowOff + tx] >= limit) return false;
}
}
return true;
}
}