private void KeepSnappedHierarchyInSnapSurfaceArea(GameObject hierarchyRoot, ProjectedBoxFacePivotPoints projectedHierarchyBoxFacePivotPoints) { OrientedBox hierarchyWorldOrientedBox = hierarchyRoot.GetHierarchyWorldOrientedBox(); List <Vector3> worldBoxPoints = hierarchyWorldOrientedBox.GetCenterAndCornerPoints(); XZOrientedQuad3D snapSurfaceQuad = _objectSnapSurface.SurfaceQuad; List <Plane> quadSegmentPlanes = snapSurfaceQuad.GetBoundarySegmentPlanesFacingOutward(); List <Vector3> pushVectors = new List <Vector3>(quadSegmentPlanes.Count); // All box points which are in front of the surface quad's plane are outside // the surface so we will have to push them back. for (int segmentPlaneIndex = 0; segmentPlaneIndex < quadSegmentPlanes.Count; ++segmentPlaneIndex) { Plane segmentPlane = quadSegmentPlanes[segmentPlaneIndex]; Vector3 furthestPointInFront; if (segmentPlane.GetFurthestPointInFront(worldBoxPoints, out furthestPointInFront)) { Vector3 projectedPoint = segmentPlane.ProjectPoint(furthestPointInFront); pushVectors.Add(projectedPoint - furthestPointInFront); } } Transform hierarchyRootTransform = hierarchyRoot.transform; foreach (Vector3 pushVector in pushVectors) { hierarchyRootTransform.position += pushVector; projectedHierarchyBoxFacePivotPoints.MovePoints(pushVector); } }
private void RenderAllPivotPoints(ProjectedBoxFacePivotPoints projectedBoxFacePivotPoints, ObjectPivotPointsRenderSettings pivotPointsRenderSettings) { List <Vector3> allPivotPoints = projectedBoxFacePivotPoints.AllPoints; if (allPivotPoints.Count != 0) { ProjectedBoxFacePivotPointsRenderSettings renderSettings = pivotPointsRenderSettings.ProjectedBoxFacePivotPointsRenderSettings; IPivotPointRenderer objectPivotPointRenderer = PivotPointRendererFactory.Create(pivotPointsRenderSettings.ShapeType); Color activePivotPointFillColor = renderSettings.ActivePivotPointRenderSettings.FillColor; Color inactivePivotPointFillColor = renderSettings.InactivePivotPointRenderSettings.FillColor; Color activePivotPointBorderLineColor = renderSettings.ActivePivotPointRenderSettings.BorderLineColor; Color inactivePivotPointBorderLineColor = renderSettings.InactivePivotPointRenderSettings.BorderLineColor; float pivotPointSizeInPixels = pivotPointsRenderSettings.PivotPointSizeInPixels; float activePivotPointScale = renderSettings.ActivePivotPointRenderSettings.Scale; float inactivePivotPointScale = renderSettings.InactivePivotPointRenderSettings.Scale; if (renderSettings.InactivePivotPointRenderSettings.IsVisible) { for (int pivotPointIndex = 0; pivotPointIndex < allPivotPoints.Count; ++pivotPointIndex) { if (pivotPointIndex != projectedBoxFacePivotPoints.IndexOfActivePoint) { objectPivotPointRenderer.Render(allPivotPoints[pivotPointIndex], inactivePivotPointFillColor, inactivePivotPointBorderLineColor, pivotPointSizeInPixels * inactivePivotPointScale); } } } if (renderSettings.ActivePivotPointRenderSettings.IsVisible) { objectPivotPointRenderer.Render(allPivotPoints[projectedBoxFacePivotPoints.IndexOfActivePoint], activePivotPointFillColor, activePivotPointBorderLineColor, pivotPointSizeInPixels * activePivotPointScale); } } }
public void SnapHierarchyToNearbyObjects(GameObject hierarchyRoot, ProjectedBoxFacePivotPoints projectedBoxFacePivotPoints) { Object2ObjectSnap.SnapResult snapResult = Object2ObjectSnap.Snap(hierarchyRoot, Settings.ObjectToObjectSnapEpsilon, ObjectSnapping.Get().ObjectSnapMask.ObjectCollectionMask.GetAllMaskedGameObjects()); if (snapResult.WasSnapped) { projectedBoxFacePivotPoints.MovePoints(snapResult.SnapDestination - snapResult.SnapPivot); } }
public ProjectedBoxFacePivotPoints TakeSnapshot() { var projectedBoxFacePivotPoints = new ProjectedBoxFacePivotPoints(); projectedBoxFacePivotPoints._pivotPointCollection = _pivotPointCollection.TakeSnapshot(); projectedBoxFacePivotPoints._unprojectedPivotPoints = GetUnprojectedPivotPoints(); projectedBoxFacePivotPoints._pointsPlane = PointsPlane; return(projectedBoxFacePivotPoints); }
public void RenderGizmos(ProjectedBoxFacePivotPoints projectedBoxFacePivotPoints, ObjectPivotPointsRenderSettings pivotPointsRenderSettings) { if (ObjectPlacementGuide.ExistsInSceneAndIsActive && SceneViewCamera.Instance.IsGameObjectHierarchyVisible(ObjectPlacementGuide.SceneObject)) { RenderPivotPointConnectionLines(projectedBoxFacePivotPoints, pivotPointsRenderSettings); RenderPivotPointProjectionLines(projectedBoxFacePivotPoints, pivotPointsRenderSettings); RenderAllPivotPoints(projectedBoxFacePivotPoints, pivotPointsRenderSettings); } }
private void RenderPivotPointConnectionLines(ProjectedBoxFacePivotPoints projectedBoxFacePivotPoints, ObjectPivotPointsRenderSettings pivotPointsRenderSettings) { ProjectedBoxFacePivotPointsRenderSettings renderSettings = pivotPointsRenderSettings.ProjectedBoxFacePivotPointsRenderSettings; if (renderSettings.RenderPivotPointConnectionLines) { List <Vector3> pivotPointsNoCenter = projectedBoxFacePivotPoints.GetAllPointsExcludingCenter(); if (pivotPointsNoCenter.Count != 0) { GizmosEx.RenderLinesBetweenPoints(pivotPointsNoCenter, renderSettings.PivotPointConnectionLineColor); } } }
public void SnapObjectHierarchy(GameObject hierarchyRoot, ProjectedBoxFacePivotPoints projectedBoxFacePivotPoints, float offsetFromSnapSurface) { _objectSnapSurface.FromMouseCursorRayHit(GetCursorRayHit()); if (_objectSnapSurface.IsValid) { OrientedBox hierarchyWorldOrientedBox = hierarchyRoot.GetHierarchyWorldOrientedBox(); if (!hierarchyWorldOrientedBox.IsValid()) { return; } Vector3 pivotPoint = projectedBoxFacePivotPoints.ActivePoint; if (Settings.UseOriginalPivot) { pivotPoint = hierarchyRoot.transform.position; } if (Settings.SnapToCursorHitPoint || Settings.EnableObjectToObjectSnap) { SnapObjectHierarchyPosition(hierarchyRoot, pivotPoint, _objectSnapSurface.CursorPickPoint, projectedBoxFacePivotPoints, offsetFromSnapSurface); } else { if (_objectSnapSurface.SurfaceType == SnapSurfaceType.GridCell && Settings.SnapCenterToCenterForXZGrid && !Settings.UseOriginalPivot) { SnapObjectHierarchyToCenterOfSnapSurface(hierarchyRoot, projectedBoxFacePivotPoints.CenterPoint, projectedBoxFacePivotPoints, offsetFromSnapSurface); } else if (_objectSnapSurface.SurfaceType == SnapSurfaceType.ObjectCollider && Settings.SnapCenterToCenterForObjectSurface && !Settings.UseOriginalPivot) { SnapObjectHierarchyToCenterOfSnapSurface(hierarchyRoot, projectedBoxFacePivotPoints.CenterPoint, projectedBoxFacePivotPoints, offsetFromSnapSurface); } else { SnapObjectHierarchyPosition(hierarchyRoot, pivotPoint, _objectSnapSurface.GetSnapDestinationPointClosestToCursorPickPoint(), projectedBoxFacePivotPoints, offsetFromSnapSurface); } if (AllShortcutCombos.Instance.KeepSnappedHierarchyInSnapSurfaceArea.IsActive()) { KeepSnappedHierarchyInSnapSurfaceArea(hierarchyRoot, projectedBoxFacePivotPoints); } } if (Settings.EnableObjectToObjectSnap) { SnapHierarchyToNearbyObjects(hierarchyRoot, projectedBoxFacePivotPoints); } } }
private void RenderPivotPointProjectionLines(ProjectedBoxFacePivotPoints projectedBoxFacePivotPoints, ObjectPivotPointsRenderSettings pivotPointsRenderSettings) { ProjectedBoxFacePivotPointsRenderSettings renderSettings = pivotPointsRenderSettings.ProjectedBoxFacePivotPointsRenderSettings; if (renderSettings.RenderProjectionLines) { List <Vector3> allPivotPoints = projectedBoxFacePivotPoints.AllPoints; if (allPivotPoints.Count != 0) { Color projectionLineColor = renderSettings.ProjectionLineColor; List <Vector3> unprojectedPoints = projectedBoxFacePivotPoints.GetUnprojectedPivotPoints(); for (int pointIndex = 0; pointIndex < unprojectedPoints.Count; ++pointIndex) { GizmosEx.RenderLine(allPivotPoints[pointIndex], unprojectedPoints[pointIndex], projectionLineColor); } } } }
public void UpdateProjectedBoxFacePivotPoints(GameObject hierarchyRoot, ProjectedBoxFacePivotPoints projectedBoxFacePivotPoints, bool keepCurrentSnapSurface) { OrientedBox hierarchyWorldOrientedBox = hierarchyRoot.GetHierarchyWorldOrientedBox(); if (!hierarchyWorldOrientedBox.IsValid()) { return; } if (keepCurrentSnapSurface) { if (!_objectSnapSurface.IsValid) { return; } projectedBoxFacePivotPoints.FromOrientedBoxAndSnapSurface(hierarchyWorldOrientedBox, _objectSnapSurface); } else { _objectSnapSurface.FromMouseCursorRayHit(GetCursorRayHit()); projectedBoxFacePivotPoints.FromOrientedBoxAndSnapSurface(hierarchyWorldOrientedBox, _objectSnapSurface); } }
private void SnapObjectHierarchyPosition(GameObject hierarchyRoot, Vector3 snapPivotPoint, Vector3 snapDestinationPoint, ProjectedBoxFacePivotPoints projectedBoxFacePivotPoints, float offsetFromSnapSurface) { snapDestinationPoint += _objectSnapSurface.Plane.normal * offsetFromSnapSurface; Transform hierarchyRootTransform = hierarchyRoot.transform; Vector3 snapVector = hierarchyRootTransform.position - snapPivotPoint; hierarchyRootTransform.position = snapDestinationPoint + snapVector; projectedBoxFacePivotPoints.MovePoints(snapDestinationPoint - snapPivotPoint); }
public void SnapObjectHierarchyToCenterOfSnapSurface(GameObject hierarchyRoot, Vector3 snapPivotPoint, ProjectedBoxFacePivotPoints projectedBoxFacePivotPoints, float offsetFromSnapSurface) { _objectSnapSurface.FromMouseCursorRayHit(GetCursorRayHit()); if (_objectSnapSurface.IsValid) { OrientedBox hierarchyWorldOrientedBox = hierarchyRoot.GetHierarchyWorldOrientedBox(); if (!hierarchyWorldOrientedBox.IsValid()) { return; } SnapObjectHierarchyPosition(hierarchyRoot, snapPivotPoint, _objectSnapSurface.Center, projectedBoxFacePivotPoints, offsetFromSnapSurface); } }
public void SnapHierarchyToNearbyObjects(GameObject hierarchyRoot, ProjectedBoxFacePivotPoints projectedBoxFacePivotPoints) { Vector3 chosenSnapDestination = Vector3.zero, chosenSnapPivot = Vector3.zero; float minDistance = float.MaxValue; float snapEpsilon = Settings.ObjectToObjectSnapEpsilon; // Snapping will only work if there is at least one mesh object in the hierarchy or at least one sprite renderer // with a valid sprite. So we will first get that out of the way. If this condition is not met, we will just return. List <GameObject> meshObjectsInHierarchy = hierarchyRoot.GetHierarchyObjectsWithMesh(); List <GameObject> spriteObjectsInHierarchy = hierarchyRoot.GetHierarchyObjectsWithSprites(); if (meshObjectsInHierarchy.Count == 0 && spriteObjectsInHierarchy.Count == 0) { return; } // When snapping, we will need to collect the nearby snap destination points (e.g. vertices or box corner points). // In order to do this we will perform an overlap test using the hierarchy's world box. The size of the box is // increased by 'snapEpsilon' on all axes to account for the snap espilon. Box hierarchyWorldBox = hierarchyRoot.GetHierarchyWorldBox(); if (!hierarchyWorldBox.IsValid()) { return; } Box hierarchyQueryBox = hierarchyWorldBox; hierarchyQueryBox.Size = hierarchyQueryBox.Size + Vector3.one * snapEpsilon; // Acquire the nearby objects that contain the possible snap destination points List <GameObject> nearbyObjects = Octave3DScene.Get().OverlapBox(hierarchyQueryBox); if (nearbyObjects.Count == 0) { return; } // If the user chose vertex snapping, we will only continue if we have at least one mesh in our hierarchy. // Otherwise we will resort to box snapping. if (Settings.ObjectToObjectSnapMode == ObjectToObjectSnapMode.Vertex && meshObjectsInHierarchy.Count != 0) { foreach (GameObject gameObject in nearbyObjects) { Box objectWorldBox = Box.GetInvalid(); // We will first attempt to retrieve the mesh's world box Mesh objectMesh = gameObject.GetMeshFromFilterOrSkinnedMeshRenderer(); bool objectHasMesh = objectMesh != null; Octave3DMesh objectOctave3DMesh = Octave3DMeshDatabase.Get().GetOctave3DMesh(objectMesh); if (objectOctave3DMesh == null) { objectHasMesh = false; } if (objectHasMesh) { objectWorldBox = gameObject.GetMeshWorldBox(); } // If the world box is still invalid, we will acquire the object's sprite world box. if (objectWorldBox.IsInvalid()) { if (gameObject.HasSpriteRendererWithSprite()) { objectWorldBox = gameObject.GetNonMeshWorldBox(); } } // If at this point the box is still invalid, it most likely means that the object doesn't have // a mesh or a sprite attached to it, so we will go on to the next iteration of the loop. if (objectWorldBox.IsInvalid()) { continue; } Box objectQueryBox = objectWorldBox; objectQueryBox.Size += Vector3.one * snapEpsilon; // At this point, we have a valid world box, but we need to check if it comes from a mesh or from // a sprite. If it's from a mesh, we will perform the vertex-to-vertex snap. Otherwise, we will // snap the vertices of all meshes in our hierarchy to the corner points of the sprite. if (objectHasMesh) { // Detect the object vertices which are overlapped by the hierarchy box List <Vector3> objectOverlappedVerts = objectOctave3DMesh.GetOverlappedWorldVerts(hierarchyQueryBox, gameObject.transform.GetWorldMatrix()); // Loop through all meshes in the hierarchy foreach (var meshObjInHierarchy in meshObjectsInHierarchy) { Mesh hierarchyMesh = meshObjInHierarchy.GetMeshFromFilterOrSkinnedMeshRenderer(); if (hierarchyMesh == null) { continue; } Octave3DMesh hierarchyOctave3DMesh = Octave3DMeshDatabase.Get().GetOctave3DMesh(hierarchyMesh); if (hierarchyOctave3DMesh == null) { continue; } // Detect all vertices inside the mesh which are overlapped by the object's box (inverse operation of what we performed in the // beginning). The idea is to collect all source vertices that could pottentially intersect with each other. List <Vector3> hierarchyMeshOverlappedVerts = hierarchyOctave3DMesh.GetOverlappedWorldVerts(objectQueryBox, meshObjInHierarchy.transform.GetWorldMatrix()); foreach (Vector3 hierarchyVertex in hierarchyMeshOverlappedVerts) { foreach (Vector3 objectVertex in objectOverlappedVerts) { float distance = (hierarchyVertex - objectVertex).magnitude; if (distance < minDistance) { minDistance = distance; chosenSnapDestination = objectVertex; chosenSnapPivot = hierarchyVertex; } } } } } else { List <Vector3> spriteWorldCornerPoints = objectWorldBox.GetCornerPoints(); foreach (var meshObjInHierarchy in meshObjectsInHierarchy) { Mesh hierarchyMesh = meshObjInHierarchy.GetMeshFromFilterOrSkinnedMeshRenderer(); if (hierarchyMesh == null) { continue; } Octave3DMesh hierarchyOctave3DMesh = Octave3DMeshDatabase.Get().GetOctave3DMesh(hierarchyMesh); if (hierarchyOctave3DMesh == null) { continue; } List <Vector3> hierarchyMeshOverlappedVerts = hierarchyOctave3DMesh.GetOverlappedWorldVerts(objectQueryBox, meshObjInHierarchy.transform.GetWorldMatrix()); foreach (Vector3 hierarchyVertex in hierarchyMeshOverlappedVerts) { foreach (Vector3 spriteCornerPt in spriteWorldCornerPoints) { float distance = (hierarchyVertex - spriteCornerPt).magnitude; if (distance < minDistance) { minDistance = distance; chosenSnapDestination = spriteCornerPt; chosenSnapPivot = hierarchyVertex; } } } } } } } else { List <Vector3> hierarchyBoxCornerPoints = hierarchyWorldBox.GetCornerPoints(); foreach (GameObject gameObject in nearbyObjects) { Box objectWorldBox = Box.GetInvalid(); Mesh objectMesh = gameObject.GetMeshFromFilterOrSkinnedMeshRenderer(); if (objectMesh != null) { objectWorldBox = gameObject.GetMeshWorldBox(); } if (objectWorldBox.IsInvalid() && gameObject.HasSpriteRendererWithSprite()) { objectWorldBox = gameObject.GetNonMeshWorldBox(); } if (objectWorldBox.IsInvalid()) { continue; } List <Vector3> worldBoxCornerPoints = objectWorldBox.GetCornerPoints(); foreach (Vector3 hierarchyBoxPt in hierarchyBoxCornerPoints) { foreach (Vector3 objectMeshBoxPt in worldBoxCornerPoints) { float distance = (hierarchyBoxPt - objectMeshBoxPt).magnitude; if (distance < minDistance) { minDistance = distance; chosenSnapDestination = objectMeshBoxPt; chosenSnapPivot = hierarchyBoxPt; } } } } } if (minDistance < snapEpsilon) { SnapObjectHierarchyPosition(hierarchyRoot, chosenSnapPivot, chosenSnapDestination, projectedBoxFacePivotPoints, 0.0f); } }