private void RotateTargets() { var boundsQConfig = GetBoundsQConfig(); float rotationAmount = InputDeviceManager.Get.MouseDelta.x * SharedSettings.RotationSensitivity; EditorUndoEx.RecordObjectTransforms(_targetParents); foreach (var grabTarget in _grabTargets) { if (grabTarget == null) { continue; } OOBB targetOOBB = ObjectBounds.CalcHierarchyWorldOOBB(grabTarget.GameObject, boundsQConfig); if (!targetOOBB.IsValid) { continue; } var layerGrabSettings = SharedSettings.GetLayerGrabSettings(grabTarget.GameObject.layer); if (layerGrabSettings.IsActive) { Quaternion rotation = Quaternion.AngleAxis(rotationAmount, layerGrabSettings.AlignAxis ? grabTarget.SittingPlane.normal : Vector3.up); grabTarget.Transform.RotateAroundPivot(rotation, targetOOBB.Center); } else { Quaternion rotation = Quaternion.AngleAxis(rotationAmount, SharedSettings.AlignAxis ? grabTarget.SittingPlane.normal : Vector3.up); grabTarget.Transform.RotateAroundPivot(rotation, targetOOBB.Center); } } CalculateGrabTargetsAnchorVectors(); }
/// <summary> /// Returns a list that contains all terminal nodes that intersect the /// specified OOBB. /// </summary> public List <SphereTreeNode <T> > OverlapBox(OOBB box) { var overlappedNodes = new List <SphereTreeNode <T> >(20); OverlapBoxRecurse(box, _root, overlappedNodes); return(overlappedNodes); }
/// <summary> /// Recursive method which moves down the hierarchy performing overlap tests /// against 'box'. At the end of the recursive chain, all terminal nodes which /// are overlapped by 'box' will be stored in 'overlappedNodes'. /// </summary> private void OverlapBoxRecurse(OOBB box, SphereTreeNode <T> node, List <SphereTreeNode <T> > overlappedNodes) { // If the parent node is not overlapped, its children can not possibly // be overlapped so thre is no need to go any further. if (!box.IntersectsSphere(node.Sphere)) { return; } else { // If this is a terminal node, add it to the output list and return if (node.IsFlagBitSet(BVHNodeFlags.Terminal)) { overlappedNodes.Add(node); return; } else { // Recurse for each child node List <SphereTreeNode <T> > childNodes = node.Children; foreach (SphereTreeNode <T> childNode in childNodes) { OverlapBoxRecurse(box, childNode, overlappedNodes); } } } }
public OOBB(OOBB copy) { _size = copy._size; _center = copy._center; _rotation = copy._rotation; _isValid = copy._isValid; }
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) { OOBB quadOOBB = Calc3DQuadOOBB(quadCenter, new Vector2(quadWidth, quadHeight), Quaternion.LookRotation(quadNormal, quadUp), epsilon); return(BoxMath.Raycast(ray, quadOOBB.Center, quadOOBB.Size, quadOOBB.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) { OOBB oobb = Calc3DTriangleOOBB(p0, p1, p2, trianglePlane.normal, epsilon); return(BoxMath.Raycast(ray, oobb.Center, oobb.Size, oobb.Rotation)); } } return(false); }
public List <GameObject> OverlapBox(OOBB oobb) { List <SphereTreeNode <GameObject> > overlappedNodes = _objectTree.OverlapBox(oobb); if (overlappedNodes.Count == 0) { return(new List <GameObject>()); } var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; boundsQConfig.NoVolumeSize = EditorScene.Get.NoVolumeObjectSize; var overlappedObjects = new List <GameObject>(); foreach (SphereTreeNode <GameObject> node in overlappedNodes) { GameObject sceneObject = (GameObject)node.Data; if (sceneObject == null || !sceneObject.activeInHierarchy) { continue; } OOBB worldOOBB = ObjectBounds.CalcWorldOOBB(sceneObject, boundsQConfig); if (oobb.IntersectsOOBB(worldOOBB)) { overlappedObjects.Add(sceneObject); } } return(overlappedObjects); }
public OOBB InverseTransformOOBB(OOBB oobb) { OOBB meshSpaceOOBB = new OOBB(InverseTransformPoint(oobb.Center), Vector3.Scale(_scale.GetInverse(), oobb.Size)); meshSpaceOOBB.Rotation = Quaternion.Inverse(_rotation) * oobb.Rotation; return(meshSpaceOOBB); }
public void OnSceneGUIRender() { if (SharedLookAndFeel == null) { return; } if (IsActive && _grabSurfaceInfo.SurfaceType != GrabSurfaceType.Invalid) { if (SharedLookAndFeel.ShowAnchorLines) { Color oldColor = Handles.color; var linePoints = new List <Vector3>(_grabTargets.Count * 2); Handles.color = SharedLookAndFeel.AnchorLineTickColor; foreach (var grabTarget in _grabTargets) { linePoints.Add(grabTarget.Transform.position); linePoints.Add(_grabSurfaceInfo.AnchorPoint); if (SharedLookAndFeel.ShowAnchorLineTicks) { float dotSize = SharedLookAndFeel.AnchorLineTickSize * HandleUtility.GetHandleSize(grabTarget.Transform.position); Handles.DotHandleCap(0, grabTarget.Transform.position, Quaternion.identity, dotSize, EventType.Repaint); } } if (SharedLookAndFeel.ShowAnchorLineTicks) { float dotAnchPtSize = SharedLookAndFeel.AnchorLineTickSize * HandleUtility.GetHandleSize(_grabSurfaceInfo.AnchorPoint); Handles.DotHandleCap(0, _grabSurfaceInfo.AnchorPoint, Quaternion.identity, dotAnchPtSize, EventType.Repaint); } Handles.color = SharedLookAndFeel.AnchorLineColor; Handles.DrawLines(linePoints.ToArray()); Handles.color = oldColor; } if (SharedLookAndFeel.ShowTargetBoxes) { Color oldColor = Handles.color; Matrix4x4 oldMatrix = Handles.matrix; Handles.color = SharedLookAndFeel.TargetWireBoxColor; var boundsQConfig = GetBoundsQConfig(); foreach (var grabTarget in _grabTargets) { OOBB targetOOBB = ObjectBounds.CalcHierarchyWorldOOBB(grabTarget.GameObject, boundsQConfig); if (targetOOBB.IsValid) { Handles.matrix = Matrix4x4.TRS(targetOOBB.Center, targetOOBB.Rotation, Vector3.one); Handles.DrawWireCube(Vector3.zero, targetOOBB.Size); } } Handles.color = oldColor; Handles.matrix = oldMatrix; } } }
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) { OOBB quadOOBB = Calc3DQuadOOBB(quadCenter, quadSize, Quaternion.LookRotation(quadNormal, quadUp), epsilon); return(BoxMath.Raycast(ray, quadOOBB.Center, quadOOBB.Size, quadOOBB.Rotation)); } } return(false); }
public static OOBB CalcWorldOOBB(GameObject gameObject, QueryConfig queryConfig) { AABB modelAABB = CalcModelAABB(gameObject, queryConfig, gameObject.GetGameObjectType()); if (!modelAABB.IsValid) { return(OOBB.GetInvalid()); } return(new OOBB(modelAABB, gameObject.transform)); }
public static OOBB GetMeshWorldOOBB(GameObject gameObject) { AABB modelAABB = CalcMeshModelAABB(gameObject); if (!modelAABB.IsValid) { return(OOBB.GetInvalid()); } return(new OOBB(modelAABB, gameObject.transform)); }
public static OOBB CalcHierarchyWorldOOBB(GameObject root, QueryConfig queryConfig) { AABB modelAABB = CalcHierarchyModelAABB(root, queryConfig); if (!modelAABB.IsValid) { return(OOBB.GetInvalid()); } return(new OOBB(modelAABB, root.transform)); }
public void Encapsulate(OOBB otherOOBB) { var otherPts = BoxMath.CalcBoxCornerPoints(otherOOBB.Center, otherOOBB.Size, otherOOBB.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 GameObjectRayHit RaycastSpriteObject(Ray ray, GameObject gameObject) { float t; OOBB worldOOBB = ObjectBounds.CalcSpriteWorldOOBB(gameObject); if (!worldOOBB.IsValid) { return(null); } if (BoxMath.Raycast(ray, out t, worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation)) { return(new GameObjectRayHit(ray, gameObject, worldOOBB.GetPointFaceNormal(ray.GetPoint(t)), t)); } return(null); }
public static OOBB Calc3DTriangleOOBB(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 normal, TriangleEpsilon epsilon = new TriangleEpsilon()) { const float eps = 1e-5f; Vector3 lgEdgeStart = p0; Vector3 lgEdgeEnd = p1; Vector3 oppositePt = p2; float sqrEdgeLength = (p0 - p1).sqrMagnitude + eps; // Add small epsilon to avoid problems with equilateral triangles float nextSqrLength = (p1 - p2).sqrMagnitude; if (nextSqrLength > sqrEdgeLength) { lgEdgeStart = p1; lgEdgeEnd = p2; oppositePt = p0; sqrEdgeLength = nextSqrLength; } nextSqrLength = (p2 - p0).sqrMagnitude; if (nextSqrLength > sqrEdgeLength) { lgEdgeStart = p2; lgEdgeEnd = p0; oppositePt = p1; sqrEdgeLength = nextSqrLength; } Quaternion oobbRotation = Quaternion.LookRotation((lgEdgeEnd - lgEdgeStart).normalized, normal); OOBB oobb = new OOBB(oobbRotation); float sizeAdd = 2.0f * epsilon.AreaEps; float oobbDepth = Mathf.Sqrt(sqrEdgeLength) + sizeAdd; float dotRight = Vector3.Dot(oobb.Right, (oppositePt - lgEdgeStart)); float oobbWidth = Mathf.Abs(dotRight) + sizeAdd; float oobbHeight = epsilon.ExtrudeEps * 2.0f; oobb.Size = new Vector3(oobbWidth, oobbHeight, oobbDepth); Vector3 right = oobb.Right * Mathf.Sign(dotRight); oobb.Center = right * oobbWidth * 0.5f - right * epsilon.AreaEps + lgEdgeStart - oobb.Look * epsilon.AreaEps + oobb.Look * oobbDepth * 0.5f; return(oobb); }
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) { OOBB oobb = Calc3DTriangleOOBB(p0, p1, p2, trianglePlane.normal, epsilon); return(BoxMath.Raycast(ray, oobb.Center, oobb.Size, oobb.Rotation)); } } return(false); }
public static Vector3 CalculateSitOnSurfaceOffset(OOBB oobb, Plane surfacePlane, float offsetFromSurface) { List <Vector3> oobbCorners = oobb.GetCornerPoints(); int pivotPointIndex = surfacePlane.GetFurthestPtBehind(oobbCorners); if (pivotPointIndex < 0) { pivotPointIndex = surfacePlane.GetClosestPtInFrontOrOnPlane(oobbCorners); } if (pivotPointIndex >= 0) { Vector3 pivotPt = oobbCorners[pivotPointIndex]; Vector3 prjPt = surfacePlane.ProjectPoint(pivotPt); return((prjPt - pivotPt) + surfacePlane.normal * offsetFromSurface); } return(Vector3.zero); }
public List <Vector3> OverlapVerts(OOBB oobb, MeshTransform meshTransform) { if (!_isBuilt) { Build(); } OOBB meshSpaceOOBB = meshTransform.InverseTransformOOBB(oobb); HashSet <int> usedIndices = new HashSet <int>(); var overlappedNodes = _tree.OverlapBox(meshSpaceOOBB); 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, meshSpaceOOBB.Center, meshSpaceOOBB.Size, meshSpaceOOBB.Rotation)) { overlappedVerts.Add(meshTransform.TransformPoint(modelVert)); usedIndices.Add(vertIndex); } } } return(overlappedVerts); }
public List <Vector3> OverlapModelVerts(OOBB modelOOBB) { return(_meshTree.OverlapModelVerts(modelOOBB)); }
public List <Vector3> OverlapVerts(OOBB oobb, Transform meshObjectTransform) { return(_meshTree.OverlapVerts(oobb, new MeshTransform(meshObjectTransform))); }
public bool IntersectsOOBB(OOBB otherOOBB) { return(BoxMath.BoxIntersectsBox(_center, _size, _rotation, otherOOBB.Center, otherOOBB.Size, otherOOBB.Rotation)); }
public static ObjectSnapResult SnapHierarchy(GameObject root, ObjectSnapConfig snapConfig) { const float collectEps = 1e-2f; const float collectBoxScale = 1e-3f; bool hierarchyHasMeshes = root.HierarchyHasMesh(); bool hierarchyHasSprites = root.HierarchyHasSprite(); if (!hierarchyHasMeshes && !hierarchyHasSprites) { return(new ObjectSnapResult()); } 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); OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new ObjectSnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.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); hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); appliedRotation.RotatePoints(collectedVerts, rootTransform.position); Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, new Plane(Vector3.up, surfaceHit.HitPoint), 0.1f); rootTransform.position += sitOnPlaneOffset; hierarchyOOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); Vector3 embedVector = Surface.CalculateEmbedVector(collectedVerts, snapConfig.SurfaceObject, -Vector3.up, snapConfig.SurfaceType); rootTransform.position += (embedVector + alignmentAxis * snapConfig.OffsetFromSurface); return(new ObjectSnapResult(new Plane(alignmentAxis, surfaceHit.HitPoint), surfaceHit.HitPoint)); } } } else { if (!isSurfaceSpherical) { rootTransform.Align(snapConfig.SurfaceHitNormal, snapConfig.AlignmentAxis); OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new ObjectSnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.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; Quaternion appliedRotation = rootTransform.Align(alignmentAxis, snapConfig.AlignmentAxis); hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); appliedRotation.RotatePoints(collectedVerts, rootTransform.position); Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, surfaceHit.HitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); return(new ObjectSnapResult(new Plane(alignmentAxis, surfaceHit.HitPoint), surfaceHit.HitPoint)); } } } 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); OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new ObjectSnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -radiusDir); var collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 sitPoint = sphereCenter + radiusDir * sphereRadius; Plane sitPlane = new Plane(radiusDir, sitPoint); Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, sitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); return(new ObjectSnapResult(sitPlane, sitPoint)); } } } else { OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new ObjectSnapResult()); } if (isSurfaceTerrain || (!isSurfaceSpherical && snapConfig.SurfaceType == Type.Mesh)) { Ray ray = new Ray(hierarchyOOBB.Center, isSurfaceTerrain ? -Vector3.up : -snapConfig.SurfaceHitNormal); GameObjectRayHit surfaceHit = raycaster.Raycast(ray); if (surfaceHit != null) { Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, surfaceHit.HitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOOBB.Center += sitOnPlaneOffset; if (isSurfaceTerrain) { BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -surfaceHit.HitNormal); var collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 embedVector = Surface.CalculateEmbedVector(collectedVerts, snapConfig.SurfaceObject, -surfaceHit.HitNormal, snapConfig.SurfaceType); rootTransform.position += (embedVector + surfaceHit.HitNormal * snapConfig.OffsetFromSurface); } return(new ObjectSnapResult(surfaceHit.HitPlane, surfaceHit.HitPoint)); } } 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(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -radiusDir); var collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 sitPoint = sphereCenter + radiusDir * sphereRadius; Plane sitPlane = new Plane(radiusDir, sitPoint); Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, sitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); return(new ObjectSnapResult(sitPlane, sitPoint)); } } } if (snapConfig.SurfaceType == Type.SceneGrid) { OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new ObjectSnapResult()); } Transform rootTransform = root.transform; if (snapConfig.AlignAxis) { rootTransform.Align(snapConfig.SurfaceHitNormal, snapConfig.AlignmentAxis); hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); } rootTransform.position += Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, snapConfig.SurfaceHitPlane, snapConfig.OffsetFromSurface); return(new ObjectSnapResult(snapConfig.SurfaceHitPlane, snapConfig.SurfaceHitPlane.ProjectPoint(hierarchyOOBB.Center))); } return(new ObjectSnapResult()); }
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; OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new List <Vector3>()); } int faceAxisIndex = BoxMath.GetFaceAxisIndex(collectFace); Vector3 faceCenter = BoxMath.CalcBoxFaceCenter(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, collectFace); Vector3 faceNormal = BoxMath.CalcBoxFaceNormal(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, collectFace); float sizeEps = collectEps * 2.0f; Vector3 collectAABBSize = hierarchyOOBB.Size; collectAABBSize[faceAxisIndex] = (hierarchyOOBB.Size[faceAxisIndex] * collectBoxScale) + sizeEps; collectAABBSize[(faceAxisIndex + 1) % 3] += sizeEps; collectAABBSize[(faceAxisIndex + 2) % 3] += sizeEps; OOBB collectOOBB = new OOBB(faceCenter + faceNormal * (-collectAABBSize[faceAxisIndex] * 0.5f + collectEps), collectAABBSize); collectOOBB.Rotation = hierarchyOOBB.Rotation; var collectedVerts = new List <Vector3>(80); foreach (var meshObject in meshObjects) { Mesh mesh = meshObject.GetMesh(); EditorMesh editorMesh = EditorMeshDb.Get.GetEditorMesh(mesh); if (editorMesh == null) { continue; } var verts = editorMesh.OverlapVerts(collectOOBB, meshObject.transform); if (verts.Count != 0) { collectedVerts.AddRange(verts); } } foreach (var spriteObject in spriteObjects) { var verts = CollectWorldSpriteVerts(spriteObject.GetSprite(), spriteObject.transform, collectOOBB); if (verts.Count != 0) { collectedVerts.AddRange(verts); } } return(collectedVerts); }
public List <GameObjectRayHit> RaycastAll(Ray ray, SceneRaycastPrecision raycastPresicion) { var nodeHits = _objectTree.RaycastAll(ray); if (nodeHits.Count == 0) { return(new List <GameObjectRayHit>()); } var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; boundsQConfig.NoVolumeSize = EditorScene.Get.NoVolumeObjectSize; if (raycastPresicion == SceneRaycastPrecision.BestFit) { var hitList = new List <GameObjectRayHit>(10); foreach (var nodeHit in nodeHits) { 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) { hitList.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)) { hitList.Add(new GameObjectRayHit(ray, hitInfo)); } } } else if (objectType == GameObjectType.Sprite) { GameObjectRayHit objectHit = RaycastSpriteObject(ray, sceneObject); if (objectHit != null) { hitList.Add(objectHit); } } else { OOBB worldOOBB = ObjectBounds.CalcWorldOOBB(sceneObject, boundsQConfig); if (worldOOBB.IsValid) { float t; if (BoxMath.Raycast(ray, out t, worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation)) { var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation); var hit = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t); hitList.Add(hit); } } } } return(hitList); } else if (raycastPresicion == SceneRaycastPrecision.Box) { var hitList = new List <GameObjectRayHit>(10); foreach (var nodeHit in nodeHits) { GameObject sceneObject = nodeHit.HitNode.Data; if (sceneObject == null || !sceneObject.activeInHierarchy) { continue; } Renderer renderer = sceneObject.GetComponent <Renderer>(); if (renderer != null && !renderer.isVisible) { continue; } OOBB worldOOBB = ObjectBounds.CalcWorldOOBB(sceneObject, boundsQConfig); if (worldOOBB.IsValid) { float t; if (BoxMath.Raycast(ray, out t, worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation)) { var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation); var hit = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t); hitList.Add(hit); } } } return(hitList); } return(new List <GameObjectRayHit>()); }
public static List <Vector3> CollectWorldSpriteVerts(Sprite sprite, Transform spriteTransform, OOBB collectOOBB) { var spriteWorldVerts = sprite.GetWorldVerts(spriteTransform); var collectedVerts = new List <Vector3>(7); foreach (var vertPos in spriteWorldVerts) { if (BoxMath.ContainsPoint(vertPos, collectOOBB.Center, collectOOBB.Size, collectOOBB.Rotation)) { collectedVerts.Add(vertPos); } } return(collectedVerts); }
public List <GameObject> OverlapBox(OOBB oobb) { return(_sceneTree.OverlapBox(oobb)); }