/// <summary>
        /// Performs a raycast and returns a list of hits for all objects whose meshes
        /// are intersected by the specified ray.
        /// </summary>
        public List <GameObjectRayHit> RaycastAllMesh(Ray ray)
        {
            // First, we will gather the objects whos boxes are intersected by the ray. If
            // no such objects exist, we will return an empty list.
            List <GameObjectRayHit> allBoxHits = RaycastAllBox(ray);

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

            // Now we will loop through all these objects and identify the ones whose meshes
            // are hit by the ray.
            var allMeshObjectHits = new List <GameObjectRayHit>(allBoxHits.Count);
            Octave3DMeshDatabase octave3DMeshDatabase = Octave3DMeshDatabase.Get();

            foreach (var boxHit in allBoxHits)
            {
                // Store the object for easy access
                GameObject hitObject = boxHit.HitObject;
                if (hitObject == null)
                {
                    continue;
                }
                if (!hitObject.activeInHierarchy)
                {
                    continue;
                }

                Renderer renderer = hitObject.GetComponent <Renderer>();
                if (!renderer.enabled)
                {
                    continue;
                }

                // Store the object's mesh. If the object doesn't have a mesh, we will ignore it
                Mesh objectMesh = hitObject.GetMeshFromFilterOrSkinnedMeshRenderer();
                if (objectMesh == null)
                {
                    continue;
                }

                // Check if the ray intersects the mesh
                Octave3DMesh octave3DMesh = octave3DMeshDatabase.GetOctave3DMesh(objectMesh);
                MeshRayHit   meshRayHit   = octave3DMesh.Raycast(ray, hitObject.transform.GetWorldMatrix());

                // If the mesh was hit by the ray, we will store the hit info inside the output array
                if (meshRayHit != null)
                {
                    allMeshObjectHits.Add(new GameObjectRayHit(ray, hitObject, null, meshRayHit, null, null));
                }
            }

            return(allMeshObjectHits);
        }
        public bool ObjectMeshIntersectsAnyMesh(Octave3DMesh octave3DQueryMesh, TransformMatrix worldMatrix, HashSet <GameObject> ignoreObjects)
        {
            if (ignoreObjects == null)
            {
                ignoreObjects = new HashSet <GameObject>();
            }
            OrientedBox queryMeshOOBB = octave3DQueryMesh.GetOOBB(worldMatrix);

            if (queryMeshOOBB.IsInvalid())
            {
                return(false);
            }

            List <SphereTreeNode <GameObject> > allOverlappedNodes = _sphereTree.OverlapBox(queryMeshOOBB);

            if (allOverlappedNodes.Count == 0)
            {
                return(false);
            }

            var overlappedObjects = new List <GameObject>();

            foreach (SphereTreeNode <GameObject> node in allOverlappedNodes)
            {
                GameObject gameObject = node.Data;
                if (gameObject == null)
                {
                    continue;
                }
                if (!gameObject.activeSelf)
                {
                    continue;
                }
                if (ignoreObjects.Contains(gameObject))
                {
                    continue;
                }

                Mesh objectMesh = gameObject.GetMeshFromFilterOrSkinnedMeshRenderer();
                if (objectMesh != null)
                {
                    Octave3DMesh octave3DMesh = Octave3DMeshDatabase.Get().GetOctave3DMesh(objectMesh);
                    if (octave3DMesh != null)
                    {
                        if (octave3DQueryMesh.IntersectsMesh(worldMatrix, octave3DMesh, gameObject.transform.GetWorldMatrix()))
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
        public static Object2ObjectBoxSnapData Create(GameObject meshObject)
        {
            if (meshObject == null)
            {
                return(null);
            }

            Mesh objectMesh = meshObject.GetMeshFromFilterOrSkinnedMeshRenderer();

            if (objectMesh == null)
            {
                return(null);
            }

            Renderer renderer = meshObject.GetRenderer();

            if (renderer == null || !renderer.enabled)
            {
                return(null);
            }

            Octave3DMesh octaveMesh = Octave3DMeshDatabase.Get().GetOctave3DMesh(objectMesh);

            if (octaveMesh == null)
            {
                return(null);
            }

            List <Box> modelVertOverlapBoxes = BuildModelVertOverlapBoxes(octaveMesh);
            var        snapBoxIDs            = Object2ObjectBoxSnapData.GetAllSnapBoxIDs();
            var        modelSnapBoxes        = new List <Box>(snapBoxIDs.Length);
            Box        modelMeshBox          = octaveMesh.ModelAABB;

            BoxFace[] meshBoxFaces = Object2ObjectBoxSnapData.GetBoxFaceToSnapBoxIDMap();
            foreach (var snapBox in snapBoxIDs)
            {
                Box            overlapBox      = modelVertOverlapBoxes[(int)snapBox];
                List <Vector3> overlappedVerts = octaveMesh.GetOverlappedModelVerts(overlapBox);
                Plane          meshFacePlane   = modelMeshBox.GetBoxFacePlane(meshBoxFaces[(int)snapBox]);
                overlappedVerts = meshFacePlane.ProjectAllPoints(overlappedVerts);

                modelSnapBoxes.Add(Box.FromPoints(overlappedVerts));
            }

            return(new Object2ObjectBoxSnapData(meshObject, modelSnapBoxes));
        }
Example #4
0
        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);
            }
        }