3D printing for kids: modelling objects with Minetest

User avatar
prestidigitator
Member
Posts: 640
Joined: Thu Feb 21, 2013 23:54

Re: 3d printing for kids: modelling objects with Minetest

by prestidigitator » Post

spin wrote:Yes, Blender supports n-gons, and recently they gave a huge boost to Boolean operations since the modifier was rewritten to use them.

I have no idea how to make a surface-only mesh from Minetest. For my purpose I care only about geometry, not textures, since FFF printers are rather monochromatic.
The approaches to building a single geometry can be different. Either:
- we try to merge the cubes using boolean operations as they are imported.
- we detect outermost faces by, idk, calculating mesh proximity or overlaps, and then remove doubles inside Blender to have them merged.
- we detect outermost vertices of cubes, and build a smooth mesh by connecting them together (in which case the result is smooth, and we treat Minetest's cubes kind of like metaballs)
-we spawn metaballs instead of cubes and let Blender do the processing :P
- something completely different. Meshlab + point cloud, idk.
Cool. Yeah. Metaballs could be interesting. I was thinking of actually traversing voxels in each coordinate direction and merging islands. I still don't trust booleans much, but it is worth a try.

Since materials aren't interesting, here's the above mod I posted, modified to export a 3D (on/off) bitmap instead of "color" data:

Code: Select all

-- Block Export [blockexport] mod.  All code is WTFPL.
-- Author: prestidigitator (as registered on forum.minetest.net)
--
-- This mod defines a new chat command "/exportblock" which writes 3D node data
-- of the player's current 80x80x80 node block to a file.  This chat command
-- requires the (new) "export" privilege.
--
-- The export file format is as follows:
--    xMin,yMin,zMin
--    rowData1
--    rowData2
--    ...
--
-- where rowData is a sequence of hex digits, each representing a bitmask of
-- booleans for block presence.  Each bit corresponds with a node having one of
-- the blocks identified in the EXPORT_NODES array.  The row data is indexed by
-- x coordinate (with 80/4 = 20 entries), with the most significant bit of each
-- hex digit representing the first node.  The first row is at y = yMin and
-- z = zMin, and they are ordered with y incrementing most often (so the second
-- row is at y = yMin+1, z = zMin).  There will be exactly 80*80 = 6400 lines
-- with row data.
--
-- The file exported is in the world directory, named
-- "<prefix><bx>-<by>-<bz><suffix>", where <prefix> is FILE_PREFIX, <suffix>
-- is FILE_SUFFIX, and <bx>, <by>, and <bz> are the (minimum) x, y, and z
-- coordinates of the exported block, with negative values prefixed by a "m"
-- character rather than a minus sign.  For example, with the default prefix of
-- "block_" and default suffix of ".mtb", exporting the block just
-- north/east/above the origin would write "block_0-0-0.mtb" and exporting the
-- one just south/west/below would write "block_m1-m1-m1.mtb".  Each exported
-- block file is very close to 1 MB in size.

---- Configuration Data: Modify to customize behavior

local FILE_PREFIX = "block_";
local FILE_SUFFIX = ".mtb";
local EXPORT_NODES = { "wool:white", "wool:red", "wool:green", "wool:blue" };

---- End Configuration Data


local MOD_NAME = minetest.get_current_modname();

if #EXPORT_NODES > 255 then
   error(MOD_NAME .. ": too many export node names");
end

local contentIdExported;
do
   local EXPORT_MAP = nil;

   contentIdExported = function(cid)
      if not EXPORT_MAP then
         EXPORT_MAP = {};
         for _, name in ipairs(EXPORT_NODES) do
            local cid = minetest.get_content_id(name);
            EXPORT_MAP[cid] = true;
         end
      end

      return EXPORT_MAP[cid] or false;
   end;
end

local function fileName(pos)
   local xs = math.floor(pos.x);
   local ys = math.floor(pos.y);
   local zs = math.floor(pos.z);
   if xs >= 0 then xs = tostring(xs); else xs = "m" .. tostring(-xs); end
   if ys >= 0 then ys = tostring(ys); else ys = "m" .. tostring(-ys); end
   if zs >= 0 then zs = tostring(zs); else zs = "m" .. tostring(-zs); end
   return FILE_PREFIX .. xs .. "-" .. ys .. "-" .. zs .. FILE_SUFFIX;
end

local function toHexDigit(value)
   value = math.floor(value) % 16;
   return string.format("%x", value);
end

local function exportBlock(pos)
   local bx = 80 * math.floor(pos.x / 80);
   local by = 80 * math.floor(pos.y / 80);
   local bz = 80 * math.floor(pos.z / 80);
   local bmin = { x = bx,      y = by,      z = bz };
   local bmax = { x = bx + 79, y = by + 79, z = bz + 79 };

   local vm = minetest.get_voxel_manip();
   bmin, bmax = vm:read_from_map(bmin, bmax);
   local data = vm:get_data();
   local va = VoxelArea:new({ MinEdge = bmin, MaxEdge = bmax });

   local fname = fileName(bmin);
   local fpath = minetest.get_worldpath() .. "/" .. fname;
   local file, emsg = io.open(fpath, "w");
   if not file then error(emsg); end

   file:write(bx .. "," .. by .. "," .. bz .. "\n");

   for zi = 0, 79 do
      for yi = 0, 79 do
         for xdi = 0, 79, 4 do
            local bitMap = 0;
            for xi = 0, 3 do
               local pos = { x = bx + xdi + xi, y = by + yi, z = bz + zi };
               bitMap = 2*bitMap;
               if va:containsp(pos) then
                  local cid = data[va:indexp(pos)];
                  if contentIdExported(cid) then
                     bitMap = bitMap + 1;
                  end
               end
            end
            file:write(toHexDigit(bitMap));
         end
         file:write("\n");
      end
   end

   file:flush();
   file:close();

   return fname;
end

minetest.register_privilege(
   "export",
   {
      description = "Allows exporting of data to files",
      give_to_singleplayer = true
   });

minetest.register_chatcommand(
   "exportblock",
   {
      params = "",
      description = "Exports your current 80x80x80 node block to a file",
      privs = { export = true },
      func =
         function(name, paramStr)
            local player = minetest.get_player_by_name(name);
            local fname = exportBlock(player:getpos());
            return true, "current block exported to " .. fname;
         end
   });
EDIT: Fixed minor error: math.min -> math.floor
Last edited by prestidigitator on Sun Aug 17, 2014 09:04, edited 1 time in total.

User avatar
prestidigitator
Member
Posts: 640
Joined: Thu Feb 21, 2013 23:54

Re: 3d printing for kids: modelling objects with Minetest

by prestidigitator » Post

Unless we really do want smooth surfaces, the voxel nature of the data should make surface generation pretty easy. If we pretended we were descending through an object in the layers between nodes (in any of the coordinate directions), then there would be a horizontal (square) surface any time there was a node above a position but not below it, or below it but not above it. That's essentially an XOR of two 2D arrays. Then, once you know which positions have square node top/bottom surfaces (pretty sure it doesn't matter which, but that requires a little more thought), it is pretty easy to merge those into solid islands with no internal edges (but with holes). Again a traversal in one of the two remaining directions, keeping track of a list of on/off ranges, would allow for easy surface generation.

User avatar
prestidigitator
Member
Posts: 640
Joined: Thu Feb 21, 2013 23:54

Re: 3d printing for kids: modelling objects with Minetest

by prestidigitator » Post

Well, given the algorithm I described above, I realized it shouldn't be too bad to do even in Lua, though it is a bit slow. It takes about 30 seconds to export a block on my machine. This exports in OBJ format, as a single mesh, with internal faces removed. The only minor issue is that I do the faces in stripes at the moment, so adjacent faces don't always share vertices. That means if you move a face or vertex it might create a rip in the mesh. That could be fixed later, but fixing it may generate quite a few extra vertices and faces too so it isn't that obvious of a gain.

(Note: I suspect the slow speed at least partially has to do with the fact that I do redundant requests for map data. I did this so that ideally the functions could be easily extended to work with sizes larger than a single 80x80x80 block later without requiring HUGE amounts of memory. All vertex data would still need to be kept around, but this way the memory requirements make it possible to have a physically large mesh as long as it is made up of mostly rectangular pieces.)

EDIT: You'll have to mirror the object in one direction in Blender. Stupid left handed coordinate system! I may fix that in the export at some point.

Code: Select all

-- Block Export [blockexport] mod.  All code is WTFPL.
-- Author: prestidigitator (as registered on forum.minetest.net)
--
-- This mod defines a new chat command "/exportblock" which writes 3D node data
-- of the player's current 80x80x80 node block to a file.  This chat command
-- requires the (new) "export" privilege.
--
-- The data is expoted in Wavefront OBJ format
--
-- The file exported is in the world directory, named
-- "<prefix><bx>-<by>-<bz><suffix>", where <prefix> is FILE_PREFIX, <suffix>
-- is FILE_SUFFIX, and <bx>, <by>, and <bz> are the (minimum) x, y, and z
-- coordinates of the exported block, with negative values prefixed by a "m"
-- character rather than a minus sign.  For example, with the default prefix of
-- "block_" and default suffix of ".obj", exporting the block just
-- north/east/above the origin would write "block_0-0-0.obj" and exporting the
-- one just south/west/below would write "block_m1-m1-m1.obj".

---- Configuration Data: Modify to customize behavior

local FILE_PREFIX = "block_";
local FILE_SUFFIX = ".obj";
local EXPORT_NODES = { "wool:white", "wool:red", "wool:green", "wool:blue" };

---- End Configuration Data


Basis =
   {
      localToGlobal = function(self, pos)
         return { [self.e] = pos.x, [self.n] = pos.y, [self.u] = pos.z };
      end,

      globalToLocal = function(self, pos)
         return { x = pos[self.e], y = pos[self.n], z = pos[self.u] };
      end
   };
setmetatable(
   Basis,
   {
      __call = function(class, up)
         local e, n;
         if up == "x" then
            e, n = "y", "z";
         elseif up == "y" then
            e, n = "z", "x";
         elseif up == "z" then
            e, n = "x", "y";
         else
            error("illegal basis direction");
         end

         return setmetatable({ e = e, n = n, u = up }, { __index = class });
      end
   });


local function fileName(x, y, z)
   local xs = math.floor(x);
   local ys = math.floor(y);
   local zs = math.floor(z);
   if xs >= 0 then xs = tostring(xs); else xs = "m" .. tostring(-xs); end
   if ys >= 0 then ys = tostring(ys); else ys = "m" .. tostring(-ys); end
   if zs >= 0 then zs = tostring(zs); else zs = "m" .. tostring(-zs); end
   return FILE_PREFIX .. xs .. "-" .. ys .. "-" .. zs .. FILE_SUFFIX;
end

local isCidExported;
do
   local exportMap = nil;

   isCidExported = function(cid)
      if not exportMap then
         exportMap = {};
         for _, name in ipairs(EXPORT_NODES) do
            local cid = minetest.get_content_id(name);
            exportMap[cid] = true;
         end
      end

      return exportMap[cid] or false;
   end;
end

local function hashVert(pos)
   return (pos.x or 0) + 80*(pos.y or 0) + 6400*(pos.z or 0);
end


local function getObjData(xMin, yMin, zMin, xMax, yMax, zMax)
   local verts = {};
   local quads = {};

   local vertMap = {};

   local function getRowData(basis, xMin, xMax, y, z)
      local vm = minetest.get_voxel_manip();
      local pMin = basis:localToGlobal({ x = xMin, y = y, z = z - 0.5 });
      local pMax = basis:localToGlobal({ x = xMax, y = y, z = z + 0.5 });
      pMin, pMax = vm:read_from_map(pMin, pMax);
      local data = vm:get_data();
      local va = VoxelArea:new({ MinEdge = pMin, MaxEdge = pMax });

      local segs = {};
      local start, wasUp = nil, false;
      for x = xMin, xMax do
         local pL = basis:localToGlobal({ x = x, y = y, z = z - 0.5 });
         local pH = basis:localToGlobal({ x = x, y = y, z = z + 0.5 });
         local haveL = va:containsp(pL) and isCidExported(data[va:indexp(pL)]);
         local haveH = va:containsp(pH) and isCidExported(data[va:indexp(pH)]);
         local on, up = (haveL ~= haveH), haveH;
         if on then
            if not start then
               start, wasUp = x, up;
            elseif up ~= wasUp then
               segs[#segs + 1] = { xs = start, xe = x-1, ys = y, up = wasUp };
               start, wasUp = x, up;
            end
         elseif start then
            segs[#segs + 1] = { xs = start, xe = x-1, ys = y, up = wasUp };
            start = nil;
         end
      end
      if start then segs[#segs + 1] = { xs = start, xe = xMax, ys = y }; end

      return segs;
   end

   local function vertexIndex(basis, pos)
      local vv = basis:localToGlobal(pos);
      local vh = hashVert(vv);
      local vlist = vertMap[vh];
      if vlist then
         for v, vi in pairs(vlist) do
            if v.x == vv.x and v.y == vv.y and v.z == vv.z then
               return vi;
            end
         end
      else
         vlist = {};
         vertMap[vh] = vlist;
      end
      local vi = #verts + 1;
      verts[vi] = vv;
      vlist[vv] = vi;
      return vi;
   end

   local function drawRect(basis, xs, ys, xe, ye, z)
      local vi1 = vertexIndex(basis, { x = xs - 0.5, y = ys - 0.5, z = z });
      local vi2 = vertexIndex(basis, { x = xe + 0.5, y = ys - 0.5, z = z });
      local vi3 = vertexIndex(basis, { x = xe + 0.5, y = ye + 0.5, z = z });
      local vi4 = vertexIndex(basis, { x = xs - 0.5, y = ye + 0.5, z = z });
      quads[#quads + 1] = { vi1, vi2, vi3, vi4 };
   end

   local function drawRects(basis, prevRow, nextRow, y, z)
      local nri = 1;
      local nrSeg = nextRow[nri];

      for _, prSeg in ipairs(prevRow) do
         while nrSeg and nrSeg.xe < prSeg.xs do
            nri = nri + 1;
            nrSeg = nextRow[nri];
         end

         if nrSeg and
               (nrSeg.xs == prSeg.xs) and
               (nrSeg.xe == prSeg.xe) and
               (nrSeg.up == prSeg.up) then
            nrSeg.ys = prSeg.ys;
         else
            drawRect(basis, prSeg.xs, prSeg.ys, prSeg.xe, y, z);
         end
      end
   end

   local function drawSlice(basis, xMin, yMin, xMax, yMax, z)
      local nextRow = getRowData(basis, xMin, xMax, yMin, z);
      for y = yMin+1, yMax do
         local prevRow = nextRow;
         nextRow = getRowData(basis, xMin, xMax, y, z);
         drawRects(basis, prevRow, nextRow, y-1, z);
      end
      drawRects(basis, nextRow, {}, yMax, z);
   end

   local function drawSlices(basis, xMin, yMin, zMin, xMax, yMax, zMax)
      for z = zMin - 0.5, zMax + 0.5 do
         drawSlice(basis, xMin, yMin, xMax, yMax, z);
      end
   end

   for _, up in ipairs({ "x", "y", "z" }) do
      local basis = Basis(up);
      local pMin = basis:globalToLocal({ x = xMin, y = yMin, z = zMin });
      local pMax = basis:globalToLocal({ x = xMax, y = yMax, z = zMax });
      drawSlices(basis, pMin.x, pMin.y, pMin.z, pMax.x, pMax.y, pMax.z);
   end

   return verts, quads;
end

local function exportBlock(pos)
   local xMin = 80 * math.floor(pos.x / 80);
   local yMin = 80 * math.floor(pos.y / 80);
   local zMin = 80 * math.floor(pos.z / 80);
   local xMax = xMin + 79;
   local yMax = yMin + 79;
   local zMax = zMin + 79;

   local fname = fileName(xMin, yMin, zMin);
   local fpath = minetest.get_worldpath() .. "/" .. fname;
   local file, emsg = io.open(fpath, "w");
   if not file then error(emsg); end

   local verts, quads = getObjData(xMin, yMin, zMin, xMax, yMax, zMax);
   for _, v in ipairs(verts) do
      file:write("v "..(v.x-xMin).." "..(v.y-yMin).." "..(v.z-zMin).."\n");
   end
   for _, f in ipairs(quads) do
      file:write("f "..f[1].." "..f[2].." "..f[3].." "..f[4].."\n");
   end

   file:flush();
   file:close();

   return fname;
end


minetest.register_privilege(
   "export",
   {
      description = "Allows exporting of data to files",
      give_to_singleplayer = true
   });

minetest.register_chatcommand(
   "exportblock",
   {
      params = "",
      description = "Exports your current 80x80x80 node block to a file",
      privs = { export = true },
      func =
         function(name, paramStr)
            local player = minetest.get_player_by_name(name);
            local fname = exportBlock(player:getpos());
            return true, "current block exported to " .. fname;
         end
   });

spin
Member
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: 3d printing for kids: modelling objects with Minetest

by spin » Post

Results from sfan5's mt2obj exporter:

This is how the obj looks like imported to Blender. Separate cube objects, 1x1x1 blender units (0.5 radius cubes) arranged in pattern exported from Minetest. Origin point (yellow dot) in the corner of the object, this was the //pos1 I set in Minetest via Worldview.
Image
I then selected everything and merged it into a single object (but not mesh), and exported to .stl. Then I ran it through Slic3r...

Slic3r 1.0.0RC3:
Unfortunately Slic3r failed to produce a printable model. It crashed on the loose meshes, not producing a good result. I used Repetier to display the data (imported into Repetier, sliced from inside Repetier via Slic3r, data display through Repetier). This is how it looked like:
1. is screenshot from import, visible non-manifold warning
2. is the toolpath visible halfway,
3. is the whole toolpath visible from top. This is not nice.
Image

Let's proceed to Cura.
Attachments
Repetier.jpg
(758.51 KiB) Not downloaded yet
obj_in_blender.jpg
(25.81 KiB) Not downloaded yet

spin
Member
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: 3d printing for kids: modelling objects with Minetest

by spin » Post

Cura 14.03 (?)
Not sure about the version, typing from memory

Cura did fine, though had some problems with toolpath display, so I imported the Gcode to Repetier.
Everything is OK, it's read correctly and very printable:
Image

Now on to makerware.
Attachments
Cura.jpg
(719.46 KiB) Not downloaded yet

spin
Member
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: 3d printing for kids: modelling objects with Minetest

by spin » Post

makerware
has internal and surface errors, otherwise OK, so all the printers that work on x3g files can swallow those models no problem:
Image
Attachments
makerware.jpg
(345.68 KiB) Not downloaded yet

spin
Member
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: 3d printing for kids: modelling objects with Minetest

by spin » Post

prestidigitator wrote: Since materials aren't interesting, here's the above mod I posted, modified to export a 3D (on/off) bitmap instead of "color" data:
Prestidigitator, is there a possibility that you could push it to git?

Also, I'm afraid my programming skills are null :( I can do things from tutorials at this point, so I'm no use in doing anything with this for now. If someone who knows bpy could use that data to generate an object in Blender, that would be awesome, but it's way out of my league at this point I'm afraid (both skill- and time-wise).

User avatar
aldobr
Member
Posts: 316
Joined: Sun Nov 25, 2012 05:46

Re: 3D printing for kids: modelling objects with Minetest

by aldobr » Post

I found a much simpler solution, using FreeCAD.

Minetest side script :

Code: Select all

-- FreeCAD exporting MOD - Minetest side
-- Copyright(C) 2014 - J. Aldo Gomes de Freitas Junior
-- GPLv2
-- Minetest side module

-- exporter proper
nodeexporter = {

	-- Populate this array with a list of nodes that should be rendered
	blockmapping = { 
			['default:dirt'] = 1,
			['default:dirt_with_grass'] = 1
		},

	-- Exports a chunk of land starting at ax1, ay1, az1 and ending at ax2, ay2, az2
	exportblocks = function(athis, afilename, ax1, ay1, az1, ax2, ay2, az2)
		local destination = io.open(minetest.get_worldpath() .. "/" .. afilename, "w")
		local x, y, z
		local swapvar
		-- Verify and swap inverted coordinates
		if ax1 > ax2 then
			swapvar = ax2
			ax2 = ax1
			ax1 = swapvar
		end
		if ay1 > ay2 then
			swapvar = ay2
			ay2 = ay1
			ay1 = swapvar
		end
		if az1 > az2 then
			swapvar = az2
			az2 = az1
			az1 = swapvar
		end
		-- Write map chunk size
		destination:write((ax2 - ax1) .. '\n' .. (ay2 - ay1) .. '\n' .. (az2 - az1) .. '\n')
		-- Write map data
		for ly = ay1, ay2 do
			for lx = ax1, ax2 do
				for lz = az1, az2 do
					local node = minetest.env:get_node({ x = lx, y = ly, z = lz })
					local value = athis.blockmapping[node.name]
					if value ~= nil then
						destination:write(value .. '\n')
					else
						destination:write('0\n')
					end
				end
			end
		end
		destination:close()
	end
}

-- Register chat command
minetest.register_chatcommand(
   "mapexport",
   {
      params = "filename x1 y1 z1 x2 y2 z2",
      description = "Exports a piece of game map in a format that can be read by FreeCAD minetest importer plugin.",
      privs = { },
      func =
         function(name, param)
						paramlist = string.split(param, " ")
						local filename = paramlist[1]
						local x1 = tonumber(paramlist[2])
						local y1 = tonumber(paramlist[3])
						local z1 = tonumber(paramlist[4])
						local x2 = tonumber(paramlist[5])
						local y2 = tonumber(paramlist[6])
						local z2 = tonumber(paramlist[7])
						nodeexporter:exportblocks(filename, x1, y1, z1, x2, y2, z2)
            return true, "Exported to " .. filename;
         end
   });
FreeCAD side script:

Code: Select all

# FreeCAD exporting MOD - Minetest side
# Copyright(C) 2014 - J. Aldo Gomes de Freitas Junior
# GPLv2
# FreeCAD side module

import Part, math

def makeCenter(x = 0, y = 0, z = 0):
	return FreeCAD.Vector(x, y, z)

def makeRotation(x = 0, y = 0, z = 0):
	return FreeCAD.Rotation(x, y, z)

def makePlacement(x, y, z, X, Y, Z):
	return FreeCAD.Placement(makeCenter(x, y, z), makeRotation(X, Y, Z))

def importvolumefile(filename, xscale = 10, yscale = 10, zscale = 10):
	cubes = []
	sourcefile = open(filename)
	xsize = int(float(sourcefile.readline()))
	ysize = int(float(sourcefile.readline()))
	zsize = int(float(sourcefile.readline()))
	for yposition in range(1, ysize):
		for xposition in range(1, xsize):
			for zposition in range(1, zsize):
				value = int(float(sourcefile.readline()))
				if value > 0:
					cube = Part.makeBox(zscale, xscale, yscale)
					cube.Placement = makePlacement(xposition * xscale, yposition * yscale, zposition * zscale, 0, 0, 0)
					cubes.append(cube)
	sourcefile.close()
	solid = Part.makeCompound(cubes)
	return solid

# replace filename - needs a beter interface
map = importvolumefile("c:/minetest/minetest-0.4.10/worlds/aldo/teste.vol")
Part.show(map)
Already works in my computer. I can - if trully needed - use FreeCAD boolean operations to fuse all cubes into a single entity, but this is quite a costly operation.

TODO:

Minetest side - Add parameter handling and checking. Populate the mapping table. There are only two entries right now. (dirt and dirt with grass)
FreeCAD side - Add file selection interface. Change tile color by minetest mod mapping. Handle nodebox.

This is the result inside freecad:

https://www.dropbox.com/s/liznoix6ezkx9uy/freecad.png

Basically, i have the whole problem solved here. FreeCAD can export the model in various kinds of formats. Blocks can be edited, etc.

To export a map piece from minetest :

Code: Select all

/minetest <filename> <x1> <y1> <z1> <x2> <y2> <z2>
To import into FreeCAD :

Edit this line:

Code: Select all

# replace filename - needs a beter interface
map = importvolumefile("c:/minetest/minetest-0.4.10/worlds/aldo/teste.vol")
"c:/minetest/minetest-0.4.10/worlds/aldo/teste.vol" is a fully qualified filename that points to a volume that i exported in my harddisk. Replace it with a correct fully qualified path name that points to the correct file inside your computer.

Cubes might happend to be mirrored/inverted, coords might happen to be rotated (x vs y, x vs z etc). Those small bugs need to be fixed by tests. First thing is to pupulate the "blockmapping" array in the lua source code. The blockmap has a simple structure, ["<registerednodename>"] = <value>. Any value above 0 will become a block inside minetest. The is scale is so that each block (node) inside minetest becomes a 10mm x 10mm x 10mm cube inside freecad. The scale can be changed by adding scale values to the importvolumefile call.

Code: Select all

p = importvolumefile(<filename>, [<xscale>, [<yscale>, [<zscale>]]])
Last edited by aldobr on Mon Aug 18, 2014 03:14, edited 10 times in total.

User avatar
prestidigitator
Member
Posts: 640
Joined: Thu Feb 21, 2013 23:54

Re: 3D printing for kids: modelling objects with Minetest

by prestidigitator » Post

Here's an example of a pyramid such as you were trying to export above.

Image
Attachments
blockExportPyramidScreenshot_2014-08-17.png
(5.64 KiB) Not downloaded yet
Last edited by prestidigitator on Mon Aug 18, 2014 02:42, edited 1 time in total.


spin
Member
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: 3D printing for kids: modelling objects with Minetest

by spin » Post

WHOA GUYS :O
I'll test this ASAP and post results, working on a lesson plan now (deadline).

User avatar
aldobr
Member
Posts: 316
Joined: Sun Nov 25, 2012 05:46

Re: 3D printing for kids: modelling objects with Minetest

by aldobr » Post

FreeCAD deals with solid geometry and has a fully constuctive solid geometry system. This is quite printer friendly. If the slicer needs a fused solid made out of the cubes i can easily make FreeCAD fuse the blocks. But this tends to be costly. I still need to implement a menu system inside FreeCAD and a better interface for Minetest. Plus i need to develop a way to export nodebox information (So as to print stairs for one). But this is a more involved development. We might arrange something. Current code is GPLv2.

User avatar
aldobr
Member
Posts: 316
Joined: Sun Nov 25, 2012 05:46

Re: 3D printing for kids: modelling objects with Minetest

by aldobr » Post

Continued development here :

viewtopic.php?f=9&t=9949

spin
Member
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: 3D printing for kids: modelling objects with Minetest

by spin » Post

For completeness: Blender Cycles render from a piece of Minetest map.
Image
full message in screenshots thread: viewtopic.php?f=3&t=156&start=2450#p151540

User avatar
Inocudom
Member
Posts: 3098
Joined: Sat Sep 29, 2012 01:14
IRC: Inocudom
In-game: Inocudom

Re: 3D printing for kids: modelling objects with Minetest

by Inocudom » Post

spin wrote:For completeness: Blender Cycles render from a piece of Minetest map.
Image
full message in screenshots thread: viewtopic.php?f=3&t=156&start=2450#p151540
Impressive. Have you ever tried this with a server?
You can now find my videos at BitChute: https://www.bitchute.com/channel/some_cheeky_jinuskian/

spin
Member
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: 3D printing for kids: modelling objects with Minetest

by spin » Post

Inocudom wrote: Impressive. Have you ever tried this with a server?
It's an .mts file exported with WorldEdit, and then ran over the mt2obj script (link to github above). Should work, but do try.

User avatar
Excalibur Zero
Member
Posts: 142
Joined: Tue Apr 02, 2013 19:45
GitHub: ExcaliburZero
Location: United States
Contact:

Re: 3D printing for kids: modelling objects with Minetest

by Excalibur Zero » Post

I tried using sfan5's mt2obj converter, however I couldn't find out how to get the script to work. When I tried to run the script it just printed a few lines of text and stopped. (http://i.imgur.com/85PGHwq.png) How exactly do you use the script?

User avatar
aldobr
Member
Posts: 316
Joined: Sun Nov 25, 2012 05:46

Re: 3D printing for kids: modelling objects with Minetest

by aldobr » Post

You need to give a filename as parameter

spin
Member
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: 3D printing for kids: modelling objects with Minetest

by spin » Post

Excalibur Zero wrote:I tried using sfan5's mt2obj converter[...]How exactly do you use the script?
I do it like so:
-place your mts map file exported from Minetest with Worldedit (check commands) in mt2obj script's folder
-open Windows command line
-go to the directory you have the script in (using cd to change directory, dir to display contents)
-execute the script by typing either:
- - python mt2obj.py yourmapfile.mts
- - whole python path, like C:\Python27\python.exe mt2obj.py yourmapifile.mts
- import resulting .obj to Blender (involves waiting :/)

Good luck.

spin
Member
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: 3D printing for kids: modelling objects with Minetest

by spin » Post

In the testing I see that day/night cycle restricts visibility, and additional time has to be spent to set up lighting, and this makes classes time spent less effective.

Is there a way to remove or limit the night/day cycle?

User avatar
Topywo
Member
Posts: 1721
Joined: Fri May 18, 2012 20:27

Re: 3D printing for kids: modelling objects with Minetest

by Topywo » Post

spin wrote:In the testing I see that day/night cycle restricts visibility, and additional time has to be spent to set up lighting, and this makes classes time spent less effective.

Is there a way to remove or limit the night/day cycle?
Frome minetest.conf.example
# Interval of sending time of day to clients
#time_send_interval = 5
# Length of day/night cycle. 72=20min, 360=4min, 1=24hour, 0=day/night/whatever stays unchanged
#time_speed = 72
# Length of year in days for seasons change. With default time_speed 365 days = 5 real days for year. 30 days = 10 real hours
#year_days = 30

So copy in your minetest.conf file this line:

time_speed = 0




Edit: some copy/paste typo...

spin
Member
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: 3D printing for kids: modelling objects with Minetest

by spin » Post

Topywo wrote: [...]time_speed = 0
Awesome, thanks!

archesys
New member
Posts: 1
Joined: Sun Jan 31, 2016 12:41
In-game: Viking

Re: 3D printing for kids: modelling objects with Minetest

by archesys » Post

Hi all..

Nothing new since 2014 ?

Sincerely,

Eric

Post Reply

Who is online

Users browsing this forum: No registered users and 5 guests