mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
speed up *some* collision detection
This commit is contained in:
parent
0f64035543
commit
049fe44d81
6 changed files with 259 additions and 21 deletions
|
|
@ -464,7 +464,7 @@ class DifBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
collider.difEdgeMap = difEdges;
|
collider.difEdgeMap = difEdges;
|
||||||
collider.generateBoundingBox();
|
collider.finalize();
|
||||||
itr.collider = collider;
|
itr.collider = collider;
|
||||||
|
|
||||||
function canFindTex(tex:String) {
|
function canFindTex(tex:String) {
|
||||||
|
|
|
||||||
|
|
@ -780,7 +780,7 @@ class Marble extends GameObject {
|
||||||
+ relLocalVel.z * deltaT * 2,
|
+ relLocalVel.z * deltaT * 2,
|
||||||
radius * 1.1);
|
radius * 1.1);
|
||||||
|
|
||||||
var surfaces = obj.octree.boundingSearch(boundThing);
|
var surfaces = obj.grid == null ? obj.octree.boundingSearch(boundThing).map(x -> cast x) : obj.grid.boundingSearch(boundThing);
|
||||||
|
|
||||||
for (surf in surfaces) {
|
for (surf in surfaces) {
|
||||||
var surface:CollisionSurface = cast surf;
|
var surface:CollisionSurface = cast surf;
|
||||||
|
|
@ -1065,7 +1065,7 @@ class Marble extends GameObject {
|
||||||
boundThing.addSpherePos(localpos.x + relLocalVel.x * dt * 2, localpos.y + relLocalVel.y * dt * 2, localpos.z + relLocalVel.z * dt * 2,
|
boundThing.addSpherePos(localpos.x + relLocalVel.x * dt * 2, localpos.y + relLocalVel.y * dt * 2, localpos.z + relLocalVel.z * dt * 2,
|
||||||
radius * 1.1);
|
radius * 1.1);
|
||||||
|
|
||||||
var surfaces = obj.octree.boundingSearch(boundThing);
|
var surfaces = obj.grid == null ? obj.octree.boundingSearch(boundThing).map(x -> cast x) : obj.grid.boundingSearch(boundThing);
|
||||||
|
|
||||||
var tform = obj.transform.clone();
|
var tform = obj.transform.clone();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,27 +15,27 @@ class ProfilerUI {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
instance = this;
|
instance = this;
|
||||||
// debugProfiler = new h3d.impl.Benchmark(s2d);
|
debugProfiler = new h3d.impl.Benchmark(s2d);
|
||||||
// debugProfiler.y = 40;
|
debugProfiler.y = 40;
|
||||||
|
|
||||||
// fpsCounter = new Text(DefaultFont.get(), s2d);
|
fpsCounter = new Text(DefaultFont.get(), s2d);
|
||||||
// fpsCounter.y = 80;
|
fpsCounter.y = 80;
|
||||||
// fpsCounter.color = new Vector(1, 1, 1, 1);
|
fpsCounter.color = new Vector(1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function begin() {
|
public static function begin() {
|
||||||
// instance.debugProfiler.begin();
|
instance.debugProfiler.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function measure(name:String) {
|
public static function measure(name:String) {
|
||||||
// instance.debugProfiler.measure(name);
|
instance.debugProfiler.measure(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function end() {
|
public static function end() {
|
||||||
// instance.debugProfiler.end();
|
instance.debugProfiler.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function update(fps:Float) {
|
public static function update(fps:Float) {
|
||||||
// instance.fpsCounter.text = "FPS: " + fps;
|
instance.fpsCounter.text = "FPS: " + fps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ class CollisionEntity implements IOctreeObject {
|
||||||
|
|
||||||
public var octree:Octree;
|
public var octree:Octree;
|
||||||
|
|
||||||
|
public var grid:Grid;
|
||||||
|
|
||||||
public var surfaces:Array<CollisionSurface>;
|
public var surfaces:Array<CollisionSurface>;
|
||||||
|
|
||||||
public var priority:Int;
|
public var priority:Int;
|
||||||
|
|
@ -49,6 +51,15 @@ class CollisionEntity implements IOctreeObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generates the grid
|
||||||
|
public function finalize() {
|
||||||
|
this.generateBoundingBox();
|
||||||
|
this.grid = new Grid(this.boundingBox);
|
||||||
|
for (surface in this.surfaces) {
|
||||||
|
this.grid.insert(surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function setTransform(transform:Matrix) {
|
public function setTransform(transform:Matrix) {
|
||||||
if (this.transform == transform)
|
if (this.transform == transform)
|
||||||
return;
|
return;
|
||||||
|
|
@ -72,15 +83,26 @@ class CollisionEntity implements IOctreeObject {
|
||||||
var rStart = rayOrigin.clone();
|
var rStart = rayOrigin.clone();
|
||||||
rStart.transform(invMatrix);
|
rStart.transform(invMatrix);
|
||||||
var rDir = rayDirection.transformed3x3(invMatrix);
|
var rDir = rayDirection.transformed3x3(invMatrix);
|
||||||
var intersections = octree.raycast(rStart, rDir);
|
if (grid == null) {
|
||||||
var iData:Array<RayIntersectionData> = [];
|
var intersections = octree.raycast(rStart, rDir);
|
||||||
for (i in intersections) {
|
var iData:Array<RayIntersectionData> = [];
|
||||||
i.point.transform(transform);
|
for (i in intersections) {
|
||||||
i.normal.transform3x3(transform);
|
i.point.transform(transform);
|
||||||
i.normal.normalize();
|
i.normal.transform3x3(transform);
|
||||||
iData.push({point: i.point, normal: i.normal, object: i.object});
|
i.normal.normalize();
|
||||||
|
iData.push({point: i.point, normal: i.normal, object: i.object});
|
||||||
|
}
|
||||||
|
return iData;
|
||||||
|
} else {
|
||||||
|
var intersections = this.grid.rayCast(rStart, rDir);
|
||||||
|
for (i in intersections) {
|
||||||
|
i.point.transform(transform);
|
||||||
|
i.normal.transform3x3(transform);
|
||||||
|
i.normal.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersections;
|
||||||
}
|
}
|
||||||
return iData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getElementType() {
|
public function getElementType() {
|
||||||
|
|
@ -105,7 +127,7 @@ class CollisionEntity implements IOctreeObject {
|
||||||
sphereBounds.addSpherePos(position.x, position.y, position.z, radius * 1.1);
|
sphereBounds.addSpherePos(position.x, position.y, position.z, radius * 1.1);
|
||||||
sphereBounds.transform(invMatrix);
|
sphereBounds.transform(invMatrix);
|
||||||
sphereBounds.addSpherePos(localPos.x, localPos.y, localPos.z, radius * 1.1);
|
sphereBounds.addSpherePos(localPos.x, localPos.y, localPos.z, radius * 1.1);
|
||||||
var surfaces = octree.boundingSearch(sphereBounds);
|
var surfaces = grid == null ? octree.boundingSearch(sphereBounds).map(x -> cast x) : grid.boundingSearch(sphereBounds);
|
||||||
|
|
||||||
var tform = transform.clone();
|
var tform = transform.clone();
|
||||||
// tform.setPosition(tform.getPosition().add(this.velocity.multiply(timeState.dt)));
|
// tform.setPosition(tform.getPosition().add(this.velocity.multiply(timeState.dt)));
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ class CollisionSurface implements IOctreeObject {
|
||||||
|
|
||||||
public var originalSurfaceIndex:Int;
|
public var originalSurfaceIndex:Int;
|
||||||
|
|
||||||
|
public var key:Bool = false;
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public function getElementType() {
|
public function getElementType() {
|
||||||
|
|
|
||||||
214
src/collision/Grid.hx
Normal file
214
src/collision/Grid.hx
Normal file
|
|
@ -0,0 +1,214 @@
|
||||||
|
package collision;
|
||||||
|
|
||||||
|
import haxe.Exception;
|
||||||
|
import h3d.Vector;
|
||||||
|
import h3d.col.Bounds;
|
||||||
|
|
||||||
|
class Grid {
|
||||||
|
public var bounds:Bounds; // The bounds of the grid
|
||||||
|
|
||||||
|
public var cellSize:Vector; // The dimensions of one cell
|
||||||
|
|
||||||
|
public static var CELL_DIV = new Vector(16, 16, 16); // split the bounds into cells of dimensions 1/16th of the corresponding dimensions of the bounds
|
||||||
|
|
||||||
|
var map:Map<Int, Array<Int>> = new Map();
|
||||||
|
|
||||||
|
var surfaces:Array<CollisionSurface> = [];
|
||||||
|
|
||||||
|
public function new(bounds:Bounds) {
|
||||||
|
this.bounds = bounds;
|
||||||
|
|
||||||
|
this.cellSize = new Vector(bounds.xSize / CELL_DIV.x, bounds.ySize / CELL_DIV.y, bounds.zSize / CELL_DIV.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insert(surface:CollisionSurface) {
|
||||||
|
// Assuming surface has built a bounding box already
|
||||||
|
if (this.bounds.containsBounds(surface.boundingBox)) {
|
||||||
|
var idx = this.surfaces.length;
|
||||||
|
this.surfaces.push(surface);
|
||||||
|
|
||||||
|
var xStart = Math.floor((surface.boundingBox.xMin - bounds.xMin) / this.cellSize.x);
|
||||||
|
var yStart = Math.floor((surface.boundingBox.yMin - bounds.yMin) / this.cellSize.y);
|
||||||
|
var zStart = Math.floor((surface.boundingBox.zMin - bounds.zMin) / this.cellSize.z);
|
||||||
|
var xEnd = Math.ceil((surface.boundingBox.xMax - bounds.xMin) / this.cellSize.x) + 1;
|
||||||
|
var yEnd = Math.ceil((surface.boundingBox.yMax - bounds.yMin) / this.cellSize.y) + 1;
|
||||||
|
var zEnd = Math.ceil((surface.boundingBox.zMax - bounds.zMin) / this.cellSize.z) + 1;
|
||||||
|
|
||||||
|
// Insert the surface references from [xStart, yStart, zStart] to [xEnd, yEnd, zEnd] into the map
|
||||||
|
for (i in xStart...xEnd) {
|
||||||
|
for (j in yStart...yEnd) {
|
||||||
|
for (k in zStart...zEnd) {
|
||||||
|
var hash = hashVector(i, j, k);
|
||||||
|
if (!this.map.exists(hash)) {
|
||||||
|
this.map.set(hash, []);
|
||||||
|
}
|
||||||
|
this.map.get(hash).push(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Exception("Surface is not contained in the grid's bounds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// searchbox should be in LOCAL coordinates
|
||||||
|
public function boundingSearch(searchbox:Bounds) {
|
||||||
|
var xStart = Math.floor((searchbox.xMin - bounds.xMin) / this.cellSize.x);
|
||||||
|
var yStart = Math.floor((searchbox.yMin - bounds.yMin) / this.cellSize.y);
|
||||||
|
var zStart = Math.floor((searchbox.zMin - bounds.zMin) / this.cellSize.z);
|
||||||
|
var xEnd = Math.ceil((searchbox.xMax - bounds.xMin) / this.cellSize.x) + 1;
|
||||||
|
var yEnd = Math.ceil((searchbox.yMax - bounds.yMin) / this.cellSize.y) + 1;
|
||||||
|
var zEnd = Math.ceil((searchbox.zMax - bounds.zMin) / this.cellSize.z) + 1;
|
||||||
|
|
||||||
|
var foundSurfaces = [];
|
||||||
|
|
||||||
|
for (surf in this.surfaces) {
|
||||||
|
surf.key = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the surface references from [xStart, yStart, zStart] to [xEnd, yEnd, zEnd] into the map
|
||||||
|
for (i in xStart...xEnd) {
|
||||||
|
for (j in yStart...yEnd) {
|
||||||
|
for (k in zStart...zEnd) {
|
||||||
|
var hash = hashVector(i, j, k);
|
||||||
|
if (this.map.exists(hash)) {
|
||||||
|
var surfs = this.map.get(hash);
|
||||||
|
var actualsurfs = surfs.map(x -> this.surfaces[x]);
|
||||||
|
for (surf in actualsurfs) {
|
||||||
|
if (surf.key)
|
||||||
|
continue;
|
||||||
|
if (searchbox.containsBounds(surf.boundingBox) || searchbox.collide(surf.boundingBox)) {
|
||||||
|
foundSurfaces.push(surf);
|
||||||
|
surf.key = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundSurfaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
function elegantPair(x:Int, y:Int) {
|
||||||
|
return (x >= y) ? (x * x + x + y) : (y * y + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hashVector(x:Int, y:Int, z:Int) {
|
||||||
|
return elegantPair(elegantPair(x, y), z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rayCast(origin:Vector, direction:Vector) {
|
||||||
|
var cell = origin.sub(this.bounds.getMin().toVector());
|
||||||
|
cell.x /= this.cellSize.x;
|
||||||
|
cell.y /= this.cellSize.y;
|
||||||
|
cell.z /= this.cellSize.z;
|
||||||
|
|
||||||
|
var stepX, outX, X = Math.floor(cell.x);
|
||||||
|
var stepY, outY, Y = Math.floor(cell.y);
|
||||||
|
var stepZ, outZ, Z = Math.floor(cell.z);
|
||||||
|
|
||||||
|
if ((X < 0) || (X >= CELL_DIV.x) || (Y < 0) || (Y >= CELL_DIV.y) || (Z < 0) || (Z >= CELL_DIV.z))
|
||||||
|
return [];
|
||||||
|
|
||||||
|
var cb = new Vector();
|
||||||
|
|
||||||
|
if (direction.x > 0) {
|
||||||
|
stepX = 1;
|
||||||
|
outX = CELL_DIV.x;
|
||||||
|
cb.x = this.bounds.getMin().x + (X + 1) * this.cellSize.x;
|
||||||
|
} else {
|
||||||
|
stepX = -1;
|
||||||
|
outX = -1;
|
||||||
|
cb.x = this.bounds.getMin().x + X * this.cellSize.x;
|
||||||
|
}
|
||||||
|
if (direction.y > 0.0) {
|
||||||
|
stepY = 1;
|
||||||
|
outY = CELL_DIV.y;
|
||||||
|
cb.y = this.bounds.getMin().y + (Y + 1) * this.cellSize.y;
|
||||||
|
} else {
|
||||||
|
stepY = -1;
|
||||||
|
outY = -1;
|
||||||
|
cb.y = this.bounds.getMin().y + Y * this.cellSize.y;
|
||||||
|
}
|
||||||
|
if (direction.z > 0.0) {
|
||||||
|
stepZ = 1;
|
||||||
|
outZ = CELL_DIV.z;
|
||||||
|
cb.z = this.bounds.getMin().z + (Z + 1) * this.cellSize.z;
|
||||||
|
} else {
|
||||||
|
stepZ = -1;
|
||||||
|
outZ = -1;
|
||||||
|
cb.z = this.bounds.getMin().z + Z * this.cellSize.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmax = new Vector();
|
||||||
|
var tdelta = new Vector();
|
||||||
|
|
||||||
|
var rxr, ryr, rzr;
|
||||||
|
if (direction.x != 0) {
|
||||||
|
rxr = 1.0 / direction.x;
|
||||||
|
tmax.x = (cb.x - origin.x) * rxr;
|
||||||
|
tdelta.x = this.cellSize.x * stepX * rxr;
|
||||||
|
} else
|
||||||
|
tmax.x = 1000000;
|
||||||
|
if (direction.y != 0) {
|
||||||
|
ryr = 1.0 / direction.y;
|
||||||
|
tmax.y = (cb.y - origin.y) * ryr;
|
||||||
|
tdelta.y = this.cellSize.y * stepY * ryr;
|
||||||
|
} else
|
||||||
|
tmax.y = 1000000;
|
||||||
|
if (direction.z != 0) {
|
||||||
|
rzr = 1.0 / direction.z;
|
||||||
|
tmax.z = (cb.z - origin.z) * rzr;
|
||||||
|
tdelta.z = this.cellSize.z * stepZ * rzr;
|
||||||
|
} else
|
||||||
|
tmax.z = 1000000;
|
||||||
|
|
||||||
|
for (surf in this.surfaces) {
|
||||||
|
surf.key = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = [];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
var hash = hashVector(X, Y, Z);
|
||||||
|
if (this.map.exists(hash)) {
|
||||||
|
var currentSurfaces = this.map.get(hash).map(x -> this.surfaces[x]);
|
||||||
|
|
||||||
|
for (surf in currentSurfaces) {
|
||||||
|
if (surf.key)
|
||||||
|
continue;
|
||||||
|
results = results.concat(surf.rayCast(origin, direction));
|
||||||
|
surf.key = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tmax.x < tmax.y) {
|
||||||
|
if (tmax.x < tmax.z) {
|
||||||
|
X = X + stepX;
|
||||||
|
if (X == outX)
|
||||||
|
break;
|
||||||
|
tmax.x += tdelta.x;
|
||||||
|
} else {
|
||||||
|
Z = Z + stepZ;
|
||||||
|
if (Z == outZ)
|
||||||
|
break;
|
||||||
|
tmax.z += tdelta.z;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (tmax.y < tmax.z) {
|
||||||
|
Y = Y + stepY;
|
||||||
|
if (Y == outY)
|
||||||
|
break;
|
||||||
|
tmax.y += tdelta.y;
|
||||||
|
} else {
|
||||||
|
Z = Z + stepZ;
|
||||||
|
if (Z == outZ)
|
||||||
|
break;
|
||||||
|
tmax.z += tdelta.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue