/// <summary> /// Performs a raycast against the mesh triangles and returns info /// about the closest hit or null if no triangle was hit by the ray. /// </summary> /// <param name="meshTransform"> /// The mesh transform which brings the mesh in the same space as the /// ray. /// </param> /// <remarks> /// This method will build the tree if it hasn't already been built. /// </remarks> public MeshRayHit RaycastClosest(Ray ray, Matrix4x4 meshTransform) { // Build the tree if it hasn't already been built if (!_isBuilt) { Build(); } // Work in mesh local space by transforming the ray by the inverse of // the mesh transform. It is faster to perform this transformation here // instead of transforming every possibly hit triangle by 'meshTransform'. Ray modelSpaceRay = ray.InverseTransform(meshTransform); // Get the list of tree nodes which are hit by the ray if (!_tree.RaycastAll(modelSpaceRay, _nodeHitBuffer)) { return(null); } // Store data in preparation for closest hit identification float t; float minT = float.MaxValue; MeshTriangle closestTriangle = null; bool foundTriangle = false; // Loop through each node hit foreach (var nodeHit in _nodeHitBuffer) { // Get the associated mesh triangle and check if the ray intersects it MeshTriangle meshTriangle = nodeHit.HitNode.Data; if (TriangleMath.Raycast(modelSpaceRay, out t, meshTriangle.Vertex0, meshTriangle.Vertex1, meshTriangle.Vertex2)) { if (Vector3.Dot(modelSpaceRay.direction, meshTriangle.Normal) < 0.0f) { // If the intersection offset is smaller than what we have so far, // it means we have a new closest hit. if (t < minT) { minT = t; closestTriangle = meshTriangle; foundTriangle = true; } } } } // If we found a triangle, we can return the mesh ray hit information if (foundTriangle) { // Convert the t value in world space. Do the same for the normal. Vector3 worldHit = meshTransform.MultiplyPoint(modelSpaceRay.GetPoint(minT)); minT = (ray.origin - worldHit).magnitude / ray.direction.magnitude; Vector3 transformedNormal = meshTransform.inverse.transpose.MultiplyVector(closestTriangle.Normal).normalized; // Return the hit instance return(new MeshRayHit(ray, closestTriangle.TriangleIndex, minT, transformedNormal)); } return(null); }
public override bool Raycast(Ray ray, out float t) { var trianglePoints = GetPoints(); if (_raycastMode == Shape3DRaycastMode.Solid) { return(TriangleMath.Raycast(ray, out t, trianglePoints[0], trianglePoints[1], trianglePoints[2], _epsilon)); } else { return(TriangleMath.RaycastWire(ray, out t, trianglePoints[0], trianglePoints[1], trianglePoints[2], _epsilon)); } }
public override bool Raycast(Ray ray, out float t) { return(TriangleMath.Raycast(ray, out t, GetPoint(EqTrianglePoint.Left), GetPoint(EqTrianglePoint.Top), GetPoint(EqTrianglePoint.Right), _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); }