358 lines
14 KiB
Plaintext
358 lines
14 KiB
Plaintext
/*
|
|
文件名:OctreeClass.nut
|
|
路径:User/GameClass/OctreeClass/OctreeClass.nut
|
|
创建日期:2024-05-18 08:19
|
|
文件用途:
|
|
*/
|
|
class AABB {
|
|
minX = null;
|
|
minY = null;
|
|
minZ = null;
|
|
maxX = null;
|
|
maxY = null;
|
|
maxZ = null;
|
|
ObjectIndex = null;
|
|
constructor(...) {
|
|
minX = vargv[0];
|
|
minY = vargv[1];
|
|
minZ = vargv[2];
|
|
maxX = vargv[3];
|
|
maxY = vargv[4];
|
|
maxZ = vargv[5];
|
|
if (vargv.len() > 6) ObjectIndex = vargv[6];
|
|
}
|
|
}
|
|
|
|
class OctreeNode {
|
|
static m_maxObjects = 8;
|
|
static m_maxDepth = 8;
|
|
|
|
m_bounds = null;
|
|
m_isLeaf = true;
|
|
m_depth = 0;
|
|
m_objects = null;
|
|
m_children = null;
|
|
|
|
constructor(bounds) {
|
|
m_bounds = bounds;
|
|
m_depth = 0;
|
|
m_objects = [];
|
|
m_children = [null, null, null, null, null, null, null, null];
|
|
}
|
|
|
|
// function insert(aabb) {
|
|
// if (!m_isLeaf) {
|
|
// local index = getIndex(aabb);
|
|
// if (index != -1) {
|
|
// m_children[index].insert(aabb);
|
|
// return;
|
|
// }
|
|
// }
|
|
|
|
// m_objects.append(aabb);
|
|
|
|
// if (m_objects.len() > m_maxObjects && m_depth< m_maxDepth) {
|
|
// if (m_isLeaf) {
|
|
// split();
|
|
// }
|
|
|
|
// foreach(obj in m_objects) {
|
|
// local index = getIndex(obj);
|
|
// if (index != -1) {
|
|
// m_children[index].insert(obj);
|
|
// }
|
|
// }
|
|
|
|
// m_objects.clear();
|
|
// }
|
|
// }
|
|
|
|
function insert(aabb) {
|
|
if (!this.m_isLeaf) {
|
|
local index = this.getIndex(aabb);
|
|
if (index != -1 && this.m_children[index]) {
|
|
this.m_children[index].insert(aabb);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (this.m_objects.len() > this.m_maxObjects && this.m_depth< this.m_maxDepth) {
|
|
if (this.m_isLeaf) {
|
|
this.split();
|
|
}
|
|
|
|
foreach(obj in this.m_objects) {
|
|
local index = this.getIndex(obj);
|
|
if (index != -1) {
|
|
this.m_children[index].insert(obj);
|
|
}
|
|
}
|
|
|
|
this.m_objects.clear();
|
|
}
|
|
|
|
if (this.m_isLeaf) {
|
|
this.m_objects.append(aabb);
|
|
}
|
|
}
|
|
|
|
function clear() {
|
|
|
|
for (local i = 0; i< m_children.len(); i++) {
|
|
if (m_children[i] != null) {
|
|
m_children[i].clear();
|
|
m_children[i] = null;
|
|
}
|
|
}
|
|
/*
|
|
foreach(child in m_children) {
|
|
if (child != null) {
|
|
child.clear();
|
|
// delete m_children.child;
|
|
child = null;
|
|
}
|
|
}
|
|
*/
|
|
|
|
m_objects.clear();
|
|
}
|
|
|
|
function retrieve(aabb) {
|
|
local collidingObjects = [];
|
|
|
|
local index = getIndex(aabb);
|
|
if (index != -1 && !m_isLeaf) {
|
|
local tmp = m_children[index].retrieve(aabb);
|
|
collidingObjects.extend(tmp);
|
|
}
|
|
|
|
collidingObjects.extend(m_objects);
|
|
|
|
return collidingObjects;
|
|
}
|
|
|
|
|
|
|
|
//判断该点是否在给定参数的立方体内
|
|
function pointIsInCubeArea(px, py, pz, startX, startY, startZ, endX, endY, endZ) {
|
|
|
|
local cubeCenterX = (startX + endX) / 2;
|
|
local cubeXLen = abs(startX - endX) / 2;
|
|
|
|
local cubeCenterY = (startY + endY) / 2;
|
|
local cubeYLen = abs(startY - endY) / 2;
|
|
|
|
local cubeCenterZ = (startZ + endZ) / 2;
|
|
local cubeZLen = abs(startZ - endZ) / 2;
|
|
|
|
if (abs(px - cubeCenterX) <= cubeXLen && abs(py - cubeCenterY) <= cubeYLen && abs(pz - cubeCenterZ) <= cubeZLen)
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
//立方体与立方体之间碰撞 暂未测试
|
|
function CubeAndCubeCollection(c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ) {
|
|
|
|
if (pointIsInCubeArea(c1StartX, c1StartY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1EndX, c1StartY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1StartX, c1EndY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1EndX, c1EndY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1StartX, c1StartY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1EndX, c1StartY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1StartX, c1EndY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1EndX, c1EndY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2StartX, c2StartY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2EndX, c2StartY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2StartX, c2EndY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2EndX, c2EndY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2StartX, c2StartY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2EndX, c2StartY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2StartX, c2EndY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2EndX, c2EndY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea((c1StartX + c1EndX) / 2, c1StartY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea((c1StartX + c1EndX) / 2, c1EndY, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea((c1StartX + c1EndX) / 2, c1StartY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea((c1StartX + c1EndX) / 2, c1EndY, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1StartX, (c1StartY + c1EndY) / 2, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1StartX, (c1StartY + c1EndY) / 2, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1EndX, (c1StartY + c1EndY) / 2, c1StartZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1EndX, (c1StartY + c1EndY) / 2, c1EndZ, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1StartX, c1StartY, (c1StartZ + c1EndZ) / 2, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1StartX, c1EndY, (c1StartZ + c1EndZ) / 2, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1EndX, c1StartY, (c1StartZ + c1EndZ) / 2, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c1EndX, c1EndY, (c1StartZ + c1EndZ) / 2, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea((c2StartX + c2EndX) / 2, c2StartY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea((c2StartX + c2EndX) / 2, c2EndY, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea((c2StartX + c2EndX) / 2, c2StartY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea((c2StartX + c2EndX) / 2, c2EndY, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2StartX, (c2StartY + c2EndY) / 2, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2StartX, (c2StartY + c2EndY) / 2, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2EndX, (c2StartY + c2EndY) / 2, c2StartZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2EndX, (c2StartY + c2EndY) / 2, c2EndZ, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2StartX, c2StartY, (c2StartZ + c2EndZ) / 2, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2StartX, c2EndY, (c2StartZ + c2EndZ) / 2, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2EndX, c2StartY, (c2StartZ + c2EndZ) / 2, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea(c2EndX, c2EndY, (c2StartZ + c2EndZ) / 2, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea((c1StartX + c1EndX) / 2, (c1StartY + c1EndY) / 2, (c1StartZ + c1EndZ) / 2, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
|
|
return true;
|
|
if (pointIsInCubeArea((c2StartX + c2EndX) / 2, (c2StartY + c2EndY) / 2, (c2StartZ + c2EndZ) / 2, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
function checkCollision(aabb1, aabb2) {
|
|
return CubeAndCubeCollection(aabb1.minX, aabb1.minY, aabb1.minZ, aabb1.maxX, aabb1.maxY, aabb1.maxZ, aabb2.minX, aabb2.minY, aabb2.minZ, aabb2.maxX, aabb2.maxY, aabb2.maxZ);
|
|
}
|
|
|
|
function checkCollisionWithNode(aabb) {
|
|
local collidingObjects = [];
|
|
|
|
foreach(obj in m_objects) {
|
|
if (checkCollision(obj, aabb)) {
|
|
collidingObjects.append(obj);
|
|
}
|
|
}
|
|
|
|
if (!m_isLeaf) {
|
|
foreach(child in m_children) {
|
|
if (child != null) {
|
|
local tmp = child.checkCollisionWithNode(aabb);
|
|
collidingObjects.extend(tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
return collidingObjects;
|
|
}
|
|
|
|
|
|
function split() {
|
|
local minX = m_bounds.minX;
|
|
local maxX = m_bounds.maxX;
|
|
local minY = m_bounds.minY;
|
|
local maxY = m_bounds.maxY;
|
|
local minZ = m_bounds.minZ;
|
|
local maxZ = m_bounds.maxZ;
|
|
local midX = (minX + maxX) / 2;
|
|
local midY = (minY + maxY) / 2;
|
|
local midZ = (minZ + maxZ) / 2;
|
|
local objectbuf = m_bounds.Object;
|
|
|
|
|
|
m_children[0] = OctreeNode(AABB(minX, minY, minZ, midX, midY, midZ, objectbuf));
|
|
m_children[1] = OctreeNode(AABB(midX, minY, minZ, maxX, midY, midZ, objectbuf));
|
|
m_children[2] = OctreeNode(AABB(minX, midY, minZ, midX, maxY, midZ, objectbuf));
|
|
m_children[3] = OctreeNode(AABB(midX, midY, minZ, maxX, maxY, midZ, objectbuf));
|
|
m_children[4] = OctreeNode(AABB(minX, minY, midZ, midX, midY, maxZ, objectbuf));
|
|
m_children[5] = OctreeNode(AABB(midX, minY, midZ, maxX, midY, maxZ, objectbuf));
|
|
m_children[6] = OctreeNode(AABB(minX, midY, midZ, midX, maxY, maxZ, objectbuf));
|
|
m_children[7] = OctreeNode(AABB(midX, midY, midZ, maxX, maxY, maxZ, objectbuf));
|
|
|
|
m_isLeaf = false;
|
|
}
|
|
|
|
function getIndex(aabb) {
|
|
local midX = (m_bounds.minX + m_bounds.maxX) / 2;
|
|
local midY = (m_bounds.minY + m_bounds.maxY) / 2;
|
|
local midZ = (m_bounds.minZ + m_bounds.maxZ) / 2;
|
|
|
|
local top = aabb.minY > midY;
|
|
local bottom = aabb.maxY< midY;
|
|
local north = aabb.minZ > midZ;
|
|
local south = aabb.maxZ< midZ;
|
|
local east = aabb.minX > midX;
|
|
local west = aabb.maxX< midX;
|
|
|
|
if (top) {
|
|
if (east) return 0;
|
|
if (west) return 1;
|
|
return -1;
|
|
}
|
|
if (bottom) {
|
|
if (east) return 2;
|
|
if (west) return 3;
|
|
return -1;
|
|
}
|
|
if (north) {
|
|
if (east) return 4;
|
|
if (west) return 5;
|
|
return -1;
|
|
}
|
|
if (south) {
|
|
if (east) return 6;
|
|
if (west) return 7;
|
|
return -1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
// local octree = OctreeNode(AABB(0, 0, 0, 100, 100, 100));
|
|
// octree.clear();
|
|
|
|
// local aabb1 = AABB(10, 10, 10, 20, 20, 20);
|
|
// local aabb2 = AABB(30, 30, 30, 40, 40, 40);
|
|
// local aabb3 = AABB(50, 50, 50, 60, 60, 60);
|
|
|
|
// octree.insert(aabb1);
|
|
// octree.insert(aabb2);
|
|
// octree.insert(aabb3);
|
|
|
|
// local testAABB = AABB(15, 15, 15, 35, 35, 35);
|
|
// local collidingObjects = octree.checkCollisionWithNode(testAABB);
|
|
|
|
// print(collidingObjects.len());
|
|
// Util.PrintTable(collidingObjects);
|
|
|
|
|
|
// foreach(obj in collidingObjects) {
|
|
// print("Colliding object: (" + obj.minX + ", " + obj.minY + ", " + obj.minZ + ") - (" +
|
|
// obj.maxX + ", " + obj.maxY + ", " + obj.maxZ + ")");
|
|
// } |