示例#1
0
        public static int PolygonizeRegularCell(Vector3i min, Vector3f offset, Vector3i xyz,
                                                IVolumeData samples, byte lodIndex, float cellSize,
                                                ref IList <Vertex> verts, ref IList <int> indices, ref RegularCache cache)
        {
            int  lodScale      = 1 << lodIndex;
            int  last          = 15 * lodScale;
            byte directionMask = (byte)((xyz.X > 0 ? 1 : 0) | ((xyz.Y > 0 ? 1 : 0) << 1) | ((xyz.Z > 0 ? 1 : 0) << 2));
            byte near          = 0;

            // Compute which of the six faces of the block that the vertex
            // is near. (near is defined as being in boundary cell.)
            for (int i = 0; i < 3; i++)
            {
                //Vertex close to negative face.
                if (min[i] == 0)
                {
                    near |= (byte)(1 << (i * 2 + 0));
                }
                //Vertex close to positive face.
                if (min[i] == last)
                {
                    near |= (byte)(1 << (i * 2 + 1));
                }
            }

            Vector3i[] cornerPositions = Tables.CornerIndex;
            for (int i = 0; i < cornerPositions.Length; i++)
            {
                cornerPositions[i] = min + cornerPositions[i] * lodScale;
            }

            //  new Vector3i[]
            //      {
            //          min + new Vector3i(0, 0, 0)*lodScale,
            //          min + new Vector3i(1, 0, 0)*lodScale,
            //          min + new Vector3i(0, 1, 0)*lodScale,
            //          min + new Vector3i(1, 1, 0)*lodScale,
            //
            //          min + new Vector3i(0, 0, 1)*lodScale,
            //          min + new Vector3i(1, 0, 1)*lodScale,
            //          min + new Vector3i(0, 1, 1)*lodScale,
            //          min + new Vector3i(1, 1, 1)*lodScale
            //      };

            Vector3i dif = cornerPositions[7] - cornerPositions[1];

            // Retrieve sample values for all the corners.
            sbyte[] cornerSamples =
                new sbyte[]
            {
                samples[cornerPositions[0]],
                samples[cornerPositions[1]],
                samples[cornerPositions[2]],
                samples[cornerPositions[3]],
                samples[cornerPositions[4]],
                samples[cornerPositions[5]],
                samples[cornerPositions[6]],
                samples[cornerPositions[7]],
            };

            Vector3f[] cornerNormals = new Vector3f[8];

            // Determine the index into the edge table which
            // tells us which vertices are inside of the surface
            uint caseCode = (uint)(((cornerSamples[0] >> 7) & 0x01)
                                   | ((cornerSamples[1] >> 6) & 0x02)
                                   | ((cornerSamples[2] >> 5) & 0x04)
                                   | ((cornerSamples[3] >> 4) & 0x08)
                                   | ((cornerSamples[4] >> 3) & 0x10)
                                   | ((cornerSamples[5] >> 2) & 0x20)
                                   | ((cornerSamples[6] >> 1) & 0x40)
                                   | (cornerSamples[7] & 0x80));

            cache[xyz].CaseIndex = (byte)caseCode;
            if ((caseCode ^ ((cornerSamples[7] >> 7) & 0xff)) == 0)
            {
                return(0);
            }

            // Compute the normals at the cell corners using central difference.
            for (int i = 0; i < 8; ++i)
            {
                var   p  = cornerPositions[i];
                float nx = (samples[p + Vector3i.UnitX] - samples[p - Vector3i.UnitX]) * 0.5f;
                float ny = (samples[p + Vector3i.UnitY] - samples[p - Vector3i.UnitY]) * 0.5f;
                float nz = (samples[p + Vector3i.UnitZ] - samples[p - Vector3i.UnitZ]) * 0.5f;
                cornerNormals[i] = new Vector3f(nx, ny, nz);
                cornerNormals[i].Normalize();
            }

            var c    = Tables.RegularCellClass[caseCode];
            var data = Tables.RegularCellData[c];

            byte nt = (byte)data.GetTriangleCount();
            byte nv = (byte)data.GetVertexCount();

            int[] localVertexMapping = new int[12];


            var vert = new Vertex();

            vert.Near = near;
            // Generate all the vertex positions by interpolating along
            // each of the edges that intersect the isosurface.
            for (int i = 0; i < nv; i++)
            {
                ushort edgeCode = Tables.RegularVertexData[caseCode][i];
                byte   v0       = HiNibble((byte)(edgeCode & 0xFF));
                byte   v1       = LoNibble((byte)(edgeCode & 0xFF));

                Vector3i p0 = cornerPositions[v0];
                Vector3i p1 = cornerPositions[v1];
                Vector3f n0 = cornerNormals[v0];
                Vector3f n1 = cornerNormals[v1];

                int d0 = samples[p0];
                int d1 = samples[p1];

                Debug.Assert(v0 < v1);

                int t = (d1 << 8) / (d1 - d0);
                int u = 0x0100 - t;

                float t0 = t * S;
                float t1 = u * S;

                if ((t & 0x00ff) != 0)
                {
                    // Vertex lies in the interior of the edge.
                    byte dir     = HiNibble((byte)(edgeCode >> 8));
                    byte idx     = LoNibble((byte)(edgeCode >> 8));
                    bool present = (dir & directionMask) == dir;

                    if (present)
                    {
                        var prev = cache[xyz + PrevOffset(dir)];

                        // I don't think this can happen for non-corner vertices.
                        if (prev.CaseIndex == 0 || prev.CaseIndex == 255)
                        {
                            localVertexMapping[i] = -1;
                        }
                        else
                        {
                            localVertexMapping[i] = prev.Verts[idx];
                        }
                    }
                    if (!present || localVertexMapping[i] < 0)
                    {
                        localVertexMapping[i] = verts.Count;
                        Vector3f pi = Interp(p0, p1, p0, p1, samples, lodIndex);
                        vert.Primary = offset + pi;
                        vert.Normal  = n0 * t0 + n1 * t1;

                        if (near > 0)
                        {
                            Vector3f delta = ComputeDelta(pi, lodIndex, 16);
                            vert.Secondary = vert.Primary + ProjectNormal(vert.Normal, delta);
                        }
                        else
                        {
                            // The vertex is not in a boundary cell, so the
                            // secondary position will never be used.
                            vert.Secondary = Unused; //vert.Primary;
                        }
                        verts.Add(vert);

                        if ((dir & 8) != 0)
                        {
                            // Store the generated vertex so that other cells can reuse it.
                            cache[xyz].Verts[idx] = localVertexMapping[i];
                        }
                    }
                }
                else if (t == 0 && v1 == 7)
                {
                    // This cell owns the vertex, so it should be created.
                    localVertexMapping[i] = verts.Count;
                    Vector3f pi = (Vector3f)p1 * t0 + (Vector3f)p1 * t1;

                    vert.Primary = offset + pi;
                    vert.Normal  = n0 * t0 + n1 * t1;

                    if (near > 0)
                    {
                        Vector3f delta = ComputeDelta(pi, lodIndex, 16);
                        vert.Secondary = vert.Primary + ProjectNormal(vert.Normal, delta);
                    }
                    else
                    {
                        // The vertex is not in a boundary cell, so the secondary
                        // position will never be used.
                        vert.Secondary = Unused;
                    }
                    verts.Add(vert);
                    cache[xyz].Verts[0] = localVertexMapping[i];
                }
                else
                {
                    // A 3-bit direction code leading to the proper cell can easily be obtained by
                    // inverting the 3-bit corner index (bitwise, by exclusive ORing with the number 7).
                    // The corner index depends on the value of t, t = 0 means that we're at the higher
                    // numbered endpoint.
                    byte dir     = t == 0 ? (byte)(v1 ^ 7) : (byte)(v0 ^ 7);
                    bool present = (dir & directionMask) == dir;

                    if (present)
                    {
                        var prev = cache[xyz + PrevOffset(dir)];

                        // The previous cell might not have any geometry, and we
                        // might therefore have to create a new vertex anyway.
                        if (prev.CaseIndex == 0 || prev.CaseIndex == 255)
                        {
                            localVertexMapping[i] = -1;
                        }
                        else
                        {
                            localVertexMapping[i] = prev.Verts[0];
                        }
                    }

                    if (!present || (localVertexMapping[i] < 0))
                    {
                        localVertexMapping[i] = verts.Count;

                        Vector3f pi = (Vector3f)p0 * t0 + (Vector3f)p1 * t1;
                        vert.Primary = offset + pi;
                        vert.Normal  = n0 * t0 + n1 * t1;

                        if (near > 0)
                        {
                            Vector3f delta = ComputeDelta(pi, lodIndex, 16);
                            vert.Secondary = vert.Primary + ProjectNormal(vert.Normal, delta);
                        }
                        else
                        {
                            vert.Secondary = Unused;
                        }
                        verts.Add(vert);
                    }
                }
            }

            for (int t = 0; t < nt; t++)
            {
                for (int i = 0; i < 3; i++)
                {
                    indices.Add(localVertexMapping[data.Indizes()[t * 3 + i]]);
                }
            }

            return(nt);
        }
        public static int PolygonizeRegularCell(Vector3i min, Vector3f offset, Vector3i xyz,
            IVolumeData samples, byte lodIndex, float cellSize,
            ref IList<Vertex> verts, ref IList<int> indices, ref RegularCache cache)
        {
            int lodScale = 1 << lodIndex;
            int last = 15 * lodScale;
            byte directionMask = (byte)((xyz.X > 0 ? 1 : 0) | ((xyz.Y > 0 ? 1 : 0) << 1) | ((xyz.Z > 0 ? 1 : 0) << 2));
            byte near = 0;

            // Compute which of the six faces of the block that the vertex
            // is near. (near is defined as being in boundary cell.)
            for (int i = 0; i < 3; i++)
            {
                //Vertex close to negative face.
                if (min[i] == 0) { near |= (byte)(1 << (i * 2 + 0)); }
                //Vertex close to positive face.
                if (min[i] == last) { near |= (byte)(1 << (i * 2 + 1)); }
            }

            Vector3i[] cornerPositions = Tables.CornerIndex;
            for (int i = 0; i < cornerPositions.Length; i++)
            {
                cornerPositions[i] = min + cornerPositions[i] * lodScale;
            }

            //  new Vector3i[]
            //      {
            //          min + new Vector3i(0, 0, 0)*lodScale,
            //          min + new Vector3i(1, 0, 0)*lodScale,
            //          min + new Vector3i(0, 1, 0)*lodScale,
            //          min + new Vector3i(1, 1, 0)*lodScale,
            //
            //          min + new Vector3i(0, 0, 1)*lodScale,
            //          min + new Vector3i(1, 0, 1)*lodScale,
            //          min + new Vector3i(0, 1, 1)*lodScale,
            //          min + new Vector3i(1, 1, 1)*lodScale
            //      };

            Vector3i dif = cornerPositions[7] - cornerPositions[1];

            // Retrieve sample values for all the corners.
            sbyte[] cornerSamples =
                new sbyte[]
                    {
                        samples[cornerPositions[0]],
                        samples[cornerPositions[1]],
                        samples[cornerPositions[2]],
                        samples[cornerPositions[3]],
                        samples[cornerPositions[4]],
                        samples[cornerPositions[5]],
                        samples[cornerPositions[6]],
                        samples[cornerPositions[7]],
                    };

            Vector3f[] cornerNormals = new Vector3f[8];

            // Determine the index into the edge table which
            // tells us which vertices are inside of the surface
            uint caseCode = (uint)(((cornerSamples[0] >> 7) & 0x01)
                                 | ((cornerSamples[1] >> 6) & 0x02)
                                 | ((cornerSamples[2] >> 5) & 0x04)
                                 | ((cornerSamples[3] >> 4) & 0x08)
                                 | ((cornerSamples[4] >> 3) & 0x10)
                                 | ((cornerSamples[5] >> 2) & 0x20)
                                 | ((cornerSamples[6] >> 1) & 0x40)
                                 | (cornerSamples[7] & 0x80));

            cache[xyz].CaseIndex = (byte)caseCode;
            if ((caseCode ^ ((cornerSamples[7] >> 7) & 0xff)) == 0)
                return 0;

            // Compute the normals at the cell corners using central difference.
            for (int i = 0; i < 8; ++i)
            {
                var p = cornerPositions[i];
                float nx = (samples[p + Vector3i.UnitX] - samples[p - Vector3i.UnitX]) * 0.5f;
                float ny = (samples[p + Vector3i.UnitY] - samples[p - Vector3i.UnitY]) * 0.5f;
                float nz = (samples[p + Vector3i.UnitZ] - samples[p - Vector3i.UnitZ]) * 0.5f;
                cornerNormals[i] = new Vector3f(nx, ny, nz);
                cornerNormals[i].Normalize();
            }

            var c = Tables.RegularCellClass[caseCode];
            var data = Tables.RegularCellData[c];

            byte nt = (byte)data.GetTriangleCount();
            byte nv = (byte)data.GetVertexCount();

            int[] localVertexMapping = new int[12];

            var vert = new Vertex();
            vert.Near = near;
            // Generate all the vertex positions by interpolating along
            // each of the edges that intersect the isosurface.
            for (int i = 0; i < nv; i++)
            {
                ushort edgeCode = Tables.RegularVertexData[caseCode][i];
                byte v0 = HiNibble((byte)(edgeCode & 0xFF));
                byte v1 = LoNibble((byte)(edgeCode & 0xFF));

                Vector3i p0 = cornerPositions[v0];
                Vector3i p1 = cornerPositions[v1];
                Vector3f n0 = cornerNormals[v0];
                Vector3f n1 = cornerNormals[v1];

                int d0 = samples[p0];
                int d1 = samples[p1];

                Debug.Assert(v0 < v1);

                int t = (d1 << 8) / (d1 - d0);
                int u = 0x0100 - t;

                float t0 = t * S;
                float t1 = u * S;

                if ((t & 0x00ff) != 0)
                {
                    // Vertex lies in the interior of the edge.
                    byte dir = HiNibble((byte)(edgeCode >> 8));
                    byte idx = LoNibble((byte)(edgeCode >> 8));
                    bool present = (dir & directionMask) == dir;

                    if (present)
                    {
                        var prev = cache[xyz + PrevOffset(dir)];

                        // I don't think this can happen for non-corner vertices.
                        if (prev.CaseIndex == 0 || prev.CaseIndex == 255)
                        {
                            localVertexMapping[i] = -1;
                        }
                        else
                        {
                            localVertexMapping[i] = prev.Verts[idx];
                        }
                    }
                    if (!present || localVertexMapping[i] < 0)
                    {
                        localVertexMapping[i] = verts.Count;
                        Vector3f pi = Interp(p0, p1, p0, p1, samples, lodIndex);
                        vert.Primary = offset + pi;
                        vert.Normal = n0 * t0 + n1 * t1;

                        if (near > 0)
                        {
                            Vector3f delta = ComputeDelta(pi, lodIndex, 16);
                            vert.Secondary = vert.Primary + ProjectNormal(vert.Normal, delta);
                        }
                        else
                        {
                            // The vertex is not in a boundary cell, so the
                            // secondary position will never be used.
                            vert.Secondary = Unused; //vert.Primary;
                        }
                        verts.Add(vert);

                        if ((dir & 8) != 0)
                        {
                            // Store the generated vertex so that other cells can reuse it.
                            cache[xyz].Verts[idx] = localVertexMapping[i];
                        }
                    }
                }
                else if (t == 0 && v1 == 7)
                {
                    // This cell owns the vertex, so it should be created.
                    localVertexMapping[i] = verts.Count;
                    Vector3f pi = (Vector3f)p1 * t0 + (Vector3f)p1 * t1;

                    vert.Primary = offset + pi;
                    vert.Normal = n0 * t0 + n1 * t1;

                    if (near > 0)
                    {
                        Vector3f delta = ComputeDelta(pi, lodIndex, 16);
                        vert.Secondary = vert.Primary + ProjectNormal(vert.Normal, delta);
                    }
                    else
                    {
                        // The vertex is not in a boundary cell, so the secondary
                        // position will never be used.
                        vert.Secondary = Unused;
                    }
                    verts.Add(vert);
                    cache[xyz].Verts[0] = localVertexMapping[i];
                }
                else
                {
                    // A 3-bit direction code leading to the proper cell can easily be obtained by
                    // inverting the 3-bit corner index (bitwise, by exclusive ORing with the number 7).
                    // The corner index depends on the value of t, t = 0 means that we're at the higher
                    // numbered endpoint.
                    byte dir = t == 0 ? (byte)(v1 ^ 7) : (byte)(v0 ^ 7);
                    bool present = (dir & directionMask) == dir;

                    if (present)
                    {
                        var prev = cache[xyz + PrevOffset(dir)];

                        // The previous cell might not have any geometry, and we
                        // might therefore have to create a new vertex anyway.
                        if (prev.CaseIndex == 0 || prev.CaseIndex == 255)
                        {
                            localVertexMapping[i] = -1;
                        }
                        else
                        {
                            localVertexMapping[i] = prev.Verts[0];
                        }
                    }

                    if (!present || (localVertexMapping[i] < 0))
                    {
                        localVertexMapping[i] = verts.Count;

                        Vector3f pi = (Vector3f)p0 * t0 + (Vector3f)p1 * t1;
                        vert.Primary = offset + pi;
                        vert.Normal = n0 * t0 + n1 * t1;

                        if (near > 0)
                        {
                            Vector3f delta = ComputeDelta(pi, lodIndex, 16);
                            vert.Secondary = vert.Primary + ProjectNormal(vert.Normal, delta);
                        }
                        else
                        {
                            vert.Secondary = Unused;
                        }
                        verts.Add(vert);
                    }
                }
            }

            for (int t = 0; t < nt; t++)
            {
                for (int i = 0; i < 3; i++)
                {
                    indices.Add(localVertexMapping[data.Indizes()[t * 3 + i]]);
                }
            }

            return nt;
        }