Voxelers/mcthings

Design and Implement vox2schematic tool

acs opened this issue · 53 comments

acs commented

This tool must be used to import voxels and meshes into McThings (schematics format).

https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox.txt
https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox-extension.txt

The primary goal is to import from vox format fo schematic. For that:

acs commented

Related to this one: #100

acs commented

Maybe we should extend:

https://gitlab.com/bztsrc/mtsedit/blob/master/docs/batch.md

so it exports Schematic format. And that's all!

Add a

-S: output to Schematic

It is implemented in C language, like GNOME :)

acs commented

vox has several importers at:

https://github.com/Zarbuz/FileToVox

So the writting of vox files is well covered here.

And probably also the reading if they have good tests. It is implemented in C# and here we have the reader and writer:

https://github.com/Zarbuz/FileToVox/tree/master/SchematicToVoxCore/Vox

In this tool, it seems all the formats are comnverted to Schematics and the Schematics is converted to Vox. In McThings, my guess is that we will use also Schematics format as the common one. Why? Becase it has solid tools to process it (NBTtools) and the format is simple and flexible and complete.

acs commented

The writing to vox format seems to be pretty easy:

https://gitlab.com/bztsrc/mtsedit/-/commit/80569a64c0c91080699f46fd9a1302b14b1847b2

and it uses the Y, X, Z order as in schematics.

it is writing a header, the data and the palette. If it is so easy to do, probably we can just implement it from scratch and later, create a library with support for reading and writing VOX files like the NBT library.

acs commented

The process for a guy doing the same for Three.js: https://luciopaiva.com/magicavoxel-threejs-howto/

acs commented

VOX uses RIFF format, and in Python there is a module built-in for reading this kind of data:

https://docs.python.org/3.8/library/chunk.html

Great!

So we can do a clean job reading and writing VOX files.

acs commented

So my conclusion is that VOX format is so easy to read and write that:

  • Implement reader and writer for Python using the RIFF Python module. Support both vox formats if possible.
  • The schematic writer is already implemented in McThings, so we just need to read the VOX file, map the voxels color and material to a Minecraft block (using mcpi.block) and save all in schematic format.
    *The parsing will be implemented with objects representing the core concepts:
    • Models
    • Material
    • Palette
    • Scene
    • World

So we have a plan!

acs commented

The name of the first library was vox-io. Not bad. I will use voxpy probably.

Screenshot from 2020-06-15 00-40-38

acs commented

https://github.com/RichysHub/MagicaVoxel-VOX-importer Blender importer for VOX format implemented in Python. A good reference.

And also in https://github.com/jpaver/opengametools they have a reader and writter implemented in C++ based on a vox parser C++ library.

For JS: https://github.com/dgoemans/VoxRenderer

acs commented

Some experiences supporting the new format:

RichysHub/MagicaVoxel-VOX-importer#6

acs commented

A very useful command to see the structure of the vox file:

(venv) strings vxs.vox 
VOX 
MAIN
SIZE
XYZI
nTRN
nGRP
nTRN-
-1 -1 2nSHP
LAYR
_name
LAYR
_name
LAYR
_name
LAYR
_name
LAYR
_name
LAYR
_name
LAYR
_name
LAYR
_name
RGBA
MATL
_type
_diffuse
_weight
_rough
_spec
_spec_p
_ior
_att
-0.5
_flux
_ldr
0MATL
....

acs commented

The proposed reading process for chunks in python lib:

«Usually an IFF-type file consists of one or more chunks. The proposed usage of the Chunk class defined here is to instantiate an instance at the start of each chunk and read from the instance until it reaches the end, after which a new instance can be instantiated. At the end of the file, creating a new instance will fail with an EOFError exception.»

Let's try to follow it! Start a new chunk given the position of the chunk on the file.

A nice example doing just that here: https://www.programcreek.com/python/example/93077/chunk.Chunk

The key is to create Chunk with the file positioned correctly for reading the next chunk. Part of:

https://github.com/pyblish/pyblish-win/blob/master/lib/Python27/Lib/wave.py

And indeed this is a pretty interesing project: https://pyblish.com/ «Pyblish is what enables our artists to focus more on the artistic barrier of raising quality instead of the technical one whilst maintaining a pipeline that raises the bar for both.»

acs commented

Ok, let's try to describe at high level the format in the current version of the file (vox-extension) using the strings command output.

acs commented

So if we want to load 1 model and only the cubes, our focus must be the Model Chunk:

5. Chunk id 'SIZE' : model size
-------------------------------------------------------------------------------
# Bytes  | Type       | Value
-------------------------------------------------------------------------------
4        | int        | size x
4        | int        | size y
4        | int        | size z : gravity direction
-------------------------------------------------------------------------------


6. Chunk id 'XYZI' : model voxels
-------------------------------------------------------------------------------
# Bytes  | Type       | Value
-------------------------------------------------------------------------------
4        | int        | numVoxels (N)
4 x N    | int        | (x, y, z, colorIndex) : 1 byte for each component
-------------------------------------------------------------------------------

and the palette

7. Chunk id 'RGBA' : palette
-------------------------------------------------------------------------------
# Bytes  | Type       | Value
-------------------------------------------------------------------------------
4 x 256  | int        | (R, G, B, A) : 1 byte for each component
                      | * <NOTICE>
                      | * color [0-254] are mapped to palette index [1-255], e.g : 
                      | 
                      | for ( int i = 0; i <= 254; i++ ) {
                      |     palette[i + 1] = ReadRGBA(); 
                      | }
-------------------------------------------------------------------------------

acs commented

In the first iteration the goal is to support the last version of the format, but probably, it is easy to support older formats.

acs commented

Great, it seems it is going to be easy and clean to support VOX format. The code is taking shape at:

https://github.com/acs/mcthings/blob/99-vox2schematics/mcthings/vox.py

acs commented

Great, it is a bit tricky to use the chunk python lib to read the vox file, but once I know how to do it, it will be much maintainable having the Chunk concept supported in the logic. 2h aprox to have a first working version.

acs commented

Ok, now we can read the blocks and the colors from a MagicaVoxel file. Cool! Now it is time to map it to Minecraft. And this is a tough problem because we don't have all colors in Minecraft. Using wool we can replicate partially the colors.

https://www.stuffaboutcode.com/p/minecraft-api-reference.html

Data Values of blocks:
WOOL:
0: White
1: Orange
2: Magenta
3: Light Blue
4: Yellow
5: Lime
6: Pink
7: Grey
8: Light grey
9: Cyan
10: Purple
11: Blue
12: Brown
13: Green
14: Red
15: Black

So we need to map the RGBA colors to this ones. The best thing is to have a Minecraft palette in MagicaVoxel to create the models using them. In this case, let's do a hack:

ee 00 00 is 14.

acs commented

Ok, here we go:

Screenshot from 2020-06-28 10-16-32

from

Screenshot from 2020-06-28 10-19-11

acs commented

mv2mc

acs commented

Colors from 15 to 0:

mc_colors

we need to create a magicavoxel palette with them (we need the hex codes for them).

COLORS = [
        "White",
        "Orange",
        "Magenta",
        "Light Blue",
        "Yellow",
        "Lime",
        "Pink",
        "Grey",
        "Light grey",
        "Cyan",
        "Purple",
        "Blue",
        "Brown",
        "Green",
        "Red",
        "Black"
    ]

https://gaming.stackexchange.com/questions/47212/what-are-the-color-values-for-dyed-wool

• White - FFe4e4e4
• Orange - FFea7e35
• Magenta - FFbe49c9
• Light Blue - FF6387d2
• Yellow - FFc2b51c
• Lime Green - FF39ba2e
• Pink - FFd98199
• Dark Gray - FF414141
• Light Gray - FFa0a7a7
• Cyan - FF267191
• Purple - FF7e34bf
• Blue - FF253193
• Brown - FF56331c
• Green - FF364b18
• Red - FF9e2b27
• Black - FF181414

So our next step is to create a palette in MagicaVoxel with this colors.

acs commented

But before working at the color detail, let's check all is working with some models in vox format.

One of our goals is to support the loading of:

https://github.com/mikelovesrobots/mmmm

And maybe this is the old version format. The goal is to support it also. So let's work on that.

Let's play with this one wich is 8 (z) x 4 (x) x 11 (y): 332 blocks. alien_engi1a

Screenshot from 2020-06-28 18-05-06

It has 4 colors: blue, black, gray and light gray. So an accurate job could be done!

It is a 6 years old model, and I love to support this old models!!! Let's do it 💯

The old format is simpler:

(venv) strings alien_engi1a.vox 
VOX 
MAIN
SIZE
XYZI
RGBA

To check the correct loading of the palette we can do it in MV. For each palette there are 32 * 8 = 256 colors.

And we can check the colors in MV:

Screenshot from 2020-06-28 21-08-22

To check the full palette:

Screenshot from 2020-06-28 21-01-10

In this palette the first color is (index 1): ffffff . The index 2: ffffcc. index 3: ffff99.

and the last color is index 255 is 111111. The 249 is aaaaaa (256 can not be selected and it is not part of the palette). So the palette goes from 0 to 254 (at least in the old version).

¿Is that the default one? I think so (but in the file, index 1 is 000000, and the colors are in different order: ffff99 is 99ffff.

Let's check that we are reading the palette correctly (I am pretty sure there are no issues with the blocks).

acs commented

The results are promising.

alien_engi1a_mc

As expected we need to fix the colors. But we are in the right path!

acs commented

Ok, before putting all focus in the colors transformation, let's try to conversion to Schematic. This is something already available in McThings, so just testing the plumbing.

The goal is to generate the Voxelers logo as a Schematic.

Screenshot from 2020-06-28 23-23-45

Loaded from a Schematic. For some reason we are exporting 24 blocks instead of 6. We need to review it, but it is working in the dev branch for vox support.

Screenshot from 2020-06-28 23-26-55

The problem is "x-axis" that must be 1 and it is 4. I will recheck it.

Screenshot from 2020-06-29 05-29-12

So the problem is the self.position. If we use init_pos and end_pos for schematic extraction, it will work. But why self.position is not init_pos? Let's review.

It is working nicely. Why? Let's take a look to MV:

Screenshot from 2020-06-29 05-41-28

The position of z is +3, x +1 and y +0- So the blocks go from z:0, 2 x:0, 3 y:0,1 (3 x 4 x 2 = 24). So the schematic is perfect. In order to avoid the offset, we need to create in MV without offset.

Screenshot from 2020-06-29 05-50-20

And using this vox model we get in the schematic:

2020-06-29 05:51:12,466 Schematic: Exporting blocks: 6

And we get the right number of blocks (3 empty blocks, and 3 red blocks)

acs commented

Ok, time to create our Minecraft wool palette for MV.

https://gaming.stackexchange.com/questions/47212/what-are-the-color-values-for-dyed-wool

• White -      e4e4e4
• Orange -     ea7e35
• Magenta -    be49c9
• Light Blue - 6387d2
• Yellow -     c2b51c
• Lime Green - 39ba2e
• Pink -       d98199
• Dark Gray -  414141
• Light Gray - a0a7a7
• Cyan -       267191
• Purple -     7e34bf
• Blue -       253193
• Brown -      56331c
• Green -      364b18
• Red -        9e2b27
• Black -      181414

Screenshot from 2020-06-29 06-33-08

minecraft_wool_palette

acs commented

wool_wall

Mostly we have it! It is flipped but this should be easy to fix.

acs commented

Ok, just pending:

  • Fix the flipped
  • Review the code to refactor if if needed
  • Add tests
    • Number of voxels imported/exported
    • Colors
  • Define a demo plan to show the possibilities of the MV and MC integration
    • use the shaders in MV to create cool regions in MC
    • use the minibots to create a museum with them in MC
  • Implement a command line tool
  • Dissemination of the new feature in the forums
acs commented

In order to fix the flip issue, the best approach is to implement the flip operation in mcthings: #112

But we have not a flip issue. It is just to look to the wall from the right side (the same side we use in MV).

wool_wall_ok

But, is it the same for the alien robot? No

alien_flip

And we have the same issue when going through vox->obj->binvox->schematic

The problem is that in general x grows in this direction >--->---> but in MC it grows in <----<-----< (and the same for z). So we need to flip.

acs commented

Much better now with the flip operation implemented.

Screenshot from 2020-06-30 08-33-17

acs commented

Ok, let's play with colors and then review code, improve tests, prepare demos and implement the command line tool and disseminate.

acs commented

Let's try to reproduce the alien colors in Minecraft. For doing it:

  • Open the alien vox model
  • Load the Minecraft palette
  • Change colors to one of the 16 from Minecraft palette
  • Save the vox model
  • Import it in McThings and check the results

This is a general workflow to be done each time you want to have valid colors inside Minecraft.

Also, we can add more colors using other blocks in Minecraft:

  • Red Stone
  • Gold
  • Diamond
  • ...
acs commented

But first, let's check if flip_z is needed also. And let's do it by default when loading VOX data for both use cases. Let's play with the model veh_ambulance.vox:

Screenshot from 2020-07-01 05-15-57

Screenshot from 2020-07-01 05-23-48

acs commented

Ok, it seems there are no flipping issues in z-axis. Let's try to recreate the ambulance colors.

For doing it, let's use the MC palette y MV.

Screenshot from 2020-07-01 05-27-12

Screenshot from 2020-07-01 05-28-12

To the left the original one, to the right using the MC wool colors:

Screenshot from 2020-07-01 05-37-59

and the result in MC:

Screenshot from 2020-07-01 05-41-24

The dark gray wool is getting red wool for some reason. But the rest of the colors are ok. Bug found: the grey in this region is not the MC one, but the empty one without color!

Screenshot from 2020-07-01 05-54-12

acs commented

Ok, just pending:

  • Implement the command line tool
  • Add unit testing using the in memory version
  • Create a video doing the ambulance with colors
acs commented

Command line tool

vox2schematic:

  • Input file to convert
  • Optional output file

In the first version that's all. In new version we can add an optional map from MV colors to MC blocks/wool colors.

The tool will work from memory version of the models, so it must be pretty fast. Test it with the 400 models from Mike.

acs commented

Goals:

acs commented

Ok, let's create the tool: vox2schematic. At some point it could be also interesting the schematic2vox, but I think it is less interesting.

acs commented

Ok, right now we are collecting the data in build_schematic_nbt from the data in the renderer. But this information is available in memory also, because we are using the Minecraft format for the memory schemas. So we need to have at least a method build_schematic_nbt_from_memory that uses the data in memory and that does not try to collect the data from the renderer.

But we are pretty close to have the feature implemented.

acs commented

Ok, the script is working:

(venv) bin/vox2schematic.py ~/devel/mmmm/vox/obj_house6.vox -o tests/schematics/obj_house6.schematic

It is slow, but increase the performace should be easy to reach a reasonable performance.

Screenshot from 2020-07-02 18-55-42
Screenshot from 2020-07-02 18-55-30

For example, with this house with 78336 blocks, it has not finished yet after 5 minutes. So let's implement the first improvement.

Fixed the performance issue:

(venv) bin/vox2schematic.py ~/devel/mmmm/vox/obj_house6.vox -o tests/schematics/obj_house6.schematic
2020-07-02 19:12:20,855 Vox input file: /home/adelcastillo/devel/mmmm/vox/obj_house6.vox
2020-07-02 19:12:20,855 Schematic output file: tests/schematics/obj_house6.schematic
2020-07-02 19:12:22,006 Schematic: Exporting blocks: 78336
2020-07-02 19:12:22,053 Creating the memory cache with positions
2020-07-02 19:12:22,119 Done memory cache with positions
2020-07-02 19:12:22,552 Schematic export finished in 0.55 secs

and the schematic result is ...

Screenshot from 2020-07-02 19-15-57
Screenshot from 2020-07-02 19-15-25

acs commented

5 minutes investment colouring the house:

Screenshot from 2020-07-02 19-21-51
Screenshot from 2020-07-02 19-28-38

and the result in Minecraft:

(venv) bin/vox2schematic.py ~/devel/voxels/MagicaVoxel-0.99.5.1-win64/export/obj_house6-mc.vox -o tests/schematics/obj_house6-mc.schematic
....
    voxel_color = self.palette[voxel.color_index]
IndexError: list index out of range

Found a bug. Let's fix it! The format of the file is different, We need to improve our parser. The problem is that for some reason during colouring two models were created. Right now, only one model is supported. Fixed.

And the result house:

Screenshot from 2020-07-03 06-25-34
Screenshot from 2020-07-03 06-24-53

acs commented

The main issue with this house is that it is for giants. So it is not at the right dimension for MC. So we need to work in MV at a smaller scale so the creations are natural inside the MC world. But this can be done. But it is a new way to create inside MV: for Minecraft. And also, the models are filled, so the house is a thick block.

So this kind of models are not useful in Minecraft to interact with them. So the question is .... is it better to create in MV that inside MC directly? My guess is that yes, but we need to improve the MC blocks can be used inside MV, and there are things that will be done better inside MC.

acs commented

Ok, so next steps:

  • Add unit testing using the in memory version
  • Release the tool
  • Create a video doing the ambulance with colours
  • Use the MV shaders to create regions and import them into MC
acs commented

Tool included in 0.51.1 and working.

Next step is to put focus in the tests!!

acs commented

About the tool, we need to capture the exceptions if the format is not the expected one: only one model for legacy and current format.

acs commented

Hay muchos conversores de otros formatos a VOX (https://github.com/Eisenwave/voxel-io y otros proyectos), así que todos ellos los podríamos llevar a Minecraft.

acs commented

More repos with models to test the conversor: https://www.mediafire.com/folder/a0znmricqxlkz/Free_Voxels

acs commented

Should we add the multi model support? Probably not in the first iteration: it is complex to have useful results with complete scenes ... but it is pretty alignet with McThings. The scene could be broken in schematics and added individually.

acs commented

Probably if we can not convert a color to the right Minecraft one, it is better to leave the block as a grey one (or stone or a fixed block).

acs commented

Ok, next steps:

acs commented

Using an improved version of the automatic coloring based on the above proposal the results are:

Screenshot from 2020-07-04 09-08-18
Screenshot from 2020-07-04 09-11-47
Screenshot from 2020-07-04 09-08-36
Screenshot from 2020-07-04 09-12-00
Screenshot from 2020-07-04 09-12-22

acs commented

Ok, time to close this ticket! The tool is ready, with doc and tweeter dissemination also done. Let's see the impact.

https://github.com/Voxelers/mcthings/tree/develop/bin

Hey acs, I was wondering were you able to get it to scale for a 1 to 1 ratio. For instance, seeing the house it was huge, did you get it to scale in MC?

Also, does your tool support each different type of block?

I have been trying to find something that will scale my 3d assets correctly in MC for years.

As I want that one meter in blender or just magic voxel to MC.

Would you know where I could go for something like this? Thanks.

acs commented

Hi @HelixCreations ,

Hey acs, I was wondering were you able to get it to scale for a 1 to 1 ratio. For instance, seeing the house it was huge, did you get it to scale in MC?

No, I have not found a way to fix the scale. And I think that it is not possible to fix this problem in a general way. In order to create models for MC with MV, you need to work in MC scale in MV.

Also, does your tool support each different type of block?

Each different type of block in MC? No, the goal is to support the designs that can be created in MV. And in MV you have:

  • Blocks
  • Colors
  • Materials

Right now the support is pretty basic. Support the colors using the wood colors in MC. And if you have selected a specific material in MV that exists in MC, use the material to define the block in MC instead of the color (for example, glass material).

I have been trying to find something that will scale my 3d assets correctly in MC for years.

The problem is that blocks in MC are fixed to 1x1x1 meter and you can not change that. So you need to create your models with this limitation in mind. You can not have a better resolution in MC.

As I want that one meter in blender or just magic voxel to MC.

In MV just work with this requirement in mind when you create the models: the voxel are 1x1x1 meter.

In blender, I want to play with remesh but at the end, the problem is the same. You can not work in MC with more
detailed models.

Would you know where I could go for something like this? Thanks.

Cheers!