forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			223 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			223 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | package iron.math; | ||
|  | 
 | ||
|  | import kha.FastFloat; | ||
|  | 
 | ||
|  | class Ray { | ||
|  | 
 | ||
|  | 	public var origin: Vec4; | ||
|  | 	public var direction: Vec4; | ||
|  | 
 | ||
|  | 	public function new(origin: Vec4 = null, direction: Vec4 = null) { | ||
|  | 		this.origin = origin == null ? new Vec4() : origin; | ||
|  | 		this.direction = direction == null ? new Vec4() : direction; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function at(t: FastFloat): Vec4 { | ||
|  | 		var result = new Vec4(); | ||
|  | 		return result.setFrom(direction).mult(t).add(origin); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function distanceToPoint(point: Vec4): FastFloat { | ||
|  | 		var v1 = new Vec4(); | ||
|  | 		var directionDistance = v1.subvecs(point, this.origin).dot(this.direction); | ||
|  | 
 | ||
|  | 		// Point behind the ray | ||
|  | 		if (directionDistance < 0) { | ||
|  | 			return this.origin.distanceTo(point); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		v1.setFrom(this.direction).mult(directionDistance).add(this.origin); | ||
|  | 
 | ||
|  | 		return v1.distanceTo(point); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function intersectsSphere(sphereCenter: Vec4, sphereRadius: FastFloat): Bool { | ||
|  | 		return distanceToPoint(sphereCenter) <= sphereRadius; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function intersectsPlane(plane: Plane): Bool { | ||
|  | 		// Check if the ray lies on the plane first | ||
|  | 		var distToPoint = plane.distanceToPoint(this.origin); | ||
|  | 		if (distToPoint == 0) return true; | ||
|  | 
 | ||
|  | 		var denominator = plane.normal.dot(this.direction); | ||
|  | 		if (denominator * distToPoint < 0) return true; | ||
|  | 
 | ||
|  | 		// Ray origin is behind the plane (and is pointing behind it) | ||
|  | 		return false; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function distanceToPlane(plane: Plane): FastFloat { | ||
|  | 		var denominator = plane.normal.dot(this.direction); | ||
|  | 		if (denominator == 0) { | ||
|  | 			// Line is coplanar, return origin | ||
|  | 			if (plane.distanceToPoint(this.origin) == 0) { | ||
|  | 				return 0; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			// Null is preferable to undefined since undefined means.... it is undefined | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		var t = -(this.origin.dot(plane.normal) + plane.constant) / denominator; | ||
|  | 
 | ||
|  | 		// Return if the ray never intersects the plane | ||
|  | 		return t >= 0 ? t : -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function intersectPlane(plane: Plane): Vec4 { | ||
|  | 		var t = this.distanceToPlane(plane); | ||
|  | 		if (t == -1) return null; | ||
|  | 		return this.at(t); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function intersectsBox(center: Vec4, dim: Vec4): Bool { | ||
|  | 		return this.intersectBox(center, dim) != null; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function intersectBox(center: Vec4, dim: Vec4): Vec4 { | ||
|  | 		// http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ | ||
|  | 		var tmin, tmax, tymin, tymax, tzmin, tzmax; | ||
|  | 
 | ||
|  | 		var halfX = dim.x / 2; | ||
|  | 		var halfY = dim.y / 2; | ||
|  | 		var halfZ = dim.z / 2; | ||
|  | 		var boxMinX = center.x - halfX; | ||
|  | 		var boxMinY = center.y - halfY; | ||
|  | 		var boxMinZ = center.z - halfZ; | ||
|  | 		var boxMaxX = center.x + halfX; | ||
|  | 		var boxMaxY = center.y + halfY; | ||
|  | 		var boxMaxZ = center.z + halfZ; | ||
|  | 
 | ||
|  | 		var invdirx = 1 / this.direction.x; | ||
|  | 		var	invdiry = 1 / this.direction.y; | ||
|  | 		var invdirz = 1 / this.direction.z; | ||
|  | 
 | ||
|  | 		var origin = this.origin; | ||
|  | 
 | ||
|  | 		if (invdirx >= 0) { | ||
|  | 			tmin = (boxMinX - origin.x) * invdirx; | ||
|  | 			tmax = (boxMaxX - origin.x) * invdirx; | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			tmin = (boxMaxX - origin.x) * invdirx; | ||
|  | 			tmax = (boxMinX - origin.x) * invdirx; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (invdiry >= 0) { | ||
|  | 			tymin = (boxMinY - origin.y) * invdiry; | ||
|  | 			tymax = (boxMaxY - origin.y) * invdiry; | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			tymin = (boxMaxY - origin.y) * invdiry; | ||
|  | 			tymax = (boxMinY - origin.y) * invdiry; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if ((tmin > tymax) || (tymin > tmax)) return null; | ||
|  | 
 | ||
|  | 		// These lines also handle the case where tmin or tmax is NaN | ||
|  | 		// (result of 0 * Infinity). x !== x returns true if x is NaN | ||
|  | 		if (tymin > tmin || tmin != tmin) tmin = tymin; | ||
|  | 		if (tymax < tmax || tmax != tmax) tmax = tymax; | ||
|  | 
 | ||
|  | 		if (invdirz >= 0) { | ||
|  | 			tzmin = (boxMinZ - origin.z) * invdirz; | ||
|  | 			tzmax = (boxMaxZ - origin.z) * invdirz; | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			tzmin = (boxMaxZ - origin.z) * invdirz; | ||
|  | 			tzmax = (boxMinZ - origin.z) * invdirz; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if ((tmin > tzmax) || (tzmin > tmax)) return null; | ||
|  | 		if (tzmin > tmin || tmin != tmin ) tmin = tzmin; | ||
|  | 		if (tzmax < tmax || tmax != tmax ) tmax = tzmax; | ||
|  | 
 | ||
|  | 		// Return point closest to the ray (positive side) | ||
|  | 		if (tmax < 0) return null; | ||
|  | 
 | ||
|  | 		return this.at(tmin >= 0 ? tmin : tmax); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function intersectTriangle(a: Vec4, b: Vec4, c: Vec4, backfaceCulling: Bool): Vec4 { | ||
|  | 		// Compute the offset origin, edges, and normal | ||
|  | 		var diff = new Vec4(); | ||
|  | 		var edge1 = new Vec4(); | ||
|  | 		var edge2 = new Vec4(); | ||
|  | 		var normal = new Vec4(); | ||
|  | 
 | ||
|  | 		// from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp | ||
|  | 		edge1.subvecs(b, a); | ||
|  | 		edge2.subvecs(c, a); | ||
|  | 		normal.crossvecs(edge1, edge2); | ||
|  | 
 | ||
|  | 		// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, | ||
|  | 		// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by | ||
|  | 		//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) | ||
|  | 		//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) | ||
|  | 		//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) | ||
|  | 		var DdN = this.direction.dot(normal); | ||
|  | 		var sign; | ||
|  | 
 | ||
|  | 		if (DdN > 0) { | ||
|  | 			if (backfaceCulling) return null; | ||
|  | 			sign = 1; | ||
|  | 		} | ||
|  | 		else if (DdN < 0) { | ||
|  | 			sign = -1; | ||
|  | 			DdN = -DdN; | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			return null; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		diff.subvecs(this.origin, a); | ||
|  | 		var DdQxE2 = sign * this.direction.dot(edge2.crossvecs(diff, edge2)); | ||
|  | 
 | ||
|  | 		// b1 < 0, no intersection | ||
|  | 		if (DdQxE2 < 0) { | ||
|  | 			return null; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		var DdE1xQ = sign * this.direction.dot(edge1.cross(diff)); | ||
|  | 
 | ||
|  | 		// b2 < 0, no intersection | ||
|  | 		if (DdE1xQ < 0) { | ||
|  | 			return null; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// b1+b2 > 1, no intersection | ||
|  | 		if (DdQxE2 + DdE1xQ > DdN) { | ||
|  | 			return null; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// Line intersects triangle, check if ray does. | ||
|  | 		var QdN = -sign * diff.dot(normal); | ||
|  | 
 | ||
|  | 		// t < 0, no intersection | ||
|  | 		if (QdN < 0) { | ||
|  | 			return null; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// Ray intersects triangle. | ||
|  | 		return this.at(QdN / DdN); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | class Plane { | ||
|  | 	public var normal = new Vec4(1.0, 0.0, 0.0); | ||
|  | 	public var constant = 0.0; | ||
|  | 
 | ||
|  | 	public function new() {} | ||
|  | 
 | ||
|  | 	public function distanceToPoint(point: Vec4): FastFloat { | ||
|  | 		return normal.dot(point) + constant; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function set(normal: Vec4, point: Vec4): Plane { | ||
|  | 		this.normal.setFrom(normal); | ||
|  | 		constant = -point.dot(this.normal); | ||
|  | 		return this; | ||
|  | 	} | ||
|  | } |