private void RotateTargets()
        {
            var   boundsQConfig  = GetBoundsQConfig();
            float rotationAmount = InputDeviceManager.Get.MouseDelta.x * SharedSettings.RotationSensitivity;

            EditorUndoEx.RecordObjectTransforms(_targetParents);
            foreach (var grabTarget in _grabTargets)
            {
                if (grabTarget == null)
                {
                    continue;
                }

                OOBB targetOOBB = ObjectBounds.CalcHierarchyWorldOOBB(grabTarget.GameObject, boundsQConfig);
                if (!targetOOBB.IsValid)
                {
                    continue;
                }

                var layerGrabSettings = SharedSettings.GetLayerGrabSettings(grabTarget.GameObject.layer);
                if (layerGrabSettings.IsActive)
                {
                    Quaternion rotation = Quaternion.AngleAxis(rotationAmount, layerGrabSettings.AlignAxis ? grabTarget.SittingPlane.normal : Vector3.up);
                    grabTarget.Transform.RotateAroundPivot(rotation, targetOOBB.Center);
                }
                else
                {
                    Quaternion rotation = Quaternion.AngleAxis(rotationAmount, SharedSettings.AlignAxis ? grabTarget.SittingPlane.normal : Vector3.up);
                    grabTarget.Transform.RotateAroundPivot(rotation, targetOOBB.Center);
                }
            }

            CalculateGrabTargetsAnchorVectors();
        }
Exemplo n.º 2
0
        /// <summary>
        /// Returns a list that contains all terminal nodes that intersect the
        /// specified OOBB.
        /// </summary>
        public List <SphereTreeNode <T> > OverlapBox(OOBB box)
        {
            var overlappedNodes = new List <SphereTreeNode <T> >(20);

            OverlapBoxRecurse(box, _root, overlappedNodes);
            return(overlappedNodes);
        }
Exemplo n.º 3
0
 /// <summary>
 /// Recursive method which moves down the hierarchy performing overlap tests
 /// against 'box'. At the end of the recursive chain, all terminal nodes which
 /// are overlapped by 'box' will be stored in 'overlappedNodes'.
 /// </summary>
 private void OverlapBoxRecurse(OOBB box, SphereTreeNode <T> node, List <SphereTreeNode <T> > overlappedNodes)
 {
     // If the parent node is not overlapped, its children can not possibly
     // be overlapped so thre is no need to go any further.
     if (!box.IntersectsSphere(node.Sphere))
     {
         return;
     }
     else
     {
         // If this is a terminal node, add it to the output list and return
         if (node.IsFlagBitSet(BVHNodeFlags.Terminal))
         {
             overlappedNodes.Add(node);
             return;
         }
         else
         {
             // Recurse for each child node
             List <SphereTreeNode <T> > childNodes = node.Children;
             foreach (SphereTreeNode <T> childNode in childNodes)
             {
                 OverlapBoxRecurse(box, childNode, overlappedNodes);
             }
         }
     }
 }
Exemplo n.º 4
0
 public OOBB(OOBB copy)
 {
     _size     = copy._size;
     _center   = copy._center;
     _rotation = copy._rotation;
     _isValid  = copy._isValid;
 }
Exemplo n.º 5
0
        public static bool Raycast(Ray ray, out float t, Vector3 quadCenter, float quadWidth, float quadHeight, Vector3 quadRight, Vector3 quadUp, QuadEpsilon epsilon = new QuadEpsilon())
        {
            t = 0.0f;
            Vector3 quadNormal = Vector3.Normalize(Vector3.Cross(quadRight, quadUp));
            Plane   quadPlane  = new Plane(quadNormal, quadCenter);

            float rayEnter;

            if (quadPlane.Raycast(ray, out rayEnter) &&
                Contains3DPoint(ray.GetPoint(rayEnter), false, quadCenter, quadWidth, quadHeight, quadRight, quadUp, epsilon))
            {
                t = rayEnter;
                return(true);
            }

            if (epsilon.ExtrudeEps != 0.0f)
            {
                float dot = Vector3Ex.AbsDot(ray.direction, quadPlane.normal);
                if (dot < ExtrudeEpsThreshold.Get)
                {
                    OOBB quadOOBB = Calc3DQuadOOBB(quadCenter, new Vector2(quadWidth, quadHeight), Quaternion.LookRotation(quadNormal, quadUp), epsilon);
                    return(BoxMath.Raycast(ray, quadOOBB.Center, quadOOBB.Size, quadOOBB.Rotation));
                }
            }

            return(false);
        }
Exemplo n.º 6
0
        public static bool Raycast(Ray ray, out float t, Vector3 p0, Vector3 p1, Vector3 p2, TriangleEpsilon epsilon = new TriangleEpsilon())
        {
            t = 0.0f;

            float rayEnter;
            Plane trianglePlane = new Plane(p0, p1, p2);

            if (trianglePlane.Raycast(ray, out rayEnter) &&
                Contains3DPoint(ray.GetPoint(rayEnter), false, p0, p1, p2, epsilon))
            {
                t = rayEnter;
                return(true);
            }

            if (epsilon.ExtrudeEps != 0.0f)
            {
                float dot = Vector3Ex.AbsDot(ray.direction, trianglePlane.normal);
                if (dot < ExtrudeEpsThreshold.Get)
                {
                    OOBB oobb = Calc3DTriangleOOBB(p0, p1, p2, trianglePlane.normal, epsilon);
                    return(BoxMath.Raycast(ray, oobb.Center, oobb.Size, oobb.Rotation));
                }
            }

            return(false);
        }
Exemplo n.º 7
0
        public List <GameObject> OverlapBox(OOBB oobb)
        {
            List <SphereTreeNode <GameObject> > overlappedNodes = _objectTree.OverlapBox(oobb);

            if (overlappedNodes.Count == 0)
            {
                return(new List <GameObject>());
            }

            var boundsQConfig = new ObjectBounds.QueryConfig();

            boundsQConfig.ObjectTypes  = GameObjectTypeHelper.AllCombined;
            boundsQConfig.NoVolumeSize = EditorScene.Get.NoVolumeObjectSize;

            var overlappedObjects = new List <GameObject>();

            foreach (SphereTreeNode <GameObject> node in overlappedNodes)
            {
                GameObject sceneObject = (GameObject)node.Data;
                if (sceneObject == null || !sceneObject.activeInHierarchy)
                {
                    continue;
                }

                OOBB worldOOBB = ObjectBounds.CalcWorldOOBB(sceneObject, boundsQConfig);
                if (oobb.IntersectsOOBB(worldOOBB))
                {
                    overlappedObjects.Add(sceneObject);
                }
            }

            return(overlappedObjects);
        }
Exemplo n.º 8
0
        public OOBB InverseTransformOOBB(OOBB oobb)
        {
            OOBB meshSpaceOOBB = new OOBB(InverseTransformPoint(oobb.Center), Vector3.Scale(_scale.GetInverse(), oobb.Size));

            meshSpaceOOBB.Rotation = Quaternion.Inverse(_rotation) * oobb.Rotation;

            return(meshSpaceOOBB);
        }
        public void OnSceneGUIRender()
        {
            if (SharedLookAndFeel == null)
            {
                return;
            }

            if (IsActive && _grabSurfaceInfo.SurfaceType != GrabSurfaceType.Invalid)
            {
                if (SharedLookAndFeel.ShowAnchorLines)
                {
                    Color oldColor   = Handles.color;
                    var   linePoints = new List <Vector3>(_grabTargets.Count * 2);
                    Handles.color = SharedLookAndFeel.AnchorLineTickColor;
                    foreach (var grabTarget in _grabTargets)
                    {
                        linePoints.Add(grabTarget.Transform.position);
                        linePoints.Add(_grabSurfaceInfo.AnchorPoint);

                        if (SharedLookAndFeel.ShowAnchorLineTicks)
                        {
                            float dotSize = SharedLookAndFeel.AnchorLineTickSize * HandleUtility.GetHandleSize(grabTarget.Transform.position);
                            Handles.DotHandleCap(0, grabTarget.Transform.position, Quaternion.identity, dotSize, EventType.Repaint);
                        }
                    }

                    if (SharedLookAndFeel.ShowAnchorLineTicks)
                    {
                        float dotAnchPtSize = SharedLookAndFeel.AnchorLineTickSize * HandleUtility.GetHandleSize(_grabSurfaceInfo.AnchorPoint);
                        Handles.DotHandleCap(0, _grabSurfaceInfo.AnchorPoint, Quaternion.identity, dotAnchPtSize, EventType.Repaint);
                    }

                    Handles.color = SharedLookAndFeel.AnchorLineColor;
                    Handles.DrawLines(linePoints.ToArray());
                    Handles.color = oldColor;
                }

                if (SharedLookAndFeel.ShowTargetBoxes)
                {
                    Color     oldColor  = Handles.color;
                    Matrix4x4 oldMatrix = Handles.matrix;
                    Handles.color = SharedLookAndFeel.TargetWireBoxColor;
                    var boundsQConfig = GetBoundsQConfig();
                    foreach (var grabTarget in _grabTargets)
                    {
                        OOBB targetOOBB = ObjectBounds.CalcHierarchyWorldOOBB(grabTarget.GameObject, boundsQConfig);
                        if (targetOOBB.IsValid)
                        {
                            Handles.matrix = Matrix4x4.TRS(targetOOBB.Center, targetOOBB.Rotation, Vector3.one);
                            Handles.DrawWireCube(Vector3.zero, targetOOBB.Size);
                        }
                    }

                    Handles.color  = oldColor;
                    Handles.matrix = oldMatrix;
                }
            }
        }
Exemplo n.º 10
0
        public static bool RaycastWire(Ray ray, out float t, Vector3 quadCenter, float quadWidth, float quadHeight, Vector3 quadRight, Vector3 quadUp, QuadEpsilon epsilon = new QuadEpsilon())
        {
            t = 0.0f;
            Vector3    quadNormal   = Vector3.Normalize(Vector3.Cross(quadRight, quadUp));
            Plane      quadPlane    = new Plane(quadNormal, quadCenter);
            Vector2    quadSize     = new Vector2(quadWidth, quadHeight);
            Quaternion quadRotation = Quaternion.LookRotation(quadNormal, quadUp);

            float rayEnter;

            if (quadPlane.Raycast(ray, out rayEnter))
            {
                Vector3 intersectPt  = ray.GetPoint(rayEnter);
                var     cornerPoints = Calc3DQuadCornerPoints(quadCenter, quadSize, quadRotation);

                float distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.TopLeft], cornerPoints[(int)QuadCorner.TopRight]);
                if (distFromSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }

                distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.TopRight], cornerPoints[(int)QuadCorner.BottomRight]);
                if (distFromSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }

                distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.BottomRight], cornerPoints[(int)QuadCorner.BottomLeft]);
                if (distFromSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }

                distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.BottomLeft], cornerPoints[(int)QuadCorner.TopLeft]);
                if (distFromSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }
            }

            if (epsilon.ExtrudeEps != 0.0f)
            {
                float dot = Vector3Ex.AbsDot(ray.direction, quadPlane.normal);
                if (dot < ExtrudeEpsThreshold.Get)
                {
                    OOBB quadOOBB = Calc3DQuadOOBB(quadCenter, quadSize, Quaternion.LookRotation(quadNormal, quadUp), epsilon);
                    return(BoxMath.Raycast(ray, quadOOBB.Center, quadOOBB.Size, quadOOBB.Rotation));
                }
            }

            return(false);
        }
Exemplo n.º 11
0
        public static OOBB CalcWorldOOBB(GameObject gameObject, QueryConfig queryConfig)
        {
            AABB modelAABB = CalcModelAABB(gameObject, queryConfig, gameObject.GetGameObjectType());

            if (!modelAABB.IsValid)
            {
                return(OOBB.GetInvalid());
            }

            return(new OOBB(modelAABB, gameObject.transform));
        }
Exemplo n.º 12
0
        public static OOBB GetMeshWorldOOBB(GameObject gameObject)
        {
            AABB modelAABB = CalcMeshModelAABB(gameObject);

            if (!modelAABB.IsValid)
            {
                return(OOBB.GetInvalid());
            }

            return(new OOBB(modelAABB, gameObject.transform));
        }
Exemplo n.º 13
0
        public static OOBB CalcHierarchyWorldOOBB(GameObject root, QueryConfig queryConfig)
        {
            AABB modelAABB = CalcHierarchyModelAABB(root, queryConfig);

            if (!modelAABB.IsValid)
            {
                return(OOBB.GetInvalid());
            }

            return(new OOBB(modelAABB, root.transform));
        }
Exemplo n.º 14
0
        public void Encapsulate(OOBB otherOOBB)
        {
            var otherPts = BoxMath.CalcBoxCornerPoints(otherOOBB.Center, otherOOBB.Size, otherOOBB.Rotation);

            Matrix4x4 transformMtx = Matrix4x4.TRS(Center, Rotation, Vector3.one);
            var       modelPts     = transformMtx.inverse.TransformPoints(otherPts);

            AABB modelAABB = new AABB(Vector3.zero, Size);

            modelAABB.Encapsulate(modelPts);

            Center = (Rotation * modelAABB.Center) + Center;
            Size   = modelAABB.Size;
        }
Exemplo n.º 15
0
        public GameObjectRayHit RaycastSpriteObject(Ray ray, GameObject gameObject)
        {
            float t;
            OOBB  worldOOBB = ObjectBounds.CalcSpriteWorldOOBB(gameObject);

            if (!worldOOBB.IsValid)
            {
                return(null);
            }

            if (BoxMath.Raycast(ray, out t, worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation))
            {
                return(new GameObjectRayHit(ray, gameObject, worldOOBB.GetPointFaceNormal(ray.GetPoint(t)), t));
            }

            return(null);
        }
Exemplo n.º 16
0
        public static OOBB Calc3DTriangleOOBB(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 normal, TriangleEpsilon epsilon = new TriangleEpsilon())
        {
            const float eps           = 1e-5f;
            Vector3     lgEdgeStart   = p0;
            Vector3     lgEdgeEnd     = p1;
            Vector3     oppositePt    = p2;
            float       sqrEdgeLength = (p0 - p1).sqrMagnitude + eps; // Add small epsilon to avoid problems with equilateral triangles

            float nextSqrLength = (p1 - p2).sqrMagnitude;

            if (nextSqrLength > sqrEdgeLength)
            {
                lgEdgeStart   = p1;
                lgEdgeEnd     = p2;
                oppositePt    = p0;
                sqrEdgeLength = nextSqrLength;
            }

            nextSqrLength = (p2 - p0).sqrMagnitude;
            if (nextSqrLength > sqrEdgeLength)
            {
                lgEdgeStart   = p2;
                lgEdgeEnd     = p0;
                oppositePt    = p1;
                sqrEdgeLength = nextSqrLength;
            }

            Quaternion oobbRotation = Quaternion.LookRotation((lgEdgeEnd - lgEdgeStart).normalized, normal);
            OOBB       oobb         = new OOBB(oobbRotation);
            float      sizeAdd      = 2.0f * epsilon.AreaEps;
            float      oobbDepth    = Mathf.Sqrt(sqrEdgeLength) + sizeAdd;

            float dotRight   = Vector3.Dot(oobb.Right, (oppositePt - lgEdgeStart));
            float oobbWidth  = Mathf.Abs(dotRight) + sizeAdd;
            float oobbHeight = epsilon.ExtrudeEps * 2.0f;

            oobb.Size = new Vector3(oobbWidth, oobbHeight, oobbDepth);

            Vector3 right = oobb.Right * Mathf.Sign(dotRight);

            oobb.Center = right * oobbWidth * 0.5f - right * epsilon.AreaEps +
                          lgEdgeStart - oobb.Look * epsilon.AreaEps + oobb.Look * oobbDepth * 0.5f;

            return(oobb);
        }
Exemplo n.º 17
0
        public static bool RaycastWire(Ray ray, out float t, Vector3 p0, Vector3 p1, Vector3 p2, TriangleEpsilon epsilon = new TriangleEpsilon())
        {
            t = 0.0f;

            float rayEnter;
            Plane trianglePlane = new Plane(p0, p1, p2);

            if (trianglePlane.Raycast(ray, out rayEnter))
            {
                Vector3 intersectPt   = ray.GetPoint(rayEnter);
                float   distToSegment = intersectPt.GetDistanceToSegment(p0, p1);
                if (distToSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }

                distToSegment = intersectPt.GetDistanceToSegment(p1, p2);
                if (distToSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }

                distToSegment = intersectPt.GetDistanceToSegment(p2, p0);
                if (distToSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }
            }

            if (epsilon.ExtrudeEps != 0.0f)
            {
                float dot = Vector3Ex.AbsDot(ray.direction, trianglePlane.normal);
                if (dot < ExtrudeEpsThreshold.Get)
                {
                    OOBB oobb = Calc3DTriangleOOBB(p0, p1, p2, trianglePlane.normal, epsilon);
                    return(BoxMath.Raycast(ray, oobb.Center, oobb.Size, oobb.Rotation));
                }
            }

            return(false);
        }
Exemplo n.º 18
0
        public static Vector3 CalculateSitOnSurfaceOffset(OOBB oobb, Plane surfacePlane, float offsetFromSurface)
        {
            List <Vector3> oobbCorners     = oobb.GetCornerPoints();
            int            pivotPointIndex = surfacePlane.GetFurthestPtBehind(oobbCorners);

            if (pivotPointIndex < 0)
            {
                pivotPointIndex = surfacePlane.GetClosestPtInFrontOrOnPlane(oobbCorners);
            }

            if (pivotPointIndex >= 0)
            {
                Vector3 pivotPt = oobbCorners[pivotPointIndex];
                Vector3 prjPt   = surfacePlane.ProjectPoint(pivotPt);
                return((prjPt - pivotPt) + surfacePlane.normal * offsetFromSurface);
            }

            return(Vector3.zero);
        }
Exemplo n.º 19
0
        public List <Vector3> OverlapVerts(OOBB oobb, MeshTransform meshTransform)
        {
            if (!_isBuilt)
            {
                Build();
            }

            OOBB          meshSpaceOOBB   = meshTransform.InverseTransformOOBB(oobb);
            HashSet <int> usedIndices     = new HashSet <int>();
            var           overlappedNodes = _tree.OverlapBox(meshSpaceOOBB);

            if (overlappedNodes.Count == 0)
            {
                return(new List <Vector3>());
            }

            var overlappedVerts = new List <Vector3>(50);

            foreach (var node in overlappedNodes)
            {
                int          triangleIndex = node.Data.TriangleIndex;
                MeshTriangle triangleInfo  = _mesh.GetTriangle(triangleIndex);
                var          modelVerts    = triangleInfo.Vertices;

                for (int ptIndex = 0; ptIndex < modelVerts.Length; ++ptIndex)
                {
                    int vertIndex = triangleInfo.GetVertIndex(ptIndex);
                    if (usedIndices.Contains(vertIndex))
                    {
                        continue;
                    }

                    Vector3 modelVert = modelVerts[ptIndex];
                    if (BoxMath.ContainsPoint(modelVert, meshSpaceOOBB.Center, meshSpaceOOBB.Size, meshSpaceOOBB.Rotation))
                    {
                        overlappedVerts.Add(meshTransform.TransformPoint(modelVert));
                        usedIndices.Add(vertIndex);
                    }
                }
            }

            return(overlappedVerts);
        }
Exemplo n.º 20
0
 public List <Vector3> OverlapModelVerts(OOBB modelOOBB)
 {
     return(_meshTree.OverlapModelVerts(modelOOBB));
 }
Exemplo n.º 21
0
 public List <Vector3> OverlapVerts(OOBB oobb, Transform meshObjectTransform)
 {
     return(_meshTree.OverlapVerts(oobb, new MeshTransform(meshObjectTransform)));
 }
Exemplo n.º 22
0
 public bool IntersectsOOBB(OOBB otherOOBB)
 {
     return(BoxMath.BoxIntersectsBox(_center, _size, _rotation, otherOOBB.Center, otherOOBB.Size, otherOOBB.Rotation));
 }
Exemplo n.º 23
0
        public static ObjectSnapResult SnapHierarchy(GameObject root, ObjectSnapConfig snapConfig)
        {
            const float collectEps      = 1e-2f;
            const float collectBoxScale = 1e-3f;

            bool hierarchyHasMeshes  = root.HierarchyHasMesh();
            bool hierarchyHasSprites = root.HierarchyHasSprite();

            if (!hierarchyHasMeshes && !hierarchyHasSprites)
            {
                return(new ObjectSnapResult());
            }

            var boundsQConfig = new ObjectBounds.QueryConfig();

            boundsQConfig.ObjectTypes = GameObjectType.Sprite | GameObjectType.Mesh;

            bool isSurfaceSpherical    = snapConfig.SurfaceType == Type.SphericalMesh;
            bool isSurfaceTerrain      = snapConfig.SurfaceType == Type.UnityTerrain || snapConfig.SurfaceType == Type.TerrainMesh;
            bool isSurfaceUnityTerrain = snapConfig.SurfaceType == Type.UnityTerrain;

            var raycaster = CreateSurfaceRaycaster(snapConfig.SurfaceType, snapConfig.SurfaceObject, true);

            if (snapConfig.SurfaceType != Type.SceneGrid)
            {
                Transform rootTransform = root.transform;
                if (snapConfig.AlignAxis)
                {
                    if (isSurfaceTerrain)
                    {
                        rootTransform.Align(Vector3.up, snapConfig.AlignmentAxis);

                        OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig);
                        if (!hierarchyOOBB.IsValid)
                        {
                            return(new ObjectSnapResult());
                        }

                        BoxFace pivotFace      = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -Vector3.up);
                        var     collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps);

                        if (collectedVerts.Count != 0)
                        {
                            Vector3          vertsCenter = Vector3Ex.GetPointCloudCenter(collectedVerts);
                            Ray              ray         = new Ray(vertsCenter + Vector3.up * 1e-3f, -Vector3.up);
                            GameObjectRayHit surfaceHit  = raycaster.Raycast(ray);

                            if (surfaceHit != null)
                            {
                                Vector3 alignmentAxis = surfaceHit.HitNormal;
                                if (isSurfaceUnityTerrain)
                                {
                                    Terrain terrain = snapConfig.SurfaceObject.GetComponent <Terrain>();
                                    alignmentAxis = terrain.GetInterpolatedNormal(surfaceHit.HitPoint);
                                }
                                Quaternion appliedRotation = rootTransform.Align(alignmentAxis, snapConfig.AlignmentAxis);

                                hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig);
                                appliedRotation.RotatePoints(collectedVerts, rootTransform.position);

                                Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, new Plane(Vector3.up, surfaceHit.HitPoint), 0.1f);
                                rootTransform.position += sitOnPlaneOffset;
                                hierarchyOOBB.Center   += sitOnPlaneOffset;
                                Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset);

                                Vector3 embedVector = Surface.CalculateEmbedVector(collectedVerts, snapConfig.SurfaceObject, -Vector3.up, snapConfig.SurfaceType);
                                rootTransform.position += (embedVector + alignmentAxis * snapConfig.OffsetFromSurface);
                                return(new ObjectSnapResult(new Plane(alignmentAxis, surfaceHit.HitPoint), surfaceHit.HitPoint));
                            }
                        }
                    }
                    else
                    {
                        if (!isSurfaceSpherical)
                        {
                            rootTransform.Align(snapConfig.SurfaceHitNormal, snapConfig.AlignmentAxis);
                            OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig);
                            if (!hierarchyOOBB.IsValid)
                            {
                                return(new ObjectSnapResult());
                            }

                            BoxFace pivotFace      = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -snapConfig.SurfaceHitNormal);
                            var     collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps);

                            if (collectedVerts.Count != 0)
                            {
                                Vector3 vertsCenter = Vector3Ex.GetPointCloudCenter(collectedVerts);

                                // Note: Cast the ray from far away enough so that we don't cast from the interior of the mesh.
                                //       This can happen when the object is embedded inside the mesh surface.
                                AABB    surfaceAABB  = ObjectBounds.CalcMeshWorldAABB(snapConfig.SurfaceObject);
                                float   sphereRadius = surfaceAABB.Extents.magnitude;
                                Vector3 rayOrigin    = vertsCenter + snapConfig.SurfaceHitNormal * sphereRadius;

                                Ray ray = new Ray(rayOrigin, -snapConfig.SurfaceHitNormal);
                                GameObjectRayHit surfaceHit = raycaster.Raycast(ray);

                                if (surfaceHit != null)
                                {
                                    Vector3    alignmentAxis   = surfaceHit.HitNormal;
                                    Quaternion appliedRotation = rootTransform.Align(alignmentAxis, snapConfig.AlignmentAxis);

                                    hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig);
                                    appliedRotation.RotatePoints(collectedVerts, rootTransform.position);

                                    Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, surfaceHit.HitPlane, 0.0f);
                                    rootTransform.position += sitOnPlaneOffset;
                                    hierarchyOOBB.Center   += sitOnPlaneOffset;
                                    Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset);

                                    return(new ObjectSnapResult(new Plane(alignmentAxis, surfaceHit.HitPoint), surfaceHit.HitPoint));
                                }
                            }
                        }
                        else
                        {
                            Transform surfaceObjectTransform = snapConfig.SurfaceObject.transform;
                            Vector3   sphereCenter           = surfaceObjectTransform.position;
                            Vector3   radiusDir    = (rootTransform.position - sphereCenter).normalized;
                            float     sphereRadius = surfaceObjectTransform.lossyScale.GetMaxAbsComp() * 0.5f;

                            rootTransform.Align(radiusDir, snapConfig.AlignmentAxis);
                            OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig);
                            if (!hierarchyOOBB.IsValid)
                            {
                                return(new ObjectSnapResult());
                            }

                            BoxFace pivotFace      = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -radiusDir);
                            var     collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps);

                            Vector3 sitPoint         = sphereCenter + radiusDir * sphereRadius;
                            Plane   sitPlane         = new Plane(radiusDir, sitPoint);
                            Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, sitPlane, 0.0f);

                            rootTransform.position += sitOnPlaneOffset;
                            hierarchyOOBB.Center   += sitOnPlaneOffset;
                            Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset);

                            return(new ObjectSnapResult(sitPlane, sitPoint));
                        }
                    }
                }
                else
                {
                    OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig);
                    if (!hierarchyOOBB.IsValid)
                    {
                        return(new ObjectSnapResult());
                    }

                    if (isSurfaceTerrain || (!isSurfaceSpherical && snapConfig.SurfaceType == Type.Mesh))
                    {
                        Ray ray = new Ray(hierarchyOOBB.Center, isSurfaceTerrain ? -Vector3.up : -snapConfig.SurfaceHitNormal);
                        GameObjectRayHit surfaceHit = raycaster.Raycast(ray);
                        if (surfaceHit != null)
                        {
                            Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, surfaceHit.HitPlane, 0.0f);
                            rootTransform.position += sitOnPlaneOffset;
                            hierarchyOOBB.Center   += sitOnPlaneOffset;

                            if (isSurfaceTerrain)
                            {
                                BoxFace pivotFace      = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -surfaceHit.HitNormal);
                                var     collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps);

                                Vector3 embedVector = Surface.CalculateEmbedVector(collectedVerts, snapConfig.SurfaceObject, -surfaceHit.HitNormal, snapConfig.SurfaceType);
                                rootTransform.position += (embedVector + surfaceHit.HitNormal * snapConfig.OffsetFromSurface);
                            }
                            return(new ObjectSnapResult(surfaceHit.HitPlane, surfaceHit.HitPoint));
                        }
                    }
                    else
                    if (isSurfaceSpherical)
                    {
                        Transform surfaceObjectTransform = snapConfig.SurfaceObject.transform;
                        Vector3   sphereCenter           = surfaceObjectTransform.position;
                        Vector3   radiusDir    = (rootTransform.position - sphereCenter).normalized;
                        float     sphereRadius = surfaceObjectTransform.lossyScale.GetMaxAbsComp() * 0.5f;

                        BoxFace pivotFace      = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -radiusDir);
                        var     collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps);

                        Vector3 sitPoint         = sphereCenter + radiusDir * sphereRadius;
                        Plane   sitPlane         = new Plane(radiusDir, sitPoint);
                        Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, sitPlane, 0.0f);

                        rootTransform.position += sitOnPlaneOffset;
                        hierarchyOOBB.Center   += sitOnPlaneOffset;
                        Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset);

                        return(new ObjectSnapResult(sitPlane, sitPoint));
                    }
                }
            }
            if (snapConfig.SurfaceType == Type.SceneGrid)
            {
                OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig);
                if (!hierarchyOOBB.IsValid)
                {
                    return(new ObjectSnapResult());
                }

                Transform rootTransform = root.transform;
                if (snapConfig.AlignAxis)
                {
                    rootTransform.Align(snapConfig.SurfaceHitNormal, snapConfig.AlignmentAxis);
                    hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig);
                }

                rootTransform.position += Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, snapConfig.SurfaceHitPlane, snapConfig.OffsetFromSurface);
                return(new ObjectSnapResult(snapConfig.SurfaceHitPlane, snapConfig.SurfaceHitPlane.ProjectPoint(hierarchyOOBB.Center)));
            }

            return(new ObjectSnapResult());
        }
Exemplo n.º 24
0
        public static List <Vector3> CollectHierarchyVerts(GameObject root, BoxFace collectFace, float collectBoxScale, float collectEps)
        {
            var meshObjects   = root.GetMeshObjectsInHierarchy();
            var spriteObjects = root.GetSpriteObjectsInHierarchy();

            if (meshObjects.Count == 0 && spriteObjects.Count == 0)
            {
                return(new List <Vector3>());
            }

            var boundsQConfig = new ObjectBounds.QueryConfig();

            boundsQConfig.ObjectTypes = GameObjectType.Mesh | GameObjectType.Sprite;

            OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig);

            if (!hierarchyOOBB.IsValid)
            {
                return(new List <Vector3>());
            }

            int     faceAxisIndex = BoxMath.GetFaceAxisIndex(collectFace);
            Vector3 faceCenter    = BoxMath.CalcBoxFaceCenter(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, collectFace);
            Vector3 faceNormal    = BoxMath.CalcBoxFaceNormal(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, collectFace);

            float   sizeEps         = collectEps * 2.0f;
            Vector3 collectAABBSize = hierarchyOOBB.Size;

            collectAABBSize[faceAxisIndex]            = (hierarchyOOBB.Size[faceAxisIndex] * collectBoxScale) + sizeEps;
            collectAABBSize[(faceAxisIndex + 1) % 3] += sizeEps;
            collectAABBSize[(faceAxisIndex + 2) % 3] += sizeEps;

            OOBB collectOOBB = new OOBB(faceCenter + faceNormal * (-collectAABBSize[faceAxisIndex] * 0.5f + collectEps), collectAABBSize);

            collectOOBB.Rotation = hierarchyOOBB.Rotation;

            var collectedVerts = new List <Vector3>(80);

            foreach (var meshObject in meshObjects)
            {
                Mesh       mesh       = meshObject.GetMesh();
                EditorMesh editorMesh = EditorMeshDb.Get.GetEditorMesh(mesh);
                if (editorMesh == null)
                {
                    continue;
                }

                var verts = editorMesh.OverlapVerts(collectOOBB, meshObject.transform);
                if (verts.Count != 0)
                {
                    collectedVerts.AddRange(verts);
                }
            }

            foreach (var spriteObject in spriteObjects)
            {
                var verts = CollectWorldSpriteVerts(spriteObject.GetSprite(), spriteObject.transform, collectOOBB);
                if (verts.Count != 0)
                {
                    collectedVerts.AddRange(verts);
                }
            }

            return(collectedVerts);
        }
Exemplo n.º 25
0
        public List <GameObjectRayHit> RaycastAll(Ray ray, SceneRaycastPrecision raycastPresicion)
        {
            var nodeHits = _objectTree.RaycastAll(ray);

            if (nodeHits.Count == 0)
            {
                return(new List <GameObjectRayHit>());
            }

            var boundsQConfig = new ObjectBounds.QueryConfig();

            boundsQConfig.ObjectTypes  = GameObjectTypeHelper.AllCombined;
            boundsQConfig.NoVolumeSize = EditorScene.Get.NoVolumeObjectSize;

            if (raycastPresicion == SceneRaycastPrecision.BestFit)
            {
                var hitList = new List <GameObjectRayHit>(10);
                foreach (var nodeHit in nodeHits)
                {
                    GameObject sceneObject = nodeHit.HitNode.Data;
                    if (sceneObject == null || !sceneObject.activeInHierarchy)
                    {
                        continue;
                    }

                    Renderer renderer = sceneObject.GetComponent <Renderer>();
                    if (renderer != null && !renderer.isVisible)
                    {
                        continue;
                    }

                    GameObjectType objectType = sceneObject.GetGameObjectType();
                    if (objectType == GameObjectType.Mesh)
                    {
                        GameObjectRayHit objectHit = RaycastMeshObject(ray, sceneObject);
                        if (objectHit != null)
                        {
                            hitList.Add(objectHit);
                        }
                    }
                    else
                    if (objectType == GameObjectType.Terrain)
                    {
                        TerrainCollider terrainCollider = sceneObject.GetComponent <TerrainCollider>();
                        if (terrainCollider != null)
                        {
                            RaycastHit hitInfo;
                            if (terrainCollider.Raycast(ray, out hitInfo, float.MaxValue))
                            {
                                hitList.Add(new GameObjectRayHit(ray, hitInfo));
                            }
                        }
                    }
                    else
                    if (objectType == GameObjectType.Sprite)
                    {
                        GameObjectRayHit objectHit = RaycastSpriteObject(ray, sceneObject);
                        if (objectHit != null)
                        {
                            hitList.Add(objectHit);
                        }
                    }
                    else
                    {
                        OOBB worldOOBB = ObjectBounds.CalcWorldOOBB(sceneObject, boundsQConfig);
                        if (worldOOBB.IsValid)
                        {
                            float t;
                            if (BoxMath.Raycast(ray, out t, worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation))
                            {
                                var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation);
                                var hit      = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t);
                                hitList.Add(hit);
                            }
                        }
                    }
                }

                return(hitList);
            }
            else
            if (raycastPresicion == SceneRaycastPrecision.Box)
            {
                var hitList = new List <GameObjectRayHit>(10);
                foreach (var nodeHit in nodeHits)
                {
                    GameObject sceneObject = nodeHit.HitNode.Data;
                    if (sceneObject == null || !sceneObject.activeInHierarchy)
                    {
                        continue;
                    }

                    Renderer renderer = sceneObject.GetComponent <Renderer>();
                    if (renderer != null && !renderer.isVisible)
                    {
                        continue;
                    }

                    OOBB worldOOBB = ObjectBounds.CalcWorldOOBB(sceneObject, boundsQConfig);
                    if (worldOOBB.IsValid)
                    {
                        float t;
                        if (BoxMath.Raycast(ray, out t, worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation))
                        {
                            var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation);
                            var hit      = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t);
                            hitList.Add(hit);
                        }
                    }
                }

                return(hitList);
            }

            return(new List <GameObjectRayHit>());
        }
Exemplo n.º 26
0
        public static List <Vector3> CollectWorldSpriteVerts(Sprite sprite, Transform spriteTransform, OOBB collectOOBB)
        {
            var spriteWorldVerts = sprite.GetWorldVerts(spriteTransform);
            var collectedVerts   = new List <Vector3>(7);

            foreach (var vertPos in spriteWorldVerts)
            {
                if (BoxMath.ContainsPoint(vertPos, collectOOBB.Center, collectOOBB.Size, collectOOBB.Rotation))
                {
                    collectedVerts.Add(vertPos);
                }
            }

            return(collectedVerts);
        }
Exemplo n.º 27
0
 public List <GameObject> OverlapBox(OOBB oobb)
 {
     return(_sceneTree.OverlapBox(oobb));
 }