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 BoxFaceAreaDesc GetWorldSnapAreaDesc(BoxFace boxFace) { Vector3 boxSize = _snapAreaBounds[(int)boxFace].Size; boxSize = Vector3.Scale(boxSize, _gameObject.transform.lossyScale.Abs()); return(BoxMath.GetBoxFaceAreaDesc(boxSize, boxFace)); }
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); }
/// <summary> /// Performs all necessary initializations. /// </summary> private void Start() { // Create the 4 gizmos _objectMoveGizmo = RTGizmosEngine.Get.CreateObjectMoveGizmo(); _objectRotationGizmo = RTGizmosEngine.Get.CreateObjectRotationGizmo(); _objectScaleGizmo = RTGizmosEngine.Get.CreateObjectScaleGizmo(); _objectUniversalGizmo = RTGizmosEngine.Get.CreateObjectUniversalGizmo(); // Call the 'SetEnabled' function on the parent gizmo to make sure // the gizmos are initially hidden in the scene. We want the gizmo // to show only when we have a target object available. _objectMoveGizmo.Gizmo.SetEnabled(false); _objectRotationGizmo.Gizmo.SetEnabled(false); _objectScaleGizmo.Gizmo.SetEnabled(false); _objectUniversalGizmo.Gizmo.SetEnabled(false); // Link the selected objects list to the gizmos // Note: The 'SetTargetObjects' function will instruct the gizmo to store // a direct reference to the '_selecteObjects' list. This means that // when you add or remove objects from this list, the gizmos will have // access to the most recent/updated collection. You don't need to call // 'SetTargetObjects' again when the list changes. _objectMoveGizmo.SetTargetObjects(_selectedObjects); _objectRotationGizmo.SetTargetObjects(_selectedObjects); _objectScaleGizmo.SetTargetObjects(_selectedObjects); _objectUniversalGizmo.SetTargetObjects(_selectedObjects); // We initialize the work gizmo to the move gizmo by default. This means // that the first time an object is clicked, the move gizmo will appear. // You can change the default gizmo, by simply changing these 2 lines of // code. For example, if you wanted the scale gizmo to be the default work // gizmo, replace '_objectMoveGizmo' with '_objectScaleGizmo' and GizmoId.Move // with GizmoId.Scale. _workGizmo = _objectMoveGizmo; _workGizmoId = GizmoId.Move; // <BEGIN TUTORIAL> // Get a reference to the object whose pivot we want to modify GameObject doorObject = GameObject.Find("GreenCube"); // Calculate the object's world OBB and then use the 'BoxMath.CalcBoxFaceCenter' // to calculate the center of the object's left face in world space. We will use // this face center as our pivot. OBB worldOBB = ObjectBounds.GetMeshWorldOBB(doorObject); Vector3 faceCenter = BoxMath.CalcBoxFaceCenter(worldOBB.Center, worldOBB.Size, worldOBB.Rotation, BoxFace.Left); // Use the 'SetObjectCustomLocalPivot' function to specify the object's pivot. // Note: We need to call 'InverseTransformPoint' on the face center because the function expects // a pivot point expressed in the object's local coordinate system. _objectRotationGizmo.SetObjectCustomLocalPivot(doorObject, doorObject.transform.InverseTransformPoint(faceCenter)); // Change the transform pivot to 'CustomObjectLocalPivot' _objectRotationGizmo.SetTransformPivot(GizmoObjectTransformPivot.CustomObjectLocalPivot); // <END TUTORIAL> }
public void Encapsulate(OBB otherOBB) { var otherPts = BoxMath.CalcBoxCornerPoints(otherOBB.Center, otherOBB.Size, otherOBB.Rotation); Matrix4x4 transformMtx = Matrix4x4.TRS(Center, Rotation, Vector3.one); var modelPts = transformMtx.inverse.TransformPoints(otherPts); AABB modelAABB = new AABB(Vector3.zero, Size); modelAABB.Encapsulate(modelPts); Center = (Rotation * modelAABB.Center) + Center; Size = modelAABB.Size; }
public static List <Vector3> CollectModelSpriteVerts(Sprite sprite, AABB collectAABB) { var spriteModelVerts = sprite.vertices; var collectedVerts = new List <Vector3>(7); foreach (var vertPos in spriteModelVerts) { if (BoxMath.ContainsPoint(vertPos, collectAABB.Center, collectAABB.Size, Quaternion.identity)) { collectedVerts.Add(vertPos); } } return(collectedVerts); }
private void UpdateTransform(Camera camera) { Vector3 midAxisPos = _sceneGizmo.SceneGizmoCamera.LookAtPoint; RTSceneGizmoCamera sceneGizmoCamera = _sceneGizmo.SceneGizmoCamera; Vector3 axisDirection = _sceneGizmo.Gizmo.Transform.GetAxis3D(_axisDesc); _zoomFactorTransform.Position3D = midAxisPos; float zoomFactor = _cap.GetZoomFactor(camera); Vector3 midCapSize = _sceneGizmo.LookAndFeel.MidCapType == GizmoCap3DType.Box ? Vector3Ex.FromValue(SceneGizmoLookAndFeel.MidCapBoxSize * zoomFactor) : Vector3Ex.FromValue(SceneGizmoLookAndFeel.MidCapSphereRadius * 2.0f * zoomFactor); Vector3 midBoxFaceCenter = BoxMath.CalcBoxFaceCenter(midAxisPos, midCapSize, Quaternion.identity, _midAxisBoxFace); _cap.CapSlider3DInvert(axisDirection, midBoxFaceCenter); }
public static List <Vector3> CollectWorldSpriteVerts(Sprite sprite, Transform spriteTransform, OBB collectOBB) { var spriteWorldVerts = sprite.GetWorldVerts(spriteTransform); var collectedVerts = new List <Vector3>(7); foreach (var vertPos in spriteWorldVerts) { if (BoxMath.ContainsPoint(vertPos, collectOBB.Center, collectOBB.Size, collectOBB.Rotation)) { collectedVerts.Add(vertPos); } } return(collectedVerts); }
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 List <Vector3> OverlapVerts(OBB obb, MeshTransform meshTransform) { if (!_isBuilt) { Build(); } OBB meshSpaceOBB = meshTransform.InverseTransformOBB(obb); HashSet <int> usedIndices = new HashSet <int>(); var overlappedNodes = _tree.OverlapBox(meshSpaceOBB); if (overlappedNodes.Count == 0) { return(new List <Vector3>()); } var overlappedVerts = new List <Vector3>(50); foreach (var node in overlappedNodes) { int triangleIndex = node.Data.TriangleIndex; MeshTriangle triangleInfo = _mesh.GetTriangle(triangleIndex); var modelVerts = triangleInfo.Vertices; for (int ptIndex = 0; ptIndex < modelVerts.Length; ++ptIndex) { int vertIndex = triangleInfo.GetVertIndex(ptIndex); if (usedIndices.Contains(vertIndex)) { continue; } Vector3 modelVert = modelVerts[ptIndex]; if (BoxMath.ContainsPoint(modelVert, meshSpaceOBB.Center, meshSpaceOBB.Size, meshSpaceOBB.Rotation)) { overlappedVerts.Add(meshTransform.TransformPoint(modelVert)); usedIndices.Add(vertIndex); } } } return(overlappedVerts); }
private void SnapToObjectHitPoint(GameObjectRayHit objectHit, SnapToPointMode snapMode) { if (snapMode == SnapToPointMode.Exact) { float distToPlane = new Plane(Normal, Vector3.zero).GetDistanceToPoint(objectHit.HitPoint); YOffset = distToPlane; } else { var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectType.Mesh; OBB worldOBB = ObjectBounds.CalcWorldOBB(objectHit.HitObject, boundsQConfig); if (worldOBB.IsValid) { Plane slicePlane = new Plane(Normal, worldOBB.Center); Vector3 destPt = worldOBB.Center; var obbCorners = BoxMath.CalcBoxCornerPoints(worldOBB.Center, worldOBB.Size, worldOBB.Rotation); float sign = Mathf.Sign(slicePlane.GetDistanceToPoint(objectHit.HitPoint)); if (sign > 0.0f) { int furthestPtInFront = slicePlane.GetFurthestPtInFront(obbCorners); if (furthestPtInFront >= 0) { destPt = obbCorners[furthestPtInFront]; } } else { int furthestPtBehind = slicePlane.GetFurthestPtBehind(obbCorners); if (furthestPtBehind >= 0) { destPt = obbCorners[furthestPtBehind]; } } float distToPlane = new Plane(Normal, Vector3.zero).GetDistanceToPoint(destPt); YOffset = distToPlane; } } }
public bool OverlapVerts(OBB obb, MeshTransform meshTransform, List <Vector3> verts) { verts.Clear(); if (!_isBuilt) { Build(); } OBB meshSpaceOBB = meshTransform.InverseTransformOBB(obb); if (!_tree.OverlapBox(meshSpaceOBB, _nodeBuffer)) { return(false); } _vertexIndexSet.Clear(); foreach (var node in _nodeBuffer) { int triangleIndex = node.Data.TriangleIndex; MeshTriangle triangleInfo = _mesh.GetTriangle(triangleIndex); var modelVerts = triangleInfo.Vertices; for (int ptIndex = 0; ptIndex < modelVerts.Length; ++ptIndex) { int vertIndex = triangleInfo.GetVertIndex(ptIndex); if (_vertexIndexSet.Contains(vertIndex)) { continue; } Vector3 modelVert = modelVerts[ptIndex]; if (BoxMath.ContainsPoint(modelVert, meshSpaceOBB.Center, meshSpaceOBB.Size, meshSpaceOBB.Rotation)) { verts.Add(meshTransform.TransformPoint(modelVert)); _vertexIndexSet.Add(vertIndex); } } } return(verts.Count != 0); }
private List <AABB> BuildVertOverlapAABBs(GameObject gameObject, Sprite sprite, RTMesh rtMesh) { if (sprite == null && rtMesh == null) { return(new List <AABB>()); } const float overlapAmount = 0.2f; float halfOverlapAmount = overlapAmount * 0.5f; AABB modelAABB = sprite != null?ObjectBounds.CalcSpriteModelAABB(gameObject) : rtMesh.AABB; Vector3 modelAABBSize = modelAABB.Size; List <BoxFace> modelAABBFaces = BoxMath.AllBoxFaces; const float sizeEps = 0.001f; Vector3[] overlapAABBSizes = new Vector3[modelAABBFaces.Count]; overlapAABBSizes[(int)BoxFace.Left] = new Vector3(overlapAmount, modelAABBSize.y + sizeEps, modelAABBSize.z + sizeEps); overlapAABBSizes[(int)BoxFace.Right] = new Vector3(overlapAmount, modelAABBSize.y + sizeEps, modelAABBSize.z + sizeEps); overlapAABBSizes[(int)BoxFace.Bottom] = new Vector3(modelAABBSize.x + sizeEps, overlapAmount, modelAABBSize.z + sizeEps); overlapAABBSizes[(int)BoxFace.Top] = new Vector3(modelAABBSize.x + sizeEps, overlapAmount, modelAABBSize.z + sizeEps); overlapAABBSizes[(int)BoxFace.Back] = new Vector3(modelAABBSize.x + sizeEps, modelAABBSize.y + sizeEps, overlapAmount); overlapAABBSizes[(int)BoxFace.Front] = new Vector3(modelAABBSize.x + sizeEps, modelAABBSize.y + sizeEps, overlapAmount); var overlapAABBs = new List <AABB>(); for (int boxFaceIndex = 0; boxFaceIndex < modelAABBFaces.Count; ++boxFaceIndex) { BoxFace modelAABBFace = modelAABBFaces[boxFaceIndex]; Vector3 faceCenter = BoxMath.CalcBoxFaceCenter(modelAABB.Center, modelAABB.Size, Quaternion.identity, modelAABBFace); Vector3 faceNormal = BoxMath.CalcBoxFaceNormal(modelAABB.Center, modelAABB.Size, Quaternion.identity, modelAABBFace); Vector3 overlapCenter = faceCenter - faceNormal * halfOverlapAmount; overlapAABBs.Add(new AABB(overlapCenter, overlapAABBSizes[boxFaceIndex])); } return(overlapAABBs); }
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 bool Initialize(GameObject gameObject) { if (gameObject == null || _gameObject != null) { return(false); } Mesh mesh = gameObject.GetMesh(); Sprite sprite = gameObject.GetSprite(); if (mesh == null && sprite == null) { return(false); } bool useMesh = true; if (mesh == null) { useMesh = false; } RTMesh rtMesh = null; if (useMesh) { Renderer meshRenderer = gameObject.GetMeshRenderer(); if (meshRenderer == null || !meshRenderer.enabled) { useMesh = false; } rtMesh = RTMeshDb.Get.GetRTMesh(mesh); if (rtMesh == null) { useMesh = false; } } if (rtMesh == null && sprite == null) { return(false); } List <AABB> vertOverlapAABBs = BuildVertOverlapAABBs(gameObject, useMesh ? null : sprite, useMesh ? rtMesh : null); if (vertOverlapAABBs.Count == 0) { return(false); } AABB modelAABB = useMesh ? rtMesh.AABB : ObjectBounds.CalcSpriteModelAABB(gameObject); var aabbFaces = BoxMath.AllBoxFaces; _gameObject = gameObject; if (useMesh) { foreach (var aabbFace in aabbFaces) { AABB overlapAABB = vertOverlapAABBs[(int)aabbFace]; List <Vector3> overlappedVerts = rtMesh.OverlapModelVerts(overlapAABB); Plane facePlane = BoxMath.CalcBoxFacePlane(modelAABB.Center, modelAABB.Size, Quaternion.identity, aabbFace); overlappedVerts = facePlane.ProjectAllPoints(overlappedVerts); _snapAreaBounds[(int)aabbFace] = new AABB(overlappedVerts); _snapAreaDesc[(int)aabbFace] = BoxMath.GetBoxFaceAreaDesc(_snapAreaBounds[(int)aabbFace].Size, aabbFace); } } else { foreach (var aabbFace in aabbFaces) { if (aabbFace != BoxFace.Front && aabbFace != BoxFace.Back) { AABB overlapAABB = vertOverlapAABBs[(int)aabbFace]; List <Vector3> overlappedVerts = ObjectVertexCollect.CollectModelSpriteVerts(sprite, overlapAABB); Plane facePlane = BoxMath.CalcBoxFacePlane(modelAABB.Center, modelAABB.Size, Quaternion.identity, aabbFace); overlappedVerts = facePlane.ProjectAllPoints(overlappedVerts); _snapAreaBounds[(int)aabbFace] = new AABB(overlappedVerts); _snapAreaDesc[(int)aabbFace] = BoxMath.GetBoxFaceAreaDesc(_snapAreaBounds[(int)aabbFace].Size, aabbFace); } else { _snapAreaBounds[(int)aabbFace] = AABB.GetInvalid(); _snapAreaDesc[(int)aabbFace] = BoxFaceAreaDesc.GetInvalid(); } } } return(true); }
public List <Vector3> GetCornerPoints() { return(BoxMath.CalcBoxCornerPoints(_center, _size, _rotation)); }
public Vector3 GetClosestPoint(Vector3 point) { return(BoxMath.CalcBoxPtClosestToPt(point, _center, _size, _rotation)); }
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 void SetFaceCenter(BoxFace boxFace, Vector3 newCenter) { Vector3 currentFaceCenter = BoxMath.CalcBoxFaceCenter(_center, _size, _rotation, boxFace); Center = newCenter + (_center - currentFaceCenter); }
public override bool Raycast(Ray ray, out float t) { return(BoxMath.Raycast(ray, out t, _center, _size, _rotation, _epsilon)); }
public static SnapResult SnapHierarchy(GameObject root, SnapConfig snapConfig) { const float collectEps = 1e-2f; const float collectBoxScale = 1e-3f; bool hierarchyHasMeshes = root.HierarchyHasMesh(); bool hierarchyHasSprites = root.HierarchyHasSprite(); if (!hierarchyHasMeshes && !hierarchyHasSprites) { Transform rootTransform = root.transform; rootTransform.position = snapConfig.SurfaceHitPlane.ProjectPoint(rootTransform.position) + snapConfig.OffsetFromSurface * snapConfig.SurfaceHitNormal; return(new SnapResult(snapConfig.SurfaceHitPlane, rootTransform.position)); } var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectType.Sprite | GameObjectType.Mesh; bool isSurfaceSpherical = snapConfig.SurfaceType == Type.SphericalMesh; bool isSurfaceTerrain = snapConfig.SurfaceType == Type.UnityTerrain || snapConfig.SurfaceType == Type.TerrainMesh; bool isSurfaceUnityTerrain = snapConfig.SurfaceType == Type.UnityTerrain; var raycaster = CreateSurfaceRaycaster(snapConfig.SurfaceType, snapConfig.SurfaceObject, true); if (snapConfig.SurfaceType != Type.SceneGrid) { Transform rootTransform = root.transform; if (snapConfig.AlignAxis) { if (isSurfaceTerrain) { rootTransform.Align(Vector3.up, snapConfig.AlignmentAxis); OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new SnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, -Vector3.up); var collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); if (collectedVerts.Count != 0) { Vector3 vertsCenter = Vector3Ex.GetPointCloudCenter(collectedVerts); Ray ray = new Ray(vertsCenter + Vector3.up * 1e-3f, -Vector3.up); GameObjectRayHit surfaceHit = raycaster.Raycast(ray); if (surfaceHit != null) { Vector3 alignmentAxis = surfaceHit.HitNormal; if (isSurfaceUnityTerrain) { Terrain terrain = snapConfig.SurfaceObject.GetComponent <Terrain>(); alignmentAxis = terrain.GetInterpolatedNormal(surfaceHit.HitPoint); } Quaternion appliedRotation = rootTransform.Align(alignmentAxis, snapConfig.AlignmentAxis); hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); appliedRotation.RotatePoints(collectedVerts, rootTransform.position); Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, new Plane(Vector3.up, surfaceHit.HitPoint), 0.1f); rootTransform.position += sitOnPlaneOffset; hierarchyOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); Vector3 embedVector = ObjectSurfaceSnap.CalculateEmbedVector(collectedVerts, snapConfig.SurfaceObject, -Vector3.up, snapConfig.SurfaceType); rootTransform.position += (embedVector + alignmentAxis * snapConfig.OffsetFromSurface); return(new SnapResult(new Plane(alignmentAxis, surfaceHit.HitPoint), surfaceHit.HitPoint)); } } } else { if (!isSurfaceSpherical) { rootTransform.Align(snapConfig.SurfaceHitNormal, snapConfig.AlignmentAxis); OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new SnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, -snapConfig.SurfaceHitNormal); var collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); if (collectedVerts.Count != 0) { Vector3 vertsCenter = Vector3Ex.GetPointCloudCenter(collectedVerts); // Note: Cast the ray from far away enough so that we don't cast from the interior of the mesh. // This can happen when the object is embedded inside the mesh surface. AABB surfaceAABB = ObjectBounds.CalcMeshWorldAABB(snapConfig.SurfaceObject); float sphereRadius = surfaceAABB.Extents.magnitude; Vector3 rayOrigin = vertsCenter + snapConfig.SurfaceHitNormal * sphereRadius; Ray ray = new Ray(rayOrigin, -snapConfig.SurfaceHitNormal); GameObjectRayHit surfaceHit = raycaster.Raycast(ray); if (surfaceHit != null) { Vector3 alignmentAxis = surfaceHit.HitNormal; rootTransform.Align(alignmentAxis, snapConfig.AlignmentAxis); hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, surfaceHit.HitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; rootTransform.position += alignmentAxis * snapConfig.OffsetFromSurface; return(new SnapResult(new Plane(alignmentAxis, surfaceHit.HitPoint), surfaceHit.HitPoint)); } else { Vector3 alignmentAxis = snapConfig.SurfaceHitNormal; rootTransform.Align(alignmentAxis, snapConfig.AlignmentAxis); hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, snapConfig.SurfaceHitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; rootTransform.position += alignmentAxis * snapConfig.OffsetFromSurface; return(new SnapResult(snapConfig.SurfaceHitPlane, snapConfig.SurfaceHitPlane.ProjectPoint(vertsCenter))); } } } else { Transform surfaceObjectTransform = snapConfig.SurfaceObject.transform; Vector3 sphereCenter = surfaceObjectTransform.position; Vector3 radiusDir = (rootTransform.position - sphereCenter).normalized; float sphereRadius = surfaceObjectTransform.lossyScale.GetMaxAbsComp() * 0.5f; rootTransform.Align(radiusDir, snapConfig.AlignmentAxis); OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new SnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, -radiusDir); var collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 sitPoint = sphereCenter + radiusDir * sphereRadius; Plane sitPlane = new Plane(radiusDir, sitPoint); Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, sitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); rootTransform.position += radiusDir * snapConfig.OffsetFromSurface; return(new SnapResult(sitPlane, sitPoint)); } } } else { OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new SnapResult()); } if (isSurfaceTerrain || (!isSurfaceSpherical && snapConfig.SurfaceType == Type.Mesh)) { Ray ray = new Ray(hierarchyOBB.Center, isSurfaceTerrain ? -Vector3.up : -snapConfig.SurfaceHitNormal); GameObjectRayHit surfaceHit = raycaster.Raycast(ray); if (surfaceHit != null) { Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, surfaceHit.HitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; if (isSurfaceTerrain) { hierarchyOBB.Center += sitOnPlaneOffset; BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, -surfaceHit.HitNormal); var collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 embedVector = ObjectSurfaceSnap.CalculateEmbedVector(collectedVerts, snapConfig.SurfaceObject, -Vector3.up, snapConfig.SurfaceType); rootTransform.position += embedVector; } rootTransform.position += surfaceHit.HitNormal * snapConfig.OffsetFromSurface; return(new SnapResult(surfaceHit.HitPlane, surfaceHit.HitPoint)); } else if (!isSurfaceSpherical && snapConfig.SurfaceType == Type.Mesh) { Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, snapConfig.SurfaceHitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; rootTransform.position += snapConfig.SurfaceHitNormal * snapConfig.OffsetFromSurface; return(new SnapResult(snapConfig.SurfaceHitPlane, snapConfig.SurfaceHitPlane.ProjectPoint(hierarchyOBB.Center))); } } else if (isSurfaceSpherical) { Transform surfaceObjectTransform = snapConfig.SurfaceObject.transform; Vector3 sphereCenter = surfaceObjectTransform.position; Vector3 radiusDir = (rootTransform.position - sphereCenter).normalized; float sphereRadius = surfaceObjectTransform.lossyScale.GetMaxAbsComp() * 0.5f; BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, -radiusDir); var collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 sitPoint = sphereCenter + radiusDir * sphereRadius; Plane sitPlane = new Plane(radiusDir, sitPoint); Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, sitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); rootTransform.position += radiusDir * snapConfig.OffsetFromSurface; return(new SnapResult(sitPlane, sitPoint)); } } } if (snapConfig.SurfaceType == Type.SceneGrid) { OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new SnapResult()); } Transform rootTransform = root.transform; if (snapConfig.AlignAxis) { rootTransform.Align(snapConfig.SurfaceHitNormal, snapConfig.AlignmentAxis); hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); } rootTransform.position += ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, snapConfig.SurfaceHitPlane, snapConfig.OffsetFromSurface); return(new SnapResult(snapConfig.SurfaceHitPlane, snapConfig.SurfaceHitPlane.ProjectPoint(hierarchyOBB.Center))); } return(new SnapResult()); }
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 List <Vector3> CollectHierarchyVerts(GameObject root, BoxFace collectFace, float collectBoxScale, float collectEps) { var meshObjects = root.GetMeshObjectsInHierarchy(); var spriteObjects = root.GetSpriteObjectsInHierarchy(); if (meshObjects.Count == 0 && spriteObjects.Count == 0) { return(new List <Vector3>()); } var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectType.Mesh | GameObjectType.Sprite; OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new List <Vector3>()); } int faceAxisIndex = BoxMath.GetFaceAxisIndex(collectFace); Vector3 faceCenter = BoxMath.CalcBoxFaceCenter(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, collectFace); Vector3 faceNormal = BoxMath.CalcBoxFaceNormal(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, collectFace); float sizeEps = collectEps * 2.0f; Vector3 collectAABBSize = hierarchyOBB.Size; collectAABBSize[faceAxisIndex] = (hierarchyOBB.Size[faceAxisIndex] * collectBoxScale) + sizeEps; collectAABBSize[(faceAxisIndex + 1) % 3] += sizeEps; collectAABBSize[(faceAxisIndex + 2) % 3] += sizeEps; OBB collectOBB = new OBB(faceCenter + faceNormal * (-collectAABBSize[faceAxisIndex] * 0.5f + collectEps), collectAABBSize); collectOBB.Rotation = hierarchyOBB.Rotation; var collectedVerts = new List <Vector3>(80); foreach (var meshObject in meshObjects) { Mesh mesh = meshObject.GetMesh(); RTMesh rtMesh = RTMeshDb.Get.GetRTMesh(mesh); if (rtMesh == null) { continue; } var verts = rtMesh.OverlapVerts(collectOBB, meshObject.transform); if (verts.Count != 0) { collectedVerts.AddRange(verts); } } foreach (var spriteObject in spriteObjects) { var verts = CollectWorldSpriteVerts(spriteObject.GetSprite(), spriteObject.transform, collectOBB); if (verts.Count != 0) { collectedVerts.AddRange(verts); } } return(collectedVerts); }
public bool ContainsPoint(Vector3 point) { return(BoxMath.ContainsPoint(point, _center, _size, Quaternion.identity)); }
public bool IntersectsOBB(OBB otherOBB) { return(BoxMath.BoxIntersectsBox(_center, _size, _rotation, otherOBB.Center, otherOBB.Size, otherOBB.Rotation)); }
public List <Vector3> GetCornerPoints() { return(BoxMath.CalcBoxCornerPoints(_center, _size, Quaternion.identity)); }
public Vector3 GetFaceCenter(BoxFace boxFace) { return(BoxMath.CalcBoxFaceCenter(_center, _size, _rotation, boxFace)); }
public void Transform(Matrix4x4 transformMatrix) { BoxMath.TransformBox(_center, _size, transformMatrix, out _center, out _size); }
public bool ContainsPoint(Vector3 point) { return(BoxMath.ContainsPoint(point, _center, _size, _rotation, _epsilon)); }