public static GameObject SpawnInFrontOfCamera(GameObject sourceObject, Camera camera, float objectSize) { float halfSize = objectSize * 0.5f; var 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; OBB spawnedOBB = ObjectBounds.CalcHierarchyWorldOBB(spawned, boundsQConfig); Ray ray = new Ray(camera.transform.position, (spawnedOBB.Center - camera.transform.position).normalized); var raycastFilter = new SceneRaycastFilter(); raycastFilter.AllowedObjectTypes.Add(GameObjectType.Mesh); var 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 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 void RegisterObject(GameObject gameObject) { if (!CanRegisterObject(gameObject)) { return; } var 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(); }
public void Focus(List <GameObject> gameObjects) { var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.NoVolumeSize = Vector3.one * 0.01f; boundsQConfig.ObjectTypes = GameObjectType.Mesh | GameObjectType.Sprite | GameObjectType.Terrain; AABB focusAABB = ObjectBounds.CalcObjectCollectionWorldAABB(gameObjects, boundsQConfig); if (focusAABB.IsValid) { Focus(focusAABB); } // var parents = GameObjectEx.FilterParentsOnly(gameObjects); // if (parents.Count != 0) // { // AABB focusAABB = ObjectBounds.CalcHierarchyCollectionWorldAABB(parents, boundsQConfig); // if (focusAABB.IsValid) Focus(focusAABB); // } }
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); RTFocusCamera.Get.GetVisibleObjects(_visibleObjectBuffer); List <GameObject> targetObjects = new List <GameObject>(_targetObjects); _visibleObjectBuffer.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 _visibleObjectBuffer) { if (!CanUseObjectAsSnapDestination(visibleObject)) { continue; } GameObjectType objectType = visibleObject.GetGameObjectType(); if (objectType == GameObjectType.Mesh || objectType == GameObjectType.Sprite) { _destinationObjects.Add(visibleObject); } } }
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 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 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)); } var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectType.Mesh | GameObjectType.Sprite; Vector3 overlapSizeAdd = Vector3.one * snapConfig.SnapRadius * 2.0f; var 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 (var 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; } var sourceSnapData = Object2ObjectSnapDataDb.Get.GetObject2ObjectSnapData(sourceObject); if (sourceSnapData == null) { continue; } sortData.SrcObject = sourceObject; foreach (var srcSnapFace in allSnapFaces) { var srcAreaDesc = sourceSnapData.GetWorldSnapAreaDesc(srcSnapFace); var srcAreaBounds = sourceSnapData.GetWorldSnapAreaBounds(srcSnapFace); var srcAreaPts = srcAreaBounds.GetCenterAndCornerPoints(); sortData.SrcSnapFace = srcSnapFace; foreach (var destObject in nearbyObjects) { var destSnapData = Object2ObjectSnapDataDb.Get.GetObject2ObjectSnapData(destObject); if (destSnapData == null) { continue; } sortData.DestObject = destObject; foreach (var destSnapFace in allSnapFaces) { sortData.DestSnapFace = destSnapFace; var 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; } } var destAreaBounds = destSnapData.GetWorldSnapAreaBounds(destSnapFace); var destAreaPts = destAreaBounds.GetCenterAndCornerPoints(); foreach (var srcPt in srcAreaPts) { sortData.SnapPivot = srcPt; foreach (var 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)); }
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 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 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 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()); }
protected bool GetWorldPointClosestToInputDevice(Camera focusCamera, IEnumerable <GameObject> gameObjects, out Vector3 point) { point = Vector3.zero; if (gameObjects == null) { return(false); } if (!RTInputDevice.Get.Device.HasPointer()) { return(false); } Vector2 inputDeviceScreenPt = RTInputDevice.Get.Device.GetPositionYAxisUp(); float minDistSqr = float.MaxValue; bool foundPoint = false; foreach (var srcObject in gameObjects) { Mesh mesh = srcObject.GetMesh(); if (mesh != null) { MeshVertexChunkCollection meshVChunkCollection = MeshVertexChunkCollectionDb.Get[mesh]; if (meshVChunkCollection == null) { continue; } Matrix4x4 worldMtx = srcObject.transform.localToWorldMatrix; List <MeshVertexChunk> testChunks = meshVChunkCollection.GetWorldChunksHoveredByPoint(inputDeviceScreenPt, worldMtx, focusCamera); if (testChunks.Count == 0) { MeshVertexChunk closestChunk = meshVChunkCollection.GetWorldVertChunkClosestToScreenPt(inputDeviceScreenPt, worldMtx, focusCamera); if (closestChunk != null && closestChunk.VertexCount != 0) { testChunks.Add(closestChunk); } } foreach (var chunk in testChunks) { Vector3 worldVert = chunk.GetWorldVertClosestToScreenPt(inputDeviceScreenPt, worldMtx, focusCamera); Vector2 screenVert = focusCamera.WorldToScreenPoint(worldVert); float distSqr = (inputDeviceScreenPt - screenVert).sqrMagnitude; if (distSqr < minDistSqr) { minDistSqr = distSqr; point = worldVert; foundPoint = true; } } } else { OBB spriteWorldOBB = ObjectBounds.CalcSpriteWorldOBB(srcObject); if (spriteWorldOBB.IsValid) { List <Vector3> obbPoints = spriteWorldOBB.GetCenterAndCornerPoints(); List <Vector2> screenPoints = focusCamera.ConvertWorldToScreenPoints(obbPoints); int closestPtIndex = Vector2Ex.GetPointClosestToPoint(screenPoints, inputDeviceScreenPt); if (closestPtIndex >= 0) { Vector2 closestPt = screenPoints[closestPtIndex]; float distSqr = (inputDeviceScreenPt - closestPt).sqrMagnitude; if (distSqr < minDistSqr) { minDistSqr = distSqr; point = obbPoints[closestPtIndex]; foundPoint = true; } } } } } return(foundPoint); }