예제 #1
0
        static void TestSlices()
        {
            Console.WriteLine("Hello World!");

            VoxelSet <Vec4b> colors = new VoxelSet <Vec4b>(32);

            colors.Set(new Vec4b(0));
            colors.Slice(new Vec3i(1), new Vec3i(30)).Set(new Vec4b(255));
            colors.Slice(new Vec3i(3), new Vec3i(28)).Set(new Vec4b(0));
            colors.Slice(new Vec3i(5), new Vec3i(26)).Set(new Vec4b(255));

            for (int i = 0; i < 32; ++i)
            {
                if (colors[16, i, 16].x == 0)
                {
                    Console.Write(".");
                }
                else
                {
                    Console.Write("#");
                }
            }
            Console.Write("\nPress any key to continue ... ");
            Console.ReadKey();
        }
예제 #2
0
        public static List <Box> MakeBoxes(VoxelSet <bool> shape)
        {
            List <Box> boxes = new List <Box>();

            // Directions to explore
            Vec3i[] dirs = new[] {
                new Vec3i(1, 0, 0),
                new Vec3i(0, 1, 0),
                new Vec3i(0, 0, 1)
            };

            // TODO: Iteration order may need to be reversed
            for (int z = 0; z < shape.Size.z; z++)
            {
                for (int y = 0; y < shape.Size.y; y++)
                {
                    for (int x = 0; x < shape.Size.x; x++)
                    {
                        if (!shape[x, y, z])
                        {
                            continue;
                        }

                        Vec3i idx    = new Vec3i(x, y, z);
                        Vec3i endIdx = new Vec3i(x, y, z);

                        // Expand box in each cardinal direction as much as possible
                        foreach (var dir in dirs)
                        {
                            Vec3i checkFromIdx = idx;

                            // Expand as much as possible in the current direction
                            while (shape.IsValid(endIdx + dir))
                            {
                                checkFromIdx += dir;

                                // Create a slice for the next layer in the current dir and make sure it's solid
                                var slice = shape.Slice(checkFromIdx, endIdx + dir);
                                if (!slice.IsAllSolid(b => b))
                                {
                                    break;
                                }
                                slice.Set(false);

                                endIdx += dir;
                            }
                        }

                        Box box = new Box();
                        box.origin  = new Vec3i(x, y, z);
                        box.extents = new Vec3i(endIdx.x + 1 - idx.x, endIdx.y + 1 - idx.y, endIdx.z + 1 - idx.z);
                        boxes.Add(box);
                    }
                }
            }

            return(boxes);
        }
예제 #3
0
        public void GetMesh(VoxelSet <Vec4b> voxels,
                            out int[] indices, out Vec3f[] points, out Vec3f[] normals, out Vec2f[] uvs,
                            out VoxelSet <Vec4b> textureAtlas)
        {
            List <int>   indicesList = new List <int>();
            List <Vec3f> pointsList  = new List <Vec3f>();
            List <Vec3f> normalsList = new List <Vec3f>();
            List <Vec2f> uvsList     = new List <Vec2f>();

            Dictionary <int, int> vertIdxRemap = new Dictionary <int, int>();

            List <Bin> bins = new List <Bin>();

            foreach (var poly in AllPolygons())
            {
                // For each connected polygon
                vertIdxRemap.Clear();
                Vec3f normal = Normal(poly.First());

                Vec3f maxP = new Vec3f(-1);
                Vec3f minP = new Vec3f(1024 * 1024);

                AtlasEntry atlasEntry = new AtlasEntry();
                atlasEntry.startVertIdx = pointsList.Count;
                atlasEntry.normal       = new Vec3i(
                    (int)Math.Round(normal.x),
                    (int)Math.Round(normal.y),
                    (int)Math.Round(normal.z)
                    );

                foreach (var baseEdge in poly)
                {
                    // Each triangle that makes up the polygon
                    foreach (var e in new int[] { baseEdge, Next(baseEdge), Prev(baseEdge) })
                    {
                        // Each vertex of each triangle
                        int vertIdx = Edges[e].vertexIdx;
                        if (!vertIdxRemap.ContainsKey(vertIdx))
                        {
                            vertIdxRemap.Add(vertIdx, pointsList.Count);
                            pointsList.Add(Points[vertIdx]);
                            normalsList.Add(normal);

                            maxP = Max3f(maxP, Points[vertIdx]);
                            minP = Min3f(minP, Points[vertIdx]);

                            // TODO: Add UV here
                        }

                        indicesList.Add(vertIdxRemap[vertIdx]);
                    }
                }

                atlasEntry.vertCount = pointsList.Count - atlasEntry.startVertIdx;

                // TODO: Add to texture atlas here
                Vec3f deltaP = maxP - minP;

                // Determine which dimension is flat
                int flatIdx = -1;
                for (int i = 0; i < 3; ++i)
                {
                    if (deltaP[i] == 0)
                    {
                        if (flatIdx >= 0)
                        {
                            throw new Exception("Two or more flat dimensions found");
                        }
                        flatIdx = i;
                    }
                }

                Vec2i size;
                if (flatIdx == 0)
                {
                    size = new Vec2i((int)Math.Round(deltaP.y), (int)Math.Round(deltaP.z));
                }
                else if (flatIdx == 1)
                {
                    size = new Vec2i((int)Math.Round(deltaP.x), (int)Math.Round(deltaP.z));
                }
                else
                {
                    size = new Vec2i((int)Math.Round(deltaP.x), (int)Math.Round(deltaP.y));
                }

                atlasEntry.flatDimension = flatIdx;
                atlasEntry.max           = new Vec3i(maxP + new Vec3f(0.5f));
                atlasEntry.min           = new Vec3i(minP + new Vec3f(0.5f));

                Bin b = new Bin();
                b.Size     = size;
                b.UserData = atlasEntry;
                bins.Add(b);
            }

            indices = indicesList.ToArray();
            points  = pointsList.ToArray();
            normals = normalsList.ToArray();

            //BinPacker bp = new BinPacker(512);
            BinPacker bp = new BinPacker(512);

            bp.BinPadding = new Vec2i(2);
            bp.Pack(bins);
            bp.MakePow2();

            textureAtlas = new VoxelSet <Vec4b>(bp.Width, bp.Height, 1);

            for (int y = 0; y < textureAtlas.Size.y; ++y)
            {
                for (int x = 0; x < textureAtlas.Size.x; ++x)
                {
                    textureAtlas[x, y, 0] = new Vec4b(0, 255, 0, 255);
                }
            }

            uvs = new Vec2f[points.Length];
            foreach (var bin in bp.Bins)
            {
                var atlasEntry = (AtlasEntry)bin.UserData;

                // Copy to atlas
                var toSlice = textureAtlas.Slice(new Vec3i(bin.Position, 0),
                                                 new Vec3i(bin.Position + bin.Size - 1, 0));

                Vec3i voxelOffset = new Vec3i(0);

                if (atlasEntry.normal.Dot(new Vec3i(1)) > 0)
                {
                    voxelOffset = atlasEntry.normal * -1;
                }
                else
                {
                    //voxelOffset = atlasEntry.normal * -1;
                    voxelOffset = new Vec3i(0);
                }

                var fromSlice = voxels.Slice(
                    atlasEntry.min + voxelOffset,
                    atlasEntry.max - atlasEntry.min + atlasEntry.Basis() * new Vec3i(0, 0, 1),
                    atlasEntry.Basis()
                    );

                if (toSlice.Size.x != fromSlice.Size.x ||
                    toSlice.Size.y != fromSlice.Size.y ||
                    toSlice.Size.z != fromSlice.Size.z)
                {
                    throw new Exception();
                }

                /*for (int y = 0; y < toSlice.Size.y; ++y) {
                 *  for (int x = 0; x < toSlice.Size.x; ++x) {
                 *      toSlice[x, y, 0] = fromSlice[x, y, 0];
                 *  }
                 * }*/

                for (int y = 0; y < toSlice.Size.y; ++y)
                {
                    for (int x = 0; x < toSlice.Size.x; ++x)
                    {
                        if (Vec4b.Dot(toSlice[x, y, 0], new Vec4b(1)) != 0)
                        {
                            ////throw new Exception();
                        }
                        toSlice[x, y, 0] = voxels[atlasEntry.To3d(new Vec2i(x, y)) + voxelOffset];
                        //toSlice[x, y, 0] = c;
                    }
                }

                // Compute UVs
                for (int i = atlasEntry.startVertIdx; i < atlasEntry.startVertIdx + atlasEntry.vertCount; ++i)
                {
                    Vec2f uv = new Vec2f(atlasEntry.To2d(new Vec3i(points[i])));

                    //uv *= new Vec2f(bin.Size - 1) / new Vec2f(bin.Size);
                    //uv += 0.5f;

                    uv *= (new Vec2f(bin.Size) - 0.01f) / new Vec2f(bin.Size);
                    uv += 0.005f;

                    /////////
                    //uv *= 0.998f;
                    //uv += 0.01f;

                    uv += new Vec2f(bin.Position);

                    ///////
                    //uv += 0.25f;

                    uv.x /= bp.Width;
                    uv.y /= bp.Height;

                    uvs[i] = uv;
                }
            }

            Console.WriteLine("Total size: {0} x {1}", bp.Width, bp.Height);
        }