Example #1
0
    void Start()
    {
        tfm = this.transform;

        cam      = GetComponent <Camera>();
        material = new Material(shader);

        cam.clearFlags = CameraClearFlags.Nothing;

        cells_order = new CellSortInfo[8];

        node_stack   = new NodeStackItem[32];
        linked_idxyz = new IdXYZ[32];
        for (int j = 0; j < node_stack.Length; j++)
        {
            node_stack[j] = new NodeStackItem();

            // the 1st and the 7 following
            var idxyz0 = new IdXYZ();
            var idxyz  = idxyz0;
            for (int i = 1; i < 8; i++)
            {
                idxyz.next = new IdXYZ();
                idxyz      = idxyz.next;
            }

            linked_idxyz[j] = idxyz0;
        }

        stopwatch = new System.Diagnostics.Stopwatch();
    }
Example #2
0
    static void RasterizeOctree(VoxelObject.OctreeNode node, float x0f, float y0f, float z, bool ortho, Color32 tint)
    {
        #region various initialization
        int stack_id = 0, stack_size = 1;

        var nsi = new NodeStackItem();
        nsi.node      = node;
        nsi.x         = x0f;
        nsi.y         = y0f;
        nsi.z         = z;
        nsi.ortho     = ortho;
        nsi.inside    = false;
        node_stack[0] = nsi;

        VoxelObject.OctreeNode subnode = null;

        float lod_r      = lod * 0.5f;
        float lod_factor = lod_r / persp_zoom_factor;

        float dk_ortho = ortho_switch_threshold * 0.5f;

        float depth_offset = -clip_near, depth_scale = ((1 << depth_buffer_bits) - 1) / (clip_far - clip_near);

        Color32 c = default(Color32);

        bool is_leaf = false;

        float xMinF = 0, xMaxF = 0, yMinF = 0, yMaxF = 0;
        int   xMin = 0, xMax = 0, yMin = 0, yMax = 0;

        float BufW1f = BufW1 + 0.5f, BufH1f = BufH1 + 0.5f;
        float BufW1f1 = BufW1f - 1f, BufH1f1 = BufH1f - 1f;

        float proj_cx = 0, proj_cy = 0, proj_r = 0;
        #endregion

        branch_down :;

        bool switch_to_ortho = false;
//		int inside_flag = 0;

        ++processed_cells;

        var   r = radiuses[stack_id];
        float closest_z = nsi.z - r.w, farthest_z = nsi.z + r.w;
        if ((closest_z > clip_far) || (farthest_z < clip_near))
        {
            goto branch_up;
        }
        else if (nsi.z < clip_near)
        {
            c = nsi.node.color;             // a == 255 is considered a leaf
            if (c.a == 255)
            {
                goto branch_up;
            }
            else
            {
                goto skip_occlusion;
            }
        }

        if (nsi.ortho)
        {
            ++ortho_cells;

            c       = nsi.node.color;                   // a == 255 is considered a leaf
            is_leaf = ((c.a == 255) || (r.z <= lod_r)); // r.z is max(r.x, r.y)

            // if intersects near plane -> no sense in trying to compute occlusion
            if (closest_z < clip_near)
            {
                if (!is_leaf)
                {
                    goto skip_occlusion;
//				} else {
//					inside_flag = -1;
                }
            }

            xMinF = (nsi.x - r.x);
            xMaxF = (nsi.x + r.x);
            yMinF = (nsi.y - r.y);
            yMaxF = (nsi.y + r.y);
        }
        else
        {
            ++persp_cells;

            float closest_z_clamped;
            if (closest_z < clip_near)
            {
                closest_z_clamped = clip_near;
            }
            else
            {
                closest_z_clamped = closest_z;
            }

            c       = nsi.node.color;       // a == 255 is considered a leaf
            is_leaf = ((c.a == 255) || (r.w <= lod_factor * closest_z_clamped));

            // if intersects near plane -> no sense in trying to compute occlusion
            if (closest_z < clip_near)
            {
                if (!is_leaf)
                {
                    goto skip_occlusion;
//				} else {
//					inside_flag = -1;
                }
            }

            //float k_farthest = persp_zoom_factor / farthest_z;
            float k_closest = persp_zoom_factor / closest_z_clamped;
            float k_center  = persp_zoom_factor / nsi.z;

            // If the min/max projections have less than 1 pixel difference, we can
            // switch to ortho. Ideally, this should check the difference between
            // closest and furthest, but seems like (closest - center) works fine too.
            switch_to_ortho = (!is_leaf) && ((k_closest - k_center) < dk_ortho);

            proj_cx = BufW2 + nsi.x * k_center;
            proj_cy = BufH2 + nsi.y * k_center;
            proj_r  = (r.w * k_closest) - 0.5f;

            xMinF = (proj_cx - proj_r);
            xMaxF = (proj_cx + proj_r);
            yMinF = (proj_cy - proj_r);
            yMaxF = (proj_cy + proj_r);
        }

        if (xMinF < 0f)
        {
            xMinF = 0f;
        }
        if (xMaxF > BufW1f)
        {
            xMaxF = BufW1f;
        }
        if (yMinF < 0f)
        {
            yMinF = 0f;
        }
        if (yMaxF > BufH1f)
        {
            yMaxF = BufH1f;
        }

//		if (xMinF < 1f) { inside_flag = -1; }
//		if (xMaxF > BufW1f1) { inside_flag = -1; }
//		if (yMinF < 1f) { inside_flag = -1; }
//		if (yMaxF > BufH1f1) { inside_flag = -1; }

        xMin = (int)xMinF;
        xMax = (int)xMaxF;
        yMin = (int)yMinF;
        yMax = (int)yMaxF;

        #region rasterization / occlusion test
        if ((xMax < xMin) || (yMax < yMin))
        {
            ++skipped_cells; goto branch_up;
        }
        else if ((xMax == xMin) && (yMax == yMin))
        {
            int i = xMin + yMin * BufW;
            if (is_leaf)
            {
                float depth = nsi.z;
                //float depth = (nsi.z + depth_offset) * depth_scale;
                //int depth = (int)((nsi.z + depth_offset) * depth_scale);
                if (depth < depth_buffer[i])
                {
                    c.r             = (byte)((c.r * tint.r + 255) >> 8); c.g = (byte)((c.g * tint.g + 255) >> 8); c.b = (byte)((c.b * tint.b + 255) >> 8);
                    depth_buffer[i] = depth; color_buffer[i] = c;
                }
                ++pixel_cells; goto branch_up;
            }
            else
            {
//				nsi.inside = (inside_flag != -1);
                float depth = closest_z;
                //float depth = (closest_z + depth_offset) * depth_scale;
                //int depth = (int)((closest_z + depth_offset) * depth_scale);
                if (depth < depth_buffer[i])
                {
                    goto skip_occlusion;
                }
                ++skipped_cells; goto branch_up;
            }
        }
        else
        {
            int i_row     = xMin + yMin * BufW;
            int row_width = (xMax - xMin);
            if (is_leaf)
            {
                float depth = nsi.z;
                //float depth = (nsi.z + depth_offset) * depth_scale;
                //int depth = (int)((nsi.z + depth_offset) * depth_scale);
                c.r = (byte)((c.r * tint.r + 255) >> 8); c.g = (byte)((c.g * tint.g + 255) >> 8); c.b = (byte)((c.b * tint.b + 255) >> 8);
                for (;;)
                {
                    int i_row1 = i_row + row_width;
                    int i      = i_row;
                    while (i <= i_row1)
                    {
                        if (depth < depth_buffer[i])
                        {
                            depth_buffer[i] = depth; color_buffer[i] = c;
                        }
                        ++i;
                    }
                    if (++yMin > yMax)
                    {
                        ++leaf_cells; goto branch_up;
                    }
                    i_row += BufW;
                }
            }
            else
            {
//				nsi.inside = (inside_flag != -1);
                float depth = closest_z;
                //float depth = (closest_z + depth_offset) * depth_scale;
                //int depth = (int)((closest_z + depth_offset) * depth_scale);
                for (;;)
                {
                    int i_row1 = i_row + row_width;
                    int i      = i_row;
                    while (i <= i_row1)
                    {
                        if (depth < depth_buffer[i])
                        {
                            goto skip_occlusion;
                        }
                        ++i;
                    }
                    if (++yMin > yMax)
                    {
                        ++skipped_cells; goto branch_up;
                    }
                    i_row += BufW;
                }
            }
        }
        #endregion

        skip_occlusion :;

        #region persp -> ortho switch
        // ortho switch is performed here to not do extra work if the node is occluded
        if (switch_to_ortho)
        {
            bool  bbox_initialized = false;
            float b0x = 0, b0y = 0, b1y = 0, b1x = 0, b0k = 0, b1k = 0;

            var idxyz0 = linked_idxyz[stack_id];
            var idxyz1 = linked_idxyz[linked_idxyz.Length - 1];

            while (idxyz0 != null)
            {
                float wrk_x = nsi.x + (idxyz0.dx + idxyz0.dx);
                float wrk_y = nsi.y + (idxyz0.dy + idxyz0.dy);
                float wrk_z = nsi.z + (idxyz0.dz + idxyz0.dz);

                float wrk_k = persp_zoom_factor / wrk_z;

                float wrk_px = (BufW2 + wrk_x * wrk_k);
                float wrk_py = (BufH2 + wrk_y * wrk_k);

                if (bbox_initialized)
                {
                    if (wrk_px < b0x)
                    {
                        b0x = wrk_px;
                    }
                    else if (wrk_px > b1x)
                    {
                        b1x = wrk_px;
                    }
                    if (wrk_py < b0y)
                    {
                        b0y = wrk_py;
                    }
                    else if (wrk_py > b1y)
                    {
                        b1y = wrk_py;
                    }
                    if (wrk_k < b0k)
                    {
                        b0k = wrk_k;
                    }
                    else if (wrk_k > b1k)
                    {
                        b1k = wrk_k;
                    }
                }
                else
                {
                    b0x = b1x = wrk_px;
                    b0y = b1y = wrk_py;
                    b0k = b1k = wrk_k;
                    bbox_initialized = true;
                }

                idxyz1.dx = (wrk_px - proj_cx) * 0.5f;
                idxyz1.dy = (wrk_py - proj_cy) * 0.5f;
                idxyz1.dz = (wrk_z - nsi.z) * 0.5f;

                idxyz0 = idxyz0.next;
                idxyz1 = idxyz1.next;
            }

            // Make more precise check, otherwise there can be glitches.
            switch_to_ortho = ((b1k - b0k) < ortho_switch_threshold);
            if (switch_to_ortho)
            {
                switch_to_ortho = false;

                idxyz0 = linked_idxyz[stack_id];
                idxyz1 = linked_idxyz[linked_idxyz.Length - 1];

                while (idxyz0 != null)
                {
                    idxyz0.dx = idxyz1.dx;
                    idxyz0.dy = idxyz1.dy;
                    idxyz0.dz = idxyz1.dz;

                    idxyz0 = idxyz0.next;
                    idxyz1 = idxyz1.next;
                }

                nsi.ortho = true;
                nsi.x     = proj_cx;
                nsi.y     = proj_cy;

                node_stack[stack_id] = nsi;

                stack_size = stack_id + 1;               // invalidate cached values of perspective projection

                var rOrt = radiuses[stack_id];
                rOrt.x = (b1x - b0x) * 0.5f;
                rOrt.y = (b1y - b0y) * 0.5f;
                rOrt.z = rOrt.x; if (rOrt.y > rOrt.z)
                {
                    rOrt.z = rOrt.y;
                }
                rOrt.x -= 0.5f;
                rOrt.y -= 0.5f;
                // w (abs radius) stays the same
                radiuses[stack_id] = rOrt;
            }
        }
        #endregion

        ++nonleaf_cells;

        nsi.idxyz = linked_idxyz[stack_id];

        resume_subnodes :;

        switch (nsi.idxyz.index)
        {
        case 0 : subnode = nsi.node.n000; break;

        case 1: subnode = nsi.node.n001; break;

        case 2: subnode = nsi.node.n010; break;

        case 3: subnode = nsi.node.n011; break;

        case 4: subnode = nsi.node.n100; break;

        case 5: subnode = nsi.node.n101; break;

        case 6: subnode = nsi.node.n110; break;

        case 7: subnode = nsi.node.n111; break;
        }

        if (subnode == null)
        {
            nsi.idxyz = nsi.idxyz.next;
            if (nsi.idxyz == null)
            {
                goto branch_up;
            }
            goto resume_subnodes;
        }

        IdXYZ idxyz = nsi.idxyz;
        nsi.idxyz = nsi.idxyz.next;

        node_stack[stack_id] = nsi;
        ++stack_id;

        if (stack_id == stack_size)
        {
            #region initialize next level's look-up tables from the current level
            r    = radiuses[stack_id - 1];
            r.x  = r.x * 0.5f - 0.25f;
            r.y  = r.y * 0.5f - 0.25f;
            r.z *= 0.5f;
            r.w *= 0.5f;
            radiuses[stack_id] = r;

            var idxyz0 = linked_idxyz[stack_id - 1];
            var idxyz1 = linked_idxyz[stack_id];
            while (idxyz0 != null)
            {
                idxyz1.index = idxyz0.index;
                idxyz1.dx    = idxyz0.dx * 0.5f;
                idxyz1.dy    = idxyz0.dy * 0.5f;
                idxyz1.dz    = idxyz0.dz * 0.5f;
                idxyz0       = idxyz0.next;
                idxyz1       = idxyz1.next;
            }
            #endregion

            ++stack_size;
        }

        nsi.node = subnode;
        nsi.x   += idxyz.dx;
        nsi.y   += idxyz.dy;
        nsi.z   += idxyz.dz;

//		if (nsi.ortho && nsi.inside) {
//			RasterizeOctreeInsideOrtho(nsi, stack_id, stack_size, tint);
//			goto branch_up;
//		}

        goto branch_down;

        branch_up :;

        if (stack_id == 0)
        {
            return;                        // EXIT POINT
        }
        bool old_ortho = nsi.ortho;
        nsi = node_stack[--stack_id];

        if (nsi.ortho != old_ortho)
        {
            stack_size = stack_id + 1;                               // invalidate cached values of ortho projection
        }
        // (nsi.idxyz == null) means that all 8 subnodes were processed and we can return to the upper node
        if (nsi.idxyz == null)
        {
            goto branch_up;
        }
        else
        {
            goto resume_subnodes;
        }
    }
Example #3
0
    static void RasterizeOctreeInsideOrtho(NodeStackItem nsi, int stack_id, int stack_size, Color32 tint)
    {
        #region various initialization
        int stack_id_0 = stack_id;

        VoxelObject.OctreeNode subnode = null;

        float lod_r = lod * 0.5f;

        float depth_offset = -clip_near, depth_scale = ((1 << depth_buffer_bits) - 1) / (clip_far - clip_near);

        Color32 c = default(Color32);

        bool is_leaf = false;

        float xMinF = 0, xMaxF = 0, yMinF = 0, yMaxF = 0;
        int   xMin = 0, xMax = 0, yMin = 0, yMax = 0;

        float BufW1f = BufW1 + 0.5f, BufH1f = BufH1 + 0.5f;
        #endregion

        branch_down :;

        ++processed_cells;

        var   r         = radiuses[stack_id];
        float closest_z = nsi.z - r.w;

        {
            ++ortho_cells;

            c       = nsi.node.color;                   // a == 255 is considered a leaf
            is_leaf = ((c.a == 255) || (r.z <= lod_r)); // r.z is max(r.x, r.y)

            xMinF = (nsi.x - r.x);
            xMaxF = (nsi.x + r.x);
            yMinF = (nsi.y - r.y);
            yMaxF = (nsi.y + r.y);
        }

        xMin = (int)xMinF;
        xMax = (int)xMaxF;
        yMin = (int)yMinF;
        yMax = (int)yMaxF;

        #region rasterization / occlusion test
        if ((xMax < xMin) || (yMax < yMin))
        {
            ++skipped_cells; goto branch_up;
        }
        else if ((xMax == xMin) && (yMax == yMin))
        {
            int i = xMin + yMin * BufW;
            if (is_leaf)
            {
                float depth = nsi.z;
                //float depth = (nsi.z + depth_offset) * depth_scale;
                //int depth = (int)((nsi.z + depth_offset) * depth_scale);
                if (depth < depth_buffer[i])
                {
                    c.r             = (byte)((c.r * tint.r + 255) >> 8); c.g = (byte)((c.g * tint.g + 255) >> 8); c.b = (byte)((c.b * tint.b + 255) >> 8);
                    depth_buffer[i] = depth; color_buffer[i] = c;
                }
                ++pixel_cells; goto branch_up;
            }
            else
            {
                float depth = closest_z;
                //float depth = (closest_z + depth_offset) * depth_scale;
                //int depth = (int)((closest_z + depth_offset) * depth_scale);
                if (depth < depth_buffer[i])
                {
                    goto skip_occlusion;
                }
                ++skipped_cells; goto branch_up;
            }
        }
        else
        {
            int i_row     = xMin + yMin * BufW;
            int row_width = (xMax - xMin);
            if (is_leaf)
            {
                float depth = nsi.z;
                //float depth = (nsi.z + depth_offset) * depth_scale;
                //int depth = (int)((nsi.z + depth_offset) * depth_scale);
                c.r = (byte)((c.r * tint.r + 255) >> 8); c.g = (byte)((c.g * tint.g + 255) >> 8); c.b = (byte)((c.b * tint.b + 255) >> 8);
                for (;;)
                {
                    int i_row1 = i_row + row_width;
                    int i      = i_row;
                    while (i <= i_row1)
                    {
                        if (depth < depth_buffer[i])
                        {
                            depth_buffer[i] = depth; color_buffer[i] = c;
                        }
                        ++i;
                    }
                    if (++yMin > yMax)
                    {
                        ++leaf_cells; goto branch_up;
                    }
                    i_row += BufW;
                }
            }
            else
            {
                float depth = closest_z;
                //float depth = (closest_z + depth_offset) * depth_scale;
                //int depth = (int)((closest_z + depth_offset) * depth_scale);
                for (;;)
                {
                    int i_row1 = i_row + row_width;
                    int i      = i_row;
                    while (i <= i_row1)
                    {
                        if (depth < depth_buffer[i])
                        {
                            goto skip_occlusion;
                        }
                        ++i;
                    }
                    if (++yMin > yMax)
                    {
                        ++skipped_cells; goto branch_up;
                    }
                    i_row += BufW;
                }
            }
        }
        #endregion

        skip_occlusion :;

        ++nonleaf_cells;

        nsi.idxyz = linked_idxyz[stack_id];

        resume_subnodes :;

        switch (nsi.idxyz.index)
        {
        case 0 : subnode = nsi.node.n000; break;

        case 1: subnode = nsi.node.n001; break;

        case 2: subnode = nsi.node.n010; break;

        case 3: subnode = nsi.node.n011; break;

        case 4: subnode = nsi.node.n100; break;

        case 5: subnode = nsi.node.n101; break;

        case 6: subnode = nsi.node.n110; break;

        case 7: subnode = nsi.node.n111; break;
        }

        if (subnode == null)
        {
            nsi.idxyz = nsi.idxyz.next;
            if (nsi.idxyz == null)
            {
                goto branch_up;
            }
            goto resume_subnodes;
        }

        IdXYZ idxyz = nsi.idxyz;
        nsi.idxyz = nsi.idxyz.next;

        node_stack[stack_id] = nsi;
        ++stack_id;

        if (stack_id == stack_size)
        {
            #region initialize next level's look-up tables from the current level
            r    = radiuses[stack_id - 1];
            r.x  = r.x * 0.5f - 0.25f;
            r.y  = r.y * 0.5f - 0.25f;
            r.z *= 0.5f;
            r.w *= 0.5f;
            radiuses[stack_id] = r;

            var idxyz0 = linked_idxyz[stack_id - 1];
            var idxyz1 = linked_idxyz[stack_id];
            while (idxyz0 != null)
            {
                idxyz1.index = idxyz0.index;
                idxyz1.dx    = idxyz0.dx * 0.5f;
                idxyz1.dy    = idxyz0.dy * 0.5f;
                idxyz1.dz    = idxyz0.dz * 0.5f;
                idxyz0       = idxyz0.next;
                idxyz1       = idxyz1.next;
            }
            #endregion

            ++stack_size;
        }

        nsi.node = subnode;
        nsi.x   += idxyz.dx;
        nsi.y   += idxyz.dy;
        nsi.z   += idxyz.dz;

        goto branch_down;

        branch_up :;

        if (stack_id <= stack_id_0)
        {
            return;                                 // EXIT POINT
        }
        bool old_ortho = nsi.ortho;
        nsi = node_stack[--stack_id];

        if (nsi.ortho != old_ortho)
        {
            stack_size = stack_id + 1;                               // invalidate cached values of ortho projection
        }
        // (nsi.idxyz == null) means that all 8 subnodes were processed and we can return to the upper node
        if (nsi.idxyz == null)
        {
            goto branch_up;
        }
        else
        {
            goto resume_subnodes;
        }
    }