GetChild() protected method

protected GetChild ( float x, float y, float z ) : OctreeNode,
x float
y float
z float
return OctreeNode,
Ejemplo n.º 1
0
    // Returns whether the node is changed.
    private bool AddInternal(IntVector3 coords, T obj, OctreeNode <T> node, int level, IntVector3 corner)
    {
        if (node.isFilled)
        {
            return(false);
        }
        else if (level == 0)
        {
            node.obj      = obj;
            node.objCount = 1;
            return(true);
        }

        int        childSize  = 1 << (level - 1);
        IntVector3 childIndex = (coords - corner) / childSize;
        var        childNode  = node.GetChild(childIndex);

        if (childNode == null)
        {
            childNode = node.CreateChild(childIndex);
        }

        long oldChildObjCount = childNode.objCount;
        bool changed          = AddInternal(coords, obj, childNode, level - 1, corner + childIndex * childSize);

        if (changed)
        {
            node.objCount += childNode.objCount - oldChildObjCount;
            if (childNode.isFilled)
            {
                node.MergeIfPossible(obj);
            }
        }
        return(changed);
    }
Ejemplo n.º 2
0
    // Returns whether the node is changed.
    private bool RemoveInternal(IntBox area, OctreeNode <T> node, int level, IntVector3 corner)
    {
        IntBox nodeArea = new IntBox(corner, corner + ((1 << level) - 1) * IntVector3.one);

        if (area.Contains(nodeArea))
        {
            if (!node.isEmpty)
            {
                node.obj      = default(T);
                node.objCount = 0;
                node.RemoveChildren();
                return(true);
            }
            else
            {
                return(false);
            }
        }
        else if (!node.obj.Equals(default(T)))
        {
            node.Split();
        }

        int        childSize     = 1 << (level - 1);
        IntVector3 childIndexMin = IntVector3.Max((area.min - corner) / childSize, IntVector3.zero);
        IntVector3 childIndexMax = IntVector3.Min((area.max - corner) / childSize, IntVector3.one);
        bool       changed       = false;

        for (int x = childIndexMin.x; x <= childIndexMax.x; x++)
        {
            for (int y = childIndexMin.y; y <= childIndexMax.y; y++)
            {
                for (int z = childIndexMin.z; z <= childIndexMax.z; z++)
                {
                    IntVector3 childIndex = new IntVector3(x, y, z);
                    var        childNode  = node.GetChild(childIndex);
                    if (childNode != null)
                    {
                        long oldChildObjCount = childNode.objCount;
                        bool childChanged     = RemoveInternal(area, childNode, level - 1, corner + childIndex * childSize);
                        if (childChanged)
                        {
                            changed        = true;
                            node.objCount += childNode.objCount - oldChildObjCount;
                            if (childNode.isEmpty)
                            {
                                node.RemoveChild(childIndex);
                            }
                        }
                    }
                }
            }
        }
        return(changed);
    }
Ejemplo n.º 3
0
    // Returns whether the node is changed.
    private bool SetInternal(IntBox area, T obj, OctreeNode <T> node, int level, IntVector3 corner)
    {
        IntBox nodeArea = new IntBox(corner, corner + ((1 << level) - 1) * IntVector3.one);

        if (node.obj.Equals(obj))
        {
            return(false);
        }
        else if (area.Contains(nodeArea))
        {
            node.obj      = obj;
            node.objCount = 1 << level;
            node.RemoveChildren();
            return(true);
        }
        else if (node.isFilled)
        {
            node.Split();
        }

        int        childSize     = 1 << (level - 1);
        IntVector3 childIndexMin = IntVector3.Max((area.min - corner) / childSize, IntVector3.zero);
        IntVector3 childIndexMax = IntVector3.Min((area.max - corner) / childSize, IntVector3.one);
        bool       changed       = false;

        for (int x = childIndexMin.x; x <= childIndexMax.x; x++)
        {
            for (int y = childIndexMin.y; y <= childIndexMax.y; y++)
            {
                for (int z = childIndexMin.z; z <= childIndexMax.z; z++)
                {
                    IntVector3 childIndex = new IntVector3(x, y, z);
                    var        childNode  = node.GetChild(childIndex);
                    if (childNode == null)
                    {
                        childNode = node.CreateChild(childIndex);
                    }

                    long oldChildObjCount = childNode.objCount;
                    bool childChanged     = SetInternal(area, obj, childNode, level - 1, corner + childIndex * childSize);
                    if (childChanged)
                    {
                        changed        = true;
                        node.objCount += childNode.objCount - oldChildObjCount;
                        if (childNode.isFilled)
                        {
                            node.MergeIfPossible(obj);
                        }
                    }
                }
            }
        }
        return(changed);
    }
Ejemplo n.º 4
0
    // Returns whether the node is changed.
    private bool RemoveInternal(IntVector3 coords, OctreeNode <T> node, int level, IntVector3 corner)
    {
        if (level == 0)
        {
            if (!node.isEmpty)
            {
                node.obj      = default(T);
                node.objCount = 0;
                return(true);
            }
            else
            {
                return(false);
            }
        }
        else if (!node.obj.Equals(default(T)))
        {
            node.Split();
        }

        int        childSize  = 1 << (level - 1);
        IntVector3 childIndex = (coords - corner) / childSize;
        var        childNode  = node.GetChild(childIndex);

        if (childNode == null)
        {
            return(false);
        }

        long oldChildObjCount = childNode.objCount;
        bool changed          = RemoveInternal(coords, childNode, level - 1, corner + childIndex * childSize);

        if (changed)
        {
            node.objCount += childNode.objCount - oldChildObjCount;
            if (childNode.isEmpty)
            {
                node.RemoveChild(childIndex);
            }
        }
        return(changed);
    }
Ejemplo n.º 5
0
    private T GetInternal(IntVector3 coords, OctreeNode <T> node, int level, IntVector3 corner)
    {
        if (node.isEmpty)
        {
            return(default(T));
        }
        else if (node.isFilled)
        {
            return(node.obj);
        }

        int        childSize  = 1 << (level - 1);
        IntVector3 childIndex = (coords - corner) / childSize;
        var        childNode  = node.GetChild(childIndex);

        if (childNode == null)
        {
            return(default(T));
        }

        return(GetInternal(coords, childNode, level - 1, corner + childIndex * childSize));
    }
Ejemplo n.º 6
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();
                    }
                }
            }