forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			179 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			179 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
| 
								 | 
							
								package iron.math;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import kha.FastFloat;
							 | 
						||
| 
								 | 
							
								import iron.object.CameraObject;
							 | 
						||
| 
								 | 
							
								import iron.object.MeshObject;
							 | 
						||
| 
								 | 
							
								import iron.object.Transform;
							 | 
						||
| 
								 | 
							
								import iron.object.Object;
							 | 
						||
| 
								 | 
							
								import iron.math.Ray;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class RayCaster {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static var VPInv = Mat4.identity();
							 | 
						||
| 
								 | 
							
									static var PInv = Mat4.identity();
							 | 
						||
| 
								 | 
							
									static var VInv = Mat4.identity();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static var loc = new Vec4();
							 | 
						||
| 
								 | 
							
									static var nor = new Vec4();
							 | 
						||
| 
								 | 
							
									static var m = Mat4.identity();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public static function getRay(inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Ray {
							 | 
						||
| 
								 | 
							
										var start = new Vec4();
							 | 
						||
| 
								 | 
							
										var end = new Vec4();
							 | 
						||
| 
								 | 
							
										getDirection(start, end, inputX, inputY, camera);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Find direction from start to end
							 | 
						||
| 
								 | 
							
										end.sub(start);
							 | 
						||
| 
								 | 
							
										end.normalize();
							 | 
						||
| 
								 | 
							
										end.x *= camera.data.raw.far_plane;
							 | 
						||
| 
								 | 
							
										end.y *= camera.data.raw.far_plane;
							 | 
						||
| 
								 | 
							
										end.z *= camera.data.raw.far_plane;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return new Ray(start, end);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public static function getDirection(start: Vec4, end: Vec4, inputX: FastFloat, inputY: FastFloat, camera: CameraObject) {
							 | 
						||
| 
								 | 
							
										// Get 3D point form screen coords
							 | 
						||
| 
								 | 
							
										// Set two vectors with opposing z values
							 | 
						||
| 
								 | 
							
										start.x = (inputX / iron.App.w()) * 2.0 - 1.0;
							 | 
						||
| 
								 | 
							
										start.y = -((inputY / iron.App.h()) * 2.0 - 1.0);
							 | 
						||
| 
								 | 
							
										start.z = -1.0;
							 | 
						||
| 
								 | 
							
										end.x = start.x;
							 | 
						||
| 
								 | 
							
										end.y = start.y;
							 | 
						||
| 
								 | 
							
										end.z = 1.0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										PInv.getInverse(camera.P);
							 | 
						||
| 
								 | 
							
										VInv.getInverse(camera.V);
							 | 
						||
| 
								 | 
							
										VPInv.multmats(VInv, PInv);
							 | 
						||
| 
								 | 
							
										start.applyproj(VPInv);
							 | 
						||
| 
								 | 
							
										end.applyproj(VPInv);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public static function boxIntersect(transform: Transform, inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Vec4 {
							 | 
						||
| 
								 | 
							
										var ray = getRay(inputX, inputY, camera);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var t = transform;
							 | 
						||
| 
								 | 
							
										var c = new Vec4(t.worldx(), t.worldy(), t.worldz());
							 | 
						||
| 
								 | 
							
										var s = new Vec4(t.dim.x, t.dim.y, t.dim.z);
							 | 
						||
| 
								 | 
							
										return ray.intersectBox(c, s);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									public static function boxIntersectObject(o: Object, inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Vec4 {
							 | 
						||
| 
								 | 
							
										var ray = getRay(inputX, inputY, camera);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var t = o.transform;
							 | 
						||
| 
								 | 
							
										var c = new Vec4(t.worldx(), t.worldy(), t.worldz());
							 | 
						||
| 
								 | 
							
										var s = new Vec4(t.dim.x, t.dim.y, t.dim.z);
							 | 
						||
| 
								 | 
							
										return ray.intersectBox(c, s);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public static function closestBoxIntersect(transforms: Array<Transform>, inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Transform {
							 | 
						||
| 
								 | 
							
										var intersects: Array<Transform> = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Get intersects
							 | 
						||
| 
								 | 
							
										for (t in transforms) {
							 | 
						||
| 
								 | 
							
											var intersect = boxIntersect(t, inputX, inputY, camera);
							 | 
						||
| 
								 | 
							
											if (intersect != null) intersects.push(t);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// No intersects
							 | 
						||
| 
								 | 
							
										if (intersects.length == 0) return null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Get closest intersect
							 | 
						||
| 
								 | 
							
										var closest: Transform = null;
							 | 
						||
| 
								 | 
							
										var minDist = Math.POSITIVE_INFINITY;
							 | 
						||
| 
								 | 
							
										for (t in intersects) {
							 | 
						||
| 
								 | 
							
											var dist = Vec4.distance(t.loc, camera.transform.loc);
							 | 
						||
| 
								 | 
							
											if (dist < minDist) {
							 | 
						||
| 
								 | 
							
												minDist = dist;
							 | 
						||
| 
								 | 
							
												closest = t;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return closest;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public static function closestBoxIntersectObject(objects: Array<Object>, inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Object {
							 | 
						||
| 
								 | 
							
										var intersects: Array<Object> = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Get intersects
							 | 
						||
| 
								 | 
							
										for (o in objects) {
							 | 
						||
| 
								 | 
							
											var intersect = boxIntersectObject(o, inputX, inputY, camera);
							 | 
						||
| 
								 | 
							
											if (intersect != null) intersects.push(o);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// No intersects
							 | 
						||
| 
								 | 
							
										if (intersects.length == 0) return null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Get closest intersect
							 | 
						||
| 
								 | 
							
										var closest: Object = null;
							 | 
						||
| 
								 | 
							
										var minDist = Math.POSITIVE_INFINITY;
							 | 
						||
| 
								 | 
							
										for (t in intersects) {
							 | 
						||
| 
								 | 
							
											var dist = Vec4.distance(t.transform.loc, camera.transform.loc);
							 | 
						||
| 
								 | 
							
											if (dist < minDist) {
							 | 
						||
| 
								 | 
							
												minDist = dist;
							 | 
						||
| 
								 | 
							
												closest = t;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return closest;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									public static function planeIntersect(normal: Vec4, a: Vec4, inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Vec4 {
							 | 
						||
| 
								 | 
							
										var ray = getRay(inputX, inputY, camera);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var plane = new Plane();
							 | 
						||
| 
								 | 
							
										plane.set(normal, a);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return ray.intersectPlane(plane);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Project screen-space point onto 3D plane
							 | 
						||
| 
								 | 
							
									public static function getPlaneUV(obj: MeshObject, screenX: FastFloat, screenY: FastFloat, camera: CameraObject): Vec2 {
							 | 
						||
| 
								 | 
							
										nor = obj.transform.up(); // Transformed normal
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Plane intersection
							 | 
						||
| 
								 | 
							
										loc.set(obj.transform.worldx(), obj.transform.worldy(), obj.transform.worldz());
							 | 
						||
| 
								 | 
							
										var hit = RayCaster.planeIntersect(nor, loc, screenX, screenY, camera);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Convert to uv
							 | 
						||
| 
								 | 
							
										if (hit != null) {
							 | 
						||
| 
								 | 
							
											var normals = obj.data.geom.normals.values;
							 | 
						||
| 
								 | 
							
											nor.set(normals[0], normals[1], normals[2]); // Raw normal
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											var a = nor.x;
							 | 
						||
| 
								 | 
							
											var b = nor.y;
							 | 
						||
| 
								 | 
							
											var c = nor.z;
							 | 
						||
| 
								 | 
							
											var e = 0.0001;
							 | 
						||
| 
								 | 
							
											var u = a >= e && b >= e ? new Vec4(b, -a, 0) : new Vec4(c, -a, 0);
							 | 
						||
| 
								 | 
							
											u.normalize();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											var v = nor.clone();
							 | 
						||
| 
								 | 
							
											v.cross(u);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											m.setFrom(obj.transform.world);
							 | 
						||
| 
								 | 
							
											m.getInverse(m);
							 | 
						||
| 
								 | 
							
											m.transpose3x3();
							 | 
						||
| 
								 | 
							
											m._30 = m._31 = m._32 = 0;
							 | 
						||
| 
								 | 
							
											u.applymat(m);
							 | 
						||
| 
								 | 
							
											u.normalize();
							 | 
						||
| 
								 | 
							
											v.applymat(m);
							 | 
						||
| 
								 | 
							
											v.normalize();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											hit.sub(loc); // Center
							 | 
						||
| 
								 | 
							
											var ucoord = u.dot(hit);
							 | 
						||
| 
								 | 
							
											var vcoord = v.dot(hit);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											var dim = obj.transform.dim;
							 | 
						||
| 
								 | 
							
											var size = dim.x > dim.y ? dim.x / 2 : dim.y / 2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Screen space
							 | 
						||
| 
								 | 
							
											var ix = ucoord / size * -0.5 + 0.5;
							 | 
						||
| 
								 | 
							
											var iy = vcoord / size * -0.5 + 0.5;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return new Vec2(ix, iy);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return null;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |