public List <Triangle3DIntersectInfo> GetIntersectingTriangles(TransformMatrix thisTransform, Octave3DMesh otherMesh, TransformMatrix otherTransform) { OrientedBox thisOOBB = new OrientedBox(ModelAABB); thisOOBB.Transform(thisTransform); OrientedBox otherOOBB = new OrientedBox(otherMesh.ModelAABB); otherOOBB.Transform(otherTransform); if (thisOOBB.Intersects(otherOOBB)) { List <Triangle3D> thisTriangles = GetOverlappedTriangles(otherOOBB, thisTransform); var output = new List <Triangle3DIntersectInfo>(50); Triangle3DIntersectInfo intersectInfo; for (int thisTriIndex = 0; thisTriIndex < thisTriangles.Count; ++thisTriIndex) { Triangle3D thisTri = thisTriangles[thisTriIndex]; OrientedBox thisTriOOBB = new OrientedBox(thisTri.GetEncapsulatingBox()); List <Triangle3D> otherTriangles = otherMesh.GetOverlappedTriangles(thisTriOOBB, otherTransform); for (int otherTriIndex = 0; otherTriIndex < otherTriangles.Count; ++otherTriIndex) { Triangle3D otherTri = otherTriangles[otherTriIndex]; if (thisTri.IntersectsTriangle(otherTri, out intersectInfo)) { output.Add(intersectInfo); } } } return(output); } else { return(new List <Triangle3DIntersectInfo>()); } }
/// <summary> /// Returns a list of all objects which are overlapped by the specified box. /// </summary> /// <param name="box"> /// The box involved in the overlap query. /// </param> public List <GameObject> OverlapBox(OrientedBox box) { // Retrieve all the sphere tree nodes which are overlapped by the box. If no nodes are overlapped, // we can return an empty list because it means that no objects could possibly be overlapped either. List <SphereTreeNode <GameObject> > allOverlappedNodes = _sphereTree.OverlapBox(box); if (allOverlappedNodes.Count == 0) { return(new List <GameObject>()); } // Loop through all overlapped nodes var overlappedObjects = new List <GameObject>(); foreach (SphereTreeNode <GameObject> node in allOverlappedNodes) { // Store the node's object for easy access GameObject gameObject = node.Data; if (gameObject == null) { continue; } if (!gameObject.activeSelf) { continue; } // We need to perform an additional check. Even though the box overlaps the object's node (which is // a sphere), we must also check if the box overlaps the object's world oriented box. This allows // for better precision. OrientedBox objectWorldOrientedBox = gameObject.GetWorldOrientedBox(); if (box.Intersects(objectWorldOrientedBox)) { overlappedObjects.Add(gameObject); } } return(overlappedObjects); }
public List <Triangle3D> GetOverlappedWorldTriangles(OrientedBox box, TransformMatrix meshTransformMatrix) { // If the tree was not yet build, we need to build it because we need // the triangle information in order to perform the raycast. if (!_wasBuilt) { Build(); } // Work in mesh model space because the tree data exists in model space OrientedBox meshSpaceBox = new OrientedBox(box); Matrix4x4 inverseTransform = meshTransformMatrix.ToMatrix4x4x.inverse; meshSpaceBox.Transform(inverseTransform); List <SphereTreeNode <MeshSphereTreeTriangle> > overlappedNodes = _sphereTree.OverlapBox(meshSpaceBox); if (overlappedNodes.Count == 0) { return(new List <Triangle3D>()); } Box queryBox = Box.FromPoints(meshSpaceBox.GetCenterAndCornerPoints()); var overlappedWorldTriangles = new List <Triangle3D>(50); foreach (var node in overlappedNodes) { int triangleIndex = node.Data.TriangleIndex; MeshTriangleInfo triangleInfo = _octave3DMesh.GetMeshTriangleInfo(triangleIndex); if (triangleInfo.ModelSpaceTriangle.IntersectsBox(queryBox)) { triangleInfo.ModelSpaceTriangle.TransformPoints(meshTransformMatrix); overlappedWorldTriangles.Add(triangleInfo.ModelSpaceTriangle); } } return(overlappedWorldTriangles); }
public void FromOrientedBoxAndDecorStrokeSurface(OrientedBox orientedBox, DecorPaintStrokeSurface decorPaintStrokeSurface) { if (!decorPaintStrokeSurface.IsValid) { return; } Vector3 surfacePlaneNormal = decorPaintStrokeSurface.Plane.normal; if (AllShortcutCombos.Instance.PlaceGuideBehindSurfacePlane.IsActive()) { surfacePlaneNormal *= -1.0f; } BoxFace boxFaceMostAlignedWithSurface = orientedBox.GetBoxFaceWhichFacesNormal(surfacePlaneNormal); List <Vector3> cornerPointsOfFaceMostAlignedWithSurface = orientedBox.GetBoxFaceCornerPoints(boxFaceMostAlignedWithSurface); CalculatePointsPlane(orientedBox, decorPaintStrokeSurface); StoreObjectPivotPoints(_pointsPlane.ProjectAllPoints(cornerPointsOfFaceMostAlignedWithSurface)); StoreUnprojectedPivotPoints(cornerPointsOfFaceMostAlignedWithSurface); CalculateArea(); }
public void SetData(ObjectPlacementPathManualConstructionSessionData sessionData) { if (!_isActive) { _path = sessionData.Path; _pathSegments = sessionData.PathSegments; _pathExtensionPlane = sessionData.PathExtensionPlane; _tileConnectionGridCells = sessionData.TileConnectionGridCells; _startObject = sessionData.StartObject; _startObjectHierarchyWorldOrientedBox = _startObject.GetHierarchyWorldOrientedBox(); _pathSettings = _path.Settings; _tileConnectionSettings = _pathSettings.TileConnectionSettings; _manualConstructionSettings = _pathSettings.ManualConstructionSettings; _heightAdjustmentSettings = _manualConstructionSettings.HeightAdjustmentSettings; _paddingSettings = _manualConstructionSettings.PaddingSettings; _borderSettings = _manualConstructionSettings.BorderSettings; _pathNoTileConnectionsObjectPlacementDataCalculator.Path = _path; _pathWithTileConnectionsObjectPlacementDataCalculator.Path = _path; } }
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); } }
public void UpdateForMouseMovement() { if (_state == State.Inactive) { return; } if (MouseButtonStates.Instance.IsMouseButtonDown(MouseButton.Left)) { _state = State.Snap; } else { _state = State.SelectPivot; } if (_state == State.SelectPivot && _selectedParents.Count != 0) { Camera camera = SceneViewCamera.Camera; Vector2 mousePos = Event.current.InvMousePos(camera); _isPivotAvailable = false; float minDistanceSq = float.MaxValue; foreach (var parent in _selectedParents) { if (parent == null) { continue; } OrientedBox worldOOBB = parent.GetHierarchyWorldOrientedBox(); if (worldOOBB.IsValid()) { List <Vector3> centerAndCorners = worldOOBB.GetCenterAndCornerPoints(); List <Vector2> oobbScreenPts = Vector2Extensions.GetScreenPoints(centerAndCorners, camera); for (int ptIndex = 0; ptIndex < centerAndCorners.Count; ++ptIndex) { Vector3 worldPt = centerAndCorners[ptIndex]; Vector2 screenPt = oobbScreenPts[ptIndex]; float distSq = (mousePos - screenPt).sqrMagnitude; if (distSq < minDistanceSq) { minDistanceSq = distSq; _pivot = worldPt; _isPivotAvailable = true; } } } } } else if (_state == State.Snap && _isPivotAvailable) { GameObjectExtensions.RecordObjectTransformsForUndo(_selectedParents); MouseCursorRayHit cursorHit = MouseCursor.Instance.GetCursorRayHitForGridCell(); if (cursorHit.WasACellHit) { Camera camera = SceneViewCamera.Camera; Vector2 mousePos = Event.current.InvMousePos(camera); GridCellRayHit cellRayHit = cursorHit.GridCellRayHit; Vector3 snapDestination = Vector3Extensions.GetClosestPointToPoint(cellRayHit.HitCell.Quad.GetCenterAndCornerPoints(), cellRayHit.HitPoint); Vector3 moveVector = snapDestination - _pivot; foreach (var parent in _selectedParents) { if (parent != null) { parent.transform.position += moveVector; } } _pivot = snapDestination; ObjectSelection.Get().ObjectSelectionTransformGizmoSystem.OnObjectSelectionUpdated(); } } }
public void RenderMirroredEntityOrientedBox(OrientedBox entityBox) { _mirroredEntityRenderer.RenderMirroredEntityOrientedBox(_mirror.WorldPlane, entityBox, _mirrorRotation, RenderSettings.MirroredBoxColor, RenderSettings.MirroredBoxBorderLineColor); }
private bool DoesGuideIntersectPreviuslyPlacedObjectHierarchy() { OrientedBox guideWorldOrientedBox = ObjectPlacementGuide.SceneObject.GetHierarchyWorldOrientedBox(); return(guideWorldOrientedBox.Intersects(_orientedBoxOfLastPlacedHierarchy)); }
public List <ObjectPlacementData> Calculate(Quaternion rotationToApplyForStrokeAlignment) { if (!ValidateCalculationRequirements()) { return(new List <ObjectPlacementData>()); } _objectNodeNetwork.Clear(); _rotationToApplyForStrokeAlignment = rotationToApplyForStrokeAlignment; CreateSurfaceColliderProjector(); _elementToNewPrefabRotation.Clear(); _allowObjectIntersection = ObjectPlacementSettings.Get().ObjectIntersectionSettings.AllowIntersectionForDecorPaintBrushModeDrag; int currentObjectIndex = 0; var objectPlacementDataInstances = new List <ObjectPlacementData>(_workingBrush.MaxNumberOfObjects); while (currentObjectIndex < _workingBrush.MaxNumberOfObjects) { DecorPaintObjectPlacementBrushElement brushElement = _brushElementSpawnChanceTable.PickEntity(UnityEngine.Random.Range(0.0f, 1.0f)); int brushElementIndex = _allValidBrushElements.FindIndex(item => item == brushElement); ++currentObjectIndex; // No object nodes were created yet? if (_objectNodeNetwork.NumberOfNodes == 0) { // Create the first node at a random position inside the brush circle Vector3 randomPositionInsideCircle = _workingBrushCircle.GetRandomPointInside(); ObjectSurfaceData objectSurfaceData = CalculateObjectSurfaceData(randomPositionInsideCircle); MatrixObjectBoxPair matrixObjectBoxPair = CalculateMatrixObjectBoxPair(brushElementIndex, objectSurfaceData); // We need to know if the normal of the surface on which the object resides lies within the desired slope range bool passesSlopeTest = DoesObjectSurfacePassSlopeTest(objectSurfaceData, brushElement); // Note: Even if the slope test is not passed, we will still create an object node. The reason for this is that // we want to have some kind of continuity in the algorithm. Imagine that the brush circle is large and is // divided by a large terrain mountain which sits in the middle. If the object generation starts on one side // of the mountain, the algorithm might never get a chance to go over the other side if the slope condition // is not satisifed. We want to spread objects as much as possible so even though this object will not be // placed in the scene, we will still add it to the node network. _objectNodeNetwork.AddNodeToEnd(matrixObjectBoxPair.ObjectBox, objectSurfaceData); if (passesSlopeTest && DoesBoxPassObjectIntersectionTest(matrixObjectBoxPair.ObjectBox, brushElement.Prefab.UnityPrefab, matrixObjectBoxPair.ObjectMatrix)) { objectPlacementDataInstances.Add(new ObjectPlacementData(matrixObjectBoxPair.ObjectMatrix, brushElement.Prefab, brushElement.MustEmbedInSurface)); } } else { // Are there any node segments available? if (_objectNodeNetwork.NumberOfSegments != 0) { // The first step is to generate a random node index and store references to that node and its immediate neighbour _objectNodeNetwork.RemoveAllNodesWhichGenerateConcavities(_workingBrushCircle.Plane); int randomNodeIndex = _objectNodeNetwork.GetRandomNodeIndex(); ObjectNode firstNode = _objectNodeNetwork.GetNodeByIndex(randomNodeIndex); ObjectNode secondNode = _objectNodeNetwork.GetNodeByIndex(randomNodeIndex + 1); // Calculate the plane of the segment which unites the 2 nodes. We will also store the // actual segment and the middle point on the segment. We will use this middle point to // generate the initial object position. Segment3D nodeSegment = ObjectNodeNetwork.CalculateSegmentBetweenNodes(firstNode, secondNode); Vector3 segmentMidPoint = nodeSegment.GetPoint(0.5f); Plane segmentPlane = ObjectNodeNetwork.CalculateSegmentPlaneNormal(firstNode, secondNode); OrientedBox firstNodeBox = firstNode.ObjectBox; OrientedBox secondNodeBox = secondNode.ObjectBox; // Calculate the furthest point in front of the plane using the corner points of the // 2 nodes. The idea is to move the new object as much as possible from the bulk of // objects that have already been generated. Vector3 furthestPointFromPlane; List <Vector3> nodeCornerPoints = firstNodeBox.GetCornerPoints(); nodeCornerPoints.AddRange(secondNodeBox.GetCornerPoints()); if (!segmentPlane.GetFurthestPointInFront(nodeCornerPoints, out furthestPointFromPlane)) { continue; } // Use the calculated furthest point from plane and the the existing plane normal to calculate the // pivot plane. The new object will reside at some distance away from this plane. Plane pivotPlane = new Plane(segmentPlane.normal, furthestPointFromPlane); // Calculate the new object transform data. We will use the segment's mid point to generate the // initial object position. ObjectSurfaceData objectSurfaceData = CalculateObjectSurfaceData(segmentMidPoint); MatrixObjectBoxPair matrixObjectBoxPair = CalculateMatrixObjectBoxPair(brushElementIndex, objectSurfaceData); OrientedBox objectBox = matrixObjectBoxPair.ObjectBox; // Identify the objects's furthest point behind the plane Vector3 objectBoxPivotPoint; List <Vector3> objectBoxCornerPoints = objectBox.GetCornerPoints(); if (!pivotPlane.GetFurthestPointBehind(objectBoxCornerPoints, out objectBoxPivotPoint)) { continue; } // Use the furthest point to move the object in front of the plane and take the distance between objects into account Vector3 fromPivotPointToCenter = objectBox.Center - objectBoxPivotPoint; Vector3 projectedPivotPoint = pivotPlane.ProjectPoint(objectBoxPivotPoint); objectBox.Center = projectedPivotPoint + fromPivotPointToCenter + pivotPlane.normal * _workingBrush.DistanceBetweenObjects; // Generate the object surface data objectSurfaceData = CalculateObjectSurfaceData(objectBox.Center); bool passesSlopeTest = DoesObjectSurfacePassSlopeTest(objectSurfaceData, brushElement); // Now we need to adjust the orientation and center of the box. If the calculated center // lies outside the brush circle, we will ignore this node. AdjustObjectBoxRotationOnSurface(objectBox, objectSurfaceData, brushElement); AdjustObjectBoxCenterToSitOnSurface(objectBox, objectSurfaceData, brushElement); if (!_workingBrushCircle.ContainsPoint(_workingBrushCircle.Plane.ProjectPoint(objectBox.Center))) { continue; } // Recalculate the object matrix using the new box data TransformMatrix objectMatrix = matrixObjectBoxPair.ObjectMatrix; objectMatrix.Rotation = objectBox.Rotation; objectMatrix.Translation = ObjectPositionCalculator.CalculateObjectHierarchyPosition(brushElement.Prefab, objectBox.Center, objectMatrix.Scale, objectBox.Rotation); // We have been modifying the matrix and box data independently so we will ensure that the box uses the latest data OrientedBox finalBox = new OrientedBox(objectBox); finalBox.SetTransformMatrix(objectMatrix); // If the slope test passed, we will calculate an object placement data instance. Otherwise, we will just insert a new node. if (passesSlopeTest && DoesBoxPassObjectIntersectionTest(finalBox, brushElement.Prefab.UnityPrefab, objectMatrix)) { objectPlacementDataInstances.Add(new ObjectPlacementData(objectMatrix, brushElement.Prefab, brushElement.MustEmbedInSurface)); } _objectNodeNetwork.InsertAfterNode(objectBox, objectSurfaceData, randomNodeIndex); } else { // When there are no segments available it means we have only one node. We will use this node to generate // a new one at some distance away from it. First we will store some data that we will need during the entire // procedure. ObjectNode pivotNode = _objectNodeNetwork.GetFirstNode(); Vector3 pivotNodeSurfaceTangent = pivotNode.ObjectSurfaceData.GetSurfaceTangentVector(); OrientedBox pivotNodeObjectBox = pivotNode.ObjectBox; // We will place the new node at some distance away from the first node's face which points // along the calculated tangent vector. We will call this the pivot face. BoxFace pivotBoxFace = pivotNodeObjectBox.GetBoxFaceMostAlignedWithNormal(pivotNodeSurfaceTangent); Plane pivotFacePlane = pivotNodeObjectBox.GetBoxFacePlane(pivotBoxFace); // Generate the data for the new node in the same position as the first node. // Note: Although the same position is used, the rotation and scale will differ and they will // be established by 'CalculateMatrixObjectBoxPair'. MatrixObjectBoxPair matrixObjectBoxPair = CalculateMatrixObjectBoxPair(brushElementIndex, pivotNode.ObjectSurfaceData); OrientedBox objectBox = matrixObjectBoxPair.ObjectBox; // At this point we have to start moving the generated object box to its new positino along the // tangent vector. We will do this by calculating the furthest box point which lies behind the // pivot plane and then move the box so that this point resides on that plane. We will call this // the pivot point. // Note: We will perform a safety check to see if this point could not be calculated and use the // closest point in front if necessary. However, this check should not be necessary. Because // we are placing te object box in the center of the previous box, we can be usre that there // will always be a point which lies behind the pivot plane. Vector3 objectBoxPivotPoint; List <Vector3> objectBoxCornerPoints = objectBox.GetCornerPoints(); if (!pivotFacePlane.GetFurthestPointBehind(objectBoxCornerPoints, out objectBoxPivotPoint) && !pivotFacePlane.GetClosestPointInFront(objectBoxCornerPoints, out objectBoxPivotPoint)) { continue; } // Project the pivot point onto the pivot plane. We will also store a vector which goes from the // original pivot point to the box center. This will allow us to maintain the relationship between // the projected pivot point and the box center so that the center can be adjusted accordingly. Vector3 fromPivotPointToCenter = objectBox.Center - objectBoxPivotPoint; Vector3 projectedPivotPoint = pivotFacePlane.ProjectPoint(objectBoxPivotPoint); // Adjust the center using the projected pivot point and also take the distance between objects into account objectBox.Center = projectedPivotPoint + fromPivotPointToCenter + pivotNodeSurfaceTangent * _workingBrush.DistanceBetweenObjects; // Generate the object surface data at the current box position. // Note: This is the step which can actually cause objects to intersect a little bit. The surface data is // calculated by projecting along the brush circle plane normal. If we are placing objects on a terrain // and the center of the circle lies somewhere at the base of the terrain where the normal points straight // up, but the center of the box resides somewhere on a clif, the new center might move the box closer // or even further away from the pivot node. This however, should not be a problem especially if the distance // between objects is not 0. ObjectSurfaceData objectSurfaceData = CalculateObjectSurfaceData(objectBox.Center); bool passesSlopeTest = DoesObjectSurfacePassSlopeTest(objectSurfaceData, brushElement); // Now we need to adjust the orientation and center of the box. If the calculated center // lies outside the brush circle, we will ignore this node. AdjustObjectBoxRotationOnSurface(objectBox, objectSurfaceData, brushElement); AdjustObjectBoxCenterToSitOnSurface(objectBox, objectSurfaceData, brushElement); if (!_workingBrushCircle.ContainsPoint(_workingBrushCircle.Plane.ProjectPoint(objectBox.Center))) { continue; } // Recalculate the object matrix using the new box data TransformMatrix objectMatrix = matrixObjectBoxPair.ObjectMatrix; objectMatrix.Rotation = objectBox.Rotation; objectMatrix.Translation = ObjectPositionCalculator.CalculateObjectHierarchyPosition(brushElement.Prefab, objectBox.Center, objectMatrix.Scale, objectBox.Rotation); // We have been modifying the matrix and box data independently so we will ensure that the box uses the latest data OrientedBox finalBox = new OrientedBox(objectBox); finalBox.SetTransformMatrix(objectMatrix); // If the slope test passed, we will calculate an object placement data instance. Otherwise, we will just insert a new node. if (passesSlopeTest && DoesBoxPassObjectIntersectionTest(finalBox, brushElement.Prefab.UnityPrefab, objectMatrix)) { objectPlacementDataInstances.Add(new ObjectPlacementData(objectMatrix, brushElement.Prefab, brushElement.MustEmbedInSurface)); } _objectNodeNetwork.InsertAfterNode(objectBox, objectSurfaceData, 0); } } } // Adjust the prefab rotations for the next time the function is called if (_elementToNewPrefabRotation.Count != 0) { foreach (var prefabRotationPair in _elementToNewPrefabRotation) { DecorPaintObjectPlacementBrushElement brushElement = prefabRotationPair.Key; if (_elementToCurrentPrefabRotation.ContainsKey(brushElement)) { _elementToCurrentPrefabRotation[brushElement] = prefabRotationPair.Value; } } } return(objectPlacementDataInstances); }
public ObjectNode(OrientedBox objectBox, ObjectSurfaceData objectSurfaceData) { _objectBox = new OrientedBox(objectBox); _objectSurfaceData = new ObjectSurfaceData(objectSurfaceData); }
public static List <OrientedBox> GetTileConnectionExtrusionOrientedBoxes(ObjectPlacementPathTileConnectionGridCell tileConnectionGridCell) { ObjectPlacementBoxStack tileConnectionStack = tileConnectionGridCell.TileConnectionStack; ObjectPlacementPathTileConnectionTypeSettings tileConnectionTypeSettings = tileConnectionGridCell.TileConnectionPath.Settings.TileConnectionSettings.GetSettingsForTileConnectionType(tileConnectionGridCell.TileConnectionType); if (tileConnectionStack != null) { if (tileConnectionStack.NumberOfBoxes == 0) { return(new List <OrientedBox>()); } if (tileConnectionTypeSettings.IsAnyExtrusionNecessary()) { // Handle upwards extrusion Vector3 nextTilePositionForUpwardsExtrusion; Vector3 extrudeOffset; Vector3 pathExtensionPlaneNormal = tileConnectionGridCell.TileConnectionPath.ExtensionPlane.normal; var tileConnectionYOffsetVectorCalculator = new ObjectPlacementPathTileConnectionYOffsetVectorCalculator(); Vector3 yOffsetVector = tileConnectionYOffsetVectorCalculator.Calculate(tileConnectionTypeSettings, tileConnectionGridCell.TileConnectionPath); extrudeOffset = pathExtensionPlaneNormal * tileConnectionStack.GetBoxSizeAlongNormalizedDirection(pathExtensionPlaneNormal); if (tileConnectionStack.IsGrowingUpwards) { nextTilePositionForUpwardsExtrusion = tileConnectionStack.GetBoxByIndex(tileConnectionStack.NumberOfBoxes - 1).Center + extrudeOffset; } else { nextTilePositionForUpwardsExtrusion = tileConnectionStack.GetBoxByIndex(0).Center + extrudeOffset; } var extrudedBox = new OrientedBox(); extrudedBox.Rotation = tileConnectionStack.Rotation; extrudedBox.ModelSpaceSize = tileConnectionStack.BoxSize; var extrusionOrientedBoxes = new List <OrientedBox>(); for (int extrudeIndex = 0; extrudeIndex < tileConnectionTypeSettings.UpwardsExtrusionAmount; ++extrudeIndex) { extrudedBox.Center = nextTilePositionForUpwardsExtrusion + yOffsetVector; extrusionOrientedBoxes.Add(new OrientedBox(extrudedBox)); nextTilePositionForUpwardsExtrusion += extrudeOffset; } // Handle downwards extrusion extrudeOffset = -pathExtensionPlaneNormal *tileConnectionStack.GetBoxSizeAlongNormalizedDirection(pathExtensionPlaneNormal); if (tileConnectionStack.IsGrowingDownwards) { nextTilePositionForUpwardsExtrusion = tileConnectionStack.GetBoxByIndex(tileConnectionStack.NumberOfBoxes - 1).Center + extrudeOffset; } else { nextTilePositionForUpwardsExtrusion = tileConnectionStack.GetBoxByIndex(0).Center + extrudeOffset; } for (int extrudeIndex = 0; extrudeIndex < tileConnectionTypeSettings.DownwardsExtrusionAmount; ++extrudeIndex) { extrudedBox.Center = nextTilePositionForUpwardsExtrusion + yOffsetVector; extrusionOrientedBoxes.Add(new OrientedBox(extrudedBox)); nextTilePositionForUpwardsExtrusion += extrudeOffset; } return(extrusionOrientedBoxes); } else { return(new List <OrientedBox>()); } } else { return(new List <OrientedBox>()); } }
public void Update() { if (IsActive) { if (AllShortcutCombos.Instance.GrabRotateSelection.IsActive()) { _state = State.Rotating; } else if (AllShortcutCombos.Instance.GrabScaleSelection.IsActive()) { if (_state != State.Scaling) { _objectToWorldScale.Clear(); foreach (var grabbedObject in _grabbedObjects) { if (grabbedObject != null) { _objectToWorldScale.Add(grabbedObject, grabbedObject.transform.lossyScale); } } _cursorPosAtScaleBegin = MouseCursor.Instance.Position; _state = State.Scaling; } } else { // Need to reset the anchor relationships because the cursor was moved without // the objects following it. if (_state == State.Rotating || _state == State.Scaling) { _objectToPivotDir.Clear(); foreach (var grabbedObject in _grabbedObjects) { if (grabbedObject != null) { _objectToPivotDir.Add(grabbedObject, grabbedObject.transform.position - _surfaceHitPoint); } } } _state = State.Moving; } _currentCursorRayHit = GetCursorRayHit(); if (!_currentCursorRayHit.WasAnythingHit) { return; } if (_currentCursorRayHit.WasAnythingHit) { if (_currentCursorRayHit.WasAnObjectHit) { _surfaceHitPoint = _currentCursorRayHit.ClosestObjectRayHit.HitPoint; } else { _surfaceHitPoint = _currentCursorRayHit.GridCellRayHit.HitPoint; } } if (_state == State.Moving || _objectToSurfaceInfo.Count == 0) { if (_currentCursorRayHit.WasAnObjectHit) { GameObjectExtensions.RecordObjectTransformsForUndo(_grabbedObjects); GameObjectRayHit objectRayHit = _currentCursorRayHit.ClosestObjectRayHit; foreach (var grabbedObject in _grabbedObjects) { if (grabbedObject == null) { continue; } Transform objectTransform = grabbedObject.transform; objectTransform.position = objectRayHit.HitPoint + _objectToPivotDir[grabbedObject]; if (objectRayHit.WasTerrainHit) { Ray ray = new Ray(grabbedObject.GetHierarchyWorldOrientedBox().Center + Vector3.up, -Vector3.up); GameObjectRayHit sitPointHit = null; if (objectRayHit.HitObject.RaycastTerrainReverseIfFail(ray, out sitPointHit)) { Plane surfacePlane = new Plane(sitPointHit.HitNormal, sitPointHit.HitPoint); if (_grabSettings.AlignAxis) { AxisAlignment.AlignObjectAxis(grabbedObject, _grabSettings.AlignmentAxis, sitPointHit.HitNormal); } grabbedObject.PlaceHierarchyOnPlane(surfacePlane); if (!_grabSettings.EmbedInSurfaceWhenNoAlign || _grabSettings.AlignAxis) { objectTransform.position += _grabSettings.OffsetFromSurface * sitPointHit.HitNormal; } if (_grabSettings.EmbedInSurfaceWhenNoAlign && !_grabSettings.AlignAxis) { grabbedObject.EmbedInSurfaceByVertex(-Vector3.up, objectRayHit.HitObject); } ObjectSurfaceInfo surfaceInfo = new ObjectSurfaceInfo(); surfaceInfo.SurfacePlane = surfacePlane; surfaceInfo.SitPoint = sitPointHit.HitPoint; SetObjectSurfaceInfo(grabbedObject, surfaceInfo); } } else if (objectRayHit.WasMeshHit) { Ray ray = new Ray(grabbedObject.GetHierarchyWorldOrientedBox().Center + objectRayHit.HitNormal * 2.0f, -objectRayHit.HitNormal); GameObjectRayHit sitPointHit = null; if (objectRayHit.HitObject.RaycastMeshReverseIfFail(ray, out sitPointHit)) { Plane surfacePlane = new Plane(sitPointHit.HitNormal, sitPointHit.HitPoint); if (_grabSettings.AlignAxis) { AxisAlignment.AlignObjectAxis(grabbedObject, _grabSettings.AlignmentAxis, sitPointHit.HitNormal); } grabbedObject.PlaceHierarchyOnPlane(surfacePlane); if (!_grabSettings.EmbedInSurfaceWhenNoAlign || _grabSettings.AlignAxis) { objectTransform.position += _grabSettings.OffsetFromSurface * sitPointHit.HitNormal; } if (_grabSettings.EmbedInSurfaceWhenNoAlign && !_grabSettings.AlignAxis) { grabbedObject.EmbedInSurfaceByVertex(-sitPointHit.HitNormal, objectRayHit.HitObject); } ObjectSurfaceInfo surfaceInfo = new ObjectSurfaceInfo(); surfaceInfo.SurfacePlane = surfacePlane; surfaceInfo.SitPoint = sitPointHit.HitPoint; SetObjectSurfaceInfo(grabbedObject, surfaceInfo); } } } } else if (_currentCursorRayHit.WasACellHit) { GameObjectExtensions.RecordObjectTransformsForUndo(_grabbedObjects); GridCellRayHit cellRayHit = _currentCursorRayHit.GridCellRayHit; foreach (var grabbedObject in _grabbedObjects) { if (grabbedObject == null) { continue; } Transform objectTransform = grabbedObject.transform; objectTransform.position = cellRayHit.HitPoint + _objectToPivotDir[grabbedObject]; Plane surfacePlane = new Plane(cellRayHit.HitNormal, cellRayHit.HitPoint); Vector3 sitPoint = surfacePlane.ProjectPoint(grabbedObject.GetWorldOrientedBox().Center); if (_grabSettings.AlignAxis) { AxisAlignment.AlignObjectAxis(grabbedObject, _grabSettings.AlignmentAxis, cellRayHit.HitNormal); } grabbedObject.PlaceHierarchyOnPlane(surfacePlane); if (!_grabSettings.EmbedInSurfaceWhenNoAlign || _grabSettings.AlignAxis) { objectTransform.position += _grabSettings.OffsetFromSurface * cellRayHit.HitNormal; } ObjectSurfaceInfo surfaceInfo = new ObjectSurfaceInfo(); surfaceInfo.SurfacePlane = surfacePlane; surfaceInfo.SitPoint = sitPoint; SetObjectSurfaceInfo(grabbedObject, surfaceInfo); } } } else if (_state == State.Rotating) { GameObjectExtensions.RecordObjectTransformsForUndo(_grabbedObjects); float rotationSensitivity = _grabSettings.RotationSensitivity; foreach (var grabbedObject in _grabbedObjects) { if (!_objectToSurfaceInfo.ContainsKey(grabbedObject)) { continue; } var surfaceInfo = _objectToSurfaceInfo[grabbedObject]; OrientedBox worldOOBB = grabbedObject.GetHierarchyWorldOrientedBox(); grabbedObject.RotateHierarchyBoxAroundPoint(MouseCursor.Instance.OffsetSinceLastMouseMove.x * rotationSensitivity, _grabSettings.AlignAxis ? surfaceInfo.SurfacePlane.normal : Vector3.up, worldOOBB.Center); } } else if (_state == State.Scaling) { GameObjectExtensions.RecordObjectTransformsForUndo(_grabbedObjects); Vector2 currentCursorPos = MouseCursor.Instance.Position; Vector2 cursorOffsetFromScaleBegin = currentCursorPos - _cursorPosAtScaleBegin; float scaleFactor = 1.0f + _grabSettings.ScaleSensitivity * cursorOffsetFromScaleBegin.x; foreach (var grabbedObject in _grabbedObjects) { if (!_objectToSurfaceInfo.ContainsKey(grabbedObject) || !_objectToWorldScale.ContainsKey(grabbedObject)) { continue; } var surfaceInfo = _objectToSurfaceInfo[grabbedObject]; grabbedObject.SetHierarchyWorldScaleByPivotPoint(_objectToWorldScale[grabbedObject] * scaleFactor, surfaceInfo.SitPoint); } } } }
public List <ObjectPlacementData> Calculate() { if (_block == null || _block.NumberOfSegments == 0 || !ObjectPlacementGuide.ExistsInScene) { return(new List <ObjectPlacementData>()); } Prefab placementGuidePrefab = ObjectPlacementGuide.Instance.SourcePrefab; Vector3 placementGuideWorldScale = ObjectPlacementGuide.Instance.WorldScale; Quaternion placementGuideWorldRotation = ObjectPlacementGuide.Instance.WorldRotation; float objectMissChance = _block.Settings.ManualConstructionSettings.ObjectMissChance; ObjectRotationRandomizationSettings blockObjectRotationRandomizationSettings = _block.Settings.ManualConstructionSettings.ObjectRotationRandomizationSettings; bool randomizeRotations = blockObjectRotationRandomizationSettings.RandomizeRotation; Vector3 objectOffsetAlongExtensionPlaneNormal = _block.Settings.ManualConstructionSettings.OffsetAlongGrowDirection * _block.ExtensionPlane.normal; bool allowObjectIntersection = ObjectPlacementSettings.Get().ObjectIntersectionSettings.AllowIntersectionForBlockPlacement; bool randomizePrefabs = _block.Settings.ManualConstructionSettings.RandomizePrefabs; PrefabCategory activePrefabCategory = PrefabCategoryDatabase.Get().ActivePrefabCategory; ObjectPlacementBlockProjectionSettings projectionSettings = _block.Settings.BlockProjectionSettings; bool canProject = projectionSettings.ProjectOnSurface && (projectionSettings.CanProjectOnMesh || projectionSettings.CanProjectOnTerrain); var objectPlacementDataInstances = new List <ObjectPlacementData>(_block.NumberOfSegments * 10); for (int segmentIndex = 0; segmentIndex < _block.NumberOfSegments; ++segmentIndex) { ObjectPlacementBoxStackSegment segment = _block.GetSegmentByIndex(segmentIndex); for (int stackIndex = 0; stackIndex < segment.NumberOfStacks; ++stackIndex) { ObjectPlacementBoxStack stack = segment.GetStackByIndex(stackIndex); if (stack.IsOverlappedByAnotherStack || stack.NumberOfBoxes == 0) { continue; } Vector3 projectionOffset = Vector3.zero; Vector3 projectionDirection = Vector3.zero; Quaternion prjAlignRotation = Quaternion.identity; GameObjectRayHit projectionSurfaceHit = null; if (canProject) { Vector3 rayOrigin = stack.GetBoxByIndex(0).Center; Vector3 rayDir = Vector3.zero; if (projectionSettings.ProjectionDirection == ObjectBlockProjectionDir.BlockUp) { rayDir = _block.ExtensionPlane.normal; } else { rayDir = -_block.ExtensionPlane.normal; } projectionDirection = rayDir; Ray ray = new Ray(rayOrigin, rayDir); GameObjectRayHit closestMeshHit = null; GameObjectRayHit closestTerrainHit = null; if (projectionSettings.CanProjectOnMesh) { closestMeshHit = Octave3DScene.Get().RaycastAllMeshClosest(ray); } if (projectionSettings.CanProjectOnTerrain) { closestTerrainHit = Octave3DScene.Get().RaycastAllTerainsClosest(ray); } // Ignore stack if no surface was found and non-projectables must be rejected if (closestMeshHit == null && closestTerrainHit == null) { if (projectionSettings.RejectNonProjectables) { continue; } } else { projectionSurfaceHit = closestMeshHit; if (closestMeshHit == null || (closestTerrainHit != null && closestMeshHit.HitEnter > closestTerrainHit.HitEnter)) { projectionSurfaceHit = closestTerrainHit; } } if (projectionSurfaceHit != null) { ObjectPlacementBox projectionBox = stack.GetBoxByIndex(0); projectionOffset = projectionSurfaceHit.HitPoint - stack.GetBoxByIndex(0).Center; if (projectionOffset.sqrMagnitude > (projectionSurfaceHit.HitPoint - stack.GetBoxByIndex(stack.NumberOfBoxes - 1).Center).sqrMagnitude) { projectionBox = stack.GetBoxByIndex(stack.NumberOfBoxes - 1); projectionOffset = projectionSurfaceHit.HitPoint - projectionBox.Center; } if (!projectionSettings.AlignToSurfaceNormal) { var oobb = projectionBox.OrientedBox; Vector3 oldCenter = oobb.Center; GameObjectExtensions.EmbedObjectBoxInSurface(oobb, projectionDirection, projectionSurfaceHit.HitObject); projectionOffset = oobb.Center - oldCenter; } } } for (int stackBoxIndex = 0; stackBoxIndex < stack.NumberOfBoxes; ++stackBoxIndex) { ObjectPlacementBox box = stack.GetBoxByIndex(stackBoxIndex); if (box.IsHidden) { continue; } if (ObjectPlacementMissChance.Missed(objectMissChance, ObjectPlacementBlockManualConstructionSettings.MinObjectMissChance, ObjectPlacementBlockManualConstructionSettings.MaxObjectMissChance)) { continue; } if (!allowObjectIntersection && ObjectQueries.IntersectsAnyObjectsInScene(box.OrientedBox, true)) { continue; } Quaternion worldRotation = placementGuideWorldRotation; if (randomizeRotations) { worldRotation = ObjectRotationRandomization.GenerateRandomRotationQuaternion(blockObjectRotationRandomizationSettings); } Vector3 worldScale = placementGuideWorldScale; Prefab prefab = placementGuidePrefab; if (randomizePrefabs && activePrefabCategory.NumberOfPrefabs != 0) { int randomPrefabIndex = UnityEngine.Random.Range(0, activePrefabCategory.NumberOfPrefabs); Prefab randomPrefab = activePrefabCategory.GetPrefabByIndex(randomPrefabIndex); if (randomPrefab != null && randomPrefab.UnityPrefab != null) { prefab = activePrefabCategory.GetPrefabByIndex(randomPrefabIndex); worldScale = prefab.UnityPrefab.transform.lossyScale; } } Vector3 boxCenter = box.Center + objectOffsetAlongExtensionPlaneNormal + projectionOffset; if (projectionSurfaceHit != null) { if (projectionSettings.AlignToSurfaceNormal) { worldRotation = AxisAlignment.CalculateRotationQuaternionForAxisAlignment(worldRotation, projectionSettings.AlignmentAxis, projectionSurfaceHit.HitNormal); OrientedBox prefabWorldOOBB = prefab.UnityPrefab.GetHierarchyWorldOrientedBox(); Vector3 oobbSize = prefabWorldOOBB.ScaledSize; int axisIndex = (int)((int)(projectionSettings.AlignmentAxis) * 0.5f); boxCenter = projectionSurfaceHit.HitPoint + projectionSurfaceHit.HitNormal * oobbSize[axisIndex] * 0.5f + (oobbSize[axisIndex] * stackBoxIndex * projectionSurfaceHit.HitNormal); } } var objectPlacementData = new ObjectPlacementData(); objectPlacementData.WorldPosition = ObjectPositionCalculator.CalculateObjectHierarchyPosition(prefab, boxCenter, worldScale, worldRotation); objectPlacementData.WorldScale = worldScale; objectPlacementData.WorldRotation = worldRotation; objectPlacementData.Prefab = prefab; objectPlacementDataInstances.Add(objectPlacementData); } } } return(objectPlacementDataInstances); }
private bool IsGameObjectFullyOverlappedByCircle(GameObject gameObject) { OrientedBox worldOrientedBox = gameObject.GetWorldOrientedBox(); return(IsWorldOrientedBoxFullyOverlappedByCircle(worldOrientedBox)); }
public override void Render(List <GameObject> selectedObjects) { ObjectSelectionRenderSettings selectionRenderSettings = ObjectSelectionRenderSettings.Get(); ObjectSelectionBoxRenderModeSettings selectionBoxRenderModeSettings = selectionRenderSettings.BoxRenderModeSettings; ObjectSelectionBoxCornerEdgesRenderModeSettings selectionBoxCornerEdgesRenderModeSettings = selectionBoxRenderModeSettings.CornerEdgesRenderModeSettings; Color boxColor = selectionBoxRenderModeSettings.BoxColor; Color edgeColor = selectionBoxRenderModeSettings.EdgeColor; float boxScale = selectionBoxRenderModeSettings.BoxScale; bool renderBoxes = boxColor.a != 0.0f; bool renderEdges = edgeColor.a != 0.0f; if (!renderBoxes && !renderEdges) { return; } // Note: Code duplication is intentional here in order to avoid further abstractions which may hinder performance. if (selectionBoxRenderModeSettings.EdgeRenderMode == ObjectSelectionBoxEdgeRenderMode.Wire) { if (renderBoxes && renderEdges) { foreach (GameObject gameObject in selectedObjects) { if (!gameObject.activeInHierarchy) { continue; } OrientedBox worldOrientedBox = gameObject.GetWorldOrientedBox(); if (worldOrientedBox.IsValid()) { worldOrientedBox.Scale *= boxScale; GizmosEx.RenderOrientedBox(worldOrientedBox, boxColor); GizmosEx.RenderOrientedBoxEdges(worldOrientedBox, edgeColor); } } } else if (renderEdges && !renderBoxes) { foreach (GameObject gameObject in selectedObjects) { if (!gameObject.activeInHierarchy) { continue; } OrientedBox worldOrientedBox = gameObject.GetWorldOrientedBox(); if (worldOrientedBox.IsValid()) { worldOrientedBox.Scale *= boxScale; GizmosEx.RenderOrientedBoxEdges(worldOrientedBox, edgeColor); } } } else if (renderBoxes && !renderEdges) { foreach (GameObject gameObject in selectedObjects) { if (!gameObject.activeInHierarchy) { continue; } OrientedBox worldOrientedBox = gameObject.GetWorldOrientedBox(); if (worldOrientedBox.IsValid()) { worldOrientedBox.Scale *= boxScale; GizmosEx.RenderOrientedBox(worldOrientedBox, boxColor); } } } } else if (selectionBoxRenderModeSettings.EdgeRenderMode == ObjectSelectionBoxEdgeRenderMode.CornerEdges) { float cornerEdgeLengthPercentage = selectionBoxCornerEdgesRenderModeSettings.CornerEdgeLengthPercentage; if (renderBoxes && renderEdges) { foreach (GameObject gameObject in selectedObjects) { if (!gameObject.activeInHierarchy) { continue; } OrientedBox worldOrientedBox = gameObject.GetWorldOrientedBox(); if (worldOrientedBox.IsValid()) { worldOrientedBox.Scale *= boxScale; GizmosEx.RenderOrientedBox(worldOrientedBox, boxColor); GizmosEx.RenderOrientedBoxCornerEdges(worldOrientedBox, cornerEdgeLengthPercentage, edgeColor); } } } else if (renderEdges && !renderBoxes) { foreach (GameObject gameObject in selectedObjects) { if (!gameObject.activeInHierarchy) { continue; } OrientedBox worldOrientedBox = gameObject.GetWorldOrientedBox(); if (worldOrientedBox.IsValid()) { worldOrientedBox.Scale *= boxScale; GizmosEx.RenderOrientedBoxCornerEdges(worldOrientedBox, cornerEdgeLengthPercentage, edgeColor); } } } else if (renderBoxes && !renderEdges) { foreach (GameObject gameObject in selectedObjects) { if (!gameObject.activeInHierarchy) { continue; } OrientedBox worldOrientedBox = gameObject.GetWorldOrientedBox(); if (worldOrientedBox.IsValid()) { worldOrientedBox.Scale *= boxScale; GizmosEx.RenderOrientedBox(worldOrientedBox, boxColor); } } } } }
public MatrixObjectBoxPair(TransformMatrix objectMatrix, OrientedBox objectBox) { _objectMatrix = objectMatrix; _objectBox = new OrientedBox(objectBox); }
public static bool IntersectsAnyObjectsInScene(OrientedBox orientedBox, List <GameObject> ignoreObjects, bool ignoreFaceTouch) { return(GetIntersectingObjects(orientedBox, ignoreObjects, ignoreFaceTouch).Count != 0); }
public void AddNodeToEnd(OrientedBox orientedBox, ObjectSurfaceData objectSurfaceData) { _nodes.Add(new ObjectNode(orientedBox, objectSurfaceData)); }
public List <GameObject> OverlapBox(OrientedBox box) { return(_gameObjectSphereTree.OverlapBox(box)); }
private MatrixObjectBoxPair CalculateMatrixObjectBoxPair(int brushElementIndex, ObjectSurfaceData objectSurfaceData) { // Store the needed data for easy access DecorPaintObjectPlacementBrushElement brushElement = _allValidBrushElements[brushElementIndex]; OrientedBox objectBox = new OrientedBox(_brushElementsPrefabOrientedBoxes[brushElementIndex]); // Establish the object's scale. Randomize the scale if necessary. Otherwise, just use the brush element's scale. Vector3 xyzObjectBoxScale = _brushElementsPrefabWorldScaleValues[brushElementIndex]; if (brushElement.ScaleRandomizationSettings.RandomizeScale) { // Generate a random scale factor and apply it to the current scale ObjectUniformScaleRandomizationSettings uniformScaleRandomizationSettings = brushElement.ScaleRandomizationSettings.UniformScaleRandomizationSettings; xyzObjectBoxScale *= UnityEngine.Random.Range(uniformScaleRandomizationSettings.MinScale, uniformScaleRandomizationSettings.MaxScale);; } else { xyzObjectBoxScale *= brushElement.Scale; } // Apply the scale that we have calculated objectBox.Scale = xyzObjectBoxScale; // Now we will calculate the rotation. First we will calculate a quaternion which allow us to take the // specified rotation offset into account. The quaternion rotates around the surface normal by an angle // of 'RotationOffset' degrees. Quaternion rotationOffset = brushElement.AlignToSurface ? Quaternion.AngleAxis(brushElement.RotationOffsetInDegrees, objectSurfaceData.SurfaceNormal) : Quaternion.identity; // If we need to align to stroke, we have some more work to do. Otherwise, we will just set the // rotation to be the same as the prefab's rotation, but offset by 'rotationOffset'. if (brushElement.AlignToStroke) { // First calculate the rotation without any offset. This is the rotation of the prefab plus the rotation which // must be applied for alignment. Quaternion rotationWithoutOffset = _rotationToApplyForStrokeAlignment * _elementToCurrentPrefabRotation[brushElement]; // The rotation of the box must be set to the rotation which we just calculated (which ensures proper alingment) plus // the rotation offset. objectBox.Rotation = rotationOffset * rotationWithoutOffset; // Store the rotation inside the dictionary if an entry doesn't already exist if (!_elementToNewPrefabRotation.ContainsKey(brushElement)) { _elementToNewPrefabRotation.Add(brushElement, rotationWithoutOffset); } } else { objectBox.Rotation = rotationOffset * brushElement.Prefab.UnityPrefab.transform.rotation; } // Adjust the rotation of the object so that its axis is aligned with the placement surface if necessary if (brushElement.AlignToSurface) { AdjustObjectBoxRotationOnSurface(objectBox, objectSurfaceData, brushElement); } // The final step is to rotate the object by a random amount around the placement surface if (brushElement.RotationRandomizationMode != BrushElementRotationRandomizationMode.None) { Vector3 rotationAxis = objectSurfaceData.SurfaceNormal; if (brushElement.RotationRandomizationMode == BrushElementRotationRandomizationMode.X) { rotationAxis = Vector3.right; } else if (brushElement.RotationRandomizationMode == BrushElementRotationRandomizationMode.Y) { rotationAxis = Vector3.up; } else if (brushElement.RotationRandomizationMode == BrushElementRotationRandomizationMode.Z) { rotationAxis = Vector3.forward; } if (!brushElement.AlignToStroke) { // When stroke alignment is not required, we will generate a random rotation angle and apply it // to the current box rotation. float randomRotationAngle = UnityEngine.Random.Range(0.0f, 360.0f); Quaternion additionalRotation = Quaternion.AngleAxis(randomRotationAngle, rotationAxis); objectBox.Rotation = additionalRotation * objectBox.Rotation; } else { // When both rotation randomization and stroke alingment are turned on, we will proudce a small // random rotation offset to randomize the alingmnet a little bit. float randomRotationAngle = UnityEngine.Random.Range(0.0f, 25.0f); Quaternion additionalRotation = Quaternion.AngleAxis(randomRotationAngle, rotationAxis); objectBox.Rotation = additionalRotation * objectBox.Rotation; } } // Place the object on the surface AdjustObjectBoxCenterToSitOnSurface(objectBox, objectSurfaceData, brushElement); // Construct the object matrix and return the object/marix pair TransformMatrix objectMatrix = new TransformMatrix(ObjectPositionCalculator.CalculateObjectHierarchyPosition(brushElement.Prefab, objectBox.Center, xyzObjectBoxScale, objectBox.Rotation), objectBox.Rotation, xyzObjectBoxScale); return(new MatrixObjectBoxPair(objectMatrix, objectBox)); }
public List <Vector3> GetOverlappedWorldVerts(OrientedBox box, TransformMatrix meshTransformMatrix) { return(_meshSphereTree.GetOverlappedWorldVerts(box, meshTransformMatrix)); }
private void AdjustGuidePivotPoints() { OrientedBox guideHierarchyWorldOrientedBox = ObjectPlacementGuide.SceneObject.GetHierarchyWorldOrientedBox(); ObjectPlacement.Get().ProjectedGuidePivotPoints.FromOrientedBoxAndDecorStrokeSurface(guideHierarchyWorldOrientedBox, _strokeSurface); }
public List <Triangle3D> GetOverlappedTriangles(OrientedBox box, TransformMatrix meshTransformMatrix) { return(_meshSphereTree.GetOverlappedWorldTriangles(box, meshTransformMatrix)); }
public OrientedBox MirrorOrientedBox(OrientedBox orientedBox) { return(Mirroring.MirrorOrientedBox(_mirror.WorldPlane, orientedBox, _mirrorRotation)); }
public ObjectPlacementBox(ObjectPlacementBox source) { _orientedBox = source.OrientedBox; }
public Octave3DBoxCollider(OrientedBox orientedBox) { _orientedBox = new OrientedBox(orientedBox); }
public bool OverlapsFullyOrPartially(OrientedBox orientedBox) { Vector3 closestPointToSphereCenter = orientedBox.GetClosestPointToPoint(_center); return((closestPointToSphereCenter - _center).sqrMagnitude <= _radius * _radius); }
/// <summary> /// Returns the world space vertices overlapped by the specified box. /// </summary> public List <Vector3> GetOverlappedWorldVerts(OrientedBox box, TransformMatrix meshTransformMatrix) { // If the tree was not yet build, we need to build it because we need // the triangle information in order to perform the raycast. if (!_wasBuilt) { Build(); } // Work in mesh model space because the tree data exists in model space OrientedBox meshSpaceOOBB = new OrientedBox(box); Matrix4x4 inverseTransform = meshTransformMatrix.ToMatrix4x4x.inverse; meshSpaceOOBB.Transform(inverseTransform); // Used to avoid duplicate indices since there can be triangles which share the same vertices // and we don't want to return the same vertex multiple times. HashSet <int> usedIndices = new HashSet <int>(); // Retrieve the nodes overlapped by the specified box List <SphereTreeNode <MeshSphereTreeTriangle> > overlappedNodes = _sphereTree.OverlapBox(meshSpaceOOBB); if (overlappedNodes.Count == 0) { return(new List <Vector3>()); } // Loop through all nodes var overlappedWorldVerts = new List <Vector3>(50); foreach (var node in overlappedNodes) { // Get the triangle associated with the node int triangleIndex = node.Data.TriangleIndex; MeshTriangleInfo triangleInfo = _octave3DMesh.GetMeshTriangleInfo(triangleIndex); List <Vector3> trianglePoints = triangleInfo.ModelSpaceTriangle.GetPoints(); for (int ptIndex = 0; ptIndex < trianglePoints.Count; ++ptIndex) { if (usedIndices.Contains(triangleInfo.VertIndices[ptIndex])) { continue; } Vector3 point = trianglePoints[ptIndex]; if (meshSpaceOOBB.ContainsPoint(point)) { overlappedWorldVerts.Add(meshTransformMatrix.MultiplyPoint(point)); usedIndices.Add(triangleInfo.VertIndices[ptIndex]); } } /*Triangle3D modelSpaceTriangle = _octave3DMesh.GetTriangle(triangleIndex); * * // Now check which of the triangle points resides inside the box * List<Vector3> trianglePoints = modelSpaceTriangle.GetPoints(); * foreach(var pt in trianglePoints) * { * // When a point resides inside the box, we will transform it in world space and add it to the final point list * if (box.ContainsPoint(pt)) overlappedWorldVerts.Add(meshTransformMatrix.MultiplyPoint(pt)); * }*/ } return(overlappedWorldVerts); }
public bool FullyContainsOrientedBoxCenterAndCornerPointsInScreenSpace(OrientedBox orientedBox, Camera camera) { List <Vector2> boxCenterAndCornerScreenPoints = orientedBox.GetScreenCenterAndCornerPoints(camera); return(ContainsAllPoints(boxCenterAndCornerScreenPoints)); }