public void TransformPoints(TransformMatrix transformMatrix) { _points[0] = transformMatrix.MultiplyPoint(_points[0]); _points[1] = transformMatrix.MultiplyPoint(_points[1]); _points[2] = transformMatrix.MultiplyPoint(_points[2]); CalculateAreaAndPlane(); }
private void CalculateInitialMinMaxPoints(out Vector3 minPoint, out Vector3 maxPoint) { // We will sort the points along the X axis, but we have to take the polygon's coordinate // system into account because if we use the global X axis, we will run into trouble when // all points of the polygon reside on the YZ plane (i.e. same X coordinate). Vector3 polyLocalRight, polyLocalLook; if (_polygonNormal.IsAlignedWith(Vector3.up)) { polyLocalRight = Vector3.right; polyLocalLook = Vector3.Cross(polyLocalRight, Vector3.up); polyLocalLook.Normalize(); } else { polyLocalRight = Vector3.Cross(_polygonNormal, Vector3.up); polyLocalRight.Normalize(); polyLocalLook = Vector3.Cross(polyLocalRight, _polygonNormal); polyLocalLook.Normalize(); } Quaternion polyRotation = Quaternion.LookRotation(polyLocalLook, _polygonNormal); TransformMatrix transformMatrix = new TransformMatrix(Vector3.zero, polyRotation, Vector3.one); // Note: We will work in polygon local space and transform the points to world space after we are done. minPoint = transformMatrix.MultiplyPointInverse(_polygonPointsOnSamePlane[0]); maxPoint = transformMatrix.MultiplyPointInverse(_polygonPointsOnSamePlane[0]); for (int ptIndex = 0; ptIndex < _polygonPointsOnSamePlane.Count; ++ptIndex) { Vector3 point = transformMatrix.MultiplyPointInverse(_polygonPointsOnSamePlane[ptIndex]); if (point.x < minPoint.x) { minPoint = point; } if (point.x > maxPoint.x) { maxPoint = point; } } minPoint = transformMatrix.MultiplyPoint(minPoint); maxPoint = transformMatrix.MultiplyPoint(maxPoint); }
public Box Transform(TransformMatrix transformMatrix) { Vector3 rightAxis = transformMatrix.GetNormalizedRightAxisNoScaleSign(); Vector3 upAxis = transformMatrix.GetNormalizedUpAxisNoScaleSign(); Vector3 lookAxis = transformMatrix.GetNormalizedLookAxisNoScaleSign(); Vector3 scale = transformMatrix.Scale; Vector3 newCenter = transformMatrix.MultiplyPoint(Center); Vector3 boxExtents = Extents; Vector3 newExtentsRight = rightAxis * boxExtents.x * scale.x; Vector3 newExtentsUp = upAxis * boxExtents.y * scale.y; Vector3 newExtentsLook = lookAxis * boxExtents.z * scale.z; float newExtentsX = Mathf.Abs(newExtentsRight.x) + Mathf.Abs(newExtentsUp.x) + Mathf.Abs(newExtentsLook.x); float newExtentsY = Mathf.Abs(newExtentsRight.y) + Mathf.Abs(newExtentsUp.y) + Mathf.Abs(newExtentsLook.y); float newExtentsZ = Mathf.Abs(newExtentsRight.z) + Mathf.Abs(newExtentsUp.z) + Mathf.Abs(newExtentsLook.z); Vector3 newSize = new Vector3(newExtentsX, newExtentsY, newExtentsZ) * 2.0f; return(new Box(newCenter, newSize)); }
public bool Raycast(Ray ray, out float t) { TransformMatrix transformMatrix = TransformMatrix; Ray modelSpaceRay = ray.InverseTransform(transformMatrix.ToMatrix4x4x); float modelSpaceT; if (_modelSpaceBox.Raycast(modelSpaceRay, out modelSpaceT)) { // Note: The intersection offset (i.e. T value) we have calculated so far is expressed in the box model space. // We have to calculate the intersection point in world space and use that to calculate the world space // T value which we will store in the output parameter. Vector3 modelSpaceIntersectionPoint = modelSpaceRay.GetPoint(modelSpaceT); Vector3 worldIntersectionPoint = transformMatrix.MultiplyPoint(modelSpaceIntersectionPoint); t = (ray.origin - worldIntersectionPoint).magnitude; return(true); } else { t = 0.0f; return(false); } }
/// <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); } }
/// <summary> /// Returns the world space vertices overlapped by the specified box. /// </summary> public List <Vector3> GetOverlappedWorldVerts(OrientedBox box, 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(); } // Work in mesh model space because the tree data exists in model space OrientedBox meshSpaceOOBB = new OrientedBox(box); Matrix4x4 inverseTransform = meshTransformMatrix.ToMatrix4x4x.inverse; meshSpaceOOBB.Transform(inverseTransform); // Used to avoid duplicate indices since there can be triangles which share the same vertices // and we don't want to return the same vertex multiple times. HashSet <int> usedIndices = new HashSet <int>(); // Retrieve the nodes overlapped by the specified box List <SphereTreeNode <MeshSphereTreeTriangle> > overlappedNodes = _sphereTree.OverlapBox(meshSpaceOOBB); if (overlappedNodes.Count == 0) { return(new List <Vector3>()); } // Loop through all nodes var overlappedWorldVerts = new List <Vector3>(50); foreach (var node in overlappedNodes) { // Get the triangle associated with the node int triangleIndex = node.Data.TriangleIndex; MeshTriangleInfo triangleInfo = _octave3DMesh.GetMeshTriangleInfo(triangleIndex); List <Vector3> trianglePoints = triangleInfo.ModelSpaceTriangle.GetPoints(); for (int ptIndex = 0; ptIndex < trianglePoints.Count; ++ptIndex) { if (usedIndices.Contains(triangleInfo.VertIndices[ptIndex])) { continue; } Vector3 point = trianglePoints[ptIndex]; if (meshSpaceOOBB.ContainsPoint(point)) { overlappedWorldVerts.Add(meshTransformMatrix.MultiplyPoint(point)); usedIndices.Add(triangleInfo.VertIndices[ptIndex]); } } /*Triangle3D modelSpaceTriangle = _octave3DMesh.GetTriangle(triangleIndex); * * // Now check which of the triangle points resides inside the box * List<Vector3> trianglePoints = modelSpaceTriangle.GetPoints(); * foreach(var pt in trianglePoints) * { * // When a point resides inside the box, we will transform it in world space and add it to the final point list * if (box.ContainsPoint(pt)) overlappedWorldVerts.Add(meshTransformMatrix.MultiplyPoint(pt)); * }*/ } return(overlappedWorldVerts); }
public Vector3 GetBoxFaceCenter(BoxFace boxFace) { Vector3 modelSpaceCenter = _modelSpaceBox.GetBoxFaceCenter(boxFace); return(TransformMatrix.MultiplyPoint(modelSpaceCenter)); }
public void SetTransformMatrix(TransformMatrix transformMatrix) { Rotation = transformMatrix.Rotation; _scale = transformMatrix.Scale; Center = transformMatrix.MultiplyPoint(_modelSpaceBox.Center); }
public void Transform(TransformMatrix transformMatrix) { Rotation = transformMatrix.Rotation * Rotation; _scale = Vector3.Scale(transformMatrix.Scale, _scale); Center = transformMatrix.MultiplyPoint(Center); }