public bool IntersectsMesh(TransformMatrix thisTransform, Octave3DMesh otherMesh, TransformMatrix otherTransform) { OrientedBox thisOOBB = new OrientedBox(ModelAABB); thisOOBB.Transform(thisTransform); OrientedBox otherOOBB = new OrientedBox(otherMesh.ModelAABB); otherOOBB.Transform(otherTransform); if (!thisOOBB.Intersects(otherOOBB)) { return(false); } List <Triangle3D> thisTriangles = GetOverlappedTriangles(otherOOBB, thisTransform); for (int thisTriIndex = 0; thisTriIndex < thisTriangles.Count; ++thisTriIndex) { Triangle3D thisTri = thisTriangles[thisTriIndex]; OrientedBox thisTriOOBB = new OrientedBox(thisTri.GetEncapsulatingBox()); List <Triangle3D> otherTriangles = otherMesh.GetOverlappedTriangles(thisTriOOBB, otherTransform); for (int otherTriIndex = 0; otherTriIndex < otherTriangles.Count; ++otherTriIndex) { Triangle3D otherTri = otherTriangles[otherTriIndex]; if (thisTri.IntersectsTriangle(otherTri)) { return(true); } } } return(false); }
public Triangle3D(Triangle3D source) { _points = new Vector3[3]; _points[0] = source.Point0; _points[1] = source.Point1; _points[2] = source.Point2; _plane = source._plane; _area = source._area; }
public Triangle3DIntersectInfo(Triangle3D firstTriangle, Triangle3D secondTriangle, List <Vector3> firstTraingleIntersectionPoints, List <Vector3> secondTraingleIntersectionPoints) { _firstTriangle = firstTriangle; _secondTriangle = secondTriangle; _firstTriangleIntersectionPoints = new List <Vector3>(firstTraingleIntersectionPoints); _secondTriangleIntersectionPoints = new List <Vector3>(secondTraingleIntersectionPoints); _allIntersectionPoints = new List <Vector3>(_firstTriangleIntersectionPoints); _allIntersectionPoints.AddRange(_secondTriangleIntersectionPoints); }
/// <summary> /// Registers the mesh trianlge with the specified index with the tree. /// </summary> /// <returns> /// True if the trianlge was registered and false otherwise. The only /// scenario in which the method can return false is when the triangle /// is degenerate. /// </returns> private bool RegisterTriangle(int triangleIndex) { // Retrieve the triangle from the mesh. If it is degenerate, we return false. Triangle3D triangle = _octave3DMesh.GetTriangle(triangleIndex); if (triangle.IsDegenerate) { return(false); } // Create the triangle node data and instruct the tree to add this node var meshSphereTreeTriangle = new MeshSphereTreeTriangle(triangleIndex); _sphereTree.AddTerminalNode(triangle.GetEncapsulatingSphere(), meshSphereTreeTriangle); return(true); }
public bool IntersectsTriangle(Triangle3D triangle, out Triangle3DIntersectInfo intersectInfo) { intersectInfo = new Triangle3DIntersectInfo(); if (triangle.Normal.IsAlignedWith(Normal)) { return(false); } float t; List <Segment3D> otherTriSegments = triangle.GetSegments(); var firstTriIntersectionPoints = new List <Vector3>(); foreach (var segment in otherTriSegments) { Ray3D ray = new Ray3D(segment.StartPoint, segment.EndPoint); if (Raycast(ray, out t)) { firstTriIntersectionPoints.Add(ray.GetPoint(t)); } } List <Segment3D> thisTriSegments = GetSegments(); var secondTriIntersectionPoints = new List <Vector3>(); foreach (var segment in thisTriSegments) { Ray3D ray = new Ray3D(segment.StartPoint, segment.EndPoint); if (triangle.Raycast(ray, out t)) { secondTriIntersectionPoints.Add(ray.GetPoint(t)); } } if (firstTriIntersectionPoints.Count != 0 || secondTriIntersectionPoints.Count != 0) { intersectInfo = new Triangle3DIntersectInfo(this, triangle, firstTriIntersectionPoints, secondTriIntersectionPoints); return(true); } return(false); }
public List <Triangle3DIntersectInfo> GetIntersectingTriangles(TransformMatrix thisTransform, Octave3DMesh otherMesh, TransformMatrix otherTransform) { OrientedBox thisOOBB = new OrientedBox(ModelAABB); thisOOBB.Transform(thisTransform); OrientedBox otherOOBB = new OrientedBox(otherMesh.ModelAABB); otherOOBB.Transform(otherTransform); if (thisOOBB.Intersects(otherOOBB)) { List <Triangle3D> thisTriangles = GetOverlappedTriangles(otherOOBB, thisTransform); var output = new List <Triangle3DIntersectInfo>(50); Triangle3DIntersectInfo intersectInfo; for (int thisTriIndex = 0; thisTriIndex < thisTriangles.Count; ++thisTriIndex) { Triangle3D thisTri = thisTriangles[thisTriIndex]; OrientedBox thisTriOOBB = new OrientedBox(thisTri.GetEncapsulatingBox()); List <Triangle3D> otherTriangles = otherMesh.GetOverlappedTriangles(thisTriOOBB, otherTransform); for (int otherTriIndex = 0; otherTriIndex < otherTriangles.Count; ++otherTriIndex) { Triangle3D otherTri = otherTriangles[otherTriIndex]; if (thisTri.IntersectsTriangle(otherTri, out intersectInfo)) { output.Add(intersectInfo); } } } return(output); } else { return(new List <Triangle3DIntersectInfo>()); } }
/// <summary> /// Performs a ray cast against the mesh tree and returns an instance of the 'MeshRayHit' /// class which holds information about the ray hit. The method returns the hit which is /// closest to the ray origin. If no triangle was hit, the method returns null. /// </summary> public MeshRayHit Raycast(Ray ray, TransformMatrix meshTransformMatrix) { // If the tree was not yet build, we need to build it because we need // the triangle information in order to perform the raycast. if (!_wasBuilt) { Build(); } // When the sphere tree is constructed it is constructed in the mesh local space (i.e. it takes // no position/rotation/scale into account). This is required because a mesh can be shared by // lots of different objects each with its own transform data. This is why we need the mes matrix // parameter. It allows us to transform the ray in the mesh local space and perform our tests there. Ray meshLocalSpaceRay = ray.InverseTransform(meshTransformMatrix.ToMatrix4x4x); // First collect all terminal nodes which are intersected by this ray. If no nodes // are intersected, we will return null. List <SphereTreeNodeRayHit <MeshSphereTreeTriangle> > nodeRayHits = _sphereTree.RaycastAll(meshLocalSpaceRay); if (nodeRayHits.Count == 0) { return(null); } // We now have to loop thorugh all intersected nodes and find the triangle whose // intersection point is closest to the ray origin. float minT = float.MaxValue; Triangle3D closestTriangle = null; int indexOfClosestTriangle = -1; Vector3 closestHitPoint = Vector3.zero; foreach (var nodeRayHit in nodeRayHits) { // Retrieve the data associated with the node and construct the mesh triangle instance MeshSphereTreeTriangle sphereTreeTriangle = nodeRayHit.HitNode.Data; Triangle3D meshTriangle = _octave3DMesh.GetTriangle(sphereTreeTriangle.TriangleIndex); // Check if the ray intersects the trianlge which resides in the node float hitEnter; if (meshTriangle.Raycast(meshLocalSpaceRay, out hitEnter)) { // The trianlge is intersected by the ray, but we also have to ensure that the // intersection point is closer than what we have found so far. If it is, we // store all relevant information. if (hitEnter < minT) { minT = hitEnter; closestTriangle = meshTriangle; indexOfClosestTriangle = sphereTreeTriangle.TriangleIndex; closestHitPoint = meshLocalSpaceRay.GetPoint(hitEnter); } } } // If we found the closest triangle, we can construct the ray hit instance and return it. // Otherwise we return null. This can happen when the ray intersects the triangle node // spheres, but the triangles themselves. if (closestTriangle != null) { // We have worked in mesh local space up until this point, but we want to return the // hit info in world space, so we have to transform the hit data accordingly. closestHitPoint = meshTransformMatrix.MultiplyPoint(closestHitPoint); minT = (ray.origin - closestHitPoint).magnitude; Vector3 worldNormal = meshTransformMatrix.MultiplyVector(closestTriangle.Normal); return(new MeshRayHit(ray, minT, _octave3DMesh, indexOfClosestTriangle, closestHitPoint, worldNormal, meshTransformMatrix)); } else { return(null); } }
public void UpdateForMouseMovement() { if (!_isActive) { return; } if (MouseButtonStates.Instance.IsMouseButtonDown(MouseButton.Left)) { _state = ObjectVertexSnapSessionState.SnapToDestination; } else { _state = ObjectVertexSnapSessionState.SelectSourceVertex; } if (_state == ObjectVertexSnapSessionState.SelectSourceVertex) { if (_sourceObjects == null || _sourceObjects.Count == 0) { _objectMask.ObjectCollectionMask.UnmaskAll(); MouseCursorRayHit cursorRayHit = GetCursorRayHit(); if (cursorRayHit.WasAnObjectHit) { GameObjectRayHit objectRayHit = cursorRayHit.ClosestObjectRayHit; MeshRayHit meshRayHit = objectRayHit.ObjectMeshHit; if (meshRayHit != null) { Octave3DMesh octaveMesh = meshRayHit.HitMesh; Triangle3D sourceTriangle = octaveMesh.GetTriangle(meshRayHit.HitTriangleIndex); sourceTriangle.TransformPoints(objectRayHit.HitObject.transform.localToWorldMatrix); _sourceVertex = sourceTriangle.GetPointClosestToPoint(meshRayHit.HitPoint); _sourceObject = objectRayHit.HitObject; _objectMask.ObjectCollectionMask.Mask(_sourceObject.transform.root.gameObject.GetAllChildrenIncludingSelf()); } else { SpriteRenderer spriteRenderer = objectRayHit.HitObject.GetComponent <SpriteRenderer>(); if (spriteRenderer != null) { _sourceObject = objectRayHit.HitObject; _sourceVertex = Vector3Extensions.GetClosestPointToPoint(objectRayHit.ObjectBoxHit.HitBox.GetCenterAndCornerPoints(), objectRayHit.HitPoint); _objectMask.ObjectCollectionMask.Mask(_sourceObject.transform.root.gameObject.GetAllChildrenIncludingSelf()); } } } } else { MouseCursorRayHit cursorRayHit = GetCursorRayHit(); if (cursorRayHit.WasAnObjectHit) { GameObjectRayHit objectRayHit = cursorRayHit.ClosestObjectRayHit; MeshRayHit meshRayHit = objectRayHit.ObjectMeshHit; if (meshRayHit != null) { Octave3DMesh octaveMesh = meshRayHit.HitMesh; Triangle3D sourceTriangle = octaveMesh.GetTriangle(meshRayHit.HitTriangleIndex); sourceTriangle.TransformPoints(objectRayHit.HitObject.transform.localToWorldMatrix); _sourceVertex = sourceTriangle.GetPointClosestToPoint(meshRayHit.HitPoint); } else { SpriteRenderer spriteRenderer = objectRayHit.HitObject.GetComponent <SpriteRenderer>(); if (spriteRenderer != null) { _sourceVertex = Vector3Extensions.GetClosestPointToPoint(objectRayHit.ObjectBoxHit.HitBox.GetCenterAndCornerPoints(), objectRayHit.HitPoint); } } } foreach (var parent in _sourceParents) { _objectMask.ObjectCollectionMask.Mask(parent.GetAllChildrenIncludingSelf()); } } } else { MouseCursorRayHit cursorRayHit = GetCursorRayHit(); if (cursorRayHit.WasAnythingHit) { bool useGridCellHit = false; if (!cursorRayHit.WasAnObjectHit) { useGridCellHit = true; } else if (cursorRayHit.WasAnObjectHit && cursorRayHit.WasACellHit) { float gridCellHitEnter = cursorRayHit.GridCellRayHit.HitEnter; float objectHitEnter = cursorRayHit.ClosestObjectRayHit.HitEnter; if (gridCellHitEnter < Mathf.Max(0.0f, (objectHitEnter - 1e-3f))) { useGridCellHit = true; } } if (useGridCellHit) { XZGridCell hitCell = cursorRayHit.GridCellRayHit.HitCell; XZOrientedQuad3D cellQuad = hitCell.Quad; _destinationObject = null; _destinationGridCell = hitCell; _snapPosition = cellQuad.GetPointClosestToPoint(cursorRayHit.GridCellRayHit.HitPoint, true); SnapToDestination(); } else { GameObjectRayHit objectRayHit = cursorRayHit.ClosestObjectRayHit; MeshRayHit meshRayHit = objectRayHit.ObjectMeshHit; if (meshRayHit != null) { _destinationObject = objectRayHit.HitObject; Triangle3D destinationTriangle = meshRayHit.HitMesh.GetTriangle(meshRayHit.HitTriangleIndex); destinationTriangle.TransformPoints(_destinationObject.transform.localToWorldMatrix); _destinationGridCell = null; _snapPosition = destinationTriangle.GetPointClosestToPoint(meshRayHit.HitPoint); SnapToDestination(); } else { SpriteRenderer spriteRenderer = objectRayHit.HitObject.GetComponent <SpriteRenderer>(); if (spriteRenderer != null) { _destinationGridCell = null; _destinationObject = objectRayHit.HitObject; _snapPosition = Vector3Extensions.GetClosestPointToPoint(objectRayHit.ObjectBoxHit.HitBox.GetCenterAndCornerPoints(), objectRayHit.HitPoint); SnapToDestination(); } } } } } }