mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
raytrace shit
This commit is contained in:
parent
38e93ea561
commit
cbc0257509
4 changed files with 73 additions and 98 deletions
|
|
@ -25,6 +25,7 @@ class BoxCollisionEntity extends CollisionEntity {
|
|||
|
||||
public override function isIntersectedByRay(rayOrigin:Vector, rayDirection:Vector, intersectionPoint:Vector):Bool {
|
||||
// TEMP cause bruh
|
||||
return false;
|
||||
return boundingBox.rayIntersection(Ray.fromValues(rayOrigin.x, rayOrigin.y, rayOrigin.z, rayDirection.x, rayDirection.y, rayDirection.z), true) != -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ class CollisionWorld {
|
|||
}
|
||||
|
||||
public function rayCast(rayStart:Vector, rayDirection:Vector) {
|
||||
return [];
|
||||
// return [];
|
||||
return this.octree.raycast(rayStart, rayDirection);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ class Octree {
|
|||
public function new() {
|
||||
this.root = new OctreeNode(this, 0);
|
||||
// Init the octree to a 1x1x1 cube
|
||||
this.root.min.set(0, 0, 0);
|
||||
this.root.size = 1;
|
||||
this.root.bounds = new Bounds();
|
||||
this.root.bounds.xMin = this.root.bounds.yMin = this.root.bounds.zMin = 0;
|
||||
this.root.bounds.xMax = this.root.bounds.yMax = this.root.bounds.zMax = 1;
|
||||
this.objectToNode = new Map();
|
||||
}
|
||||
|
||||
|
|
@ -25,6 +26,8 @@ class Octree {
|
|||
return; // Don't insert if already contained in the tree
|
||||
while (!this.root.largerThan(object) || !this.root.containsCenter(object)) {
|
||||
// The root node does not fit the object; we need to grow the tree.
|
||||
var a = this.root.largerThan(object);
|
||||
var b = this.root.containsCenter(object);
|
||||
if (this.root.depth == -32) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -68,18 +71,20 @@ class Octree {
|
|||
}
|
||||
averagePoint = averagePoint.multiply(1 / count); // count should be greater than 0, because that's why we're growing in the first place.
|
||||
// Determine the direction from the root center to the determined point
|
||||
var rootCenter = this.root.min.clone().add(new Vector(this.root.size / 2, this.root.size / 2, this.root.size / 2));
|
||||
var rootCenter = this.root.bounds.getCenter().toVector();
|
||||
var direction = averagePoint.sub(rootCenter); // Determine the "direction of growth"
|
||||
// Create a new root. The current root will become a quadrant in this new root.
|
||||
var newRoot = new OctreeNode(this, this.root.depth - 1);
|
||||
newRoot.min = this.root.min.clone();
|
||||
newRoot.size = this.root.size * 2;
|
||||
newRoot.bounds = this.root.bounds.clone();
|
||||
newRoot.bounds.xSize *= 2;
|
||||
newRoot.bounds.ySize *= 2;
|
||||
newRoot.bounds.zSize *= 2;
|
||||
if (direction.x < 0)
|
||||
newRoot.min.x -= this.root.size;
|
||||
newRoot.bounds.xMin -= this.root.bounds.xSize;
|
||||
if (direction.y < 0)
|
||||
newRoot.min.y -= this.root.size;
|
||||
newRoot.bounds.yMin -= this.root.bounds.ySize;
|
||||
if (direction.z < 0)
|
||||
newRoot.min.z -= this.root.size;
|
||||
newRoot.bounds.zMin -= this.root.bounds.zSize;
|
||||
if (this.root.count > 0) {
|
||||
var octantIndex = ((direction.x < 0) ? 1 : 0) + ((direction.y < 0) ? 2 : 0) + ((direction.z < 0) ? 4 : 0);
|
||||
newRoot.createOctants();
|
||||
|
|
@ -93,12 +98,12 @@ class Octree {
|
|||
|
||||
/** Tries to shrink the octree if large parts of the octree are empty. */
|
||||
public function shrink() {
|
||||
if (this.root.size < 1 || this.root.objects.length > 0)
|
||||
if (this.root.bounds.xSize < 1 || this.root.bounds.ySize < 1 || this.root.bounds.zSize < 1 || this.root.objects.length > 0)
|
||||
return;
|
||||
if (this.root.count == 0) {
|
||||
// Reset to default empty octree
|
||||
this.root.min.set(0, 0, 0);
|
||||
this.root.size = 1;
|
||||
this.root.bounds.xMin = this.root.bounds.yMin = this.root.bounds.zMin = 0;
|
||||
this.root.bounds.xMax = this.root.bounds.yMax = this.root.bounds.zMin = 1;
|
||||
this.root.depth = 0;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,9 @@ class OctreeNode implements IOctreeElement {
|
|||
public var position:Int;
|
||||
|
||||
/** The min corner of the bounding box. */
|
||||
public var min = new Vector();
|
||||
public var bounds:Bounds;
|
||||
|
||||
/** The size of the bounding box on all three axes. This forces the bounding box to be a cube. */
|
||||
public var size:Float;
|
||||
|
||||
public var octants:Array<OctreeNode> = null;
|
||||
|
||||
/** A list of objects contained in this node. Note that the node doesn't need to be a leaf node for this set to be non-empty; since this is an octree of bounding boxes, some volumes cannot fit into an octant and therefore need to be stored in the node itself. */
|
||||
|
|
@ -36,18 +34,13 @@ class OctreeNode implements IOctreeElement {
|
|||
public function insert(object:IOctreeObject) {
|
||||
this.count++;
|
||||
if (this.octants != null) {
|
||||
// First we check if the object can fit into any of the octants (they all have the same size, so checking only one suffices)
|
||||
if (this.octants[0].largerThan(object)) {
|
||||
// Try to insert the object into one of the octants...
|
||||
for (i in 0...8) {
|
||||
var octant = this.octants[i];
|
||||
if (octant.containsCenter(object)) {
|
||||
octant.insert(object);
|
||||
return;
|
||||
}
|
||||
for (i in 0...8) {
|
||||
var octant = this.octants[i];
|
||||
if (octant.largerThan(object) && octant.containsCenter(object)) {
|
||||
octant.insert(object);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// No octant fit the object, so add it to the list of objects instead
|
||||
this.objects.push(object);
|
||||
this.octree.objectToNode.set(object, this);
|
||||
} else {
|
||||
|
|
@ -63,13 +56,12 @@ class OctreeNode implements IOctreeElement {
|
|||
this.createOctants();
|
||||
// Put the objects into the correct octants. Note that all objects that couldn't fit into any octant will remain in the set.
|
||||
for (object in this.objects) {
|
||||
if (this.octants[0].largerThan(object)) {
|
||||
for (j in 0...8) {
|
||||
var octant = this.octants[j];
|
||||
if (octant.containsCenter(object)) {
|
||||
octant.insert(object);
|
||||
this.objects.remove(object);
|
||||
}
|
||||
for (j in 0...8) {
|
||||
var octant = this.octants[j];
|
||||
if (octant.largerThan(object) && octant.containsCenter(object)) {
|
||||
octant.insert(object);
|
||||
this.objects.remove(object);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -84,14 +76,16 @@ class OctreeNode implements IOctreeElement {
|
|||
for (i in 0...8) {
|
||||
var newNode = new OctreeNode(this.octree, this.depth + 1);
|
||||
newNode.parent = this;
|
||||
newNode.size = this.size / 2;
|
||||
newNode.min.set(this.min.x
|
||||
+ newNode.size * ((i & 1) >> 0), // The x coordinate changes every index
|
||||
this.min.y
|
||||
+ newNode.size * ((i & 2) >> 1), // The y coordinate changes every 2 indices
|
||||
this.min.z
|
||||
+ newNode.size * ((i & 4) >> 2) // The z coordinate changes every 4 indices
|
||||
);
|
||||
var newSize = this.bounds.getSize().multiply(1 / 2);
|
||||
newNode.bounds = this.bounds.clone();
|
||||
newNode.bounds.setMin(new Point(this.bounds.xMin
|
||||
+ newSize.x * ((i & 1) >> 0), this.bounds.yMin
|
||||
+ newSize.y * ((i & 2) >> 1),
|
||||
this.bounds.zMin
|
||||
+ newSize.z * ((i & 4) >> 2)));
|
||||
newNode.bounds.xSize = newSize.x;
|
||||
newNode.bounds.ySize = newSize.y;
|
||||
newNode.bounds.zSize = newSize.z;
|
||||
this.octants.push(newNode);
|
||||
}
|
||||
}
|
||||
|
|
@ -125,71 +119,46 @@ class OctreeNode implements IOctreeElement {
|
|||
}
|
||||
|
||||
public function largerThan(object:IOctreeObject) {
|
||||
var box = object.boundingBox;
|
||||
var bb = new Bounds();
|
||||
bb.setMin(this.min.toPoint());
|
||||
bb.xMax = bb.xMin + this.size;
|
||||
bb.yMax = bb.yMin + this.size;
|
||||
bb.zMax = bb.zMin + this.size;
|
||||
return bb.containsBounds(box);
|
||||
return this.bounds.containsBounds(object.boundingBox);
|
||||
// return this.size > (box.xMax - box.xMin) && this.size > (box.yMax - box.yMin) && this.size > (box.zMax - box.zMin);
|
||||
}
|
||||
|
||||
public function containsCenter(object:IOctreeObject) {
|
||||
var box = object.boundingBox;
|
||||
var x = box.xMin + (box.xMax - box.xMin) / 2;
|
||||
var y = box.yMin + (box.yMax - box.yMin) / 2;
|
||||
var z = box.zMin + (box.zMax - box.zMin) / 2;
|
||||
return this.min.x <= x && x < (this.min.x + this.size) && this.min.y <= y && y < (this.min.y + this.size) && this.min.z <= z
|
||||
&& z < (this.min.z + this.size);
|
||||
return this.bounds.contains(object.boundingBox.getCenter());
|
||||
}
|
||||
|
||||
public function containsPoint(point:Vector) {
|
||||
var x = point.x;
|
||||
var y = point.y;
|
||||
var z = point.z;
|
||||
return this.min.x <= x && x < (this.min.x + this.size) && this.min.y <= y && y < (this.min.y + this.size) && this.min.z <= z
|
||||
&& z < (this.min.z + this.size);
|
||||
return this.bounds.contains(point.toPoint());
|
||||
}
|
||||
|
||||
public function raycast(rayOrigin:Vector, rayDirection:Vector, intersections:Array<OctreeIntersection>) {
|
||||
var ray = Ray.fromValues(rayOrigin.x, rayOrigin.y, rayOrigin.z, rayDirection.x, rayDirection.y, rayDirection.z);
|
||||
// Construct the loose bounding box of this node (2x in size, with the regular bounding box in the center)
|
||||
var looseBoundingBox = this.octree.tempBox;
|
||||
looseBoundingBox.xMin += this.min.x + (-this.size / 2);
|
||||
looseBoundingBox.yMin += this.min.y + (-this.size / 2);
|
||||
looseBoundingBox.zMin += this.min.z + (-this.size / 2);
|
||||
looseBoundingBox.xMax += this.min.x + (this.size * 3 / 2);
|
||||
looseBoundingBox.yMax += this.min.y + (this.size * 3 / 2);
|
||||
looseBoundingBox.zMax += this.min.z + (this.size * 3 / 2);
|
||||
if (looseBoundingBox.rayIntersection(Ray.fromValues(rayOrigin.x, rayOrigin.y, rayOrigin.z, rayDirection.x, rayDirection.y, rayDirection.z),
|
||||
true) == -1)
|
||||
return; // The ray doesn't hit the node's loose bounding box; we can stop
|
||||
var vec = new Vector();
|
||||
// Test all objects for intersection
|
||||
if (this.objects.length > 0)
|
||||
for (object in this.objects) {
|
||||
if (object.isIntersectedByRay(rayOrigin, rayDirection, vec)) {
|
||||
var intersection:OctreeIntersection = new OctreeIntersection();
|
||||
intersection.object = object;
|
||||
intersection.point = vec;
|
||||
intersection.distance = rayOrigin.distance(vec);
|
||||
intersections.push(intersection);
|
||||
vec = new Vector();
|
||||
}
|
||||
|
||||
if (this.bounds.rayIntersection(ray, true) == -1)
|
||||
return;
|
||||
|
||||
for (obj in this.objects) {
|
||||
var iSec = new Vector();
|
||||
if (obj.isIntersectedByRay(rayOrigin, rayDirection, iSec)) {
|
||||
var intersectionData = new OctreeIntersection();
|
||||
intersectionData.distance = rayOrigin.distance(iSec);
|
||||
intersectionData.object = obj;
|
||||
intersectionData.point = iSec;
|
||||
intersections.push(intersectionData);
|
||||
}
|
||||
// Recurse into the octants
|
||||
if (this.octants != null)
|
||||
}
|
||||
|
||||
if (this.octants != null) {
|
||||
for (i in 0...8) {
|
||||
var octant = this.octants[i];
|
||||
octant.raycast(rayOrigin, rayDirection, intersections);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function boundingSearch(bounds:Bounds, intersections:Array<IOctreeElement>) {
|
||||
var thisBounds = new Bounds();
|
||||
thisBounds.setMin(this.min.toPoint());
|
||||
thisBounds.xSize = thisBounds.ySize = thisBounds.zSize = this.size;
|
||||
if (thisBounds.collide(bounds)) {
|
||||
if (this.bounds.collide(bounds)) {
|
||||
for (obj in this.objects) {
|
||||
if (obj.boundingBox.collide(bounds))
|
||||
intersections.push(obj);
|
||||
|
|
@ -203,24 +172,24 @@ class OctreeNode implements IOctreeElement {
|
|||
|
||||
public function getClosestPoint(point:Vector) {
|
||||
var closest = new Vector();
|
||||
if (this.min.x > point.x)
|
||||
closest.x = this.min.x;
|
||||
else if (this.min.x + this.size < point.x)
|
||||
closest.x = this.min.x + this.size;
|
||||
if (this.bounds.xMin > point.x)
|
||||
closest.x = this.bounds.xMin;
|
||||
else if (this.bounds.xMax < point.x)
|
||||
closest.x = this.bounds.xMax;
|
||||
else
|
||||
closest.x = point.x;
|
||||
|
||||
if (this.min.y > point.y)
|
||||
closest.y = this.min.y;
|
||||
else if (this.min.y + this.size < point.y)
|
||||
closest.y = this.min.y + this.size;
|
||||
if (this.bounds.yMin > point.y)
|
||||
closest.y = this.bounds.yMin;
|
||||
else if (this.bounds.yMax < point.y)
|
||||
closest.y = this.bounds.yMax;
|
||||
else
|
||||
closest.y = point.y;
|
||||
|
||||
if (this.min.z > point.z)
|
||||
closest.z = this.min.z;
|
||||
else if (this.min.z + this.size < point.z)
|
||||
closest.z = this.min.z + this.size;
|
||||
if (this.bounds.zMin > point.z)
|
||||
closest.z = this.bounds.zMin;
|
||||
else if (this.bounds.zMax < point.z)
|
||||
closest.z = this.bounds.zMax;
|
||||
else
|
||||
closest.z = point.z;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue