public static bool RaycastShArc(Ray ray, out float t, Vector3 arcOrigin, Vector3 arcStartPoint, Vector3 arcPlaneNormal, float degreesFromStart, ArcEpsilon epsilon = new ArcEpsilon()) { t = 0.0f; degreesFromStart = ConvertToSh3DArcAngle(arcOrigin, arcStartPoint, arcPlaneNormal, degreesFromStart); Plane arcPlane = new Plane(arcPlaneNormal, arcOrigin); float rayEnter; if (arcPlane.Raycast(ray, out rayEnter) && ShArcContains3DPoint(ray.GetPoint(rayEnter), false, arcOrigin, arcStartPoint, arcPlaneNormal, degreesFromStart, epsilon)) { t = rayEnter; return(true); } if (epsilon.ExtrudeEps != 0.0f) { float dot = Vector3Ex.AbsDot(ray.direction, arcPlaneNormal); if (dot < ExtrudeEpsThreshold.Get) { OBB arcOBB = CalcSh3DArcOBB(arcOrigin, arcStartPoint, arcPlaneNormal, degreesFromStart, epsilon); return(BoxMath.Raycast(ray, arcOBB.Center, arcOBB.Size, arcOBB.Rotation)); } } return(false); }
public static bool Raycast(Ray ray, out float t, Vector3 quadCenter, float quadWidth, float quadHeight, Vector3 quadRight, Vector3 quadUp, QuadEpsilon epsilon = new QuadEpsilon()) { t = 0.0f; Vector3 quadNormal = Vector3.Normalize(Vector3.Cross(quadRight, quadUp)); Plane quadPlane = new Plane(quadNormal, quadCenter); float rayEnter; if (quadPlane.Raycast(ray, out rayEnter) && Contains3DPoint(ray.GetPoint(rayEnter), false, quadCenter, quadWidth, quadHeight, quadRight, quadUp, epsilon)) { t = rayEnter; return(true); } if (epsilon.ExtrudeEps != 0.0f) { float dot = Vector3Ex.AbsDot(ray.direction, quadPlane.normal); if (dot < ExtrudeEpsThreshold.Get) { OBB quadOBB = Calc3DQuadOBB(quadCenter, new Vector2(quadWidth, quadHeight), Quaternion.LookRotation(quadNormal, quadUp), epsilon); return(BoxMath.Raycast(ray, quadOBB.Center, quadOBB.Size, quadOBB.Rotation)); } } return(false); }
public static bool Raycast(Ray ray, out float t, Vector3 p0, Vector3 p1, Vector3 p2, TriangleEpsilon epsilon = new TriangleEpsilon()) { t = 0.0f; float rayEnter; Plane trianglePlane = new Plane(p0, p1, p2); if (trianglePlane.Raycast(ray, out rayEnter) && Contains3DPoint(ray.GetPoint(rayEnter), false, p0, p1, p2, epsilon)) { t = rayEnter; return(true); } if (epsilon.ExtrudeEps != 0.0f) { float dot = Vector3Ex.AbsDot(ray.direction, trianglePlane.normal); if (dot < ExtrudeEpsThreshold.Get) { OBB obb = Calc3DTriangleOBB(p0, p1, p2, trianglePlane.normal, epsilon); return(BoxMath.Raycast(ray, obb.Center, obb.Size, obb.Rotation)); } } return(false); }
public static bool RaycastWire(Ray ray, out float t, Vector3 quadCenter, float quadWidth, float quadHeight, Vector3 quadRight, Vector3 quadUp, QuadEpsilon epsilon = new QuadEpsilon()) { t = 0.0f; Vector3 quadNormal = Vector3.Normalize(Vector3.Cross(quadRight, quadUp)); Plane quadPlane = new Plane(quadNormal, quadCenter); Vector2 quadSize = new Vector2(quadWidth, quadHeight); Quaternion quadRotation = Quaternion.LookRotation(quadNormal, quadUp); float rayEnter; if (quadPlane.Raycast(ray, out rayEnter)) { Vector3 intersectPt = ray.GetPoint(rayEnter); var cornerPoints = Calc3DQuadCornerPoints(quadCenter, quadSize, quadRotation); float distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.TopLeft], cornerPoints[(int)QuadCorner.TopRight]); if (distFromSegment <= epsilon.WireEps) { t = rayEnter; return(true); } distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.TopRight], cornerPoints[(int)QuadCorner.BottomRight]); if (distFromSegment <= epsilon.WireEps) { t = rayEnter; return(true); } distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.BottomRight], cornerPoints[(int)QuadCorner.BottomLeft]); if (distFromSegment <= epsilon.WireEps) { t = rayEnter; return(true); } distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.BottomLeft], cornerPoints[(int)QuadCorner.TopLeft]); if (distFromSegment <= epsilon.WireEps) { t = rayEnter; return(true); } } if (epsilon.ExtrudeEps != 0.0f) { float dot = Vector3Ex.AbsDot(ray.direction, quadPlane.normal); if (dot < ExtrudeEpsThreshold.Get) { OBB quadOBB = Calc3DQuadOBB(quadCenter, quadSize, Quaternion.LookRotation(quadNormal, quadUp), epsilon); return(BoxMath.Raycast(ray, quadOBB.Center, quadOBB.Size, quadOBB.Rotation)); } } return(false); }
public GameObjectRayHit RaycastSpriteObject(Ray ray, GameObject gameObject) { float t; OBB worldOBB = ObjectBounds.CalcSpriteWorldOBB(gameObject); if (!worldOBB.IsValid) { return(null); } if (BoxMath.Raycast(ray, out t, worldOBB.Center, worldOBB.Size, worldOBB.Rotation)) { return(new GameObjectRayHit(ray, gameObject, worldOBB.GetPointFaceNormal(ray.GetPoint(t)), t)); } return(null); }
public static bool RaycastWire(Ray ray, out float t, Vector3 p0, Vector3 p1, Vector3 p2, TriangleEpsilon epsilon = new TriangleEpsilon()) { t = 0.0f; float rayEnter; Plane trianglePlane = new Plane(p0, p1, p2); if (trianglePlane.Raycast(ray, out rayEnter)) { Vector3 intersectPt = ray.GetPoint(rayEnter); float distToSegment = intersectPt.GetDistanceToSegment(p0, p1); if (distToSegment <= epsilon.WireEps) { t = rayEnter; return(true); } distToSegment = intersectPt.GetDistanceToSegment(p1, p2); if (distToSegment <= epsilon.WireEps) { t = rayEnter; return(true); } distToSegment = intersectPt.GetDistanceToSegment(p2, p0); if (distToSegment <= epsilon.WireEps) { t = rayEnter; return(true); } } if (epsilon.ExtrudeEps != 0.0f) { float dot = Vector3Ex.AbsDot(ray.direction, trianglePlane.normal); if (dot < ExtrudeEpsThreshold.Get) { OBB obb = Calc3DTriangleOBB(p0, p1, p2, trianglePlane.normal, epsilon); return(BoxMath.Raycast(ray, obb.Center, obb.Size, obb.Rotation)); } } return(false); }
public bool RaycastAll(Ray ray, SceneRaycastPrecision raycastPresicion, List <GameObjectRayHit> hits) { hits.Clear(); if (!_objectTree.RaycastAll(ray, _nodeHitBuffer)) { return(false); } var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; boundsQConfig.NoVolumeSize = Vector3Ex.FromValue(_nonMeshObjectSize); Vector3 camLook = RTFocusCamera.Get.Look; if (raycastPresicion == SceneRaycastPrecision.BestFit) { foreach (var nodeHit in _nodeHitBuffer) { GameObject sceneObject = nodeHit.HitNode.Data; if (sceneObject == null || !sceneObject.activeInHierarchy) { continue; } Renderer renderer = sceneObject.GetComponent <Renderer>(); if (renderer != null && !renderer.isVisible) { continue; } GameObjectType objectType = sceneObject.GetGameObjectType(); if (objectType == GameObjectType.Mesh) { GameObjectRayHit objectHit = RaycastMeshObject(ray, sceneObject); if (objectHit != null) { hits.Add(objectHit); } } else if (objectType == GameObjectType.Terrain) { TerrainCollider terrainCollider = sceneObject.GetComponent <TerrainCollider>(); if (terrainCollider != null) { RaycastHit hitInfo; if (terrainCollider.Raycast(ray, out hitInfo, float.MaxValue)) { hits.Add(new GameObjectRayHit(ray, hitInfo)); } } } else if (objectType == GameObjectType.Sprite) { GameObjectRayHit objectHit = RaycastSpriteObject(ray, sceneObject); if (objectHit != null) { hits.Add(objectHit); } } else { OBB worldOBB = ObjectBounds.CalcWorldOBB(sceneObject, boundsQConfig); if (worldOBB.IsValid) { float t; if (BoxMath.Raycast(ray, out t, worldOBB.Center, worldOBB.Size, worldOBB.Rotation)) { var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOBB.Center, worldOBB.Size, worldOBB.Rotation, camLook); var hit = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t); hits.Add(hit); } } } } } else if (raycastPresicion == SceneRaycastPrecision.Box) { foreach (var nodeHit in _nodeHitBuffer) { GameObject sceneObject = nodeHit.HitNode.Data; if (sceneObject == null || !sceneObject.activeInHierarchy) { continue; } Renderer renderer = sceneObject.GetComponent <Renderer>(); if (renderer != null && !renderer.isVisible) { continue; } OBB worldOBB = ObjectBounds.CalcWorldOBB(sceneObject, boundsQConfig); if (worldOBB.IsValid) { float t; if (BoxMath.Raycast(ray, out t, worldOBB.Center, worldOBB.Size, worldOBB.Rotation)) { var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOBB.Center, worldOBB.Size, worldOBB.Rotation, camLook); var hit = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t); hits.Add(hit); } } } } return(hits.Count != 0); }
public static bool Raycast(Ray ray, out float t, Vector3 coneBaseCenter, float coneBaseRadius, float coneHeight, Quaternion coneRotation, ConeEpsilon epsilon = new ConeEpsilon()) { t = 0.0f; Ray coneSpaceRay = ray.InverseTransform(Matrix4x4.TRS(coneBaseCenter, coneRotation, Vector3.one)); float xzAABBSize = coneBaseRadius * 2.0f; Vector3 aabbSize = new Vector3(xzAABBSize, coneHeight + epsilon.VertEps * 2.0f, xzAABBSize); if (!BoxMath.Raycast(coneSpaceRay, Vector3.up * coneHeight * 0.5f, aabbSize, Quaternion.identity)) { return(false); } // We will first perform a preliminary check to see if the ray intersects the bottom cap of the cone. // This is necessary because the cone equation views the cone as infinite (i.e. no bottom cap), and // if we didn't perform this check, we would never be able to tell when the bottom cap was hit. float rayEnter; Plane bottomCapPlane = new Plane(-Vector3.up, Vector3.zero); if (bottomCapPlane.Raycast(coneSpaceRay, out rayEnter)) { // If the ray intersects the plane of the bottom cap, we will calculate the intersection point // and if it lies inside the cone's bottom cap area, it means we have a valid intersection. We // store the t value and then return true. Vector3 intersectionPoint = coneSpaceRay.origin + coneSpaceRay.direction * rayEnter; if (intersectionPoint.magnitude <= coneBaseRadius) { t = rayEnter; return(true); } } // We need this for the calculation of the quadratic coefficients float ratioSquared = coneBaseRadius / coneHeight; ratioSquared *= ratioSquared; // Calculate the coefficients. // Note: The cone equation which was used is: (X^2 + Z^2) / ratioSquared = (Y - coneHeight)^2. // Where X, Y and Z are the coordinates of the point along the ray: (Origin + Direction * t).xyz float a = coneSpaceRay.direction.x * coneSpaceRay.direction.x + coneSpaceRay.direction.z * coneSpaceRay.direction.z - ratioSquared * coneSpaceRay.direction.y * coneSpaceRay.direction.y; float b = 2.0f * (coneSpaceRay.origin.x * coneSpaceRay.direction.x + coneSpaceRay.origin.z * coneSpaceRay.direction.z - ratioSquared * coneSpaceRay.direction.y * (coneSpaceRay.origin.y - coneHeight)); float c = coneSpaceRay.origin.x * coneSpaceRay.origin.x + coneSpaceRay.origin.z * coneSpaceRay.origin.z - ratioSquared * (coneSpaceRay.origin.y - coneHeight) * (coneSpaceRay.origin.y - coneHeight); // The intersection happnes only if the quadratic equation has solutions float t1, t2; if (MathEx.SolveQuadratic(a, b, c, out t1, out t2)) { // Make sure the ray does not intersect the cone only from behind if (t1 < 0.0f && t2 < 0.0f) { return(false); } // Make sure we are using the smallest positive t value if (t1 < 0.0f) { float temp = t1; t1 = t2; t2 = temp; } t = t1; // Make sure the intersection point does not sit below the cone's bottom cap or above the cone's cap Vector3 intersectionPoint = coneSpaceRay.origin + coneSpaceRay.direction * t; if (intersectionPoint.y < -epsilon.VertEps || intersectionPoint.y > coneHeight + epsilon.VertEps) { t = 0.0f; return(false); } // The intersection point is valid return(true); } // If we reached this point, it means the ray does not intersect the cone in any way return(false); }
public static bool Raycast(Ray ray, out float t, Vector3 baseCenter, float baseWidth, float baseDepth, float height, Quaternion rotation) { t = 0.0f; ray = ray.InverseTransform(Matrix4x4.TRS(baseCenter, rotation, Vector3.one)); Vector3 aabbSize = new Vector3(baseWidth, height, baseDepth); if (!BoxMath.Raycast(ray, Vector3.up * height * 0.5f, aabbSize, Quaternion.identity)) { return(false); } List <float> tValues = new List <float>(5); Plane basePlane = new Plane(Vector3.up, Vector3.zero); float rayEnter = 0.0f; if (basePlane.Raycast(ray, out rayEnter) && QuadMath.Contains3DPoint(ray.GetPoint(rayEnter), false, baseCenter, baseWidth, baseDepth, Vector3.right, Vector3.forward)) { tValues.Add(rayEnter); } float halfWidth = 0.5f * baseWidth; float halfDepth = 0.5f * baseDepth; Vector3 tipPosition = Vector3.up * height; Vector3 p0 = tipPosition; Vector3 p1 = Vector3.right * halfWidth - Vector3.forward * halfDepth; Vector3 p2 = p1 - Vector3.right * baseWidth; Plane trianglePlane = new Plane(p0, p1, p2); if (trianglePlane.Raycast(ray, out rayEnter) && TriangleMath.Contains3DPoint(ray.GetPoint(rayEnter), false, p0, p1, p2)) { tValues.Add(rayEnter); } p0 = tipPosition; p1 = Vector3.right * halfWidth + Vector3.forward * halfDepth; p2 = p1 - Vector3.forward * baseDepth; trianglePlane = new Plane(p0, p1, p2); if (trianglePlane.Raycast(ray, out rayEnter) && TriangleMath.Contains3DPoint(ray.GetPoint(rayEnter), false, p0, p1, p2)) { tValues.Add(rayEnter); } p0 = tipPosition; p1 = -Vector3.right * halfWidth + Vector3.forward * halfDepth; p2 = p1 + Vector3.right * baseWidth; trianglePlane = new Plane(p0, p1, p2); if (trianglePlane.Raycast(ray, out rayEnter) && TriangleMath.Contains3DPoint(ray.GetPoint(rayEnter), false, p0, p1, p2)) { tValues.Add(rayEnter); } p0 = tipPosition; p1 = -Vector3.right * halfWidth - Vector3.forward * halfDepth; p2 = p1 + Vector3.forward * baseDepth; trianglePlane = new Plane(p0, p1, p2); if (trianglePlane.Raycast(ray, out rayEnter) && TriangleMath.Contains3DPoint(ray.GetPoint(rayEnter), false, p0, p1, p2)) { tValues.Add(rayEnter); } if (tValues.Count == 0) { return(false); } tValues.Sort(delegate(float t0, float t1) { return(t0.CompareTo(t1)); }); t = tValues[0]; return(true); }
public override bool Raycast(Ray ray, out float t) { return(BoxMath.Raycast(ray, out t, _center, _size, _rotation, _epsilon)); }
public static bool RaycastTriangular(Ray ray, out float t, Vector3 baseCenter, float baseWidth, float baseDepth, float topWidth, float topDepth, float height, Quaternion prismRotation) { t = 0.0f; if (baseWidth == 0.0f || baseDepth == 0.0f || topWidth == 0.0f || topDepth == 0.0f || height == 0.0f) { return(false); } baseWidth = Mathf.Abs(baseWidth); baseDepth = Mathf.Abs(baseDepth); topWidth = Mathf.Abs(topWidth); topDepth = Mathf.Abs(topDepth); ray = ray.InverseTransform(Matrix4x4.TRS(baseCenter, prismRotation, Vector3.one)); // Since the raycast calculations can be quite expensive for a prism, we will // first check if the ray intersects its AABB to quickly return false if no // intersection is found. If the ray does not intersect the AABB it can not // possibly intersect the prism. Vector3 aabbSize = Vector3.Max(new Vector3(baseWidth, height, baseDepth), new Vector3(topWidth, height, topDepth)); if (!BoxMath.Raycast(ray, Vector3.up * height * 0.5f, aabbSize, Quaternion.identity)) { return(false); } List <Vector3> cornerPoints = CalcTriangPrismCornerPoints(Vector3.zero, baseWidth, baseDepth, topWidth, topDepth, height, Quaternion.identity); Vector3 baseLeftPt = cornerPoints[(int)TriangularPrismCorner.BaseLeft]; Vector3 baseRightPt = cornerPoints[(int)TriangularPrismCorner.BaseRight]; Vector3 baseForwardPt = cornerPoints[(int)TriangularPrismCorner.BaseForward]; Vector3 topLeftPt = cornerPoints[(int)TriangularPrismCorner.TopLeft]; Vector3 topRightPt = cornerPoints[(int)TriangularPrismCorner.TopRight]; Vector3 topForwardPt = cornerPoints[(int)TriangularPrismCorner.TopForward]; List <float> tValues = new List <float>(5); // Base triangle float rayEnter; if (TriangleMath.Raycast(ray, out rayEnter, baseLeftPt, baseRightPt, baseForwardPt)) { tValues.Add(rayEnter); } // Top triangle if (TriangleMath.Raycast(ray, out rayEnter, topLeftPt, topForwardPt, topRightPt)) { tValues.Add(rayEnter); } // Back face List <Vector3> facePoints = new List <Vector3>(4) { baseLeftPt, topLeftPt, topRightPt, baseRightPt }; Vector3 faceNormal = Vector3.Cross((facePoints[1] - facePoints[0]), facePoints[3] - facePoints[0]).normalized; if (PolygonMath.Raycast(ray, out rayEnter, facePoints, false, faceNormal)) { tValues.Add(rayEnter); } // Left face // facePoints[0] = baseLeftPt; facePoints[1] = baseForwardPt; facePoints[2] = topForwardPt; facePoints[3] = topLeftPt; faceNormal = Vector3.Cross((facePoints[1] - facePoints[0]), facePoints[3] - facePoints[0]).normalized; if (PolygonMath.Raycast(ray, out rayEnter, facePoints, false, faceNormal)) { tValues.Add(rayEnter); } // Right face facePoints[0] = baseRightPt; facePoints[1] = topRightPt; // facePoints[2] = topForwardPt; facePoints[3] = baseForwardPt; faceNormal = Vector3.Cross((facePoints[1] - facePoints[0]), facePoints[3] - facePoints[0]).normalized; if (PolygonMath.Raycast(ray, out rayEnter, facePoints, false, faceNormal)) { tValues.Add(rayEnter); } if (tValues.Count == 0) { return(false); } tValues.Sort(delegate(float t0, float t1) { return(t0.CompareTo(t1)); }); t = tValues[0]; return(true); }