public void OnObjectTransformChanged(Transform objectTransform) { var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; boundsQConfig.NoVolumeSize = Vector3Ex.FromValue(RTScene.Get.Settings.NonMeshObjectSize); AABB worldAABB = ObjectBounds.CalcWorldAABB(objectTransform.gameObject, boundsQConfig); Sphere worldSphere = new Sphere(worldAABB); SphereTreeNode <GameObject> objectNode = _objectToNode[objectTransform.gameObject]; objectNode.Sphere = worldSphere; _objectTree.OnNodeSphereUpdated(objectNode); RTFocusCamera.Get.SetObjectVisibilityDirty(); }
public static GameObject SpawnInFrontOfCamera(GameObject sourceObject, Camera camera, Config config) { float halfSize = config.ObjectSize * 0.5f; ObjectBounds.QueryConfig boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; boundsQConfig.NoVolumeSize = Vector3Ex.FromValue(1.0f); Transform cameraTransform = camera.transform; AABB aabb = ObjectBounds.CalcHierarchyWorldAABB(sourceObject, boundsQConfig); if (!aabb.IsValid) { return(null); } Sphere sphere = new Sphere(aabb); Vector3 fromCenterToPos = sourceObject.transform.position - sphere.Center; float zOffset = Mathf.Max(camera.nearClipPlane + sphere.Radius, sphere.Radius / halfSize); Vector3 spherePos = cameraTransform.position + cameraTransform.forward * zOffset; GameObject spawned = GameObject.Instantiate(sourceObject, spherePos + fromCenterToPos, sourceObject.transform.rotation) as GameObject; spawned.SetActive(true); OBB spawnedOBB = ObjectBounds.CalcHierarchyWorldOBB(spawned, boundsQConfig); Ray ray = new Ray(camera.transform.position, (spawnedOBB.Center - camera.transform.position).normalized); SceneRaycastFilter raycastFilter = new SceneRaycastFilter(); raycastFilter.AllowedObjectTypes.Add(GameObjectType.Mesh); raycastFilter.AllowedObjectTypes.Add(GameObjectType.Terrain); raycastFilter.AllowedObjectTypes.Add(GameObjectType.Sprite); SceneRaycastHit rayHit = RTScene.Get.Raycast(ray, SceneRaycastPrecision.BestFit, raycastFilter); if (rayHit.WasAnObjectHit) { Vector3 oldCenter = spawnedOBB.Center; spawnedOBB.Center = rayHit.ObjectHit.HitPoint; Vector3 offsetVector = spawnedOBB.Center - oldCenter; offsetVector += ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(spawnedOBB, rayHit.ObjectHit.HitPlane, 0.0f); spawned.transform.position += offsetVector; } return(spawned); }
private static void AlignRootsToPlane(List <GameObject> roots, Plane alignmentPlane) { var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.NoVolumeSize = Vector3.zero; boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; foreach (var root in roots) { OBB worldOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (worldOBB.IsValid) { Vector3 projectedCenter = alignmentPlane.ProjectPoint(worldOBB.Center); root.transform.position += (projectedCenter - worldOBB.Center); } } }
public bool OverlapsObject(GameObject gameObject, Camera camera, ObjectBounds.QueryConfig boundsQConfig, MultiSelectOverlapMode overlapMode) { if (!IsBigEnoughForOverlap()) { return(false); } if (overlapMode == MultiSelectOverlapMode.Partial) { Rect objectScreenRect = ObjectBounds.CalcScreenRect(gameObject, camera, boundsQConfig); return(_enclosingRect.Overlaps(objectScreenRect, true)); } else { Rect objectScreenRect = ObjectBounds.CalcScreenRect(gameObject, camera, boundsQConfig); return(_enclosingRect.ContainsAllPoints(objectScreenRect.GetCornerPoints())); } }
private void SnapToObjectHitPoint(GameObjectRayHit objectHit, SnapToPointMode snapMode) { if (snapMode == SnapToPointMode.Exact) { float distToPlane = new Plane(Normal, Vector3.zero).GetDistanceToPoint(objectHit.HitPoint); YOffset = distToPlane; } else { ObjectBounds.QueryConfig 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; List <Vector3> 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 void RegisterObject(GameObject gameObject) { if (!CanRegisterObject(gameObject)) { return; } ObjectBounds.QueryConfig boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; boundsQConfig.NoVolumeSize = Vector3Ex.FromValue(RTScene.Get.Settings.NonMeshObjectSize); AABB worldAABB = ObjectBounds.CalcWorldAABB(gameObject, boundsQConfig); Sphere worldSphere = new Sphere(worldAABB); SphereTreeNode <GameObject> objectNode = _objectTree.AddNode(gameObject, worldSphere); _objectToNode.Add(gameObject, objectNode); RTFocusCamera.Get.SetObjectVisibilityDirty(); }
private void GatherDestinationObjects() { Camera focusCamera = RTFocusCamera.Get.TargetCamera; _destinationObjects.Clear(); IInputDevice inputDevice = RTInputDevice.Get.Device; if (!inputDevice.HasPointer()) { return; } Vector2 inputDevicePos = inputDevice.GetPositionYAxisUp(); var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; boundsQConfig.NoVolumeSize = Vector3Ex.FromValue(1e-5f); List <GameObject> visibleObjects = RTFocusCamera.Get.GetVisibleObjects(); List <GameObject> targetObjects = new List <GameObject>(_targetObjects); visibleObjects.RemoveAll(a => targetObjects.Contains(a) || !ObjectBounds.CalcScreenRect(a, focusCamera, boundsQConfig).Contains(inputDevicePos) || targetObjects.FindAll(b => a.transform.IsChildOf(b.transform)).Count != 0); foreach (var visibleObject in visibleObjects) { if (!CanUseObjectAsSnapDestination(visibleObject)) { continue; } GameObjectType objectType = visibleObject.GetGameObjectType(); if (objectType == GameObjectType.Mesh || objectType == GameObjectType.Sprite) { _destinationObjects.Add(visibleObject); } } }
private void SelectPivot() { if (!RTInputDevice.Get.Device.HasPointer()) { return; } ObjectBounds.QueryConfig boundsQConfig = GetObjectBoundsQConfig(); Vector2 inputDevicePos = RTInputDevice.Get.Device.GetPositionYAxisUp(); float minDistFromDevice = float.MaxValue; foreach (GameObject targetObject in _targetObjects) { if (targetObject == null) { continue; } OBB worldOBB = ObjectBounds.CalcWorldOBB(targetObject, boundsQConfig); if (worldOBB.IsValid) { Camera camera = RTFocusCamera.Get.TargetCamera; List <Vector3> centerAndCorners = worldOBB.GetCenterAndCornerPoints(); List <Vector2> screenCenterAndCorners = camera.ConvertWorldToScreenPoints(centerAndCorners); for (int ptIndex = 0; ptIndex < screenCenterAndCorners.Count; ++ptIndex) { float distance = (inputDevicePos - screenCenterAndCorners[ptIndex]).magnitude; if (distance < minDistFromDevice) { minDistFromDevice = distance; _snapPivotPoint = centerAndCorners[ptIndex]; } } } } }
public AABB CalculateBounds() { var activeScene = SceneManager.GetActiveScene(); var roots = new List <GameObject>(Mathf.Max(10, activeScene.rootCount)); SceneManager.GetActiveScene().GetRootGameObjects(roots); var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.NoVolumeSize = Vector3.zero; boundsQConfig.ObjectTypes = GameObjectType.Mesh | GameObjectType.Sprite; AABB sceneAABB = new AABB(); foreach (var root in roots) { var allChildrenAndSelf = root.GetAllChildrenAndSelf(); foreach (var sceneObject in allChildrenAndSelf) { AABB aabb = ObjectBounds.CalcWorldAABB(sceneObject, boundsQConfig); if (aabb.IsValid) { if (sceneAABB.IsValid) { sceneAABB.Encapsulate(aabb); } else { sceneAABB = aabb; } } } } return(sceneAABB); }
public void Render() { if (SharedLookAndFeel == null) { return; } if (IsActive && _grabSurfaceInfo.SurfaceType != GrabSurfaceType.Invalid) { Material material = MaterialPool.Get.SimpleColor; if (SharedLookAndFeel.DrawAnchorLines) { List <Vector3> linePoints = new List <Vector3>(_grabTargets.Count * 2); foreach (GrabTarget grabTarget in _grabTargets) { linePoints.Add(grabTarget.Transform.position); linePoints.Add(_grabSurfaceInfo.AnchorPoint); } material.SetZTestAlways(); material.SetColor(_sharedLookAndFeel.AnchorLineColor); material.SetPass(0); GLRenderer.DrawLines3D(linePoints); } if (SharedLookAndFeel.DrawObjectBoxes) { material.SetZTestLess(); material.SetColor(SharedLookAndFeel.ObjectBoxWireColor); material.SetPass(0); ObjectBounds.QueryConfig boundsQConfig = GetObjectBoundsQConfig(); foreach (GrabTarget grabTarget in _grabTargets) { OBB obb = ObjectBounds.CalcHierarchyWorldOBB(grabTarget.GameObject, boundsQConfig); if (obb.IsValid) { GraphicsEx.DrawWireBox(obb); } } } if (SharedLookAndFeel.DrawObjectPosTicks) { material.SetColor(SharedLookAndFeel.ObjectPosTickColor); material.SetPass(0); foreach (GrabTarget grabTarget in _grabTargets) { Vector2 screenPos = Camera.current.WorldToScreenPoint(grabTarget.Transform.position); GLRenderer.DrawRect2D(RectEx.FromCenterAndSize(screenPos, Vector2Ex.FromValue(SharedLookAndFeel.ObjectPosTickSize)), Camera.current); } } if (SharedLookAndFeel.DrawAnchorPosTick) { material.SetColor(SharedLookAndFeel.AnchorPosTickColor); material.SetPass(0); Vector2 anchorScreenPos = Camera.current.WorldToScreenPoint(_grabSurfaceInfo.AnchorPoint); GLRenderer.DrawRect2D(RectEx.FromCenterAndSize(anchorScreenPos, Vector2Ex.FromValue(SharedLookAndFeel.AnchorPosTickSize)), Camera.current); } } }
public void Render() { if (_sharedLookAndFeel == null) { return; } if (IsActive) { Material material = MaterialPool.Get.SimpleColor; if (_sharedLookAndFeel.DrawBoxes) { material.SetColor(_sharedLookAndFeel.BoxLineColor); material.SetZTestEnabled(true); material.SetPass(0); ObjectBounds.QueryConfig boundsQConfig = GetObjectBoundsQConfig(); foreach (GameObject targetObject in _targetObjects) { if (targetObject == null) { continue; } OBB worldOBB = ObjectBounds.CalcWorldOBB(targetObject, boundsQConfig); if (worldOBB.IsValid) { GraphicsEx.DrawWireBox(worldOBB); } } } Camera camera = Camera.current; Vector2 screenSnapPivot = camera.WorldToScreenPoint(_snapPivotPoint); if (_sharedLookAndFeel.PivotShapeType == PivotPointShapeType.Circle) { material.SetZTestEnabled(false); material.SetColor(_sharedLookAndFeel.PivotPointFillColor); material.SetPass(0); const int numCirclePoints = 100; List <Vector2> pivotCirclePoints = PrimitiveFactory.Generate2DCircleBorderPointsCW(screenSnapPivot, _sharedLookAndFeel.PivotCircleRadius, numCirclePoints); GLRenderer.DrawTriangleFan2D(screenSnapPivot, pivotCirclePoints, camera); if (_sharedLookAndFeel.DrawPivotBorder) { material.SetColor(_sharedLookAndFeel.PivotPointBorderColor); material.SetPass(0); GLRenderer.DrawLineLoop2D(pivotCirclePoints, camera); } } else if (_sharedLookAndFeel.PivotShapeType == PivotPointShapeType.Square) { material.SetZTestEnabled(false); material.SetColor(_sharedLookAndFeel.PivotPointFillColor); material.SetPass(0); Rect pivotRect = RectEx.FromCenterAndSize(screenSnapPivot, Vector2Ex.FromValue(_sharedLookAndFeel.PivotSquareSideLength)); GLRenderer.DrawRect2D(pivotRect, camera); if (_sharedLookAndFeel.DrawPivotBorder) { material.SetColor(_sharedLookAndFeel.PivotPointBorderColor); material.SetPass(0); GLRenderer.DrawRectBorder2D(pivotRect, camera); } } } }
public List <GameObject> GetOverlappedObjects(List <GameObject> gameObjects, Camera camera, ObjectBounds.QueryConfig boundsQConfig, MultiSelectOverlapMode overlapMode) { if (gameObjects.Count == 0 || !IsBigEnoughForOverlap()) { return(new List <GameObject>()); } List <GameObject> overlappedObjects = new List <GameObject>(gameObjects.Count); if (overlapMode == MultiSelectOverlapMode.Partial) { foreach (GameObject gameObject in gameObjects) { Rect objectScreenRect = ObjectBounds.CalcScreenRect(gameObject, camera, boundsQConfig); if (_enclosingRect.Overlaps(objectScreenRect, true)) { overlappedObjects.Add(gameObject); } } } else { foreach (GameObject gameObject in gameObjects) { Rect objectScreenRect = ObjectBounds.CalcScreenRect(gameObject, camera, boundsQConfig); if (_enclosingRect.ContainsAllPoints(objectScreenRect.GetCornerPoints())) { overlappedObjects.Add(gameObject); } } } return(overlappedObjects); }
public List <GameObjectRayHit> RaycastAll(Ray ray, SceneRaycastPrecision raycastPresicion) { List <SphereTreeNodeRayHit <GameObject> > nodeHits = _objectTree.RaycastAll(ray); if (nodeHits.Count == 0) { return(new List <GameObjectRayHit>()); } ObjectBounds.QueryConfig boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; boundsQConfig.NoVolumeSize = Vector3Ex.FromValue(RTScene.Get.Settings.NonMeshObjectSize); Vector3 camLook = RTFocusCamera.Get.Look; if (raycastPresicion == SceneRaycastPrecision.BestFit) { List <GameObjectRayHit> hitList = new List <GameObjectRayHit>(10); foreach (SphereTreeNodeRayHit <GameObject> 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 { OBB worldOBB = ObjectBounds.CalcWorldOBB(sceneObject, boundsQConfig); if (worldOBB.IsValid) { float t; if (BoxMath.Raycast(ray, out t, worldOBB.Center, worldOBB.Size, worldOBB.Rotation)) { BoxFaceDesc faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOBB.Center, worldOBB.Size, worldOBB.Rotation, camLook); GameObjectRayHit hit = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t); hitList.Add(hit); } } } } return(hitList); } else if (raycastPresicion == SceneRaycastPrecision.Box) { List <GameObjectRayHit> hitList = new List <GameObjectRayHit>(10); foreach (SphereTreeNodeRayHit <GameObject> 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; } OBB worldOBB = ObjectBounds.CalcWorldOBB(sceneObject, boundsQConfig); if (worldOBB.IsValid) { float t; if (BoxMath.Raycast(ray, out t, worldOBB.Center, worldOBB.Size, worldOBB.Rotation)) { BoxFaceDesc faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOBB.Center, worldOBB.Size, worldOBB.Rotation, camLook); GameObjectRayHit hit = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t); hitList.Add(hit); } } } return(hitList); } return(new List <GameObjectRayHit>()); }
private OBB CalcTargetRootOBB(GameObject targetRoot) { ObjectBounds.QueryConfig boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectType.Mesh | GameObjectType.Sprite; return(ObjectBounds.CalcHierarchyWorldOBB(targetRoot, boundsQConfig)); }
public static List <Vector3> CollectHierarchyVerts(GameObject root, BoxFace collectFace, float collectBoxScale, float collectEps) { List <GameObject> meshObjects = root.GetMeshObjectsInHierarchy(); List <GameObject> spriteObjects = root.GetSpriteObjectsInHierarchy(); if (meshObjects.Count == 0 && spriteObjects.Count == 0) { return(new List <Vector3>()); } ObjectBounds.QueryConfig 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; List <Vector3> collectedVerts = new List <Vector3>(80); foreach (GameObject meshObject in meshObjects) { Mesh mesh = meshObject.GetMesh(); RTMesh rtMesh = RTMeshDb.Get.GetRTMesh(mesh); if (rtMesh == null) { continue; } List <Vector3> verts = rtMesh.OverlapVerts(collectOBB, meshObject.transform); if (verts.Count != 0) { collectedVerts.AddRange(verts); } } foreach (GameObject spriteObject in spriteObjects) { List <Vector3> verts = CollectWorldSpriteVerts(spriteObject.GetSprite(), spriteObject.transform, collectOBB); if (verts.Count != 0) { collectedVerts.AddRange(verts); } } return(collectedVerts); }
public static SnapResult CalculateSnapResult(GameObject root, Config snapConfig) { if (snapConfig.IgnoreDestObjects == null) { snapConfig.IgnoreDestObjects = new List <GameObject>(); } List <GameObject> sourceObjects = root.GetAllChildrenAndSelf(); if (sourceObjects.Count > MaxSourceObjects) { return(new SnapResult(SnapFailReson.MaxObjectsExceeded)); } List <GameObject> sourceMeshObjects = root.GetMeshObjectsInHierarchy(); List <GameObject> sourceSpriteObjects = root.GetSpriteObjectsInHierarchy(); if (sourceMeshObjects.Count == 0 && sourceSpriteObjects.Count == 0) { return(new SnapResult(SnapFailReson.InvalidSourceObjects)); } ObjectBounds.QueryConfig boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectType.Mesh | GameObjectType.Sprite; Vector3 overlapSizeAdd = Vector3.one * snapConfig.SnapRadius * 2.0f; List <BoxFace> allSnapFaces = BoxMath.AllBoxFaces; bool tryMatchAreas = (snapConfig.Prefs & Prefs.TryMatchArea) != 0; bool foundMatchingAreas = false; List <SnapSortData> sortedSnapData = new List <SnapSortData>(10); SnapSortData sortData = new SnapSortData(); foreach (GameObject sourceObject in sourceObjects) { OBB overlapOBB = ObjectBounds.CalcWorldOBB(sourceObject, boundsQConfig); overlapOBB.Size = overlapOBB.Size + overlapSizeAdd; List <GameObject> nearbyObjects = RTScene.Get.OverlapBox(overlapOBB); nearbyObjects.RemoveAll(item => item.transform.IsChildOf(root.transform) || snapConfig.IgnoreDestObjects.Contains(item) || !LayerEx.IsLayerBitSet(snapConfig.DestinationLayers, item.layer)); if (nearbyObjects.Count == 0) { continue; } Object2ObjectSnapData sourceSnapData = Object2ObjectSnapDataDb.Get.GetObject2ObjectSnapData(sourceObject); if (sourceSnapData == null) { continue; } sortData.SrcObject = sourceObject; foreach (BoxFace srcSnapFace in allSnapFaces) { BoxFaceAreaDesc srcAreaDesc = sourceSnapData.GetWorldSnapAreaDesc(srcSnapFace); OBB srcAreaBounds = sourceSnapData.GetWorldSnapAreaBounds(srcSnapFace); List <Vector3> srcAreaPts = srcAreaBounds.GetCenterAndCornerPoints(); sortData.SrcSnapFace = srcSnapFace; foreach (GameObject destObject in nearbyObjects) { Object2ObjectSnapData destSnapData = Object2ObjectSnapDataDb.Get.GetObject2ObjectSnapData(destObject); if (destSnapData == null) { continue; } sortData.DestObject = destObject; foreach (BoxFace destSnapFace in allSnapFaces) { sortData.DestSnapFace = destSnapFace; BoxFaceAreaDesc destAreaDesc = destSnapData.GetWorldSnapAreaDesc(destSnapFace); sortData.FaceAreasMatch = false; if (tryMatchAreas && destAreaDesc.AreaType == srcAreaDesc.AreaType) { sortData.FaceAreaDiff = Mathf.Abs(destAreaDesc.Area - srcAreaDesc.Area); if (sortData.FaceAreaDiff <= 1000.0f) { sortData.FaceAreasMatch = true; } } OBB destAreaBounds = destSnapData.GetWorldSnapAreaBounds(destSnapFace); List <Vector3> destAreaPts = destAreaBounds.GetCenterAndCornerPoints(); foreach (Vector3 srcPt in srcAreaPts) { sortData.SnapPivot = srcPt; foreach (Vector3 destPt in destAreaPts) { sortData.SnapDistance = (destPt - srcPt).magnitude; if (sortData.SnapDistance < snapConfig.SnapRadius) { sortData.SnapDest = destPt; sortedSnapData.Add(sortData); if (sortData.FaceAreasMatch) { foundMatchingAreas = true; } } } } } } } } if (sortedSnapData.Count != 0) { if (!tryMatchAreas || !foundMatchingAreas) { sortedSnapData.Sort(delegate(SnapSortData s0, SnapSortData s1) { return(s0.SnapDistance.CompareTo(s1.SnapDistance)); }); } else { while (true) { if (!sortedSnapData[0].FaceAreasMatch) { sortedSnapData.RemoveAt(0); } else { break; } } sortedSnapData.Sort(delegate(SnapSortData s0, SnapSortData s1) { return(s0.FaceAreaDiff.CompareTo(s1.FaceAreaDiff)); }); } return(new SnapResult(sortedSnapData[0].SnapPivot, sortedSnapData[0].SnapDest, sortedSnapData[0].SnapDistance)); } return(new SnapResult(SnapFailReson.NoDestinationFound)); }
private ObjectBounds.QueryConfig GetObjectBoundsQConfig() { ObjectBounds.QueryConfig boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectType.Mesh | GameObjectType.Sprite; return(boundsQConfig); }
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)); } ObjectBounds.QueryConfig 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; SurfaceRaycaster 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); List <Vector3> 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); List <Vector3> 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); List <Vector3> 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); List <Vector3> 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); List <Vector3> 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()); }