Ejemplo n.º 1
0
 // I think this can be more efficient...no? At least could combine
 // all the axis-interval updates before updating Center...
 public void Contain(Box3d o)
 {
     Vector3d[] v = o.ComputeVertices();
     for (int k = 0; k < 8; ++k)
     {
         Contain(v[k]);
     }
 }
Ejemplo n.º 2
0
        public override MeshGenerator Generate()
        {
            int N = EdgeVertices;   int Nm2 = N - 2;
            int NT = N - 1;
            int N2 = N * N;

            vertices  = new VectorArray3d((NoSharedVertices) ? (N2 * 6) : (8 + Nm2 * 12 + Nm2 * Nm2 * 6));
            uv        = new VectorArray2f(vertices.Count);
            normals   = new VectorArray3f(vertices.Count);
            triangles = new IndexArray3i(2 * NT * NT * 6);
            groups    = new int[triangles.Count];

            Vector3d[] boxvertices = Box.ComputeVertices();

            int vi = 0;
            int ti = 0;

            if (NoSharedVertices)
            {
                for (int fi = 0; fi < 6; ++fi)
                {
                    // get corner vertices
                    Vector3d v00   = boxvertices[gIndices.BoxFaces[fi, 0]];
                    Vector3d v01   = boxvertices[gIndices.BoxFaces[fi, 1]];
                    Vector3d v11   = boxvertices[gIndices.BoxFaces[fi, 2]];
                    Vector3d v10   = boxvertices[gIndices.BoxFaces[fi, 3]];
                    Vector3f faceN = Math.Sign(gIndices.BoxFaceNormals[fi]) * (Vector3f)Box.Axis(Math.Abs(gIndices.BoxFaceNormals[fi]) - 1);

                    // add vertex rows
                    int start_vi = vi;
                    for (int yi = 0; yi < N; ++yi)
                    {
                        double ty = (double)yi / (double)(N - 1);
                        for (int xi = 0; xi < N; ++xi)
                        {
                            double tx = (double)xi / (double)(N - 1);
                            normals[vi]    = faceN;
                            uv[vi]         = new Vector2f(tx, ty);
                            vertices[vi++] = bilerp(ref v00, ref v01, ref v11, ref v10, tx, ty);
                        }
                    }

                    // add faces
                    for (int y0 = 0; y0 < NT; ++y0)
                    {
                        for (int x0 = 0; x0 < NT; ++x0)
                        {
                            int i00 = start_vi + y0 * N + x0;
                            int i10 = start_vi + (y0 + 1) * N + x0;
                            int i01 = i00 + 1, i11 = i10 + 1;

                            groups[ti] = fi;
                            triangles.Set(ti++, i00, i01, i11, Clockwise);
                            groups[ti] = fi;
                            triangles.Set(ti++, i00, i11, i10, Clockwise);
                        }
                    }
                }
            }
            else
            {
                // construct integer coordinates
                Vector3i[] intvertices = new Vector3i[boxvertices.Length];
                for (int k = 0; k < boxvertices.Length; ++k)
                {
                    Vector3d v = boxvertices[k] - Box.Center;
                    intvertices[k] = new Vector3i(
                        v.x < 0 ? 0 : N - 1,
                        v.y < 0 ? 0 : N - 1,
                        v.z < 0 ? 0 : N - 1);
                }
                int[] faceIndicesV = new int[N2];

                // add edge vertices and store in this map
                // todo: don't use a map (?)  how do we do that, though...
                //   - each index is in range [0,N). If we have (i,j,k), then for a given
                //     i, we have a finite number of j and k (< 2N?).
                //     make N array of 2N length, key on i, linear search for matching j/k?
                Dictionary <Vector3i, int> edgeVerts = new Dictionary <Vector3i, int>();
                for (int fi = 0; fi < 6; ++fi)
                {
                    // get corner vertices
                    int c00 = gIndices.BoxFaces[fi, 0], c01 = gIndices.BoxFaces[fi, 1],
                        c11 = gIndices.BoxFaces[fi, 2], c10 = gIndices.BoxFaces[fi, 3];
                    Vector3d v00 = boxvertices[c00];  Vector3i vi00 = intvertices[c00];
                    Vector3d v01 = boxvertices[c01];  Vector3i vi01 = intvertices[c01];
                    Vector3d v11 = boxvertices[c11];  Vector3i vi11 = intvertices[c11];
                    Vector3d v10 = boxvertices[c10];  Vector3i vi10 = intvertices[c10];

                    Action <Vector3d, Vector3d, Vector3i, Vector3i> do_edge = (a, b, ai, bi) => {
                        for (int i = 0; i < N; ++i)
                        {
                            double   t    = (double)i / (double)(N - 1);
                            Vector3i vidx = lerp(ref ai, ref bi, t);
                            if (edgeVerts.ContainsKey(vidx) == false)
                            {
                                Vector3d v = Vector3d.Lerp(ref a, ref b, t);
                                normals[vi]     = (Vector3f)v.Normalized;
                                uv[vi]          = Vector2f.Zero;
                                edgeVerts[vidx] = vi;
                                vertices[vi++]  = v;
                            }
                        }
                    };
                    do_edge(v00, v01, vi00, vi01);
                    do_edge(v01, v11, vi01, vi11);
                    do_edge(v11, v10, vi11, vi10);
                    do_edge(v10, v00, vi10, vi00);
                }


                // now generate faces
                for (int fi = 0; fi < 6; ++fi)
                {
                    // get corner vertices
                    int c00 = gIndices.BoxFaces[fi, 0], c01 = gIndices.BoxFaces[fi, 1],
                        c11 = gIndices.BoxFaces[fi, 2], c10 = gIndices.BoxFaces[fi, 3];
                    Vector3d v00 = boxvertices[c00]; Vector3i vi00 = intvertices[c00];
                    Vector3d v01 = boxvertices[c01]; Vector3i vi01 = intvertices[c01];
                    Vector3d v11 = boxvertices[c11]; Vector3i vi11 = intvertices[c11];
                    Vector3d v10 = boxvertices[c10]; Vector3i vi10 = intvertices[c10];
                    Vector3f faceN = Math.Sign(gIndices.BoxFaceNormals[fi]) * (Vector3f)Box.Axis(Math.Abs(gIndices.BoxFaceNormals[fi]) - 1);

                    // add vertex rows, using existing vertices if we have them in map
                    for (int yi = 0; yi < N; ++yi)
                    {
                        double ty = (double)yi / (double)(N - 1);
                        for (int xi = 0; xi < N; ++xi)
                        {
                            double   tx   = (double)xi / (double)(N - 1);
                            Vector3i vidx = bilerp(ref vi00, ref vi01, ref vi11, ref vi10, tx, ty);
                            int      use_vi;
                            if (edgeVerts.TryGetValue(vidx, out use_vi) == false)
                            {
                                Vector3d v = bilerp(ref v00, ref v01, ref v11, ref v10, tx, ty);
                                use_vi           = vi++;
                                normals[use_vi]  = faceN;
                                uv[use_vi]       = new Vector2f(tx, ty);
                                vertices[use_vi] = v;
                            }
                            faceIndicesV[yi * N + xi] = use_vi;
                        }
                    }

                    // add faces
                    for (int y0 = 0; y0 < NT; ++y0)
                    {
                        int y1 = y0 + 1;
                        for (int x0 = 0; x0 < NT; ++x0)
                        {
                            int x1  = x0 + 1;
                            int i00 = faceIndicesV[y0 * N + x0];
                            int i01 = faceIndicesV[y0 * N + x1];
                            int i11 = faceIndicesV[y1 * N + x1];
                            int i10 = faceIndicesV[y1 * N + x0];

                            groups[ti] = fi;
                            triangles.Set(ti++, i00, i01, i11, Clockwise);
                            groups[ti] = fi;
                            triangles.Set(ti++, i00, i11, i10, Clockwise);
                        }
                    }
                }
            }

            return(this);
        }
Ejemplo n.º 3
0
        // ported from WildMagic5 Wm5ContBox3.cpp::MergeBoxes
        public static Box3d Merge(ref Box3d box0, ref Box3d box1)
        {
            // Construct a box that contains the input boxes.
            var box = new Box3d();

            // The first guess at the box center.  This value will be updated later
            // after the input box vertices are projected onto axes determined by an
            // average of box axes.
            box.Center = 0.5 * (box0.Center + box1.Center);

            // A box's axes, when viewed as the columns of a matrix, form a rotation
            // matrix.  The input box axes are converted to quaternions.  The average
            // quaternion is computed, then normalized to unit length.  The result is
            // the slerp of the two input quaternions with t-value of 1/2.  The result
            // is converted back to a rotation matrix and its columns are selected as
            // the merged box axes.
            Quaterniond q0 = new Quaterniond(), q1 = new Quaterniond();
            var         rot0 = new Matrix3d(ref box0.AxisX, ref box0.AxisY, ref box0.AxisZ, false);

            q0.SetFromRotationMatrix(ref rot0);
            var rot1 = new Matrix3d(ref box1.AxisX, ref box1.AxisY, ref box1.AxisZ, false);

            q1.SetFromRotationMatrix(ref rot1);
            if (q0.Dot(q1) < 0)
            {
                q1 = -q1;
            }

            Quaterniond q         = q0 + q1;
            double      invLength = 1.0 / Math.Sqrt(q.Dot(q));

            q = q * invLength;
            Matrix3d q_mat = q.ToRotationMatrix();

            box.AxisX = q_mat.Column(0); box.AxisY = q_mat.Column(1); box.AxisZ = q_mat.Column(2);              //q.ToRotationMatrix(box.Axis);

            // Project the input box vertices onto the merged-box axes.  Each axis
            // D[i] containing the current center C has a minimum projected value
            // min[i] and a maximum projected value max[i].  The corresponding end
            // points on the axes are C+min[i]*D[i] and C+max[i]*D[i].  The point C
            // is not necessarily the midpoint for any of the intervals.  The actual
            // box center will be adjusted from C to a point C' that is the midpoint
            // of each interval,
            //   C' = C + sum_{i=0}^2 0.5*(min[i]+max[i])*D[i]
            // The box extents are
            //   e[i] = 0.5*(max[i]-min[i])

            int      i, j;
            double   dot;
            var      vertex = new Vector3d[8];
            Vector3d pmin   = Vector3d.Zero;
            Vector3d pmax   = Vector3d.Zero;

            box0.ComputeVertices(vertex);
            for (i = 0; i < 8; ++i)
            {
                Vector3d diff = vertex[i] - box.Center;
                for (j = 0; j < 3; ++j)
                {
                    dot = box.Axis(j).Dot(ref diff);
                    if (dot > pmax[j])
                    {
                        pmax[j] = dot;
                    }
                    else if (dot < pmin[j])
                    {
                        pmin[j] = dot;
                    }
                }
            }

            box1.ComputeVertices(vertex);
            for (i = 0; i < 8; ++i)
            {
                Vector3d diff = vertex[i] - box.Center;
                for (j = 0; j < 3; ++j)
                {
                    dot = box.Axis(j).Dot(ref diff);
                    if (dot > pmax[j])
                    {
                        pmax[j] = dot;
                    }
                    else if (dot < pmin[j])
                    {
                        pmin[j] = dot;
                    }
                }
            }

            // [min,max] is the axis-aligned box in the coordinate system of the
            // merged box axes.  Update the current box center to be the center of
            // the new box.  Compute the extents based on the new center.
            for (j = 0; j < 3; ++j)
            {
                box.Center   += (0.5 * (pmax[j] + pmin[j])) * box.Axis(j);
                box.Extent[j] = 0.5 * (pmax[j] - pmin[j]);
            }

            return(box);
        }