Exemplo n.º 1
0
            public static void syncNodeWithVolumeCollider(GameObject nodeGameObject, VolumeCollider volumeCollider, bool processChildren)
            {
                MeshCollider meshCollider = nodeGameObject.GetComponent <MeshCollider>();

                if (meshCollider != null)
                {
                    meshCollider.enabled = volumeCollider.enabled;
                }

                if (processChildren)
                {
                    foreach (Transform child in nodeGameObject.transform)
                    {
                        OctreeNode.syncNodeWithVolumeCollider(child.gameObject, volumeCollider, processChildren);
                    }
                }
            }
Exemplo n.º 2
0
        /// <summary>
        /// Raises the destroy event. However, never destroy the OctreeNodeAlt alone. Instead, destroy the game object it belongs to, so that the entire tree can be cleaned up. This fuction will be automatically called as a result.
        /// </summary>
        public void OnDestroy()
        {
            this.volRend = null;
            this.volColl = null;

            //this should make it easier for GC to dismantle a particularly large tree;
            //but truth is I'm just a c++ nerd who likes cleaning up after myself, wise or unwise :(
            if (this.children != null)
            {
                for (uint i = 0; i < 8; i++)
                {
                    children[i] = null;
                }
                this.children = null;
            }
            //Debug.Log ("Destroyed");
        }
Exemplo n.º 3
0
        /// <summary>
        /// Performs operations on a new OctreeNodeAlt GameObject, and does not have to be called by the average Editor-User. Typically called in CreateOctreeNode, immediately after InitializeNode.
        /// It may be overwritten with care (particularly in building the localPosition)
        /// </summary>
        /// <param name="parent">The parent game object, typically expected to either be something derived from Cubiquity.Volume OR another Octree Node of an identical type.</param>
        public virtual void AttachParent(GameObject parent)
        {
            //we Should be the child of something, but just in case... (Hey it worries me whether !parent works... null is odd in some languages)
            if (parent == null)
            {
                gameObject.transform.localPosition = lowerCorner;
                return;
            }

            //yay unity-relevant initialization stuff
            gameObject.layer            = parent.layer;
            gameObject.transform.parent = parent.transform;             //this is actually what physically hooks them together. It makes gameObject the child of parent

            //this might seem odd to place here instead of at the top but the order we add transforms matters. If we change localPosition before the parent
            //transform we'll get funny errors where the whole map condenses on itself.
            gameObject.transform.localPosition = lowerCorner;

            //see if we are the child of a volume, or of another node...
            OctreeNodeAlt parentNode = parent.GetComponent <OctreeNodeAlt>();

            //if there is no parent node...
            if (parentNode != null)
            {
                //Debug.Log ("No Parents");
                //Transform the localposition by the parentnode
                gameObject.transform.localPosition -= parentNode.lowerCorner;

                //grab the parent node's volume renderer & collider
                volRend = parentNode.volRend;
                volColl = parentNode.volColl;
            }
            else
            {
                //Debug.Log ("Volume renderer and collider successfully passed to root.");
                //otherwise I really hope this is the child of a Volume!
                volRend = parent.GetComponent <VolumeRenderer>();
                volColl = parent.GetComponent <VolumeCollider>();
            }

            //Debug.Log ("Testing VolRend & VolColl: " + volRend.ToString() + volColl.ToString());
        }
Exemplo n.º 4
0
        /// <summary>
        /// This function can be used to force the entire mesh to sync on next update, which is useful in situations where a very important top level component has changed dramatically (ie, if volumeRenderer is gone).
        /// </summary>
        public void ForceSync()
        {
            //see if we can get our parent node
            OctreeNodeAlt parentNode = gameObject.GetComponentInParent <OctreeNodeAlt>() as OctreeNodeAlt;

            //if there is no parent node...
            if (parentNode != null)
            {
                //grab the parent node's volume renderer & collider
                volRend = parentNode.volRend;
                volColl = parentNode.volColl;
            }
            else
            {
                //Debug.Log ("Volume renderer and collider successfully passed to root.");
                //otherwise I really hope this is the child of a Volume!
                volRend = gameObject.GetComponentInParent <VolumeRenderer>() as VolumeRenderer;
                volColl = gameObject.GetComponentInParent <VolumeCollider>() as VolumeCollider;
            }

            //doing this will force all meshes to be rebuilt. Which will force the octreenode to ask "Do i have a volume renderer to even display this with?"
            meshLastSyncronised = 0;

            if (children == null)
            {
                return;
            }

            //this loop will iterate through all the children
            for (uint i = 0; i < 8; i++)
            {
                if (children[i] != null)
                {
                    children[i].RelayComponentChanges();
                }
            }
        }
Exemplo n.º 5
0
            public static void syncNodeWithVolumeCollider(GameObject nodeGameObject, VolumeCollider volumeCollider, bool processChildren)
            {
                MeshCollider meshCollider = nodeGameObject.GetComponent<MeshCollider>();
                if (meshCollider != null)
                {
                    meshCollider.enabled = volumeCollider.enabled;
                }

                if (processChildren)
                {
                    foreach (Transform child in nodeGameObject.transform)
                    {
                        OctreeNode.syncNodeWithVolumeCollider(child.gameObject, volumeCollider, processChildren);
                    }
                }
            }
Exemplo n.º 6
0
            public int syncNode(int availableNodeSyncs, GameObject voxelTerrainGameObject)
            {
                int nodeSyncsPerformed = 0;

                if (availableNodeSyncs <= 0)
                {
                    return(nodeSyncsPerformed);
                }

                uint meshLastUpdated = CubiquityDLL.GetMeshLastUpdated(nodeHandle);

                if (meshLastSyncronised < meshLastUpdated)
                {
                    if (CubiquityDLL.NodeHasMesh(nodeHandle) == 1)
                    {
                        // Set up the rendering mesh
                        VolumeRenderer volumeRenderer = voxelTerrainGameObject.GetComponent <VolumeRenderer>();
                        if (volumeRenderer != null)
                        {
                            //Mesh renderingMesh = volumeRenderer.BuildMeshFromNodeHandle(nodeHandle);

                            Mesh renderingMesh = null;
                            if (voxelTerrainGameObject.GetComponent <Volume>().GetType() == typeof(TerrainVolume))
                            {
                                renderingMesh = BuildMeshFromNodeHandleForTerrainVolume(nodeHandle);
                            }
                            else if (voxelTerrainGameObject.GetComponent <Volume>().GetType() == typeof(ColoredCubesVolume))
                            {
                                renderingMesh = BuildMeshFromNodeHandleForColoredCubesVolume(nodeHandle);
                            }

                            MeshFilter   meshFilter   = gameObject.GetOrAddComponent <MeshFilter>() as MeshFilter;
                            MeshRenderer meshRenderer = gameObject.GetOrAddComponent <MeshRenderer>() as MeshRenderer;

                            if (meshFilter.sharedMesh != null)
                            {
                                DestroyImmediate(meshFilter.sharedMesh);
                            }

                            meshFilter.sharedMesh = renderingMesh;

                            meshRenderer.sharedMaterial = volumeRenderer.material;

                                                        #if UNITY_EDITOR
                            EditorUtility.SetSelectedWireframeHidden(meshRenderer, true);
                                                        #endif
                        }

                        // Set up the collision mesh
                        VolumeCollider volumeCollider = voxelTerrainGameObject.GetComponent <VolumeCollider>();
                        if ((volumeCollider != null) && (Application.isPlaying))
                        {
                            Mesh         collisionMesh = volumeCollider.BuildMeshFromNodeHandle(nodeHandle);
                            MeshCollider meshCollider  = gameObject.GetOrAddComponent <MeshCollider>() as MeshCollider;
                            meshCollider.sharedMesh = collisionMesh;
                        }
                    }
                    // If there is no mesh in Cubiquity then we make sure there isn't on in Unity.
                    else
                    {
                        MeshCollider meshCollider = gameObject.GetComponent <MeshCollider>() as MeshCollider;
                        if (meshCollider)
                        {
                            DestroyImmediate(meshCollider);
                        }

                        MeshRenderer meshRenderer = gameObject.GetComponent <MeshRenderer>() as MeshRenderer;
                        if (meshRenderer)
                        {
                            DestroyImmediate(meshRenderer);
                        }

                        MeshFilter meshFilter = gameObject.GetComponent <MeshFilter>() as MeshFilter;
                        if (meshFilter)
                        {
                            DestroyImmediate(meshFilter);
                        }
                    }

                    meshLastSyncronised = CubiquityDLL.GetCurrentTime();
                    availableNodeSyncs--;
                    nodeSyncsPerformed++;
                }

                VolumeRenderer vr = voxelTerrainGameObject.GetComponent <VolumeRenderer>();
                MeshRenderer   mr = gameObject.GetComponent <MeshRenderer>();
                if (vr != null && mr != null)
                {
                    if (mr.enabled != vr.enabled)                    // Not sure we really need this check?
                    {
                        mr.enabled = vr.enabled;
                    }

                    if (lastSyncronisedWithVolumeRenderer < vr.lastModified)
                    {
                        mr.receiveShadows = vr.receiveShadows;
                        mr.castShadows    = vr.castShadows;
                        lastSyncronisedWithVolumeRenderer = Clock.timestamp;
                    }
                }

                VolumeCollider vc = voxelTerrainGameObject.GetComponent <VolumeCollider>();
                MeshCollider   mc = gameObject.GetComponent <MeshCollider>();
                if (vc != null && mc != null)
                {
                    if (mc.enabled != vc.enabled)                    // Not sure we really need this check?
                    {
                        mc.enabled = vc.enabled;
                    }

                    if (lastSyncronisedWithVolumeCollider < vc.lastModified)
                    {
                        // Actual syncronization to be filled in in the future when we have something to syncronize.
                        lastSyncronisedWithVolumeCollider = Clock.timestamp;
                    }
                }

                //Now syncronise any children
                for (uint z = 0; z < 2; z++)
                {
                    for (uint y = 0; y < 2; y++)
                    {
                        for (uint x = 0; x < 2; x++)
                        {
                            if (CubiquityDLL.HasChildNode(nodeHandle, x, y, z) == 1)
                            {
                                uint childNodeHandle = CubiquityDLL.GetChildNode(nodeHandle, x, y, z);

                                GameObject childGameObject = GetChild(x, y, z);

                                if (childGameObject == null)
                                {
                                    childGameObject = OctreeNode.CreateOctreeNode(childNodeHandle, gameObject);

                                    SetChild(x, y, z, childGameObject);
                                }

                                //syncNode(childNodeHandle, childGameObject);

                                OctreeNode childOctreeNode = childGameObject.GetComponent <OctreeNode>();
                                int        syncs           = childOctreeNode.syncNode(availableNodeSyncs, voxelTerrainGameObject);
                                availableNodeSyncs -= syncs;
                                nodeSyncsPerformed += syncs;
                            }
                        }
                    }
                }

                return(nodeSyncsPerformed);
            }
Exemplo n.º 7
0
            public static void syncNode(ref uint availableSyncOperations, GameObject nodeGameObject, uint nodeHandle, GameObject voxelTerrainGameObject)
            {
                OctreeNode   octreeNode   = nodeGameObject.GetComponent <OctreeNode>();
                CuOctreeNode cuOctreeNode = CubiquityDLL.GetOctreeNode(nodeHandle);

                ////////////////////////////////////////////////////////////////////////////////
                // Has anything in this node or its children changed? If so, we may need to syncronise the node's properties, mesh and
                // structure. Each of these can be tested against a timestamp. We may also need to do this recursively on child nodes.
                ////////////////////////////////////////////////////////////////////////////////
                if (cuOctreeNode.nodeOrChildrenLastChanged > octreeNode.nodeAndChildrenLastSynced)
                {
                    bool resyncedProperties = false; // See comments where this is tested - it's a bit of a hack

                    ////////////////////////////////////////////////////////////////////////////////
                    // 1st test - Have the properties of the node changed?
                    ////////////////////////////////////////////////////////////////////////////////
                    if (cuOctreeNode.propertiesLastChanged > octreeNode.propertiesLastSynced)
                    {
                        octreeNode.renderThisNode       = cuOctreeNode.renderThisNode != 0;
                        octreeNode.height               = cuOctreeNode.height;
                        octreeNode.propertiesLastSynced = CubiquityDLL.GetCurrentTime();
                        resyncedProperties              = true;
                    }

                    ////////////////////////////////////////////////////////////////////////////////
                    // 2nd test - Has the mesh changed and do we have time to syncronise it?
                    ////////////////////////////////////////////////////////////////////////////////
                    if ((cuOctreeNode.meshLastChanged > octreeNode.meshLastSynced) && (availableSyncOperations > 0))
                    {
                        if (cuOctreeNode.hasMesh == 1)
                        {
                            // Set up the rendering mesh
                            VolumeRenderer volumeRenderer = voxelTerrainGameObject.GetComponent <VolumeRenderer>();
                            if (volumeRenderer != null)
                            {
                                MeshFilter meshFilter = nodeGameObject.GetOrAddComponent <MeshFilter>() as MeshFilter;
                                if (meshFilter.sharedMesh == null)
                                {
                                    meshFilter.sharedMesh = new Mesh();
                                }
                                MeshRenderer meshRenderer = nodeGameObject.GetOrAddComponent <MeshRenderer>() as MeshRenderer;

                                if (voxelTerrainGameObject.GetComponent <Volume>().GetType() == typeof(TerrainVolume))
                                {
                                    MeshConversion.BuildMeshFromNodeHandleForTerrainVolume(meshFilter.sharedMesh, nodeHandle, false);
                                }
                                else if (voxelTerrainGameObject.GetComponent <Volume>().GetType() == typeof(ColoredCubesVolume))
                                {
                                    MeshConversion.BuildMeshFromNodeHandleForColoredCubesVolume(meshFilter.sharedMesh, nodeHandle, false);
                                }

                                meshRenderer.enabled = volumeRenderer.enabled && octreeNode.renderThisNode;

                                // For syncing materials, shadow properties, etc.
                                syncNodeWithVolumeRenderer(nodeGameObject, volumeRenderer, false);
                            }

                            // Set up the collision mesh
                            VolumeCollider volumeCollider = voxelTerrainGameObject.GetComponent <VolumeCollider>();
                            if (volumeCollider != null)
                            {
                                bool useCollider = volumeCollider.useInEditMode || Application.isPlaying;

                                if (useCollider)
                                {
                                    // I'm not quite comfortable with this. For some reason we have to create this new mesh, fill it,
                                    // and set it as the collider's shared mesh, whereas I would rather just pass the collider's sharedMesh
                                    // straight to the functon that fills it. For some reason that doesn't work properly, and we see
                                    // issues with objects falling through terrain or not updating when part of the terrain is deleted.
                                    // It's to be investigated further... perhaps we could try deleting and recreating the MeshCollider?
                                    // Still, the approach below seems to work properly.
                                    Mesh collisionMesh = new Mesh();
                                    if (voxelTerrainGameObject.GetComponent <Volume>().GetType() == typeof(TerrainVolume))
                                    {
                                        MeshConversion.BuildMeshFromNodeHandleForTerrainVolume(collisionMesh, nodeHandle, true);
                                    }
                                    else if (voxelTerrainGameObject.GetComponent <Volume>().GetType() == typeof(ColoredCubesVolume))
                                    {
                                        MeshConversion.BuildMeshFromNodeHandleForColoredCubesVolume(collisionMesh, nodeHandle, true);
                                    }

                                    MeshCollider meshCollider = nodeGameObject.GetOrAddComponent <MeshCollider>() as MeshCollider;
                                    meshCollider.sharedMesh = collisionMesh;
                                }
                            }
                        }
                        // If there is no mesh in Cubiquity then we make sure there isn't one in Unity.
                        else
                        {
                            MeshCollider meshCollider = nodeGameObject.GetComponent <MeshCollider>() as MeshCollider;
                            if (meshCollider)
                            {
                                Utility.DestroyOrDestroyImmediate(meshCollider);
                            }

                            MeshRenderer meshRenderer = nodeGameObject.GetComponent <MeshRenderer>() as MeshRenderer;
                            if (meshRenderer)
                            {
                                Utility.DestroyOrDestroyImmediate(meshRenderer);
                            }

                            MeshFilter meshFilter = nodeGameObject.GetComponent <MeshFilter>() as MeshFilter;
                            if (meshFilter)
                            {
                                Utility.DestroyOrDestroyImmediate(meshFilter);
                            }
                        }

                        octreeNode.meshLastSynced = CubiquityDLL.GetCurrentTime();
                        availableSyncOperations--;
                    }

                    // We want to syncronize the properties before the mesh, so that the enabled flag can be set correctly when the mesh
                    // is created. But we also want to syncronize properties after the mesh, so we can apply the correct enabled flag to
                    // existing meshes when the node's 'renderThisNode' flag has changed. Therefore we set the 'resyncedProperties' flag
                    // previously to let ourseves know that we should come back an finish the propertiy syncing here. It's a bit of a hack.
                    if (resyncedProperties)
                    {
                        VolumeRenderer volumeRenderer = voxelTerrainGameObject.GetComponent <VolumeRenderer>();
                        if (volumeRenderer != null)
                        {
                            syncNodeWithVolumeRenderer(nodeGameObject, volumeRenderer, false);
                        }

                        VolumeCollider volumeCollider = voxelTerrainGameObject.GetComponent <VolumeCollider>();
                        if (volumeCollider != null)
                        {
                            syncNodeWithVolumeCollider(nodeGameObject, volumeCollider, false);
                        }
                    }

                    uint[, ,] childHandleArray = new uint[2, 2, 2];
                    childHandleArray[0, 0, 0]  = cuOctreeNode.childHandle000;
                    childHandleArray[0, 0, 1]  = cuOctreeNode.childHandle001;
                    childHandleArray[0, 1, 0]  = cuOctreeNode.childHandle010;
                    childHandleArray[0, 1, 1]  = cuOctreeNode.childHandle011;
                    childHandleArray[1, 0, 0]  = cuOctreeNode.childHandle100;
                    childHandleArray[1, 0, 1]  = cuOctreeNode.childHandle101;
                    childHandleArray[1, 1, 0]  = cuOctreeNode.childHandle110;
                    childHandleArray[1, 1, 1]  = cuOctreeNode.childHandle111;

                    ////////////////////////////////////////////////////////////////////////////////
                    // 3rd test - Has the structure of the octree node changed (gained or lost children)?
                    ////////////////////////////////////////////////////////////////////////////////
                    if (cuOctreeNode.structureLastChanged > octreeNode.structureLastSynced)
                    {
                        //Now syncronise any children
                        for (uint z = 0; z < 2; z++)
                        {
                            for (uint y = 0; y < 2; y++)
                            {
                                for (uint x = 0; x < 2; x++)
                                {
                                    if (childHandleArray[x, y, z] != 0xFFFFFFFF)
                                    {
                                        uint childNodeHandle = childHandleArray[x, y, z];

                                        if (octreeNode.GetChild(x, y, z) == null)
                                        {
                                            octreeNode.SetChild(x, y, z, OctreeNode.CreateOctreeNode(childNodeHandle, nodeGameObject));
                                        }
                                    }
                                    else
                                    {
                                        if (octreeNode.GetChild(x, y, z))
                                        {
                                            Utility.DestroyOrDestroyImmediate(octreeNode.GetChild(x, y, z));
                                            octreeNode.SetChild(x, y, z, null);
                                        }
                                    }
                                }
                            }
                        }

                        octreeNode.structureLastSynced = CubiquityDLL.GetCurrentTime();
                    }

                    ////////////////////////////////////////////////////////////////////////////////
                    // The last step of syncronization is to apply it recursively to our children.
                    ////////////////////////////////////////////////////////////////////////////////
                    for (uint z = 0; z < 2; z++)
                    {
                        for (uint y = 0; y < 2; y++)
                        {
                            for (uint x = 0; x < 2; x++)
                            {
                                if (octreeNode.GetChild(x, y, z) != null && availableSyncOperations > 0)
                                {
                                    OctreeNode.syncNode(ref availableSyncOperations, octreeNode.GetChild(x, y, z), childHandleArray[x, y, z], voxelTerrainGameObject);
                                }
                            }
                        }
                    }

                    // We've reached the end of our syncronization process. If there are still sync operations available then
                    // we did less work then we could have, which implies we finished. Therefore mark the whole tree as synced.
                    if (availableSyncOperations > 0)
                    {
                        octreeNode.nodeAndChildrenLastSynced = CubiquityDLL.GetCurrentTime();
                    }
                }
            }