raytrace shit

This commit is contained in:
RandomityGuy 2021-06-17 22:01:18 +05:30
parent 38e93ea561
commit cbc0257509
4 changed files with 73 additions and 98 deletions

View file

@ -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;
}

View file

@ -86,7 +86,7 @@ class CollisionWorld {
}
public function rayCast(rayStart:Vector, rayDirection:Vector) {
return [];
// return [];
return this.octree.raycast(rayStart, rayDirection);
}

View file

@ -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;
}

View file

@ -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;