Beispiel #1
0
 /// <summary>
 /// Initializes and divides tree
 /// </summary>
 /// <param name="depthDivision">Depth of division</param>
 /// <param name="transformParent">Parent for tree trunk GameObject</param>
 public void InitializeTree(int depthDivision, Transform transformParent = null)
 {
     trunk = new OctreeNode();
     trunk.gameObject = new GameObject();
     trunk.gameObject.transform.parent = transformParent;
     trunk.AABB = new Bounds(Vector3.zero, new Vector3(4, 4, 4));
     DivideTree(2);
     InitializeDeepestNodesValue();
 }
Beispiel #2
0
 public void Build(MeshDesc desc, OctreeNode root)
 {
     desc.Clear();
     meshDesc = desc;
     if (root != null)
     {
         GenerateVertices(root);
         ContourCellProc(root);
     }
 }
Beispiel #3
0
    /// <summary>
    /// Recursively divides tree
    /// </summary>
    /// <param name="n">Current node</param>
    /// <param name="depth">Depth of division</param>
    /// <param name="_deepestNodes">List to add deepest nodes to</param>
    private void DivideTreeNode(OctreeNode n, int depth, List<OctreeNode> _deepestNodes)
    {
        var parentBB = n.AABB;
        OctreeNode t;
        Vector3 e = parentBB.extents /= 2;

        n.children.Add(t = new OctreeNode());
        t.AABB = parentBB;
        t.AABB.center += new Vector3(e.x, e.y, e.z);

        n.children.Add(t = new OctreeNode());
        t.AABB = parentBB;
        t.AABB.center += new Vector3(-e.x, e.y, e.z);

        n.children.Add(t = new OctreeNode());
        t.AABB = parentBB;
        t.AABB.center += new Vector3(e.x, -e.y, e.z);

        n.children.Add(t = new OctreeNode());
        t.AABB = parentBB;
        t.AABB.center += new Vector3(-e.x, -e.y, e.z);

        n.children.Add(t = new OctreeNode());
        t.AABB = parentBB;
        t.AABB.center += new Vector3(e.x, e.y, -e.z);

        n.children.Add(t = new OctreeNode());
        t.AABB = parentBB;
        t.AABB.center += new Vector3(-e.x, e.y, -e.z);

        n.children.Add(t = new OctreeNode());
        t.AABB = parentBB;
        t.AABB.center += new Vector3(e.x, -e.y, -e.z);

        n.children.Add(t = new OctreeNode());
        t.AABB = parentBB;
        t.AABB.center += new Vector3(-e.x, -e.y, -e.z);

        for (int i = 0; i < n.children.Count; i++)
        {
            t = n.children[i];
            t.parent = n;
            t.gameObject = new GameObject();
            t.gameObject.transform.position = t.AABB.center;
            t.gameObject.transform.localScale = t.AABB.size;
            t.gameObject.transform.parent = n.gameObject.transform;
        }

        if (depth-- > 0)
            for (int i = 0; i < n.children.Count; i++)
                DivideTreeNode(n.children[i], depth, _deepestNodes);
        else
            _deepestNodes.AddRange(n.children);
    }
Beispiel #4
0
 void DrawNode(OctreeNode node)
 {
     switch (mode)
     {
         case Mode.Hierarchy:
             DrawNode_HierarchyMode(node);
             break;
         case Mode.Edges:
             DrawNode_EdgesMode(node);
             break;
     }
 }
Beispiel #5
0
    void DrawNode_EdgesMode(OctreeNode node)
    {
        const float dotSize = 0.01f;
        if (node.type == OctreeNode.Type.Leaf)
        {
            Vector3 nodeSize = new Vector3(size, size, size) * node.size;
            Vector3 center = node.min + nodeSize * 0.5f;
            Gizmos.DrawWireCube(center, nodeSize);

            Gizmos.DrawCube(node.info.position, new Vector3(dotSize, dotSize, dotSize));
        }
    }
Beispiel #6
0
 public Octree(BoundingBox bounds, int maxDepth, int maxObjectsPerNode, int minObjectsPerNode)
 {
     Bounds = bounds;
     MaxDepth = maxDepth;
     MaxObjectsPerNode = maxObjectsPerNode;
     MinObjectsPerNode = minObjectsPerNode;
     Root = new OctreeNode(Bounds, this, 0, null);
     DebugDraw = false;
     Lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
     ObjectsToNodes = new Dictionary<IBoundedObject, OctreeNode>();
     ObjectsToUpdate = new Dictionary<IBoundedObject, bool>();
     UpdateTimer = new Timer(1.0f, false);
 }
Beispiel #7
0
 void DrawNode_HierarchyMode(OctreeNode node)
 {
     Vector3 nodeSize = new Vector3(size, size, size) * node.size;
     Vector3 center = node.min + nodeSize * 0.5f;
     switch (node.type)
     {
         case OctreeNode.Type.Leaf:
             Gizmos.DrawCube(center, nodeSize);
             break;
         case OctreeNode.Type.Internal:
             Gizmos.DrawWireCube(center, nodeSize);
             break;
     }
 }
Beispiel #8
0
    public static void Build(OctreeNode node, int minSize)
    {
        if (node == null)
            return;
        if (node.size < minSize)
            return;

        int childSize = node.size / 2;
        for (int i = 0; i < 8; ++i)
        {
            OctreeNode child = new OctreeNode();
            child.type = OctreeNode.Type.Internal;
            child.size = childSize;
            child.min = node.min + (CHILD_MIN_OFFSETS[i] * childSize);
            Build(child, minSize);
            node.children[i] = child;
        }
    }
Beispiel #9
0
    void ContourCellProc(OctreeNode node)
    {
        if (node.type == OctreeNode.Type.Internal)
        {
            for (int i = 0; i < node.children.Length; ++i)
            {
                OctreeNode child = node.children[i];
                if (child != null)
                    ContourCellProc(child);
            }

            for (int i = 0; i < 12; ++i)
            {
                OctreeNode[] faceNodes = new OctreeNode[2];
                int[] c = new int[2]{ cellProcFaceMask[i, 0], cellProcFaceMask[i, 1] };

                faceNodes[0] = node.children[c[0]];
                faceNodes[1] = node.children[c[1]];

                ContourFaceProc(faceNodes, cellProcFaceMask[i, 2]);
            }

            for (int i = 0; i < 6; ++i)
            {
                OctreeNode[] edgeNodes = new OctreeNode[4];
                int[] c = new int[4]
                {
                    cellProcEdgeMask[i, 0],
                    cellProcEdgeMask[i, 1],
                    cellProcEdgeMask[i, 2],
                    cellProcEdgeMask[i, 3],
                };

                for (int j = 0; j < 4; ++j)
                {
                    edgeNodes[j] = node.children[c[j]];
                }

                ContourEdgeProc(edgeNodes, cellProcEdgeMask[i, 4]);
            }
        }
    }
Beispiel #10
0
        public Window()
            : base(1280, 720, new GraphicsMode(32, 0, 0, 4), "OpenCAD")
        {
            stl = new STL("Models/elephant.stl", Color.Green, STLType.Binary);

            var s1 = new Sphere {Center = Vect3.Zero, Radius = 4};
            var s2 = new Sphere {Center = new Vect3(0,5,0), Radius = 4};
            var t1 = new Octree<Voxel>(Vect3.Zero, 32.0);
            var t2 = new Octree<Voxel>(Vect3.Zero, 32.0);

            Test2(t1, node => s1.Intersects(node.AABB));
            Test(t2, stl.Elements);

            _tree = t1.Union(t2);

            //_tree.Test(node => sphere.Intersects(node.AABB),maxLevel);
            //Test2(t, node => sphere.Intersects(node.AABB));

            //t[0].Clear();
            //t[0].Clear();
            //Test(_tree,stl.Elements);
            //create from stl
            //foreach (var tri in stl.Elements)
            //{
            //    Intersect(_tree, tri);
            //}

            VSync = VSyncMode.On;

            _camera = new Camera();
            Mouse.WheelChanged += (sender, args) =>
                {
                    _camera.View = _camera.View * Mat4.Translate(0, 0, args.DeltaPrecise * -10.0);
                    //_camera.Eye += new Vect3(0, 0, args.DeltaPrecise * -10.0);
                    // Console.WriteLine(_camera.Eye);
                };
        }
Beispiel #11
0
 public static OctreeChildCoords FromIndex(OctreeNode.ChildIndex index)
 {
     switch (index)
     {
         case OctreeNode.ChildIndex.LeftBelowBack:
             return new OctreeChildCoords(0, 0, 0);
         case OctreeNode.ChildIndex.LeftBelowForward:
             return new OctreeChildCoords(0, 0, 1);
         case OctreeNode.ChildIndex.LeftAboveBack:
             return new OctreeChildCoords(0, 1, 0);
         case OctreeNode.ChildIndex.LeftAboveForward:
             return new OctreeChildCoords(0, 1, 1);
         case OctreeNode.ChildIndex.RightBelowBack:
             return new OctreeChildCoords(1, 0, 0);
         case OctreeNode.ChildIndex.RightBelowForward:
             return new OctreeChildCoords(1, 0, 1);
         case OctreeNode.ChildIndex.RightAboveBack:
             return new OctreeChildCoords(1, 1, 0);
         case OctreeNode.ChildIndex.RightAboveForward:
             return new OctreeChildCoords(1, 1, 1);
         default:
             throw new ArgumentOutOfRangeException("index", index, null);
     }
 }
Beispiel #12
0
            /// <summary>
            /// Reduce the depth of the tree
            /// </summary>
            public void reduce()
            {
                int index;

                for (index = _maxColorBits - 1; (index > 0) && (null == _reducibleNodes[index]); ++index) ;

                OctreeNode node = _reducibleNodes[index];
                _reducibleNodes[index] = node.nextReducible;

                _leafCount -= node.reduce();
                _previousNode = null;
            }
Beispiel #13
0
 /// <summary>
 /// Keep track of the previous node that was quantized
 /// </summary>
 /// <param name="node">The node last quantized</param>
 protected void TrackPrevious(OctreeNode node)
 {
     _previousNode = node;
 }
Beispiel #14
0
 protected void TrackPrevious(OctreeNode node) => this.previousNode = node;
Beispiel #15
0
        ///
        /// <summary>
        /// Add items to the Octree
        /// </summary>
        ///
        /// <param name="itemPositions">
        /// The positions (centroid) of the items being added
        /// </param>
        ///
        /// <param name="itemBoundingBoxes">
        /// The bounding boxes for each item being added
        /// </param>
        ///
        /// <param name="searchRoot">
        /// The node to attempt to add the items within
        /// </param>
        ///
        private void AddItems(Vector3[] itemPositions, BoundingBox[] itemBoundingBoxes, OctreeNode searchRoot)
        {
            if (itemPositions.Length != itemBoundingBoxes.Length)
            {
                throw new ArgumentException("there must be as many item positions as there are item bounding boxes");
            }

            for (int i = 0; i < itemPositions.Length; ++i)
            {
                List <OctreeNode> nodes = FindContainingNodes(searchRoot, itemBoundingBoxes[i]);

                foreach (OctreeNode node in nodes)
                {
                    if (node.InternalObjectPositions.Count + 1 >= _maximumObjectsInNode)
                    {
                        BreakDownNode(node);
                        List <OctreeNode> newNodes = FindContainingNodes(node, itemBoundingBoxes[i]);
                        foreach (OctreeNode newNode in newNodes)
                        {
                            // These nodes will be brand new, so we can always add 1 item to them without checks
                            newNode.AddObject(itemPositions[i], itemBoundingBoxes[i]);
                        }
                    }
                    else
                    {
                        node.AddObject(itemPositions[i], itemBoundingBoxes[i]);
                    }
                }
            }
        }
    private List <OctreeNode> ComputeVoxels(ComputeShader shader, Vector3 min, int octreeSize)
    {
        float gpuStart = Time.realtimeSinceStartup;

        float[] chunkPos = new float[3] {
            min.x, min.y, min.z
        };
        shader.SetFloats("chunkPosition", chunkPos);

        shader.SetInt("resolution", octreeSize);
        shader.SetInt("octreeSize", octreeSize);

        float sqRTRC  = Mathf.Sqrt(octreeSize * octreeSize * octreeSize);
        int   sqRTRes = (int)sqRTRC;

        if (sqRTRC > sqRTRes)
        {
            sqRTRes++;
        }

        ComputeBuffer Perm = new ComputeBuffer(512, sizeof(int));

        Perm.SetData(permutations);

        ComputeBuffer cornCount    = new ComputeBuffer(sqRTRes, sizeof(int));
        ComputeBuffer finalCount   = new ComputeBuffer(1, sizeof(float));
        ComputeBuffer voxMatBuffer = new ComputeBuffer(octreeSize * octreeSize * octreeSize, sizeof(uint));

        float rD8  = octreeSize / 8.0f;
        int   rD8I = (int)rD8;

        if (rD8 > rD8I)
        {
            rD8I++;
        }

        int kernel = shader.FindKernel("ComputeCorners");

        shader.SetBuffer(kernel, "Perm", Perm);
        shader.SetBuffer(kernel, "voxelMaterials", voxMatBuffer);
        shader.Dispatch(kernel, rD8I, rD8I, rD8I);

        /*kernel = shader.FindKernel("ComputeLength");
         * shader.SetBuffer(kernel, "voxelMaterials", voxMatBuffer);
         * shader.SetBuffer(kernel, "cornerCount", cornCount);
         * shader.Dispatch(kernel, 1, 1, 1);*/

        kernel = shader.FindKernel("AddLength");
        shader.SetBuffer(kernel, "cornerCount", cornCount);
        shader.SetBuffer(kernel, "finalCount", finalCount);
        shader.Dispatch(kernel, 1, 1, 1);

        float[] voxelCount = new float[1];
        finalCount.GetData(voxelCount);
        finalCount.SetData(voxelCount);
        int count = (int)voxelCount[0];

        //Debug.Log (count);

        if (count <= 0)
        {
            voxMatBuffer.Dispose();
            cornCount.Dispose();
            finalCount.Dispose();
            Perm.Dispose();
            return(null);
        }

        ComputeBuffer cornerIndexes = new ComputeBuffer(count, sizeof(uint));

        kernel = shader.FindKernel("ComputePositions");
        shader.SetBuffer(kernel, "voxelMaterials", voxMatBuffer);
        shader.SetBuffer(kernel, "cornerCount", cornCount);
        shader.SetBuffer(kernel, "cornerIndexes", cornerIndexes);
        shader.Dispatch(kernel, 1, 1, 1);

        ComputeBuffer voxBuffer      = new ComputeBuffer(count, (sizeof(float) * 6) + sizeof(int));
        ComputeBuffer positionBuffer = new ComputeBuffer(count, sizeof(float) * 3);

        kernel = shader.FindKernel("ComputeVoxels");
        shader.SetBuffer(kernel, "Perm", Perm);
        shader.SetBuffer(kernel, "voxMins", positionBuffer);
        shader.SetBuffer(kernel, "voxelMaterials", voxMatBuffer);
        shader.SetBuffer(kernel, "finalCount", finalCount);
        shader.SetBuffer(kernel, "cornerIndexes", cornerIndexes);
        shader.SetBuffer(kernel, "voxels", voxBuffer);
        //int dispatchCount = count / 10;
        shader.Dispatch(kernel, (count / 128) + 1, 1, 1);

        List <OctreeNode> computedVoxels = new List <OctreeNode>();

        Vector3[] voxelMins = new Vector3[count];
        positionBuffer.GetData(voxelMins);
        positionBuffer.Dispose();

        uint[] voxelMaterials = new uint[count];
        cornerIndexes.GetData(voxelMaterials);
        cornerIndexes.Dispose();

        GPUVOX[] voxs = new GPUVOX[count];
        voxBuffer.GetData(voxs);
        voxBuffer.Dispose();

        voxMatBuffer.Dispose();
        cornCount.Dispose();
        finalCount.Dispose();
        Perm.Dispose();

        float gpuEnd = Time.realtimeSinceStartup;
        //Debug.Log ("GPU time on chunk: " + (gpuEnd - gpuStart));

        int HIGHEST_VOXEL_RES = 64;
        int voxelSize         = HIGHEST_VOXEL_RES / octreeSize;


        for (int i = 0; i < count; i++)
        {
            if (voxs[i].numPoints != 0)
            {
                OctreeNode leaf = new OctreeNode();
                leaf.type = OctreeNodeType.Node_Leaf;
                leaf.size = voxelSize;
                OctreeDrawInfo drawInfo = new OctreeDrawInfo();
                drawInfo.position      = voxs[i].vertPoint;
                drawInfo.averageNormal = voxs[i].avgNormal;
                drawInfo.corners       = (int)voxelMaterials[i];
                leaf.drawInfo          = drawInfo;
                leaf.min = voxelMins[i];
                computedVoxels.Add(leaf);
            }
        }

        //Debug.Log ("CPU Leaf generation time on chunk: " + (Time.realtimeSinceStartup - gpuEnd));
        //Debug.Log (computedVoxels.Count);

        return(computedVoxels);
    }
Beispiel #17
0
 public virtual void Awake()
 {
     rootNode = new OctreeNode(new Vector3Int(-2, -2, -2), 8);
 }
    //costruisce il nodo terminale (foglia) calcolando le NodeInfo per la generazione della mesh
    public OctreeNode BuildLeaf(OctreeNode leaf, int size)
    {
        if (leaf == null || leaf.size != size)
        {
            return(null);
        }

        int corners = 0;

        for (int i = 0; i < 8; i++)
        {
            Vector3 cornerPos = leaf.min + (CHILD_MIN_OFFSETS[i] * size);
            float   density   = Density.DensityFunc(cornerPos);
            int     material  = density < 0.0f ? SOLID : AIR;
            corners |= (material << i);
        }

        if (corners == 0 || corners == 255)
        {
            leaf = null;
            return(null);
        }

        int       edgeCount     = 0;
        Vector3   averageNormal = new Vector3();
        QefSolver qef           = new QefSolver();

        for (int i = 0; i < 12 && edgeCount < MAX_CROSSINGS; i++)
        {
            int c1 = edgevmap[i][0];
            int c2 = edgevmap[i][1];

            int m1 = (corners >> c1) & 1;
            int m2 = (corners >> c2) & 1;

            if ((m1 == AIR && m2 == AIR) || (m1 == SOLID && m2 == SOLID))
            {
                continue;
            }

            Vector3 p1 = leaf.min + (CHILD_MIN_OFFSETS[c1] * size);
            Vector3 p2 = leaf.min + (CHILD_MIN_OFFSETS[c2] * size);
            Vector3 p  = ApproximateZeroCrossingPosition(p1, p2, 8);
            Vector3 n  = CalculateSurfaceNormal(p);
            qef.Add(p.x, p.y, p.z, n.x, n.y, n.z);

            averageNormal += n;
            edgeCount++;
        }

        Vector3 qefPosition = new Vector3();

        qef.Solve(qefPosition, QEF_ERROR, QEF_SWEEPS, QEF_ERROR);

        NodeInfo info = new NodeInfo();

        info.index    = -1;
        info.corners  = 0;
        info.position = qefPosition;
        info.qef      = qef.GetData();

        Vector3 min = leaf.min;
        Vector3 max = new Vector3(leaf.min.x + leaf.size, leaf.min.y + leaf.size, leaf.min.z + leaf.size);

        if (info.position.x < min.x || info.position.x > max.x ||
            info.position.y < min.y || info.position.y > max.y ||
            info.position.z < min.z || info.position.z > max.z)
        {
            info.position = qef.GetMassPoint();
        }

        info.avgNormal = (averageNormal / (float)edgeCount).normalized;
        info.corners   = corners;

        leaf.type     = NodeType.LEAF;
        leaf.nodeInfo = info;
        return(leaf);
    }
Beispiel #19
0
            /// <summary>
            /// Return a color palette for the computed octree.
            /// </summary>
            /// <returns>A color palette for the computed octree</returns>
            internal Color[] GetPaletteColors()
            {
                // If we haven't already computed it, compute it now
                if (this.octreePalette == null)
                {
                    // Start at the second-to-last reducible level
                    int reductionLevel = this.octreeReducibleNodes.Length - 1;

                    // We want to subtract one from the target if we have a transparent
                    // bit because we want to save room for that special color
                    int targetCount = this.octreeMaxColors - (this.octreeHasTransparent ? 1 : 0);

                    // While we still have more colors than the target...
                    while (this.octreeColorCount > targetCount)
                    {
                        // Find the first reducible node, starting with the last level
                        // that can have reducible nodes
                        while (reductionLevel > 0 && this.octreeReducibleNodes[reductionLevel] == null)
                        {
                            --reductionLevel;
                        }

                        if (this.octreeReducibleNodes[reductionLevel] == null)
                        {
                            // Shouldn't get here
                            break;
                        }

                        // We should have a node now
                        OctreeNode newLeaf = this.octreeReducibleNodes[reductionLevel];
                        this.octreeReducibleNodes[reductionLevel] = newLeaf.NextReducibleNode;
                        this.octreeColorCount -= newLeaf.Reduce() - 1;
                    }

                    if (reductionLevel == 0 && !this.octreeHasTransparent)
                    {
                        // If this was the top-most level, we now only have a single color
                        // representing the average. That's not what we want.
                        // use just black and white
                        this.octreePalette    = new Color[2];
                        this.octreePalette[0] = Color.Black;
                        this.octreePalette[1] = Color.White;

                        // And empty the octree so it always picks the closer of the black and white entries
                        this.octreeRoot = new OctreeNode(0, this);
                    }
                    else
                    {
                        // Now walk the tree, adding all the remaining colors to the list
                        int paletteIndex = 0;
                        this.octreePalette = new Color[this.octreeColorCount + (this.octreeHasTransparent ? 1 : 0)];

                        // Add the transparent color if we need it
                        if (this.octreeHasTransparent)
                        {
                            this.octreePalette[paletteIndex++] = Color.Transparent;
                        }

                        // Have the nodes insert their leaf colors
                        this.octreeRoot.AddColorsToPalette(this.octreePalette, ref paletteIndex);
                    }
                }

                return(this.octreePalette);
            }
Beispiel #20
0
        /// \cond
        protected override bool SynchronizeOctree(uint availableSyncOperations)
        {
            VolumeRenderer volumeRenderer = gameObject.GetComponent <VolumeRenderer>();
            VolumeCollider volumeCollider = gameObject.GetComponent <VolumeCollider>();

            Vector3 camPos = CameraUtils.getCurrentCameraPosition();

            // This is messy - perhaps the LOD thresold shold not be a parameter to update. Instead it could be passed
            // as a parameter during traversal, so different traversal could retrieve differnt LODs. We then wouldn't
            // want a single 'renderThisNode' member of Cubiquity nodes, but instead some threshold we could compare to.
            float lodThreshold = GetComponent <VolumeRenderer>() ? GetComponent <VolumeRenderer>().lodThreshold : 1.0f;

            int minimumLOD = GetComponent <VolumeRenderer>() ? GetComponent <VolumeRenderer>().minimumLOD : 0;

            // Although the LOD system is partially functional I don't feel it's ready for release yet.
            // The following line disables it by forcing the highest level of detail to always be used.
            minimumLOD = 0;

            // Next line commented out so the system starts up with LOD disabled.
            //if (volumeRenderer.hasChanged)
            {
                CubiquityDLL.SetLodRange(data.volumeHandle.Value, minimumLOD, 0);
            }

            bool cubiquityUpToDate = CubiquityDLL.UpdateVolume(data.volumeHandle.Value, camPos.x, camPos.y, camPos.z, lodThreshold);

            if (CubiquityDLL.HasRootOctreeNode(data.volumeHandle.Value) == 1)
            {
                uint rootNodeHandle = CubiquityDLL.GetRootOctreeNode(data.volumeHandle.Value);

                if (rootOctreeNodeGameObject == null)
                {
                    rootOctreeNodeGameObject = OctreeNode.CreateOctreeNode(rootNodeHandle, gameObject);
                }

                OctreeNode.syncNode(ref availableSyncOperations, rootOctreeNodeGameObject, rootNodeHandle, gameObject);

                if (volumeRenderer != null && volumeRenderer.hasChanged)
                {
                    OctreeNode.syncNodeWithVolumeRenderer(rootOctreeNodeGameObject, volumeRenderer, true);
                }

                if (volumeCollider != null && volumeCollider.hasChanged)
                {
                    OctreeNode.syncNodeWithVolumeCollider(rootOctreeNodeGameObject, volumeCollider, true);
                }
            }

            // These properties might have to be synced with the volume (e.g. LOD settings) or with components
            // (e.g. shadow/material settings). Therefore we don't clear the flags until all syncing is completed.
            if (volumeRenderer != null)
            {
                volumeRenderer.hasChanged = false;
            }
            if (volumeCollider != null)
            {
                volumeCollider.hasChanged = false;
            }

            // If there were still sync operations available then there was no more syncing to be done with the
            // Cubiquity octree. So if the Cubiquity octree was also up to date then we have synced everything.
            return(cubiquityUpToDate && availableSyncOperations > 0);
        }
Beispiel #21
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();
                    }
                }
            }
Beispiel #22
0
    void FinishUpChunkLoading()
    {
        if (finishedChunk)
        {
            finishedChunk = false;
            busy          = false;

            if (changingChunk == null)
            {
                if (thread.m_Root != null && loadingChunk != null)
                {
                    //if (loadingChunk.LOD == 6)
                    //Debug.Log ("Chunk time on CPU: " + (Time.realtimeSinceStartup - cpuStartTime));
                    loadingChunk.CreateSeamChunk(thread.m_Root, thread.m_Root.min);
                    if (loadingChunk.GenerateMesh(thread.m_Vertices, thread.m_Normals, thread.m_Indices) > 0)
                    {
                        loadingChunk.containsNothing = false;
                    }


                    List <Chunk> seamChunks    = new List <Chunk>();
                    bool         foundAllEight = FindSeamChunks(loadingChunk, seamChunks);

                    if (foundAllEight)
                    {
                        List <OctreeNode> seams    = FindSeamNodes(loadingChunk, seamChunks);
                        OctreeNode        seamRoot = loadingChunk.BuildSeamTree(seams, loadingChunk.min, octreeSize * 2);
                        if (seamRoot != null)
                        {
                            Chunk seamChunk = new Chunk();
                            seamChunk.LOD = 6;
                            seamChunk.CreateSeamChunk(seamRoot, seamRoot.min);
                            seamChunk.GenerateMesh();
                            //Debug.Log (seamChunk.GenerateMesh());
                            seamChunk.DestroyOctree();
                            loadingChunk.seamChunk = seamChunk;
                        }
                    }



                    //loadingChunk.DestroyOctree();
                }

                if (loadingChunk != null && thread.m_Root == null)
                {
                    loadingChunk.DestroyMesh();
                }

                if (loadingChunk != null)
                {
                    chunks.Add(loadingChunk.min, loadingChunk);
                }
            }
            else
            {
                if (thread.m_Root != null && changingChunk != null)
                {
                    changingChunk.clearMesh();
                    changingChunk.DestroyOctree();
                    changingChunk.CreateSeamChunk(thread.m_Root, thread.m_Root.min);
                    //float meshReloadStart = Time.realtimeSinceStartup;
                    changingChunk.GenerateMesh(thread.m_Vertices, thread.m_Normals, thread.m_Indices);
                    //Debug.Log (Time.realtimeSinceStartup - meshReloadStart);


                    List <Chunk> seamChunks    = new List <Chunk>();
                    bool         foundAllEight = FindSeamChunks(changingChunk, seamChunks);

                    if (foundAllEight)
                    {
                        List <OctreeNode> seams    = FindSeamNodes(changingChunk, seamChunks);
                        OctreeNode        seamRoot = changingChunk.BuildSeamTree(seams, changingChunk.min, octreeSize * 2);
                        if (seamRoot != null)
                        {
                            Chunk seamChunk = changingChunk.seamChunk;
                            if (seamChunk == null)
                            {
                                seamChunk = new Chunk();
                                changingChunk.seamChunk = seamChunk;
                            }

                            if (seamChunk != null)
                            {
                                seamChunk.LOD = 6;
                                seamChunk.CreateSeamChunk(seamRoot, seamRoot.min);
                                seamChunk.GenerateMesh();
                                //Debug.Log (seamChunk.GenerateMesh());
                                seamChunk.DestroyOctree();
                            }
                        }
                    }


                    //changingChunk.DestroyOctree();
                    changingChunk = null;
                }
            }

            thread.m_Vertices.Clear();
            thread.m_Normals.Clear();
            thread.m_Indices.Clear();
            loadingChunk  = null;
            thread.m_Root = null;
        }
    }
Beispiel #23
0
            private OctreeNode <T> CreateNewNode(ref BoundingBox bounds)
            {
                OctreeNode <T> node = new OctreeNode <T>(ref bounds, MaxChildren, this, null);

                return(node);
            }
    public void ContourFaceProc(OctreeNode[] node, int dir, MeshData data)
    {
        if (node[0] == null || node[1] == null)
        {
            return;
        }

        if (node[0].type == NodeType.INTERNAL ||
            node[1].type == NodeType.INTERNAL)
        {
            for (int i = 0; i < 4; i++)
            {
                OctreeNode[] faceNodes = new OctreeNode[2];
                int[]        c         =
                {
                    faceProcFaceMask[dir][i][0],
                    faceProcFaceMask[dir][i][1],
                };
                for (int j = 0; j < 2; j++)
                {
                    if (node[j].type != NodeType.INTERNAL)
                    {
                        faceNodes[j] = node[j];
                    }
                    else
                    {
                        faceNodes[j] = node[j].children[c[j]];
                    }
                }
                ContourFaceProc(faceNodes, faceProcFaceMask[dir][i][2], data);
            }
            int[][] orders =
            {
                new int[] { 0, 0, 1, 1 },
                new int[] { 0, 1, 0, 1 },
            };
            for (int i = 0; i < 4; i++)
            {
                OctreeNode[] edgeNodes = new OctreeNode[4];
                int[]        c         =
                {
                    faceProcEdgeMask[dir][i][1],
                    faceProcEdgeMask[dir][i][2],
                    faceProcEdgeMask[dir][i][3],
                    faceProcEdgeMask[dir][i][4],
                };
                int[] order = orders[faceProcEdgeMask[dir][i][0]];
                for (int j = 0; j < 4; j++)
                {
                    if (node[order[j]].type == NodeType.LEAF ||
                        node[order[j]].type == NodeType.PSEUDO)
                    {
                        edgeNodes[j] = node[order[j]];
                    }
                    else
                    {
                        edgeNodes[j] = node[order[j]].children[c[j]];
                    }
                }
                ContourEdgeProc(edgeNodes, faceProcEdgeMask[dir][i][5], data);
            }
        }
    }
    //semplifica l'octree
    public OctreeNode SimplifyOctree(OctreeNode node, float threshold)
    {
        if (node == null)
        {
            return(null);
        }

        if (node.type != NodeType.INTERNAL)
        {
            // can't simplify!
            return(node);
        }

        QefSolver qef = new QefSolver();

        int[] signs = new int[8] {
            -1, -1, -1, -1, -1, -1, -1, -1,
        };
        int  midsign       = -1;
        int  edgeCount     = 0;
        bool isCollapsible = true;

        for (int i = 0; i < 8; i++)
        {
            node.children[i] = SimplifyOctree(node.children[i], threshold);

            if (node.children[i] != null)
            {
                OctreeNode child = node.children[i];
                if (child.type == NodeType.INTERNAL)
                {
                    isCollapsible = false;
                }
                else
                {
                    qef.Add(child.nodeInfo.qef);
                    midsign  = (child.nodeInfo.corners >> (7 - i)) & 1;
                    signs[i] = (child.nodeInfo.corners >> i) & 1;
                    edgeCount++;
                }
            }
        }
        if (!isCollapsible)
        {
            // at least one child is an internal node, can't collapse
            return(node);
        }

        Vector3 qefPosition = new Vector3();
        float   error       = qef.Solve(qefPosition, QEF_ERROR, QEF_SWEEPS, QEF_ERROR);
        Vector3 position    = new Vector3(qefPosition.x, qefPosition.y, qefPosition.z);

        // at this point the masspoint will actually be a sum, so divide to make it the average
        if (error > threshold)
        {
            // this collapse breaches the threshold
            return(node);
        }

        if (position.x < node.min.x || position.x > (node.min.x + node.size) ||
            position.y < node.min.y || position.y > (node.min.y + node.size) ||
            position.z < node.min.z || position.z > (node.min.z + node.size))
        {
            position = qef.GetMassPoint();
        }

        // change the node from an internal node to a 'pseudo leaf' node
        NodeInfo info = new NodeInfo();

        for (int i = 0; i < 8; i++)
        {
            if (signs[i] == -1)
            {
                // Undetermined, use centre sign instead
                info.corners |= (midsign << i);
            }
            else
            {
                info.corners |= (signs[i] << i);
            }
        }
        info.avgNormal = new Vector3(0, 0, 0);
        for (int i = 0; i < 8; i++)
        {
            if (node.children[i] != null)
            {
                if (node.children[i].type == NodeType.PSEUDO ||
                    node.children[i].type == NodeType.LEAF)
                {
                    info.avgNormal += node.children[i].nodeInfo.avgNormal;
                }
            }
        }
        info.avgNormal = info.avgNormal.normalized;
        info.position  = position;
        info.qef       = qef.GetData();

        for (int i = 0; i < 8; i++)
        {
            DestroyOctree(node.children[i]);
            node.children[i] = null;
        }
        node.type = NodeType.PSEUDO;
        node.nodeInfo.Set(info);
        return(node);
    }
Beispiel #26
0
                /// <summary>
                /// Add a color into the tree
                /// </summary>
                /// <param name="pixel">The color</param>
                /// <param name="colorBits">The number of significant color bits</param>
                /// <param name="level">The level in the tree</param>
                /// <param name="octree">The tree to which this node belongs</param>
                public void addColor(Color32* pixel, int colorBits, int level, Octree octree)
                {
                    // Update the color information if this is a leaf
                    if (_leaf)
                    {
                        inc(pixel);
                        // Setup the previous node
                        octree.trackPrevious(this);
                    }
                    else
                    {
                        // Go to the next level down in the tree
                        int shift = 7 - level;
                        int index = ((pixel->Red & mask[level]) >> (shift - 2)) |
                           ((pixel->Green & mask[level]) >> (shift - 1)) |
                           ((pixel->Blue & mask[level]) >> (shift));

                        OctreeNode child = _children[index];

                        if (child == null)
                        {
                            // Create a new child node & store in the array
                            child = new OctreeNode(level + 1, colorBits, octree);
                            _children[index] = child;
                        }

                        // Add the color to the child node
                        child.addColor(pixel, colorBits, level + 1, octree);
                    }
                }
 /// <summary>
 /// Create an octree around the given root node.
 /// </summary>
 /// <param name="root"></param>
 private Octree(OctreeNode <StoredType> root)
 {
     depth     = root.depth;
     this.root = root;
 }
Beispiel #28
0
 private OctreeNode_GPU OctreeNode2OctreeNode_GPU(OctreeNode node)
 {
     return(new OctreeNode_GPU(node));
 }
 /// <summary>When a reducible node is added, this method is called to add it to the appropriate
 /// reducible node list (given its level)</summary>
 /// <param name="reducibleNode">node to add to a reducible list</param>
 private void AddReducibleNode(OctreeNode reducibleNode)
 {
     // hook this node into the front of the list.
     // this means the last one added will be the first in the list.
     reducibleNode.NextReducibleNode = this.octreeReducibleNodes[reducibleNode.Level];
     this.octreeReducibleNodes[reducibleNode.Level] = reducibleNode;
 }
 public OctreeNode(T obj, OctreeNode <T> parent)
 {
     mObject     = obj;
     mParentNode = parent;
     mChilden    = new OctreeNode <T> [(int)OctreeNodePos.max];
 }
    private void ContourFaceProc(OctreeNode[] node, int dir, List <int> indices)
    {
        if (node[0] == null || node[1] == null)
        {
            return;
        }

        if (node[0].type == OctreeNodeType.Node_Internal ||
            node[1].type == OctreeNodeType.Node_Internal)
        {
            for (int i = 0; i < 4; i++)
            {
                OctreeNode[] faceNodes = new OctreeNode[2];

                int[] c = new int[2]
                {
                    faceProcFaceMask[dir, i, 0],
                    faceProcFaceMask[dir, i, 1]
                };

                for (int j = 0; j < 2; j++)
                {
                    if (node[j].type != OctreeNodeType.Node_Internal)
                    {
                        faceNodes[j] = node[j];
                    }
                    else
                    {
                        faceNodes[j] = node[j].children[c[j]];
                    }
                }

                ContourFaceProc(faceNodes, faceProcFaceMask[dir, i, 2], indices);
            }

            int[,] orders = new int[, ]
            {
                { 0, 0, 1, 1 },
                { 0, 1, 0, 1 }
            };

            for (int i = 0; i < 4; i++)
            {
                OctreeNode[] edgeNodes = new OctreeNode[4];
                int[]        c         = new int[4]
                {
                    faceProcEdgeMask[dir, i, 1],
                    faceProcEdgeMask[dir, i, 2],
                    faceProcEdgeMask[dir, i, 3],
                    faceProcEdgeMask[dir, i, 4]
                };

                int[] order = new int[4]
                {
                    orders[faceProcEdgeMask[dir, i, 0], 0],
                    orders[faceProcEdgeMask[dir, i, 0], 1],
                    orders[faceProcEdgeMask[dir, i, 0], 2],
                    orders[faceProcEdgeMask[dir, i, 0], 3]
                };

                for (int j = 0; j < 4; j++)
                {
                    if (node[order[j]].type == OctreeNodeType.Node_Leaf ||
                        node[order[j]].type == OctreeNodeType.Node_Psuedo)
                    {
                        edgeNodes[j] = node[order[j]];
                    }
                    else
                    {
                        edgeNodes[j] = node[order[j]].children[c[j]];
                    }
                }

                ContourEdgeProc(edgeNodes, faceProcEdgeMask[dir, i, 5], indices);
            }
        }
    }
Beispiel #32
0
 private int childHasObjects = 0; //Bitmask for child nodes
 public void Initialize(int index, LooseOctree <T> tree, OctreeNode parent)
 {
     Initialize(index, tree);
     this.parent = parent;
     treeDepth   = parent.treeDepth + 1;
 }
Beispiel #33
0
        ///
        /// <summary>
        /// Recursively traverse the octree looking for the closest object intersected by the rage
        /// </summary>
        ///
        /// <param name="node">
        /// The node to traverse from
        /// </param>
        ///
        /// <param name="ray">
        /// The ray to check for intersections against
        /// </param>
        ///
        /// <param name="intersectedPosition">
        /// [output] the postion of the closest object intersected
        /// </param>
        ///
        /// <returns>
        /// The distance to the nearest object intersected by the input ray (null if there are no intersections)
        /// </returns>
        ///
        private float?RayIntersection(OctreeNode node, Ray ray, out Vector3 intersectedPosition)
        {
            intersectedPosition = new Vector3();

            BoundingBox translatedBoundingBox = _masterBoundingBoxList[node.BoundingBoxIndex];

            translatedBoundingBox.Max += node.BoundingBoxPosition;
            translatedBoundingBox.Min += node.BoundingBoxPosition;

            if (ray.Intersects(translatedBoundingBox) != null)
            {
                if (node.Children == null)
                {
                    float shortestDistance      = float.MaxValue;
                    int   shortestDistanceIndex = -1;
                    for (int i = 0; i < node.InternalObjectPositions.Count; ++i)
                    {
                        float?distance = ray.Intersects(node.InternalObjectBoundingBoxes[i]);
                        if (distance.HasValue && distance.Value < shortestDistance)
                        {
                            shortestDistance      = distance.Value;
                            shortestDistanceIndex = i;
                        }
                    }
                    if (shortestDistance == float.MaxValue)
                    {
                        return(null);
                    }
                    else
                    {
                        intersectedPosition = node.InternalObjectPositions[shortestDistanceIndex];
                        return(shortestDistance);
                    }
                }
                else
                {
                    float shortestDistance = float.MaxValue;
                    foreach (OctreeNode childNode in node.Children)
                    {
                        Vector3 position;
                        float?  distance = RayIntersection(childNode, ray, out position);
                        if (distance.HasValue && distance.Value < shortestDistance)
                        {
                            shortestDistance    = distance.Value;
                            intersectedPosition = position;
                        }
                    }

                    if (shortestDistance == float.MaxValue)
                    {
                        return(null);
                    }
                    else
                    {
                        return(shortestDistance);
                    }
                }
            }

            return(null);
        }
Beispiel #34
0
 public Octree(float xMax, float xMin, float yMax, float yMin, float zMax, float zMin, int maxItems, float minSize)
 {
     Top = new OctreeNode(xMax, xMin, yMax, yMin, zMax, zMin, maxItems, minSize);
 }
Beispiel #35
0
 ///
 /// <summary>
 /// C'tor
 /// </summary>
 ///
 /// <param name="topLevelBoundingBox">
 /// A top level bounding showing the size of the region that this octree will represent
 /// </param>
 ///
 /// <param name="topLevelBoundingBoxPosition">
 /// The world coordinates of the minimum corner of the top level bounding box
 /// </param>
 ///
 public Octree(BoundingBox topLevelBoundingBox, Vector3 topLevelBoundingBoxPosition)
 {
     _masterBoundingBoxList.Add(topLevelBoundingBox);
     _root = new OctreeNode(_masterBoundingBoxList.Count - 1, topLevelBoundingBoxPosition);
 }
Beispiel #36
0
 /// <summary>
 /// Construct the octree
 /// </summary>
 /// <param name="maxColorBits">The maximum number of significant bits in the image</param>
 public Octree(int maxColorBits)
 {
     _maxColorBits = maxColorBits;
     _leafCount = 0;
     _reducibleNodes = new OctreeNode[9];
     _root = new OctreeNode(0, _maxColorBits, this);
     _previousColor = 0;
     _previousNode = null;
 }
Beispiel #37
0
 public OctreeRenderer(OctreeNode <T> octree, AssetDatabase ad, RenderContext rc) : base(ad, rc, RgbaFloat.Red)
 {
     _octree = octree;
 }
Beispiel #38
0
                /// <summary>
                /// Construct the node
                /// </summary>
                /// <param name="level">The level in the tree = 0 - 7</param>
                /// <param name="colorBits">The number of significant color bits in the image</param>
                /// <param name="octree">The tree to which this node belongs</param>
                public OctreeNode(int level, int colorBits, Octree octree)
                {
                    // Construct the new node
                    _leaf = (level == colorBits);

                    _red = _green = _blue = 0;
                    _pixelCount = 0;

                    // If a leaf, increment the leaf count
                    if (_leaf)
                    {
                        octree.Leaves++;
                        _nextReducible = null;
                        _children = null;
                    }
                    else
                    {
                        // Otherwise add this to the reducible nodes
                        _nextReducible = octree.ReducibleNodes[level];
                        octree.ReducibleNodes[level] = this;
                        _children = new OctreeNode[8];
                    }
                }
Beispiel #39
0
    /// <summary>
    /// Recursively updates tree visibility
    /// </summary>
    /// <param name="n">Current node</param>
    /// <param name="p">Camera frustum planes</param>
    private void __updateOctreeNodeVisibility(OctreeNode n, Plane[] p)
    {
        if (GeometryUtility.TestPlanesAABB(p, n.AABB) && CanCameraSeeAABB(n.AABB, Camera.main.transform.position))
        {
            n.gameObject.SetActive(true);

            for (int i = 0; i < n.children.Count; i++)
                __updateOctreeNodeVisibility(n.children[i], p);
        }
        else
            n.gameObject.SetActive(false);
    }
 /// <summary>
 /// Keep track of the previous node that was quantized
 /// </summary>
 /// <param name="node">
 /// The node last quantized
 /// </param>
 protected void TrackPrevious(OctreeNode node)
 {
     this.previousNode = node;
 }
Beispiel #41
0
 /// <summary>
 /// Keep track of the previous node that was quantized
 /// </summary>
 /// <param name="node">The node last quantized</param>
 protected void trackPrevious(OctreeNode node)
 {
     _previousNode = node;
 }
                /// <summary>
                /// Initializes a new instance of the <see cref="OctreeNode"/> class. 
                /// </summary>
                /// <param name="level">
                /// The level in the tree = 0 - 7
                /// </param>
                /// <param name="colorBits">
                /// The number of significant color bits in the image
                /// </param>
                /// <param name="octree">
                /// The tree to which this node belongs
                /// </param>
                public OctreeNode(int level, int colorBits, Octree octree)
                {
                    // Construct the new node
                    this.leaf = level == colorBits;

                    this.red = this.green = this.blue = 0;
                    this.pixelCount = 0;

                    // If a leaf, increment the leaf count
                    if (this.leaf)
                    {
                        octree.Leaves++;
                        this.nextReducible = null;
                        this.children = null;
                    }
                    else
                    {
                        // Otherwise add this to the reducible nodes
                        this.nextReducible = octree.ReducibleNodes[level];
                        octree.ReducibleNodes[level] = this;
                        this.children = new OctreeNode[8];
                    }
                }
Beispiel #43
0
 /// <summary>
 /// Recursively removes empty nodes
 /// </summary>
 /// <param name="n">Current node</param>
 /// <param name="_deepestNodes">List of deepest nodes to remove values from</param>
 private void __removeEmptyTreeNodes(OctreeNode n, List<OctreeNode> _deepestNodes)
 {
     for (int i = n.children.Count - 1; i >= 0; i--)
         __removeEmptyTreeNodes(n.children[i], _deepestNodes);
     if (n.children.Count == 0 && (n.value == null || n.value.mapObjects.Count == 0))
     {
         _deepestNodes.Remove(n);
         GameObject.Destroy(n.gameObject);
         n.parent.children.Remove(n);
     }
 }
            /// <summary>Initializes a new instance of the <see cref="Octree"/> class. Constructor</summary>
            /// <param name="pixelFormat">desired pixel format</param>
            internal Octree(PixelFormat pixelFormat)
            {
                // figure out the maximum colors from the pixel format passed in
                switch (pixelFormat)
                {
                    case PixelFormat.Format1bppIndexed:
                        this.octreeMaxColors = 2;
                        break;

                    case PixelFormat.Format4bppIndexed:
                        this.octreeMaxColors = 16;
                        break;

                    case PixelFormat.Format8bppIndexed:
                        this.octreeMaxColors = 256;
                        break;

                    default:
                        throw new ArgumentException("Invalid Pixel Format", "pixelFormat");
                }

                // we need a list for each level that may have reducible nodes.
                // since the last level (level 7) is only made up of leaf nodes,
                // we don't need an array entry for it.
                this.octreeReducibleNodes = new OctreeNode[7];

                // add the initial level-0 root node
                this.octreeRoot = new OctreeNode(0, this);
            }
Beispiel #45
0
            /// <summary>
            /// Find a node that fully contains the given bounds
            /// </summary>
            public bool ContainingNode(ref Vector3 center, ref Vector3 minBounds, ref Vector3 maxBounds, out OctreeNode node)
            {
                node = null;
                OctreeNode childNode = this;//Start here
                int        index;

                while (true)
                {
                    if (!childNode.ContainsBounds(ref minBounds, ref maxBounds))
                    { //Doesn't fit in this node. Put it in the parent node.
                        if (childNode.childIndex == -1)
                        {
                            return(false);
                        }

                        node = childNode.parent;
                        return(true);
                    }

                    index = childNode.BestFitChild(ref center);
                    if (!childNode.isLeaf)
                    { //Drop down another level if we have children
                        childNode = childNode.children[index];
                    }
                    else
                    { //Place it here. No children
                        node = childNode;
                        return(true);
                    }
                }
            }
Beispiel #46
0
 /// <summary>set up the values we need to reuse the given pointer if the next color is argb</summary>
 /// <param name="node">last node to which we added a color</param>
 /// <param name="argb">last color we added</param>
 private void SetLastNode(OctreeNode node, int argb)
 {
     this.octreeLastNode = node;
     this.octreeLastArgb = argb;
 }
Beispiel #47
0
 /// <summary> Keep track of the previous node that was quantized. </summary>
 /// <param name="node"> The node last quantized. </param>
 void TrackPrevious( OctreeNode node ) {
     previousNode = node;
 }
Beispiel #48
0
    /// <summary>
    /// 分八个区
    /// </summary>
    /// <param name="childNodes">八个子节点</param>
    /// <param name="oneBounds">当前节点的信息</param>
    private void SplitBounds(ref OctreeNode <T> currentNode, List <GameObject> objectList, int deep)
    {
        if (deep < m_MaxDepth)
        {
            currentNode.m_ObjectList = new List <GameObject>();
            // 1、判断是否相交 相交就添加到当前节点的列表里
            foreach (var gameObject in objectList)
            {
                if (gameObject.GetComponent <SphereCollider>() != null)
                {
                    var gameObjectBounds = gameObject.GetComponent <Collider>().bounds;
                    // 如果gameobject与分区相交 就添加到当前分区的列表里
                    if (currentNode.m_Bounds.Intersects(gameObjectBounds))
                    {
                        currentNode.m_ObjectList.Add(gameObject);
                    }
                }
            }

            // 2、分八个区域
            currentNode.m_ChildNodes   = new OctreeNode <T> [8];
            currentNode.m_CurrentDepth = deep;

            var     oneBounds   = currentNode.m_Bounds;
            Vector3 half2Vector = oneBounds.size / 4;
            // 八块空间的位置
            currentNode.m_ChildNodes[0].m_Bounds.center = oneBounds.center - half2Vector;
            currentNode.m_ChildNodes[0].m_Bounds.size   = oneBounds.size / 2;
            currentNode.m_ChildNodes[1].m_Bounds.center = currentNode.m_ChildNodes[0].m_Bounds.center + new Vector3(oneBounds.size.x / 2, 0, 0);
            currentNode.m_ChildNodes[1].m_Bounds.size   = oneBounds.size / 2;
            currentNode.m_ChildNodes[2].m_Bounds.center = currentNode.m_ChildNodes[1].m_Bounds.center + new Vector3(0, 0, oneBounds.size.z / 2);
            currentNode.m_ChildNodes[2].m_Bounds.size   = oneBounds.size / 2;
            currentNode.m_ChildNodes[3].m_Bounds.center = currentNode.m_ChildNodes[0].m_Bounds.center + new Vector3(0, 0, oneBounds.size.z / 2);
            currentNode.m_ChildNodes[3].m_Bounds.size   = oneBounds.size / 2;
            currentNode.m_ChildNodes[4].m_Bounds.center = currentNode.m_ChildNodes[0].m_Bounds.center + new Vector3(0, oneBounds.size.y / 2, 0);
            currentNode.m_ChildNodes[4].m_Bounds.size   = oneBounds.size / 2;
            currentNode.m_ChildNodes[5].m_Bounds.center = currentNode.m_ChildNodes[1].m_Bounds.center + new Vector3(0, oneBounds.size.y / 2, 0);
            currentNode.m_ChildNodes[5].m_Bounds.size   = oneBounds.size / 2;
            currentNode.m_ChildNodes[6].m_Bounds.center = currentNode.m_ChildNodes[2].m_Bounds.center + new Vector3(0, oneBounds.size.y / 2, 0);
            currentNode.m_ChildNodes[6].m_Bounds.size   = oneBounds.size / 2;
            currentNode.m_ChildNodes[7].m_Bounds.center = currentNode.m_ChildNodes[3].m_Bounds.center + new Vector3(0, oneBounds.size.y / 2, 0);
            currentNode.m_ChildNodes[7].m_Bounds.size   = oneBounds.size / 2;

            // 3、遍历8个区域 递归调用
            for (int i = 0; i < currentNode.m_ChildNodes.Length; i++)
            {
                // 递归调用
                if (currentNode.m_ObjectList.Count != 0)
                {
                    // check if child node intersect
                    bool isIntersects = false;
                    currentNode.m_ChildNodes[i].m_ObjectList = new List <GameObject>();
                    foreach (var gameObject in currentNode.m_ObjectList)
                    {
                        if (gameObject.GetComponent <SphereCollider>() != null)
                        {
                            var gameObjectBounds = gameObject.GetComponent <Collider>().bounds;
                            if (currentNode.m_ChildNodes[i].m_Bounds.Intersects(gameObjectBounds))
                            {
                                currentNode.m_ChildNodes[i].m_ObjectList.Add(gameObject);
                                isIntersects = true;
                            }
                        }
                    }
                    if (isIntersects)
                    {
                        if (currentNode.m_CurrentDepth != 0 &&
                            currentNode.m_ObjectList.Count == currentNode.m_ChildNodes[i].m_ObjectList.Count)
                        {
                            continue;
                        }
                        currentNode.m_CurrentDepth++;
                        SplitBounds(ref currentNode.m_ChildNodes[i], currentNode.m_ObjectList, currentNode.m_CurrentDepth);
                    }
                }
            }
        }
    }
Beispiel #49
0
            /// <summary>
            /// Reduce the depth of the tree
            /// </summary>
            public void Reduce()
            {
                int index;

                // Find the deepest level containing at least one reducible node
                for (index = _maxColorBits - 1; (index > 0) && (null == _reducibleNodes[index]); index--) ;

                // Reduce the node most recently added to the list at level 'index'
                OctreeNode node = _reducibleNodes[index];
                _reducibleNodes[index] = node.NextReducible;

                // Decrement the leaf count after reducing the node
                _leafCount -= node.Reduce();

                // And just in case I've reduced the last color to be added, and the next color to
                // be added is the same, invalidate the previousNode...
                _previousNode = null;
            }
Beispiel #50
0
    public void Add(T content)
    {
        if (!this.Bounds.Contains(content.Position))
        {
            throw new UnityException("Cannot add an object outside of octree");
        }

        // just add if empty
        if ((IsLeaf() && _Contents.Count == 0) || Level == MaxLevel)
        {
            _Contents.Add(content);
        }
        else
        {
            if (content.Position.Equals(this.Bounds.center) || (_Contents.Count > 0 && _Contents.TrueForAll(i => content.Position.Equals(i.Position))))
            {
                _Contents.Add(content);
            }
            else
            {
                if (IsLeaf())
                {
                    // build children
                    _IsLeaf = false;

                    var ex = this.Bounds.extents * 0.5f;

                    Children[0] = new OctreeNode <T>(new Bounds(this.Bounds.center + new Vector3(-ex.x, -ex.y, -ex.z), this.Bounds.extents), Level + 1, MaxLevel);
                    Children[1] = new OctreeNode <T>(new Bounds(this.Bounds.center + new Vector3(-ex.x, -ex.y, ex.z), this.Bounds.extents), Level + 1, MaxLevel);
                    Children[2] = new OctreeNode <T>(new Bounds(this.Bounds.center + new Vector3(ex.x, -ex.y, -ex.z), this.Bounds.extents), Level + 1, MaxLevel);
                    Children[3] = new OctreeNode <T>(new Bounds(this.Bounds.center + new Vector3(ex.x, -ex.y, ex.z), this.Bounds.extents), Level + 1, MaxLevel);
                    Children[4] = new OctreeNode <T>(new Bounds(this.Bounds.center + new Vector3(-ex.x, ex.y, -ex.z), this.Bounds.extents), Level + 1, MaxLevel);
                    Children[5] = new OctreeNode <T>(new Bounds(this.Bounds.center + new Vector3(-ex.x, ex.y, ex.z), this.Bounds.extents), Level + 1, MaxLevel);
                    Children[6] = new OctreeNode <T>(new Bounds(this.Bounds.center + new Vector3(ex.x, ex.y, -ex.z), this.Bounds.extents), Level + 1, MaxLevel);
                    Children[7] = new OctreeNode <T>(new Bounds(this.Bounds.center + new Vector3(ex.x, ex.y, ex.z), this.Bounds.extents), Level + 1, MaxLevel);

                    // move any existing items
                    for (var i = 0; i < Contents.Count; i++)
                    {
                        if (!content.Position.Equals(this.Bounds.center))
                        {
                            for (var j = 0; j < 8; j++)
                            {
                                T c = Contents[i];
                                if (Children[j].Contains(c.Position))
                                {
                                    Children[j].Add(c);
                                }
                            }
                            _Contents.Clear();
                        }
                    }
                }

                // add new item into child
                for (var i = 0; i < 8; i++)
                {
                    if (Children[i].Contains(content.Position))
                    {
                        Children[i].Add(content);
                    }
                }
            }
        }
    }
 /// <summary>
 /// Initializes a new instance of the <see cref="Octree"/> class. 
 /// </summary>
 /// <param name="maxColorBits">
 /// The maximum number of significant bits in the image
 /// </param>
 public Octree(int maxColorBits)
 {
     this.maxColorBits = maxColorBits;
     this.leafCount = 0;
     this.reducibleNodes = new OctreeNode[9];
     this.root = new OctreeNode(0, this.maxColorBits, this);
     this.previousColor = 0;
     this.previousNode = null;
 }
Beispiel #52
0
        private void AddVerticesAndIndices(OctreeNode <T> octree, List <VertexPositionNormalTexture> vertices, List <int> indices)
        {
            int baseIndex = vertices.Count;
            var bounds    = octree.Bounds;

            vertices.Add(new VertexPositionNormalTexture(new Vector3(bounds.Min.X, bounds.Min.Y, bounds.Min.Z), Vector3.Zero, Vector2.Zero));
            vertices.Add(new VertexPositionNormalTexture(new Vector3(bounds.Min.X, bounds.Max.Y, bounds.Min.Z), Vector3.Zero, Vector2.Zero));
            vertices.Add(new VertexPositionNormalTexture(new Vector3(bounds.Max.X, bounds.Max.Y, bounds.Min.Z), Vector3.Zero, Vector2.Zero));
            vertices.Add(new VertexPositionNormalTexture(new Vector3(bounds.Max.X, bounds.Min.Y, bounds.Min.Z), Vector3.Zero, Vector2.Zero));
            vertices.Add(new VertexPositionNormalTexture(new Vector3(bounds.Min.X, bounds.Min.Y, bounds.Max.Z), Vector3.Zero, Vector2.Zero));
            vertices.Add(new VertexPositionNormalTexture(new Vector3(bounds.Min.X, bounds.Max.Y, bounds.Max.Z), Vector3.Zero, Vector2.Zero));
            vertices.Add(new VertexPositionNormalTexture(new Vector3(bounds.Max.X, bounds.Max.Y, bounds.Max.Z), Vector3.Zero, Vector2.Zero));
            vertices.Add(new VertexPositionNormalTexture(new Vector3(bounds.Max.X, bounds.Min.Y, bounds.Max.Z), Vector3.Zero, Vector2.Zero));

            indices.Add(baseIndex + 0);
            indices.Add(baseIndex + 1);
            indices.Add(baseIndex + 0);
            indices.Add(baseIndex + 1);
            indices.Add(baseIndex + 2);
            indices.Add(baseIndex + 1);
            indices.Add(baseIndex + 2);
            indices.Add(baseIndex + 3);
            indices.Add(baseIndex + 2);
            indices.Add(baseIndex + 0);
            indices.Add(baseIndex + 3);
            indices.Add(baseIndex + 0);

            indices.Add(baseIndex + 4);
            indices.Add(baseIndex + 5);
            indices.Add(baseIndex + 4);
            indices.Add(baseIndex + 5);
            indices.Add(baseIndex + 1);
            indices.Add(baseIndex + 5);
            indices.Add(baseIndex + 1);
            indices.Add(baseIndex + 0);
            indices.Add(baseIndex + 1);
            indices.Add(baseIndex + 4);
            indices.Add(baseIndex + 0);
            indices.Add(baseIndex + 4);

            indices.Add(baseIndex + 7);
            indices.Add(baseIndex + 6);
            indices.Add(baseIndex + 7);
            indices.Add(baseIndex + 6);
            indices.Add(baseIndex + 5);
            indices.Add(baseIndex + 6);
            indices.Add(baseIndex + 5);
            indices.Add(baseIndex + 4);
            indices.Add(baseIndex + 5);
            indices.Add(baseIndex + 7);
            indices.Add(baseIndex + 4);
            indices.Add(baseIndex + 7);

            indices.Add(baseIndex + 3);
            indices.Add(baseIndex + 2);
            indices.Add(baseIndex + 3);
            indices.Add(baseIndex + 2);
            indices.Add(baseIndex + 6);
            indices.Add(baseIndex + 2);
            indices.Add(baseIndex + 6);
            indices.Add(baseIndex + 7);
            indices.Add(baseIndex + 6);
            indices.Add(baseIndex + 3);
            indices.Add(baseIndex + 7);
            indices.Add(baseIndex + 3);

            foreach (var child in octree.Children)
            {
                AddVerticesAndIndices(child, vertices, indices);
            }
        }
            /// <summary>
            /// Reduce the depth of the tree
            /// </summary>
            private void Reduce()
            {
                // Find the deepest level containing at least one reducible node
                int index = this.maxColorBits - 1;
                while ((index > 0) && (null == this.reducibleNodes[index]))
                {
                    index--;
                }

                // Reduce the node most recently added to the list at level 'index'
                OctreeNode node = this.reducibleNodes[index];
                this.reducibleNodes[index] = node.NextReducible;

                // Decrement the leaf count after reducing the node
                this.leafCount -= node.Reduce();

                // And just in case I've reduced the last color to be added, and the next color to
                // be added is the same, invalidate the previousNode...
                this.previousNode = null;
            }
Beispiel #54
0
 public Octree(Vector3 position, float size, int depth)
 {
     node = new OctreeNode <T>(position, size);
     node.Subdivide(depth);
 }
                /// <summary>
                /// Add a color into the tree
                /// </summary>
                /// <param name="pixel">
                /// The color
                /// </param>
                /// <param name="colorBits">
                /// The number of significant color bits
                /// </param>
                /// <param name="level">
                /// The level in the tree
                /// </param>
                /// <param name="octree">
                /// The tree to which this node belongs
                /// </param>
                public void AddColor(Color32* pixel, int colorBits, int level, Octree octree)
                {
                    // Update the color information if this is a leaf
                    if (this.leaf)
                    {
                        this.Increment(pixel);

                        // Setup the previous node
                        octree.TrackPrevious(this);
                    }
                    else
                    {
                        // Go to the next level down in the tree
                        int shift = 7 - level;
                        int index = ((pixel->R & Mask[level]) >> (shift - 2)) |
                                    ((pixel->G & Mask[level]) >> (shift - 1)) |
                                    ((pixel->B & Mask[level]) >> shift);

                        OctreeNode child = this.children[index];

                        if (null == child)
                        {
                            // Create a new child node & store in the array
                            child = new OctreeNode(level + 1, colorBits, octree);
                            this.children[index] = child;
                        }

                        // Add the color to the child node
                        child.AddColor(pixel, colorBits, level + 1, octree);
                    }
                }
    //-------------------------------------------------------------------------------------------

    void UpdateOctree()
    {
        playerNode = OctreeNode.getRoot.CreateSubdivisionsWithItem(maxOctreeGenerations, Player.position);
        //Invoke("UpdateGrpahics", 0.4f);
        //UpdateGrpahics();
    }
            /// <summary>
            /// Return a color palette for the computed octree.
            /// </summary>
            /// <returns>A color palette for the computed octree</returns>
            internal Color[] GetPaletteColors()
            {
                // If we haven't already computed it, compute it now
                if (this.octreePalette == null)
                {
                    // Start at the second-to-last reducible level
                    int reductionLevel = this.octreeReducibleNodes.Length - 1;

                    // We want to subtract one from the target if we have a transparent
                    // bit because we want to save room for that special color
                    int targetCount = this.octreeMaxColors - (this.octreeHasTransparent ? 1 : 0);

                    // While we still have more colors than the target...
                    while (this.octreeColorCount > targetCount)
                    {
                        // Find the first reducible node, starting with the last level
                        // that can have reducible nodes
                        while (reductionLevel > 0 && this.octreeReducibleNodes[reductionLevel] == null)
                        {
                            --reductionLevel;
                        }

                        if (this.octreeReducibleNodes[reductionLevel] == null)
                        {
                            // Shouldn't get here
                            break;
                        }

                        // We should have a node now
                        OctreeNode newLeaf = this.octreeReducibleNodes[reductionLevel];
                        this.octreeReducibleNodes[reductionLevel] = newLeaf.NextReducibleNode;
                        this.octreeColorCount -= newLeaf.Reduce() - 1;
                    }

                    if (reductionLevel == 0 && !this.octreeHasTransparent)
                    {
                        // If this was the top-most level, we now only have a single color
                        // representing the average. That's not what we want.
                        // use just black and white
                        this.octreePalette = new Color[2];
                        this.octreePalette[0] = Color.Black;
                        this.octreePalette[1] = Color.White;

                        // And empty the octree so it always picks the closer of the black and white entries
                        this.octreeRoot = new OctreeNode(0, this);
                    }
                    else
                    {
                        // Now walk the tree, adding all the remaining colors to the list
                        int paletteIndex = 0;
                        this.octreePalette = new Color[this.octreeColorCount + (this.octreeHasTransparent ? 1 : 0)];

                        // Add the transparent color if we need it
                        if (this.octreeHasTransparent)
                        {
                            this.octreePalette[paletteIndex++] = Color.Transparent;
                        }

                        // Have the nodes insert their leaf colors
                        this.octreeRoot.AddColorsToPalette(this.octreePalette, ref paletteIndex);
                    }
                }

                return this.octreePalette;
            }
 private void Awake()
 {
     _vm = this;
     vdm = new DataGenerator(worldSize.y);
     OctreeNode.Init();
 }
 /// <summary>set up the values we need to reuse the given pointer if the next color is argb</summary>
 /// <param name="node">last node to which we added a color</param>
 /// <param name="argb">last color we added</param>
 private void SetLastNode(OctreeNode node, int argb)
 {
     this.octreeLastNode = node;
     this.octreeLastArgb = argb;
 }
    public OctreeNode ConstructUpwards(List <OctreeNode> inputNodes, Vector3 rootMin, int rootNodeSize)
    {
        if (inputNodes.Count == 0)
        {
            return(null);
        }

        int baseNodeSize = inputNodes[0].size;

        List <OctreeNode> nodes = new List <OctreeNode>();

        for (int i = 0; i < inputNodes.Count; i++)
        {
            nodes.Add(inputNodes[i]);
        }
        nodes.Sort(delegate(OctreeNode lhs, OctreeNode rhs)
        {
            return(lhs.size - rhs.size);
        });

        // the input nodes may be different sizes if a seam octree is being constructed
        // in that case we need to process the input nodes in stages along with the newly
        // constructed parent nodes until all the nodes have the same size
        while (nodes[0].size != nodes[nodes.Count - 1].size)
        {
            // find the end of this run
            int iter = 0;
            int size = nodes[iter].size;
            do
            {
                ++iter;
            } while (nodes[iter].size == size);

            // construct the new parent nodes for this run
            List <OctreeNode> newNodes = new List <OctreeNode>();
            for (int i = 0; i < iter; i++)
            {
                newNodes.Add(nodes[i]);
            }
            newNodes = ConstructParents(newNodes, rootMin, size * 2);

            // set up for the next iteration: the parents produced plus any remaining input nodes
            for (int i = iter; i < nodes.Count; i++)
            {
                newNodes.Add(nodes[i]);
            }

            nodes.Clear();
            for (int i = 0; i < newNodes.Count; i++)
            {
                nodes.Add(newNodes[i]);
            }
            newNodes.Clear();
            newNodes = null;
        }

        int parentSize = nodes[0].size * 2;

        while (parentSize <= rootNodeSize)
        {
            nodes       = ConstructParents(nodes, rootMin, parentSize);
            parentSize *= 2;
        }

        if (nodes.Count != 1)
        {
            Debug.Log(baseNodeSize);
            Debug.Log(rootMin);
            Debug.Log(rootNodeSize);
            Debug.LogError("There can only be one root node!");
            Application.Quit();
        }

        OctreeNode root = nodes[0];

        nodes.Clear();
        nodes = null;
        return(root);
    }